LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
MathematicalModelMetaheuristicEncoding.cs
Go to the documentation of this file.
2using MetaheuristicsPlatform.SearchSpaces.Continuous;
3
5
7{
8 private readonly MathematicalVariable[] _variables;
9 private readonly int[] _searchModelIndices;
10 private readonly double[] _effectiveLowerBounds;
11 private readonly double[] _effectiveUpperBounds;
12 private readonly double[] _fixedValues;
13 private readonly Dictionary<int, int> _modelIndexByVariableId;
14
18 {
19 ArgumentNullException.ThrowIfNull(
20 model);
21
22 model.EnsureValid();
23
24 options ??=
26
27 ArgumentNullException.ThrowIfNull(
28 options.BoundOverrides);
29
30 _variables =
31 model.Variables
32 .OrderBy(
33 variable =>
34 variable.Id)
35 .ToArray();
36
37 if (_variables.Length == 0)
38 {
39 throw new InvalidOperationException(
40 "A metaheuristic encoding requires at least one mathematical variable.");
41 }
42
43 _modelIndexByVariableId =
44 _variables
45 .Select(
46 (variable, index) =>
47 new
48 {
49 variable.Id,
50 Index = index
51 })
52 .ToDictionary(
53 entry =>
54 entry.Id,
55 entry =>
56 entry.Index);
57
58 foreach (int variableId
59 in options.BoundOverrides.Keys)
60 {
61 if (!_modelIndexByVariableId.ContainsKey(
62 variableId))
63 {
64 throw new InvalidOperationException(
65 $"Bound override references unknown variable identifier '{variableId}'.");
66 }
67 }
68
69 _fixedValues =
70 Enumerable.Repeat(
71 double.NaN,
72 _variables.Length)
73 .ToArray();
74
75 var searchIndices =
76 new List<int>();
77
78 var searchLower =
79 new List<double>();
80
81 var searchUpper =
82 new List<double>();
83
84 var effectiveLower =
85 new List<double>();
86
87 var effectiveUpper =
88 new List<double>();
89
90 for (int modelIndex = 0;
91 modelIndex < _variables.Length;
92 modelIndex++)
93 {
94 MathematicalVariable variable =
95 _variables[modelIndex];
96
97 EnsureSupportedVariableType(
98 variable);
99
100 double lower =
101 variable.LowerBound;
102
103 double upper =
104 variable.UpperBound;
105
106 if (options.BoundOverrides.TryGetValue(
107 variable.Id,
108 out MetaheuristicVariableBounds overrideBounds))
109 {
110 ValidateOverride(
111 variable,
112 overrideBounds);
113
114 lower =
115 overrideBounds.Lower;
116
117 upper =
118 overrideBounds.Upper;
119 }
120
121 if (!double.IsFinite(lower) ||
122 !double.IsFinite(upper))
123 {
124 throw new NotSupportedException(
125 $"Variable '{variable.Name}' requires explicit finite metaheuristic bounds.");
126 }
127
128 if (lower >
129 upper)
130 {
131 throw new InvalidOperationException(
132 $"Effective bounds for variable '{variable.Name}' are inconsistent.");
133 }
134
135 if (lower ==
136 upper)
137 {
138 _fixedValues[modelIndex] =
139 NormalizeValue(
140 variable,
141 lower,
142 lower,
143 upper);
144
145 continue;
146 }
147
148 ValidateFreeBounds(
149 variable,
150 lower,
151 upper);
152
153 searchIndices.Add(
154 modelIndex);
155
156 searchLower.Add(
157 lower);
158
159 searchUpper.Add(
160 upper);
161
162 effectiveLower.Add(
163 lower);
164
165 effectiveUpper.Add(
166 upper);
167 }
168
169 if (searchIndices.Count == 0)
170 {
171 throw new NotSupportedException(
172 "Metaheuristic search requires at least one non-fixed variable.");
173 }
174
175 _searchModelIndices =
176 searchIndices.ToArray();
177
178 _effectiveLowerBounds =
179 effectiveLower.ToArray();
180
181 _effectiveUpperBounds =
182 effectiveUpper.ToArray();
183
185 new BoundedContinuousSearchSpace(
186 searchLower,
187 searchUpper);
188 }
189
190 public IBoundedContinuousSearchSpace SearchSpace
191 {
192 get;
193 }
194
195 public IReadOnlyList<MathematicalVariable> ModelVariables =>
196 _variables;
197
198 public int ModelDimension =>
199 _variables.Length;
200
201 public int SearchDimension =>
202 _searchModelIndices.Length;
203
204 public double[] Decode(
205 ReadOnlySpan<double> searchPoint)
206 {
207 if (searchPoint.Length !=
209 {
210 throw new ArgumentException(
211 $"Expected search dimension {SearchDimension}, received {searchPoint.Length}.",
212 nameof(searchPoint));
213 }
214
215 var values =
216 (double[])_fixedValues.Clone();
217
218 for (int searchIndex = 0;
219 searchIndex < _searchModelIndices.Length;
220 searchIndex++)
221 {
222 double raw =
223 searchPoint[searchIndex];
224
225 if (!double.IsFinite(
226 raw))
227 {
228 throw new InvalidOperationException(
229 $"Search coordinate {searchIndex} is not finite.");
230 }
231
232 int modelIndex =
233 _searchModelIndices[searchIndex];
234
235 MathematicalVariable variable =
236 _variables[modelIndex];
237
238 values[modelIndex] =
239 NormalizeValue(
240 variable,
241 raw,
242 _effectiveLowerBounds[searchIndex],
243 _effectiveUpperBounds[searchIndex]);
244 }
245
246 return values;
247 }
248
249 public int GetModelIndex(
250 int variableId)
251 {
252 if (!_modelIndexByVariableId.TryGetValue(
253 variableId,
254 out int index))
255 {
256 throw new KeyNotFoundException(
257 $"Unknown mathematical variable identifier '{variableId}'.");
258 }
259
260 return index;
261 }
262
263 private static void EnsureSupportedVariableType(
264 MathematicalVariable variable)
265 {
266 switch (variable.VariableType)
267 {
268 case MathematicalVariableType.Continuous:
269 case MathematicalVariableType.Integer:
270 case MathematicalVariableType.Binary:
271 return;
272
273 case MathematicalVariableType.SemiContinuous:
274 case MathematicalVariableType.SemiInteger:
275 throw new NotSupportedException(
276 $"Variable '{variable.Name}' uses a semi-domain not enabled in alpha.37.");
277
278 default:
279 throw new NotSupportedException(
280 $"Variable '{variable.Name}' uses unsupported type '{variable.VariableType}'.");
281 }
282 }
283
284 private static void ValidateOverride(
285 MathematicalVariable variable,
287 {
288 if (!double.IsFinite(bounds.Lower) ||
289 !double.IsFinite(bounds.Upper) ||
290 bounds.Lower >=
291 bounds.Upper)
292 {
293 throw new InvalidOperationException(
294 $"Finite strictly ordered override bounds are required for variable '{variable.Name}'.");
295 }
296
297 if (variable.HasFiniteLowerBound &&
298 bounds.Lower <
299 variable.LowerBound)
300 {
301 throw new InvalidOperationException(
302 $"Override lower bound for variable '{variable.Name}' violates the mathematical lower bound.");
303 }
304
305 if (variable.HasFiniteUpperBound &&
306 bounds.Upper >
307 variable.UpperBound)
308 {
309 throw new InvalidOperationException(
310 $"Override upper bound for variable '{variable.Name}' violates the mathematical upper bound.");
311 }
312 }
313
314 private static void ValidateFreeBounds(
315 MathematicalVariable variable,
316 double lower,
317 double upper)
318 {
319 if (variable.VariableType ==
321 {
322 if (lower != 0.0 ||
323 upper != 1.0)
324 {
325 throw new NotSupportedException(
326 $"A free binary variable '{variable.Name}' must expose the complete [0,1] latent interval.");
327 }
328
329 return;
330 }
331
332 if (variable.VariableType ==
333 MathematicalVariableType.Integer &&
334 (lower !=
335 Math.Truncate(lower) ||
336 upper !=
337 Math.Truncate(upper)))
338 {
339 throw new InvalidOperationException(
340 $"Integer variable '{variable.Name}' requires integral effective bounds.");
341 }
342 }
343
344 private static double NormalizeValue(
345 MathematicalVariable variable,
346 double raw,
347 double lower,
348 double upper)
349 {
350 double clamped =
351 Math.Clamp(
352 raw,
353 lower,
354 upper);
355
356 return variable.VariableType switch
357 {
358 MathematicalVariableType.Continuous =>
359 clamped,
360
361 MathematicalVariableType.Integer =>
362 Math.Clamp(
363 Math.Round(
364 clamped,
365 MidpointRounding.AwayFromZero),
366 lower,
367 upper),
368
369 MathematicalVariableType.Binary =>
370 clamped >= 0.5
371 ? 1.0
372 : 0.0,
373
374 _ =>
375 throw new NotSupportedException(
376 $"Variable type '{variable.VariableType}' cannot be normalized by alpha.37.")
377 };
378 }
379}
MathematicalModelMetaheuristicEncoding(MathematicalModel model, MathematicalModelMetaheuristicEncodingOptions? options=null)
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.
bool HasFiniteUpperBound
Gets a value indicating whether the variable has a finite upper bound.
int Id
Gets or sets the unique variable identifier within the mathematical model.
double LowerBound
Gets or sets the variable lower bound.
bool HasFiniteLowerBound
Gets a value indicating whether the variable has a finite lower bound.
double UpperBound
Gets or sets the variable upper bound.
readonly record struct MetaheuristicVariableBounds(double Lower, double Upper)
MathematicalVariableType
Identifies the domain of a mathematical decision variable.