LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
MathematicalModel.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Xml.Serialization;
5
7
8/// <summary>
9/// Represents a solver-independent mathematical optimization
10/// model.
11/// </summary>
12/// <remarks>
13/// The model can be translated by solver adapters into native
14/// CPLEX, Gurobi, FICO Xpress, or COIN-OR CBC models.
15/// </remarks>
16[Serializable]
17[XmlRoot("mathematicalModel")]
18[XmlType(TypeName = "mathematicalModel")]
19public sealed class MathematicalModel
20{
21 private readonly List<MathematicalVariable> _variables =
22 new();
23
24 private readonly List<LinearConstraint> _constraints =
25 new();
26
27 /// <summary>
28 /// Initializes an empty mathematical model.
29 /// </summary>
31 {
32 Name =
33 string.Empty;
34
36 string.Empty;
37
38 Objective =
40 }
41
42 /// <summary>
43 /// Gets or sets the model name.
44 /// </summary>
45 [XmlAttribute("name")]
46 public string Name
47 {
48 get;
49 set;
50 }
51
52 /// <summary>
53 /// Gets or sets an optional model description.
54 /// </summary>
55 [XmlElement("description")]
56 public string Description
57 {
58 get;
59 set;
60 }
61
62 /// <summary>
63 /// Gets or sets the mathematical objective.
64 /// </summary>
65 [XmlElement("objective")]
67 {
68 get;
69 set;
70 }
71
72 /// <summary>
73 /// Gets the mathematical variables.
74 /// </summary>
75 [XmlArray("variables")]
76 [XmlArrayItem("variable")]
77 public List<MathematicalVariable> Variables =>
78 _variables;
79
80 /// <summary>
81 /// Gets the linear constraints.
82 /// </summary>
83 [XmlArray("constraints")]
84 [XmlArrayItem("constraint")]
85 public List<LinearConstraint> Constraints =>
86 _constraints;
87
88 /// <summary>
89 /// Gets the number of mathematical variables.
90 /// </summary>
91 [XmlIgnore]
92 public int VariableCount =>
93 _variables.Count;
94
95 /// <summary>
96 /// Gets the number of enabled linear constraints.
97 /// </summary>
98 [XmlIgnore]
100 _constraints.Count(
101 constraint =>
102 constraint.IsEnabled);
103
104 /// <summary>
105 /// Gets the number of binary variables.
106 /// </summary>
107 [XmlIgnore]
109 _variables.Count(
110 variable =>
111 variable.VariableType ==
113
114 /// <summary>
115 /// Gets the number of general integer variables.
116 /// </summary>
117 [XmlIgnore]
119 _variables.Count(
120 variable =>
121 variable.VariableType is
122 MathematicalVariableType.Integer or
123 MathematicalVariableType.SemiInteger);
124
125 /// <summary>
126 /// Gets the number of continuous variables.
127 /// </summary>
128 [XmlIgnore]
130 _variables.Count(
131 variable =>
132 variable.VariableType is
133 MathematicalVariableType.Continuous or
134 MathematicalVariableType.SemiContinuous);
135
136 /// <summary>
137 /// Adds a mathematical variable.
138 /// </summary>
139 /// <param name="variable">
140 /// Variable to add.
141 /// </param>
142 /// <exception cref="ArgumentNullException">
143 /// Thrown when <paramref name="variable"/> is
144 /// <see langword="null"/>.
145 /// </exception>
146 /// <exception cref="InvalidOperationException">
147 /// Thrown when the variable identifier or name is already
148 /// used.
149 /// </exception>
150 public void AddVariable(
151 MathematicalVariable variable)
152 {
153 ArgumentNullException.ThrowIfNull(
154 variable);
155
156 variable.EnsureValid();
157
158 if (_variables.Any(
159 existingVariable =>
160 existingVariable.Id ==
161 variable.Id))
162 {
163 throw new InvalidOperationException(
164 $"Variable identifier '{variable.Id}' is " +
165 "already used.");
166 }
167
168 if (_variables.Any(
169 existingVariable =>
170 string.Equals(
171 existingVariable.Name,
172 variable.Name,
173 StringComparison.Ordinal)))
174 {
175 throw new InvalidOperationException(
176 $"Variable name '{variable.Name}' is already " +
177 "used.");
178 }
179
180 _variables.Add(
181 variable);
182 }
183
184 /// <summary>
185 /// Adds a linear constraint.
186 /// </summary>
187 /// <param name="constraint">
188 /// Constraint to add.
189 /// </param>
190 /// <exception cref="ArgumentNullException">
191 /// Thrown when <paramref name="constraint"/> is
192 /// <see langword="null"/>.
193 /// </exception>
194 /// <exception cref="InvalidOperationException">
195 /// Thrown when the constraint identifier or name is already
196 /// used, or when the constraint references an unknown
197 /// variable.
198 /// </exception>
199 public void AddConstraint(
200 LinearConstraint constraint)
201 {
202 ArgumentNullException.ThrowIfNull(
203 constraint);
204
205 constraint.EnsureValid();
206
207 if (_constraints.Any(
208 existingConstraint =>
209 existingConstraint.Id ==
210 constraint.Id))
211 {
212 throw new InvalidOperationException(
213 $"Constraint identifier '{constraint.Id}' is " +
214 "already used.");
215 }
216
217 if (_constraints.Any(
218 existingConstraint =>
219 string.Equals(
220 existingConstraint.Name,
221 constraint.Name,
222 StringComparison.Ordinal)))
223 {
224 throw new InvalidOperationException(
225 $"Constraint name '{constraint.Name}' is " +
226 "already used.");
227 }
228
229 EnsureExpressionReferencesKnownVariables(
230 constraint.LeftHandSide,
231 $"constraint '{constraint.Name}'");
232
233 _constraints.Add(
234 constraint);
235 }
236
237 /// <summary>
238 /// Finds a mathematical variable by identifier.
239 /// </summary>
240 /// <param name="variableId">
241 /// Variable identifier.
242 /// </param>
243 /// <returns>
244 /// Matching variable, or <see langword="null"/> when no
245 /// variable has the supplied identifier.
246 /// </returns>
248 int variableId)
249 {
250 return _variables.FirstOrDefault(
251 variable =>
252 variable.Id ==
253 variableId);
254 }
255
256 /// <summary>
257 /// Finds a mathematical variable by name.
258 /// </summary>
259 /// <param name="name">
260 /// Variable name.
261 /// </param>
262 /// <returns>
263 /// Matching variable, or <see langword="null"/> when no
264 /// variable has the supplied name.
265 /// </returns>
267 string name)
268 {
269 if (string.IsNullOrWhiteSpace(
270 name))
271 {
272 throw new ArgumentException(
273 "A variable name is required.",
274 nameof(name));
275 }
276
277 return _variables.FirstOrDefault(
278 variable =>
279 string.Equals(
280 variable.Name,
281 name.Trim(),
282 StringComparison.Ordinal));
283 }
284
285 /// <summary>
286 /// Validates the complete mathematical model.
287 /// </summary>
288 /// <exception cref="InvalidOperationException">
289 /// Thrown when the model contains inconsistent or invalid
290 /// definitions.
291 /// </exception>
292 public void EnsureValid()
293 {
294 if (string.IsNullOrWhiteSpace(
295 Name))
296 {
297 throw new InvalidOperationException(
298 "A mathematical model name is required.");
299 }
300
301 ArgumentNullException.ThrowIfNull(
302 Objective);
303
304 Objective.EnsureValid();
305
306 EnsureUniqueVariables();
307 EnsureUniqueConstraints();
308
309 foreach (
310 MathematicalVariable variable
311 in _variables)
312 {
313 if (variable is null)
314 {
315 throw new InvalidOperationException(
316 "The variable collection cannot contain a " +
317 "null entry.");
318 }
319
320 variable.EnsureValid();
321 }
322
323 foreach (
324 LinearConstraint constraint
325 in _constraints)
326 {
327 if (constraint is null)
328 {
329 throw new InvalidOperationException(
330 "The constraint collection cannot contain " +
331 "a null entry.");
332 }
333
334 constraint.EnsureValid();
335
336 EnsureExpressionReferencesKnownVariables(
337 constraint.LeftHandSide,
338 $"constraint '{constraint.Name}'");
339 }
340
341 EnsureExpressionReferencesKnownVariables(
342 Objective.Expression,
343 "objective");
344 }
345
346 /// <summary>
347 /// Creates an independent copy of the mathematical model.
348 /// </summary>
349 /// <returns>
350 /// Cloned mathematical model.
351 /// </returns>
353 {
354 var clone =
356 {
357 Name =
358 Name,
359
362
363 Objective =
364 Objective.Clone()
365 };
366
367 foreach (
368 MathematicalVariable variable
369 in _variables)
370 {
371 clone.Variables.Add(
373 {
374 Id =
375 variable.Id,
376
377 Name =
378 variable.Name,
379
380 VariableType =
381 variable.VariableType,
382
383 LowerBound =
384 variable.LowerBound,
385
386 UpperBound =
387 variable.UpperBound,
388
389 DomainKey =
390 variable.DomainKey,
391
393 variable.Description
394 });
395 }
396
397 foreach (
398 LinearConstraint constraint
399 in _constraints)
400 {
401 clone.Constraints.Add(
402 constraint.Clone());
403 }
404
405 return clone;
406 }
407
408 private void EnsureExpressionReferencesKnownVariables(
409 LinearExpression expression,
410 string context)
411 {
412 foreach (
413 LinearTerm term
414 in expression.Terms)
415 {
417 term.VariableId) is null)
418 {
419 throw new InvalidOperationException(
420 $"The {context} references unknown variable " +
421 $"identifier '{term.VariableId}'.");
422 }
423 }
424 }
425
426 private void EnsureUniqueVariables()
427 {
428 if (_variables
429 .GroupBy(
430 variable =>
431 variable.Id)
432 .Any(
433 group =>
434 group.Count() > 1))
435 {
436 throw new InvalidOperationException(
437 "Mathematical variable identifiers must be " +
438 "unique.");
439 }
440
441 if (_variables
442 .GroupBy(
443 variable =>
444 variable.Name,
445 StringComparer.Ordinal)
446 .Any(
447 group =>
448 group.Count() > 1))
449 {
450 throw new InvalidOperationException(
451 "Mathematical variable names must be unique.");
452 }
453 }
454
455 private void EnsureUniqueConstraints()
456 {
457 if (_constraints
458 .GroupBy(
459 constraint =>
460 constraint.Id)
461 .Any(
462 group =>
463 group.Count() > 1))
464 {
465 throw new InvalidOperationException(
466 "Linear constraint identifiers must be unique.");
467 }
468
469 if (_constraints
470 .GroupBy(
471 constraint =>
472 constraint.Name,
473 StringComparer.Ordinal)
474 .Any(
475 group =>
476 group.Count() > 1))
477 {
478 throw new InvalidOperationException(
479 "Linear constraint names must be unique.");
480 }
481 }
482}
Represents one linear constraint in a mathematical optimization model.
void EnsureValid()
Validates the linear constraint.
string Name
Gets or sets the constraint name.
LinearConstraint Clone()
Creates an independent copy of this constraint.
LinearExpression LeftHandSide
Gets or sets the left-hand-side linear expression.
int Id
Gets or sets the unique constraint identifier within the mathematical model.
Represents a linear expression composed of variable terms and a constant value.
List< LinearTerm > Terms
Gets the linear terms 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
List< MathematicalVariable > Variables
Gets the mathematical variables.
int IntegerVariableCount
Gets the number of general integer variables.
void AddVariable(MathematicalVariable variable)
Adds a mathematical variable.
int VariableCount
Gets the number of mathematical variables.
MathematicalModel()
Initializes an empty mathematical 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.
int BinaryVariableCount
Gets the number of binary variables.
MathematicalVariable? FindVariableById(int variableId)
Finds a mathematical variable by identifier.
List< LinearConstraint > Constraints
Gets the linear constraints.
void EnsureValid()
Validates the complete mathematical model.
string Description
Gets or sets an optional model description.
int EnabledConstraintCount
Gets the number of enabled linear constraints.
int ContinuousVariableCount
Gets the number of continuous variables.
MathematicalVariable? FindVariableByName(string name)
Finds a mathematical variable by name.
Represents the objective function of a mathematical optimization model.
Represents one decision variable in a mathematical optimization model.
MathematicalVariableType VariableType
Gets or sets the variable domain.
string DomainKey
Gets or sets an optional domain key used to map the mathematical variable back to a lot-sizing decisi...
int Id
Gets or sets the unique variable identifier within the mathematical model.
double LowerBound
Gets or sets the variable lower bound.
void EnsureValid()
Validates the mathematical variable.
double UpperBound
Gets or sets the variable upper bound.
MathematicalVariableType
Identifies the domain of a mathematical decision variable.