ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
PortableLpModelWriter.cs
Go to the documentation of this file.
1using System.Globalization;
2using System.Text;
4
6
7/// <summary>
8/// Writes a conservative LP representation understood by all four supported
9/// execution backends.
10/// </summary>
11/// <remarks>
12/// Stable names <c>v_&lt;id&gt;</c> are used instead of semantic model names so
13/// solution-file parsing is independent of punctuation and provider-specific
14/// name normalization.
15/// </remarks>
16public sealed class PortableLpModelWriter
17{
18 /// <summary>Gets the stable portable variable name.</summary>
19 public static string GetVariableName(
20 int variableId) =>
21 $"v_{variableId}";
22
23 /// <summary>Writes the supplied model to an LP file.</summary>
24 public void Write(
25 LinearModel model,
26 string path)
27 {
28 ArgumentNullException.ThrowIfNull(model);
29 ArgumentException.ThrowIfNullOrWhiteSpace(path);
30
31 string fullPath =
32 Path.GetFullPath(path);
33
34 string? directory =
35 Path.GetDirectoryName(fullPath);
36
37 if (!string.IsNullOrWhiteSpace(directory))
38 {
39 Directory.CreateDirectory(directory);
40 }
41
42 using var writer =
43 new StreamWriter(
44 fullPath,
45 append: false,
46 new UTF8Encoding(
47 encoderShouldEmitUTF8Identifier: false));
48
49 writer.WriteLine(
50 "\\ Generated by ULSAlgorithms portable solver execution layer");
51
52 writer.WriteLine("Minimize");
53 writer.Write(" obj: ");
54
55 // The objective constant is deliberately omitted from the LP file.
56 // It cannot alter the optimizer's decisions and is added back by the
57 // independent objective reconstruction.
58 WriteExpression(
59 writer,
60 model.Objective.Terms);
61
62 writer.WriteLine();
63 writer.WriteLine("Subject To");
64
65 for (int index = 0;
66 index < model.Constraints.Count;
67 index++)
68 {
69 LinearConstraint constraint =
70 model.Constraints[index];
71
72 writer.Write(
73 $" c_{index}: ");
74
75 WriteExpression(
76 writer,
77 constraint.Terms);
78
79 writer.Write(
80 constraint.Sense switch
81 {
82 LinearConstraintSense.LessOrEqual => " <= ",
83 LinearConstraintSense.Equal => " = ",
84 LinearConstraintSense.GreaterOrEqual => " >= ",
85 _ =>
86 throw new NotSupportedException(
87 $"Unsupported constraint sense '{constraint.Sense}'.")
88 });
89
90 writer.WriteLine(
91 FormatNumber(
92 constraint.RightHandSide));
93 }
94
95 writer.WriteLine("Bounds");
96
97 foreach (LinearVariable variable in model.Variables)
98 {
99 WriteBounds(
100 writer,
101 variable);
102 }
103
104 LinearVariable[] generals =
105 model.Variables
106 .Where(
107 static variable =>
108 variable.Type ==
109 LinearVariableType.Integer)
110 .ToArray();
111
112 if (generals.Length > 0)
113 {
114 writer.WriteLine("Generals");
115
116 foreach (LinearVariable variable in generals)
117 {
118 writer.WriteLine(
119 $" {GetVariableName(variable.Id)}");
120 }
121 }
122
123 LinearVariable[] binaries =
124 model.Variables
125 .Where(
126 static variable =>
127 variable.Type ==
128 LinearVariableType.Binary)
129 .ToArray();
130
131 if (binaries.Length > 0)
132 {
133 writer.WriteLine("Binaries");
134
135 foreach (LinearVariable variable in binaries)
136 {
137 writer.WriteLine(
138 $" {GetVariableName(variable.Id)}");
139 }
140 }
141
142 writer.WriteLine("End");
143 }
144
145 private static void WriteExpression(
146 TextWriter writer,
147 IEnumerable<LinearTerm> terms)
148 {
149 bool wroteTerm = false;
150
151 foreach (LinearTerm term in terms)
152 {
153 double coefficient =
154 term.Coefficient;
155
156 if (coefficient == 0.0)
157 {
158 continue;
159 }
160
161 if (wroteTerm)
162 {
163 writer.Write(
164 coefficient >= 0.0
165 ? " + "
166 : " - ");
167 }
168 else if (coefficient < 0.0)
169 {
170 writer.Write("-");
171 }
172
173 double magnitude =
174 Math.Abs(coefficient);
175
176 if (magnitude != 1.0)
177 {
178 writer.Write(
179 FormatNumber(magnitude));
180
181 writer.Write(" ");
182 }
183
184 writer.Write(
186 term.VariableId));
187
188 wroteTerm = true;
189 }
190
191 if (!wroteTerm)
192 {
193 writer.Write("0");
194 }
195 }
196
197 private static void WriteBounds(
198 TextWriter writer,
199 LinearVariable variable)
200 {
201 string name =
202 GetVariableName(variable.Id);
203
204 if (variable.LowerBound ==
205 variable.UpperBound)
206 {
207 writer.WriteLine(
208 $" {name} = {FormatNumber(variable.LowerBound)}");
209
210 return;
211 }
212
213 if (!double.IsPositiveInfinity(
214 variable.UpperBound))
215 {
216 writer.WriteLine(
217 $" {FormatNumber(variable.LowerBound)} <= {name} <= " +
218 $"{FormatNumber(variable.UpperBound)}");
219
220 return;
221 }
222
223 writer.WriteLine(
224 $" {FormatNumber(variable.LowerBound)} <= {name}");
225 }
226
227 private static string FormatNumber(
228 double value)
229 {
230 if (!double.IsFinite(value))
231 {
232 throw new ArgumentOutOfRangeException(
233 nameof(value),
234 value,
235 "LP coefficients and finite bounds must be finite.");
236 }
237
238 return value.ToString(
239 "G17",
240 CultureInfo.InvariantCulture);
241 }
242}
Writes a conservative LP representation understood by all four supported execution backends.
void Write(LinearModel model, string path)
Writes the supplied model to an LP file.
static string GetVariableName(int variableId)
Gets the stable portable variable name.
Describes one portable linear constraint.
LinearConstraintSense Sense
Gets the constraint sense.
IReadOnlyList< LinearTerm > Terms
Gets the nonzero terms.
Immutable solver-independent linear or mixed-integer linear model.
Definition LinearModel.cs:7
LinearObjective Objective
Gets the minimization objective.
IReadOnlyList< LinearConstraint > Constraints
Gets all constraints.
IReadOnlyList< LinearTerm > Terms
Gets nonzero objective terms.
Describes one variable in a portable linear mathematical model.
LinearVariableType Type
Gets the variable domain.
int Id
Gets the stable zero-based variable identifier.
LinearVariableType
Identifies the domain of a variable in a portable linear mathematical model.
Stores one coefficient of a portable linear expression.
Definition LinearTerm.cs:7
int VariableId
Gets the referenced variable identifier.
Definition LinearTerm.cs:31
double Coefficient
Gets the coefficient.
Definition LinearTerm.cs:34