LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
MathematicalModelCandidateEvaluator.cs
Go to the documentation of this file.
3
5
7{
8 private readonly MathematicalModel _model;
9 private readonly MathematicalVariable[] _variables;
10 private readonly Dictionary<int, int> _indexByVariableId;
11
14 {
15 ArgumentNullException.ThrowIfNull(
16 model);
17
18 model.EnsureValid();
19
20 _model =
21 model;
22
23 _variables =
24 model.Variables
25 .OrderBy(
26 variable =>
27 variable.Id)
28 .ToArray();
29
30 if (_variables.Length == 0)
31 {
32 throw new InvalidOperationException(
33 "A metaheuristic mathematical model requires at least one variable.");
34 }
35
36 _indexByVariableId =
37 _variables
38 .Select(
39 (variable, index) =>
40 new
41 {
42 variable.Id,
43 Index = index
44 })
45 .ToDictionary(
46 entry =>
47 entry.Id,
48 entry =>
49 entry.Index);
50 }
51
52 public IReadOnlyList<MathematicalVariable> Variables =>
53 _variables;
54
55 public int Dimension =>
56 _variables.Length;
57
58 public double EvaluateObjective(
59 IReadOnlyList<double> values)
60 {
61 return EvaluateExpression(
62 _model.Objective.Expression,
63 values);
64 }
65
66 public double EvaluateExpression(
67 LinearExpression expression,
68 IReadOnlyList<double> values)
69 {
70 ArgumentNullException.ThrowIfNull(
71 expression);
72
73 EnsureDimension(
74 values);
75
76 double result =
77 expression.Constant;
78
79 foreach (LinearTerm term
80 in expression.Terms)
81 {
82 if (!_indexByVariableId.TryGetValue(
83 term.VariableId,
84 out int index))
85 {
86 throw new InvalidOperationException(
87 $"Expression references unknown variable identifier '{term.VariableId}'.");
88 }
89
90 result +=
91 term.Coefficient *
92 values[index];
93 }
94
95 if (!double.IsFinite(
96 result))
97 {
98 throw new InvalidOperationException(
99 "Candidate expression evaluation must be finite.");
100 }
101
102 return result;
103 }
104
106 LinearConstraint constraint,
107 IReadOnlyList<double> values)
108 {
109 ArgumentNullException.ThrowIfNull(
110 constraint);
111
112 double leftHandSide =
114 constraint.LeftHandSide,
115 values);
116
117 return constraint.Sense switch
118 {
120 leftHandSide -
121 constraint.RightHandSide,
122
124 constraint.RightHandSide -
125 leftHandSide,
126
128 leftHandSide -
129 constraint.RightHandSide,
130
131 _ =>
132 throw new NotSupportedException(
133 $"Constraint sense '{constraint.Sense}' is not supported by the metaheuristic bridge.")
134 };
135 }
136
137 public bool IsIntegerFeasible(
138 IReadOnlyList<double> values,
139 double tolerance = 1.0e-7)
140 {
141 EnsureDimension(
142 values);
143
144 EnsureTolerance(
145 tolerance);
146
147 for (int index = 0;
148 index < _variables.Length;
149 index++)
150 {
151 MathematicalVariable variable =
152 _variables[index];
153
154 double value =
155 values[index];
156
157 if (!double.IsFinite(
158 value))
159 {
160 return false;
161 }
162
163 if (value <
164 variable.LowerBound -
165 tolerance ||
166 value >
167 variable.UpperBound +
168 tolerance)
169 {
170 return false;
171 }
172
173 switch (variable.VariableType)
174 {
175 case MathematicalVariableType.Continuous:
176 break;
177
178 case MathematicalVariableType.Integer:
179 if (Math.Abs(
180 value -
181 Math.Round(
182 value,
183 MidpointRounding.AwayFromZero)) >
184 tolerance)
185 {
186 return false;
187 }
188
189 break;
190
191 case MathematicalVariableType.Binary:
192 if (Math.Abs(value) >
193 tolerance &&
194 Math.Abs(value - 1.0) >
195 tolerance)
196 {
197 return false;
198 }
199
200 break;
201
202 case MathematicalVariableType.SemiContinuous:
203 case MathematicalVariableType.SemiInteger:
204 throw new NotSupportedException(
205 "Semi-continuous and semi-integer domains are not enabled in alpha.37.");
206
207 default:
208 throw new NotSupportedException(
209 $"Variable type '{variable.VariableType}' is not supported by alpha.37.");
210 }
211 }
212
213 return true;
214 }
215
217 IReadOnlyList<double> values,
218 double equalityTolerance = 1.0e-6)
219 {
220 EnsureDimension(
221 values);
222
223 EnsureTolerance(
224 equalityTolerance);
225
226 foreach (LinearConstraint constraint
227 in _model.Constraints)
228 {
229 if (!constraint.IsEnabled)
230 {
231 continue;
232 }
233
234 double residual =
236 constraint,
237 values);
238
239 if (constraint.Sense ==
241 {
242 if (Math.Abs(
243 residual) >
244 equalityTolerance)
245 {
246 return false;
247 }
248 }
249 else if (residual >
250 equalityTolerance)
251 {
252 return false;
253 }
254 }
255
256 return true;
257 }
258
259 public bool IsFeasible(
260 IReadOnlyList<double> values,
261 double equalityTolerance = 1.0e-6)
262 {
263 return IsIntegerFeasible(
264 values,
265 equalityTolerance) &&
267 values,
268 equalityTolerance);
269 }
270
271 public double[] ExtractCompleteValues(
273 {
274 ArgumentNullException.ThrowIfNull(
275 solveResult);
276
277 var values =
278 new double[_variables.Length];
279
280 for (int index = 0;
281 index < _variables.Length;
282 index++)
283 {
284 MathematicalVariable variable =
285 _variables[index];
286
288 solveResult.FindVariableValue(
289 variable.Id);
290
291 if (value is null)
292 {
293 throw new InvalidOperationException(
294 $"Solver result does not contain variable identifier '{variable.Id}'.");
295 }
296
297 values[index] =
298 value.Value;
299 }
300
301 return values;
302 }
303
304 private void EnsureDimension(
305 IReadOnlyList<double> values)
306 {
307 ArgumentNullException.ThrowIfNull(
308 values);
309
310 if (values.Count !=
311 Dimension)
312 {
313 throw new ArgumentException(
314 $"Expected candidate dimension {Dimension}, received {values.Count}.",
315 nameof(values));
316 }
317 }
318
319 private static void EnsureTolerance(
320 double tolerance)
321 {
322 if (!double.IsFinite(
323 tolerance) ||
324 tolerance < 0.0)
325 {
326 throw new ArgumentOutOfRangeException(
327 nameof(tolerance));
328 }
329 }
330}
bool IsConstraintFeasible(IReadOnlyList< double > values, double equalityTolerance=1.0e-6)
double EvaluateCanonicalConstraintResidual(LinearConstraint constraint, IReadOnlyList< double > values)
Stores the solver result for a solver-independent mathematical model.
MathematicalVariableValue? FindVariableValue(int variableId)
Finds a variable value by mathematical-variable identifier.
Stores the value returned by a solver for one mathematical decision variable.
double Value
Gets or sets the value returned by the solver.
Represents one linear constraint in a mathematical optimization model.
double RightHandSide
Gets or sets the right-hand-side constant value.
MathematicalConstraintSense Sense
Gets or sets the relational sense of the constraint.
bool IsEnabled
Gets or sets a value indicating whether the constraint is enabled.
LinearExpression LeftHandSide
Gets or sets the left-hand-side linear expression.
Represents a linear expression composed of variable terms and a constant value.
double Constant
Gets or sets the constant value of the expression.
Represents one coefficient-variable term in a linear expression.
Definition LinearTerm.cs:13
int VariableId
Gets or sets the identifier of the referenced mathematical variable.
Definition LinearTerm.cs:49
Represents a solver-independent mathematical optimization model.
void EnsureValid()
Validates the complete mathematical model.
Represents one decision variable in a mathematical optimization model.
MathematicalVariableType VariableType
Gets or sets the variable domain.
int Id
Gets or sets the unique variable identifier within the mathematical model.
double LowerBound
Gets or sets the variable lower bound.
double UpperBound
Gets or sets the variable upper bound.
MathematicalConstraintSense
Identifies the relational sense of a mathematical constraint.
@ GreaterThanOrEqual
The left-hand side must be greater than or equal to the right-hand side.
@ LessThanOrEqual
The left-hand side must be less than or equal to the right-hand side.
@ Equal
The left-hand side must be equal to the right-hand side.
MathematicalVariableType
Identifies the domain of a mathematical decision variable.