LotSizingDataModel.Solver.Cplex 2.0.1
IBM ILOG CPLEX adapter and installation discovery integration.
Loading...
Searching...
No Matches
CplexModelTranslator.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using ILOG.Concert;
4using ILOG.CPLEX;
5using NativeCplex = global::ILOG.CPLEX.Cplex;
6using LotSizingDataModel.Solver.Modeling;
7using GenericObjectiveSense = global::LotSizingDataModel.Solver.Modeling.ObjectiveSense;
8
10
11/// <summary>
12/// Translates a solver-independent linear mathematical model to
13/// IBM ILOG Concert/CPLEX objects.
14/// </summary>
15public sealed class CplexModelTranslator
16{
17 /// <summary>
18 /// Translates a complete mathematical model.
19 /// </summary>
20 /// <param name="model">
21 /// Validated generic mathematical model.
22 /// </param>
23 /// <returns>
24 /// Native CPLEX model and variable mapping.
25 /// </returns>
27 MathematicalModel model)
28 {
29 ArgumentNullException.ThrowIfNull(model);
30
31 model.EnsureValid();
32
33 var cplex =
34 new NativeCplex();
35
36 try
37 {
38 if (!string.IsNullOrWhiteSpace(model.Name))
39 {
40 cplex.Name =
41 model.Name;
42 }
43
44 var variablesById =
45 new Dictionary<int, INumVar>(
46 model.VariableCount);
47
48 foreach (MathematicalVariable variable in model.Variables)
49 {
50 INumVar nativeVariable =
51 CreateVariable(
52 cplex,
53 variable);
54
55 variablesById.Add(
56 variable.Id,
57 nativeVariable);
58 }
59
60 AddObjective(
61 cplex,
62 model.Objective,
63 variablesById);
64
65 foreach (LinearConstraint constraint in model.Constraints)
66 {
67 if (!constraint.IsEnabled)
68 {
69 continue;
70 }
71
72 AddConstraint(
73 cplex,
74 constraint,
75 variablesById);
76 }
77
79 cplex,
80 variablesById);
81 }
82 catch
83 {
84 cplex.End();
85 throw;
86 }
87 }
88
89 private static INumVar CreateVariable(
90 NativeCplex cplex,
91 MathematicalVariable variable)
92 {
93 double lowerBound =
94 NormalizeLowerBound(
95 variable.LowerBound);
96
97 double upperBound =
98 NormalizeUpperBound(
99 variable.UpperBound);
100
101 return variable.VariableType switch
102 {
103 MathematicalVariableType.Continuous =>
104 cplex.NumVar(
105 lowerBound,
106 upperBound,
107 NumVarType.Float,
108 variable.Name),
109
110 MathematicalVariableType.Integer =>
111 cplex.NumVar(
112 lowerBound,
113 upperBound,
114 NumVarType.Int,
115 variable.Name),
116
117 MathematicalVariableType.Binary =>
118 cplex.BoolVar(
119 variable.Name),
120
121 MathematicalVariableType.SemiContinuous =>
122 throw new NotSupportedException(
123 "The first CPLEX adapter version does not " +
124 "translate semi-continuous variables."),
125
126 MathematicalVariableType.SemiInteger =>
127 throw new NotSupportedException(
128 "The first CPLEX adapter version does not " +
129 "translate semi-integer variables."),
130
131 _ =>
132 throw new NotSupportedException(
133 $"Unsupported mathematical variable type " +
134 $"'{variable.VariableType}'.")
135 };
136 }
137
138 private static void AddObjective(
139 NativeCplex cplex,
140 MathematicalObjective objective,
141 IReadOnlyDictionary<int, INumVar> variablesById)
142 {
143 INumExpr expression =
144 BuildExpression(
145 cplex,
146 objective.Expression,
147 variablesById);
148
149 switch (objective.Sense)
150 {
151 case GenericObjectiveSense.Minimize:
152 cplex.AddMinimize(
153 expression,
154 objective.Name);
155 break;
156
157 case GenericObjectiveSense.Maximize:
158 cplex.AddMaximize(
159 expression,
160 objective.Name);
161 break;
162
163 default:
164 throw new NotSupportedException(
165 $"Unsupported objective sense " +
166 $"'{objective.Sense}'.");
167 }
168 }
169
170 private static void AddConstraint(
171 NativeCplex cplex,
172 LinearConstraint constraint,
173 IReadOnlyDictionary<int, INumVar> variablesById)
174 {
175 ILinearNumExpr leftHandSide =
176 BuildLinearExpression(
177 cplex,
178 constraint.LeftHandSide,
179 variablesById);
180
181 double adjustedRightHandSide =
182 constraint.RightHandSide -
183 constraint.LeftHandSide.Constant;
184
185 switch (constraint.Sense)
186 {
187 case MathematicalConstraintSense.LessThanOrEqual:
188 cplex.AddLe(
189 leftHandSide,
190 adjustedRightHandSide,
191 constraint.Name);
192 break;
193
194 case MathematicalConstraintSense.Equal:
195 cplex.AddEq(
196 leftHandSide,
197 adjustedRightHandSide,
198 constraint.Name);
199 break;
200
201 case MathematicalConstraintSense.GreaterThanOrEqual:
202 cplex.AddGe(
203 leftHandSide,
204 adjustedRightHandSide,
205 constraint.Name);
206 break;
207
208 default:
209 throw new NotSupportedException(
210 $"Unsupported constraint sense " +
211 $"'{constraint.Sense}'.");
212 }
213 }
214
215 private static INumExpr BuildExpression(
216 NativeCplex cplex,
217 LinearExpression expression,
218 IReadOnlyDictionary<int, INumVar> variablesById)
219 {
220 ILinearNumExpr linear =
221 BuildLinearExpression(
222 cplex,
223 expression,
224 variablesById);
225
226 if (expression.Constant == 0.0)
227 {
228 return linear;
229 }
230
231 return cplex.Sum(
232 linear,
233 expression.Constant);
234 }
235
236 private static ILinearNumExpr BuildLinearExpression(
237 NativeCplex cplex,
238 LinearExpression expression,
239 IReadOnlyDictionary<int, INumVar> variablesById)
240 {
241 var result =
242 cplex.LinearNumExpr();
243
244 foreach (LinearTerm term in expression.Terms)
245 {
246 if (!variablesById.TryGetValue(
247 term.VariableId,
248 out INumVar? variable))
249 {
250 throw new InvalidOperationException(
251 $"Expression references unknown mathematical " +
252 $"variable identifier {term.VariableId}.");
253 }
254
255 result.AddTerm(
256 term.Coefficient,
257 variable);
258 }
259
260 return result;
261 }
262
263 private static double NormalizeLowerBound(
264 double value)
265 {
266 return double.IsNegativeInfinity(value)
267 ? -double.MaxValue
268 : value;
269 }
270
271 private static double NormalizeUpperBound(
272 double value)
273 {
274 return double.IsPositiveInfinity(value)
275 ? double.MaxValue
276 : value;
277 }
278}
global::ILOG.CPLEX.Cplex NativeCplex
global::LotSizingDataModel.Solver.Modeling.ObjectiveSense GenericObjectiveSense
Stores the native CPLEX model objects created from one solver-independent mathematical model.
Translates a solver-independent linear mathematical model to IBM ILOG Concert/CPLEX objects.
CplexModelTranslationResult Translate(MathematicalModel model)
Translates a complete mathematical model.