LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
MetaheuristicsPlatformExactRepairSubproblemBuilder.cs
Go to the documentation of this file.
2using MetaheuristicsPlatform.Matheuristics;
3
5
7{
9 MathematicalModel sourceModel,
10 ExactRepairRequest request)
11 {
12 ArgumentNullException.ThrowIfNull(
13 sourceModel);
14
15 ArgumentNullException.ThrowIfNull(
16 request);
17
18 sourceModel.EnsureValid();
19
20 EnsureSupportedMode(
21 request);
22
23 MathematicalModel result =
24 sourceModel.Clone();
25
26 MathematicalVariable[] variables =
27 result.Variables
28 .OrderBy(
29 variable =>
30 variable.Id)
31 .ToArray();
32
33 ApplyBounds(
34 variables,
35 request);
36
37 ApplyAllowedActiveIndices(
38 variables,
39 request);
40
41 int nextConstraintId =
42 result.Constraints.Count == 0
43 ? 1
44 : result.Constraints.Max(
45 constraint =>
46 constraint.Id) + 1;
47
48 if (request.HammingRadius.HasValue)
49 {
50 nextConstraintId =
51 AddHammingConstraint(
52 result,
53 variables,
54 request,
55 nextConstraintId);
56 }
57
58 if (request.ObjectiveCutoff.HasValue)
59 {
60 AddObjectiveCutoff(
61 result,
62 request.ObjectiveCutoff.Value,
63 nextConstraintId);
64 }
65
66 result.EnsureValid();
67
68 return result;
69 }
70
72 MathematicalModel sourceModel,
73 IReadOnlyList<double> referenceValues,
74 int hammingRadius,
75 int nodeLimit)
76 {
77 ArgumentNullException.ThrowIfNull(
78 referenceValues);
79
80 return BuildExact(
81 sourceModel,
82 new ExactRepairRequest
83 {
84 Mode =
85 MatheuristicSolveMode.OriginalObjective,
86
87 ReferenceValues =
88 referenceValues,
89
90 HammingRadius =
91 hammingRadius,
92
93 NodeLimit =
94 nodeLimit
95 });
96 }
97
99 MathematicalModel sourceModel,
100 ExactRepairRequest request)
101 {
102 MathematicalModel result =
104 sourceModel,
105 request);
106
107 foreach (MathematicalVariable variable
108 in result.Variables)
109 {
110 if (variable.VariableType is
111 MathematicalVariableType.Integer or
113 {
114 variable.VariableType =
115 MathematicalVariableType.Continuous;
116 }
117 }
118
119 result.EnsureValid();
120
121 return result;
122 }
123
124 private static void EnsureSupportedMode(
125 ExactRepairRequest request)
126 {
127 if (request.NodeLimit <= 0)
128 {
129 throw new InvalidOperationException(
130 "An exact-repair node limit must be strictly positive.");
131 }
132
133 if (request.Mode !=
134 MatheuristicSolveMode.OriginalObjective)
135 {
136 throw new NotSupportedException(
137 $"Alpha.37 exact-repair bridge supports OriginalObjective mode only; received '{request.Mode}'.");
138 }
139
140 if (request.DistanceLimit.HasValue ||
141 request.TargetValues is not null)
142 {
143 throw new NotSupportedException(
144 "Distance-target exact-repair modes are deferred beyond alpha.37.");
145 }
146 }
147
148 private static void ApplyBounds(
149 IReadOnlyList<MathematicalVariable> variables,
150 ExactRepairRequest request)
151 {
152 foreach (KeyValuePair<int, MatheuristicVariableBound> bound
153 in request.Bounds)
154 {
155 MathematicalVariable variable =
156 GetVariable(
157 variables,
158 bound.Key);
159
160 EnsureBoundInsideSource(
161 variable,
162 bound.Value.Lower,
163 bound.Value.Upper);
164
165 variable.LowerBound =
166 bound.Value.Lower;
167
168 variable.UpperBound =
169 bound.Value.Upper;
170 }
171
172 foreach (KeyValuePair<int, double> fixing
173 in request.FixedValues)
174 {
175 MathematicalVariable variable =
176 GetVariable(
177 variables,
178 fixing.Key);
179
180 EnsureBoundInsideSource(
181 variable,
182 fixing.Value,
183 fixing.Value);
184
185 EnsureValueMatchesType(
186 variable,
187 fixing.Value);
188
189 variable.LowerBound =
190 fixing.Value;
191
192 variable.UpperBound =
193 fixing.Value;
194 }
195 }
196
197 private static void ApplyAllowedActiveIndices(
198 IReadOnlyList<MathematicalVariable> variables,
199 ExactRepairRequest request)
200 {
201 if (request.AllowedActiveIndices is null)
202 {
203 return;
204 }
205
206 var allowed =
207 new HashSet<int>(
208 request.AllowedActiveIndices);
209
210 for (int index = 0;
211 index < variables.Count;
212 index++)
213 {
214 MathematicalVariable variable =
215 variables[index];
216
217 if (variable.VariableType !=
219 allowed.Contains(
220 index))
221 {
222 continue;
223 }
224
225 EnsureBoundInsideSource(
226 variable,
227 0.0,
228 0.0);
229
230 variable.LowerBound =
231 0.0;
232
233 variable.UpperBound =
234 0.0;
235 }
236 }
237
238 private static int AddHammingConstraint(
239 MathematicalModel model,
240 IReadOnlyList<MathematicalVariable> variables,
241 ExactRepairRequest request,
242 int constraintId)
243 {
244 if (request.ReferenceValues is null)
245 {
246 throw new InvalidOperationException(
247 "A Hamming-radius request requires reference values.");
248 }
249
250 if (request.ReferenceValues.Count !=
251 variables.Count)
252 {
253 throw new InvalidOperationException(
254 "Hamming reference dimension does not match the mathematical model.");
255 }
256
257 int radius =
258 request.HammingRadius ??
259 throw new InvalidOperationException(
260 "A Hamming radius is required.");
261
262 if (radius < 0)
263 {
264 throw new InvalidOperationException(
265 "A Hamming radius cannot be negative.");
266 }
267
268 var expression =
269 new LinearExpression();
270
271 int referenceOneCount =
272 0;
273
274 for (int index = 0;
275 index < variables.Count;
276 index++)
277 {
278 MathematicalVariable variable =
279 variables[index];
280
281 if (variable.VariableType !=
283 {
284 continue;
285 }
286
287 double reference =
288 request.ReferenceValues[index];
289
290 bool isZero =
291 Math.Abs(reference) <=
292 1.0e-7;
293
294 bool isOne =
295 Math.Abs(reference - 1.0) <=
296 1.0e-7;
297
298 if (!isZero &&
299 !isOne)
300 {
301 throw new InvalidOperationException(
302 $"Binary Hamming reference at index {index} is not zero or one.");
303 }
304
305 if (isOne)
306 {
307 referenceOneCount++;
308
309 expression.AddTerm(
310 variable.Id,
311 -1.0);
312 }
313 else
314 {
315 expression.AddTerm(
316 variable.Id,
317 1.0);
318 }
319 }
320
321 model.AddConstraint(
322 new LinearConstraint(
323 constraintId,
324 "metaheuristicLocalBranchingHamming",
325 expression,
326 MathematicalConstraintSense.LessThanOrEqual,
327 radius -
328 referenceOneCount));
329
330 return constraintId + 1;
331 }
332
333 private static void AddObjectiveCutoff(
334 MathematicalModel model,
335 double cutoff,
336 int constraintId)
337 {
338 if (!double.IsFinite(
339 cutoff))
340 {
341 throw new InvalidOperationException(
342 "A matheuristic objective cutoff must be finite.");
343 }
344
345 LinearExpression expression =
346 model.Objective.Expression.Clone();
347
348 double constant =
349 expression.Constant;
350
351 expression.AddConstant(
352 -constant);
353
355 model.Objective.Sense switch
356 {
357 ObjectiveSense.Minimize =>
358 MathematicalConstraintSense.LessThanOrEqual,
359
360 ObjectiveSense.Maximize =>
361 MathematicalConstraintSense.GreaterThanOrEqual,
362
363 _ =>
364 throw new NotSupportedException(
365 $"Objective sense '{model.Objective.Sense}' cannot define a matheuristic objective cutoff.")
366 };
367
368 model.AddConstraint(
369 new LinearConstraint(
370 constraintId,
371 "metaheuristicObjectiveCutoff",
372 expression,
373 sense,
374 cutoff -
375 constant));
376 }
377
378 private static MathematicalVariable GetVariable(
379 IReadOnlyList<MathematicalVariable> variables,
380 int index)
381 {
382 if (index < 0 ||
383 index >=
384 variables.Count)
385 {
386 throw new ArgumentOutOfRangeException(
387 nameof(index));
388 }
389
390 return variables[index];
391 }
392
393 private static void EnsureBoundInsideSource(
394 MathematicalVariable variable,
395 double lower,
396 double upper)
397 {
398 if (!double.IsFinite(lower) ||
399 !double.IsFinite(upper) ||
400 lower >
401 upper)
402 {
403 throw new InvalidOperationException(
404 $"Invalid exact-repair bounds for variable '{variable.Name}'.");
405 }
406
407 if (lower <
408 variable.LowerBound ||
409 upper >
410 variable.UpperBound)
411 {
412 throw new InvalidOperationException(
413 $"Exact-repair bounds for variable '{variable.Name}' exceed its source domain.");
414 }
415 }
416
417 private static void EnsureValueMatchesType(
418 MathematicalVariable variable,
419 double value)
420 {
421 switch (variable.VariableType)
422 {
423 case MathematicalVariableType.Continuous:
424 return;
425
426 case MathematicalVariableType.Integer:
427 if (value !=
428 Math.Truncate(
429 value))
430 {
431 throw new InvalidOperationException(
432 $"Integer variable '{variable.Name}' cannot be fixed to {value:G17}.");
433 }
434
435 return;
436
437 case MathematicalVariableType.Binary:
438 if (value != 0.0 &&
439 value != 1.0)
440 {
441 throw new InvalidOperationException(
442 $"Binary variable '{variable.Name}' can only be fixed to zero or one.");
443 }
444
445 return;
446
447 default:
448 throw new NotSupportedException(
449 $"Variable type '{variable.VariableType}' is outside the alpha.37 exact-repair bridge.");
450 }
451 }
452}
MathematicalModel BuildLocalBranchingSubproblem(MathematicalModel sourceModel, IReadOnlyList< double > referenceValues, int hammingRadius, int nodeLimit)
LinearExpression Clone()
Creates an independent copy of this expression.
void AddConstant(double value)
Adds a constant value to the expression.
double Constant
Gets or sets the constant value of the expression.
Represents a solver-independent mathematical optimization model.
MathematicalModel Clone()
Creates an independent copy of the mathematical model.
void AddConstraint(LinearConstraint constraint)
Adds a linear constraint.
MathematicalObjective Objective
Gets or sets the mathematical objective.
List< LinearConstraint > Constraints
Gets the linear constraints.
void EnsureValid()
Validates the complete mathematical model.
LinearExpression Expression
Gets or sets the linear objective expression.
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.
MathematicalVariableType
Identifies the domain of a mathematical decision variable.