LotSizingDataModel.Solver 2.0.1
Solver-independent modeling, execution, monitoring and adapter infrastructure.
Loading...
Searching...
No Matches
DemandSatisfactionConstraintFamilyBuilder.cs
Go to the documentation of this file.
1using System;
2using System.Linq;
3using System.Threading;
4using System.Threading.Tasks;
5using LotSizingDataModel.Core.Relationships;
6using LotSizingDataModel.Instance;
10
12
13/// <summary>
14/// Builds demand-satisfaction constraints for each distribution
15/// center, item, and period.
16/// </summary>
17/// <remarks>
18/// The generated relation is:
19/// <code>
20/// sum(delivery)
21/// + sum(current backlog)
22/// - sum(previous backlog)
23/// + sum(shortage)
24/// = demand.
25/// </code>
26/// Backlog therefore carries unmet demand to the next period,
27/// while shortage represents demand abandoned in the current
28/// period.
29/// </remarks>
32{
33 /// <summary>
34 /// Gets the unique constraint-family identifier.
35 /// </summary>
36 public override string ConstraintFamilyId =>
37 "demandSatisfaction";
38
39 /// <summary>
40 /// Determines whether demand constraints are required.
41 /// </summary>
42 public override bool IsEnabled(
43 LotSizingInstance instance,
45 {
46 ArgumentNullException.ThrowIfNull(instance);
47 ArgumentNullException.ThrowIfNull(options);
48
49 return instance.SupplyChain.Demands.Count > 0;
50 }
51
52 /// <summary>
53 /// Builds demand-satisfaction constraints.
54 /// </summary>
55 protected override ValueTask BuildConstraintsAsync(
56 LotSizingInstance instance,
59 CancellationToken cancellationToken)
60 {
61 foreach (Demand demand in instance.SupplyChain.Demands)
62 {
63 DistributionCenterSourcing[] sourcings =
64 instance.SupplyChain.DistributionCenterSourcings
65 .Where(
66 sourcing =>
67 sourcing.DistributionCenterId ==
68 demand.DistributionCenterId &&
69 sourcing.ItemId == demand.ItemId)
70 .ToArray();
71
72 if (sourcings.Length == 0)
73 {
74 throw new InvalidOperationException(
75 $"Demand for distribution center " +
76 $"{demand.DistributionCenterId} and item " +
77 $"{demand.ItemId} has no sourcing relation.");
78 }
79
80 for (int period = 1;
81 period <= instance.PlanningHorizon;
82 period++)
83 {
84 cancellationToken.ThrowIfCancellationRequested();
85
86 var expression =
88
89 foreach (DistributionCenterSourcing sourcing
90 in sourcings)
91 {
92 expression.Add(
93 context.GetVariable(
97 demand.DistributionCenterId,
98 demand.ItemId,
99 sourcing.Warehouse,
100 period)));
101
102 if (options.IncludeBacklog &&
103 sourcing.BacklogConstraint is not null)
104 {
105 string currentBacklogKey =
109 demand.DistributionCenterId,
110 demand.ItemId,
111 sourcing.Warehouse,
112 period);
113
114 if (context.VariableRegistry.TryGet(
115 currentBacklogKey,
116 out MathematicalVariable? currentBacklog) &&
117 currentBacklog is not null)
118 {
119 expression.Add(
120 currentBacklog);
121 }
122
123 if (period > 1)
124 {
125 string previousBacklogKey =
129 demand.DistributionCenterId,
130 demand.ItemId,
131 sourcing.Warehouse,
132 period - 1);
133
134 if (context.VariableRegistry.TryGet(
135 previousBacklogKey,
136 out MathematicalVariable? previousBacklog) &&
137 previousBacklog is not null)
138 {
139 expression.Subtract(
140 previousBacklog);
141 }
142 }
143 }
144
145 if (options.IncludeShortage &&
146 sourcing.ShortageConstraint is not null)
147 {
148 string shortageKey =
152 demand.DistributionCenterId,
153 demand.ItemId,
154 sourcing.Warehouse,
155 period);
156
157 if (context.VariableRegistry.TryGet(
158 shortageKey,
159 out MathematicalVariable? shortage) &&
160 shortage is not null)
161 {
162 expression.Add(
163 shortage);
164 }
165 }
166 }
167
169 context,
170 $"demand_c{demand.DistributionCenterId}" +
171 $"_i{demand.ItemId}_t{period}",
172 expression.Build(),
174 demand.GetQuantity(period),
175 description:
176 "Demand satisfaction with optional " +
177 "backlog and shortage.");
178 }
179 }
180
181 return ValueTask.CompletedTask;
182 }
183}
Provides a fluent builder for linear expressions.
Provides the shared state required while constructing a solver-independent mathematical model.
Builds demand-satisfaction constraints for each distribution center, item, and period.
override ValueTask BuildConstraintsAsync(LotSizingInstance instance, MathematicalModelBuildContext context, StandardLotSizingFormulationOptions options, CancellationToken cancellationToken)
Builds demand-satisfaction constraints.
override bool IsEnabled(LotSizingInstance instance, StandardLotSizingFormulationOptions options)
Determines whether demand constraints are required.
Creates canonical variable domain keys used by the standard formulation constraint builders.
static string CreateDistributionKey(string category, int distributionCenterId, int itemId, WarehouseReference warehouse, int period)
Creates a distribution decision key.
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 Shortage
Identifies shortage or lost-sales decision variables.
const string Backlog
Identifies backlog-level decision variables.
const string Delivery
Identifies delivered-quantity decision variables.
Represents one decision variable in a mathematical optimization model.
MathematicalConstraintSense
Identifies the relational sense of a mathematical constraint.