LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
GroupingConstraintFamilyBuilder.cs
Go to the documentation of this file.
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4using LotSizingDataModel.Core.Relationships;
5using LotSizingDataModel.Instance;
9
11
12/// <summary>
13/// Enforces the minimum temporal spacing between consecutive
14/// production setups defined by each routing grouping
15/// constraint.
16/// </summary>
17/// <remarks>
18/// <para>
19/// The grouping value is interpreted as a minimum setup spacing
20/// measured in planning periods.
21/// </para>
22/// <para>
23/// If a routing has <c>GroupingConstraint[t] = g</c> and a setup
24/// occurs in period <c>t</c>, no new setup may occur in periods
25/// <c>t + 1</c> through <c>t + g - 1</c>. A new setup is allowed
26/// again in period <c>t + g</c>.
27/// </para>
28/// <para>
29/// For a time-dependent grouping value, the formulation uses
30/// pairwise inequalities:
31/// </para>
32/// <code>
33/// y[r,t] + y[r,k] &lt;= 1
34/// for k = t+1, ..., min(T, t+g[t]-1).
35/// </code>
36/// <para>
37/// When the grouping value is constant, this is equivalent to
38/// requiring at most one setup in every sliding window of that
39/// many consecutive periods.
40/// </para>
41/// </remarks>
44{
45 /// <summary>
46 /// Gets the unique constraint-family identifier.
47 /// </summary>
48 public override string ConstraintFamilyId =>
49 "productionSetupGrouping";
50
51 /// <summary>
52 /// Determines whether at least one production routing
53 /// defines a grouping constraint.
54 /// </summary>
55 /// <param name="instance">
56 /// Source lot-sizing instance.
57 /// </param>
58 /// <param name="options">
59 /// Standard formulation options.
60 /// </param>
61 /// <returns>
62 /// <see langword="true"/> when at least one routing defines
63 /// a grouping constraint; otherwise, <see langword="false"/>.
64 /// </returns>
65 /// <exception cref="ArgumentNullException">
66 /// Thrown when an argument is <see langword="null"/>.
67 /// </exception>
68 /// <exception cref="InvalidOperationException">
69 /// Thrown when grouping constraints are present while
70 /// production setup variables are disabled.
71 /// </exception>
72 public override bool IsEnabled(
73 LotSizingInstance instance,
75 {
76 ArgumentNullException.ThrowIfNull(
77 instance);
78
79 ArgumentNullException.ThrowIfNull(
80 options);
81
82 bool hasGroupingConstraint =
83 false;
84
85 foreach (
86 ProductionRouting routing
87 in instance.SupplyChain.ProductionRoutings)
88 {
89 if (routing.GroupingConstraint is not null)
90 {
91 hasGroupingConstraint =
92 true;
93
94 break;
95 }
96 }
97
98 if (hasGroupingConstraint &&
99 !options.IncludeProductionSetups)
100 {
101 throw new InvalidOperationException(
102 "Production grouping constraints require " +
103 "production setup variables. Enable " +
104 "IncludeProductionSetups before building the " +
105 "standard formulation.");
106 }
107
108 return hasGroupingConstraint;
109 }
110
111 /// <summary>
112 /// Builds all setup-spacing constraints.
113 /// </summary>
114 /// <param name="instance">
115 /// Source lot-sizing instance.
116 /// </param>
117 /// <param name="context">
118 /// Mathematical-model build context.
119 /// </param>
120 /// <param name="options">
121 /// Standard formulation options.
122 /// </param>
123 /// <param name="cancellationToken">
124 /// Token used to cancel constraint construction.
125 /// </param>
126 /// <returns>
127 /// Task representing grouping-constraint construction.
128 /// </returns>
129 protected override ValueTask BuildConstraintsAsync(
130 LotSizingInstance instance,
133 CancellationToken cancellationToken)
134 {
135 int planningHorizon =
136 instance.PlanningHorizon;
137
138 foreach (
139 ProductionRouting routing
140 in instance.SupplyChain.ProductionRoutings)
141 {
142 if (routing.GroupingConstraint is null)
143 {
144 continue;
145 }
146
147 for (
148 int setupPeriod = 1;
149 setupPeriod <= planningHorizon;
150 setupPeriod++)
151 {
152 cancellationToken.ThrowIfCancellationRequested();
153
154 int minimumSpacing =
155 routing.GroupingConstraint[setupPeriod];
156
157 if (minimumSpacing <= 0)
158 {
159 throw new InvalidOperationException(
160 $"Grouping constraint for routing " +
161 $"{routing.Id}, period {setupPeriod}, " +
162 "must be strictly positive.");
163 }
164
165 if (minimumSpacing == 1)
166 {
167 continue;
168 }
169
170 MathematicalVariable firstSetup =
171 GetSetupVariable(
172 context,
173 routing.Id,
174 setupPeriod);
175
176 int lastForbiddenPeriod =
177 Math.Min(
178 planningHorizon,
179 setupPeriod +
180 minimumSpacing -
181 1);
182
183 for (
184 int forbiddenPeriod = setupPeriod + 1;
185 forbiddenPeriod <= lastForbiddenPeriod;
186 forbiddenPeriod++)
187 {
188 cancellationToken.ThrowIfCancellationRequested();
189
190 MathematicalVariable laterSetup =
191 GetSetupVariable(
192 context,
193 routing.Id,
194 forbiddenPeriod);
195
196 var expression =
198 .Add(
199 firstSetup)
200 .Add(
201 laterSetup);
202
204 context,
205 $"grouping_r{routing.Id}" +
206 $"_t{setupPeriod}" +
207 $"_k{forbiddenPeriod}",
208 expression.Build(),
209 MathematicalConstraintSense.LessThanOrEqual,
210 1.0,
211 description:
212 $"A setup in period {setupPeriod} " +
213 $"for routing {routing.Id} forbids " +
214 $"another setup before period " +
215 $"{setupPeriod + minimumSpacing}.");
216 }
217 }
218 }
219
220 return ValueTask.CompletedTask;
221 }
222
223 /// <summary>
224 /// Resolves one production setup variable.
225 /// </summary>
226 /// <param name="context">
227 /// Mathematical-model build context.
228 /// </param>
229 /// <param name="routingId">
230 /// Production routing identifier.
231 /// </param>
232 /// <param name="period">
233 /// One-based planning period.
234 /// </param>
235 /// <returns>
236 /// Registered binary setup variable.
237 /// </returns>
238 private static MathematicalVariable GetSetupVariable(
240 int routingId,
241 int period)
242 {
243 string domainKey =
246 .Add(
248 routingId)
249 .Add(
251 period)
252 .Build();
253
254 return context.GetVariable(
255 domainKey);
256 }
257}
Provides a fluent builder for linear expressions.
LinearExpressionBuilder Add(MathematicalVariable variable, double coefficient=1.0)
Adds a variable term to the expression.
Builds stable business-domain keys for mathematical variables and constraints.
MathematicalDomainKeyBuilder Add(string name, string value)
Adds a text segment.
Provides the shared state required while constructing a solver-independent mathematical model.
MathematicalVariable GetVariable(string domainKey)
Gets a required mathematical variable from its business-domain key.
Enforces the minimum temporal spacing between consecutive production setups defined by each routing g...
override ValueTask BuildConstraintsAsync(LotSizingInstance instance, MathematicalModelBuildContext context, StandardLotSizingFormulationOptions options, CancellationToken cancellationToken)
Builds all setup-spacing constraints.
override string ConstraintFamilyId
Gets the unique constraint-family identifier.
override bool IsEnabled(LotSizingInstance instance, StandardLotSizingFormulationOptions options)
Determines whether at least one production routing defines a grouping constraint.
Provides common validation and helper methods for one constraint family of the standard lot-sizing fo...
static void AddConstraint(MathematicalModelBuildContext context, string name, LinearExpression expression, MathematicalConstraintSense sense, double rightHandSide, string domainKey="", string description="")
Adds one linear constraint to the mathematical model.
Configures the standard solver-independent mixed-integer lot-sizing formulation.
Provides the canonical mathematical domain-key categories used to identify lot-sizing decision famili...
const string Setup
Identifies production setup decision variables.
Provides the canonical mathematical domain-key segment names used by lot-sizing variables and constra...
Represents one decision variable in a mathematical optimization model.
MathematicalConstraintSense
Identifies the relational sense of a mathematical constraint.