LotSizingDataModel.Core 2.0.1
Core domain model, shared abstractions and XML-serializable entities.
Loading...
Searching...
No Matches
TransportCharacteristic.DecisionModel.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Xml.Serialization;
9
11
12/// <summary>
13/// Adds the optional decision-model parameters associated with
14/// transporting an item using a transport resource.
15/// </summary>
16public sealed partial class TransportCharacteristic :
17 IPlanningHorizonAware
18{
19 private CapacityConstraint? _capacityConstraint;
20 private AdditionalCapacity? _additionalCapacity;
21 private AdditionalCapacityCost? _additionalCapacityCost;
22
23 private UnitCapacityConsumption? _unitCapacityConsumption;
24 private SetupTime? _setupTime;
25 private FixedSetupCost? _fixedSetupCost;
26 private UnitUsageCost? _unitUsageCost;
27
28 /// <summary>
29 /// Gets or sets the maximum transport capacity available
30 /// specifically for this item during each planning period.
31 ///
32 /// A null value means that no item-specific capacity limit
33 /// is defined.
34 /// </summary>
35 [XmlElement("capacityConstraint")]
37 {
38 get => _capacityConstraint;
39 set => SetDecisionParameter(
40 ref _capacityConstraint,
41 value,
42 nameof(CapacityConstraint));
43 }
44
45 /// <summary>
46 /// Gets or sets the maximum additional transport capacity
47 /// available specifically for this item.
48 ///
49 /// This parameter should only be defined when an item-specific
50 /// capacity constraint is also defined.
51 /// </summary>
52 [XmlElement("additionalCapacity")]
54 {
55 get => _additionalCapacity;
56 set => SetDecisionParameter(
57 ref _additionalCapacity,
58 value,
59 nameof(AdditionalCapacity));
60 }
61
62 /// <summary>
63 /// Gets or sets the unit cost of additional transport
64 /// capacity allocated to this item.
65 /// </summary>
66 [XmlElement("additionalCapacityCost")]
68 {
69 get => _additionalCapacityCost;
70 set => SetDecisionParameter(
71 ref _additionalCapacityCost,
72 value,
74 }
75
76 /// <summary>
77 /// Gets or sets the transport capacity consumed by one unit
78 /// of the item during each planning period.
79 /// </summary>
80 [XmlElement("unitCapacityConsumption")]
82 {
83 get => _unitCapacityConsumption;
84 set => SetDecisionParameter(
85 ref _unitCapacityConsumption,
86 value,
88 }
89
90 /// <summary>
91 /// Gets or sets the capacity consumed to prepare the transport
92 /// resource for this item during each planning period.
93 /// </summary>
94 [XmlElement("setupTime")]
96 {
97 get => _setupTime;
98 set => SetDecisionParameter(
99 ref _setupTime,
100 value,
101 nameof(SetupTime));
102 }
103
104 /// <summary>
105 /// Gets or sets the fixed cost incurred when the transport
106 /// resource is prepared for this item.
107 /// </summary>
108 [XmlElement("fixedSetupCost")]
110 {
111 get => _fixedSetupCost;
112 set => SetDecisionParameter(
113 ref _fixedSetupCost,
114 value,
115 nameof(FixedSetupCost));
116 }
117
118 /// <summary>
119 /// Gets or sets the cost of transporting one unit of the item
120 /// during each planning period.
121 /// </summary>
122 [XmlElement("unitUsageCost")]
124 {
125 get => _unitUsageCost;
126 set => SetDecisionParameter(
127 ref _unitUsageCost,
128 value,
129 nameof(UnitUsageCost));
130 }
131
132 /// <summary>
133 /// Gets the planning horizon represented by the first active
134 /// period-dependent parameter.
135 ///
136 /// Returns zero when no decision parameter is active.
137 /// </summary>
138 [XmlIgnore]
140 {
141 get
142 {
143 // Return the first active parameter's horizon.
144 foreach (IPlanningHorizonAware parameter
145 in GetDecisionParameters())
146 {
147 return parameter.PlanningHorizon;
148 }
149
150 // No active parameter → horizon is zero.
151 return 0;
152 }
153 }
154
155 /// <summary>
156 /// Gets a value indicating whether at least one
157 /// decision-model parameter is active.
158 /// </summary>
159 [XmlIgnore]
161 CapacityConstraint is not null ||
162 AdditionalCapacity is not null ||
163 AdditionalCapacityCost is not null ||
164 UnitCapacityConsumption is not null ||
165 SetupTime is not null ||
166 FixedSetupCost is not null ||
167 UnitUsageCost is not null;
168
169 /// <summary>
170 /// Gets a value indicating whether all active parameters
171 /// use the same planning horizon.
172 /// </summary>
173 [XmlIgnore]
175 {
176 get
177 {
178 int? expectedHorizon = null;
179
180 // Compare each active parameter's horizon against the first.
181 foreach (IPlanningHorizonAware parameter
182 in GetDecisionParameters())
183 {
184 if (expectedHorizon is null)
185 {
186 expectedHorizon =
187 parameter.PlanningHorizon;
188
189 continue;
190 }
191
192 if (parameter.PlanningHorizon !=
193 expectedHorizon.Value)
194 {
195 return false;
196 }
197 }
198
199 return true;
200 }
201 }
202
203 /// <summary>
204 /// Gets a value indicating whether the dependencies between
205 /// the transport parameters are respected.
206 /// </summary>
207 [XmlIgnore]
209 (AdditionalCapacity is null ||
210 CapacityConstraint is not null) &&
211
212 (AdditionalCapacityCost is null ||
213 AdditionalCapacity is not null);
214
215 /// <summary>
216 /// Resizes every active period-dependent parameter.
217 ///
218 /// Existing values are preserved.
219 /// </summary>
220 /// <param name="periodCount">
221 /// New number of planning periods.
222 /// </param>
223 public void ResizeTimeSeries(int periodCount)
224 {
225 if (periodCount < 0)
226 {
227 throw new ArgumentOutOfRangeException(
228 nameof(periodCount),
229 periodCount,
230 "The planning horizon cannot be negative.");
231 }
232
233 // Resize every active decision parameter.
234 foreach (IPlanningHorizonAware parameter
235 in GetDecisionParameters())
236 {
237 parameter.ResizeTimeSeries(periodCount);
238 }
239
240 // Notify dependent computed properties.
244 }
245
246 /// <summary>
247 /// Removes all optional decision-model parameters from this
248 /// transport characteristic.
249 /// </summary>
251 {
252 CapacityConstraint = null;
253 AdditionalCapacity = null;
255
257 SetupTime = null;
258 FixedSetupCost = null;
259 UnitUsageCost = null;
260 }
261
262 private void SetDecisionParameter<T>(
263 ref T? field,
264 T? value,
265 string propertyName)
267 {
268 if (ReferenceEquals(field, value))
269 {
270 return;
271 }
272
273 // Unsubscribe from old parameter.
274 if (field is not null)
275 {
276 field.PropertyChanged -=
277 OnDecisionParameterPropertyChanged;
278 }
279
280 field = value;
281
282 // Subscribe to new parameter.
283 if (field is not null)
284 {
285 field.PropertyChanged +=
286 OnDecisionParameterPropertyChanged;
287 }
288
289 // Notify the specific property plus all dependent ones.
290 OnPropertyChanged(propertyName);
297 }
298
299 private IEnumerable<IPlanningHorizonAware>
300 GetDecisionParameters()
301 {
302 if (CapacityConstraint is not null)
303 {
304 yield return CapacityConstraint;
305 }
306
307 if (AdditionalCapacity is not null)
308 {
309 yield return AdditionalCapacity;
310 }
311
312 if (AdditionalCapacityCost is not null)
313 {
314 yield return AdditionalCapacityCost;
315 }
316
317 if (UnitCapacityConsumption is not null)
318 {
319 yield return UnitCapacityConsumption;
320 }
321
322 if (SetupTime is not null)
323 {
324 yield return SetupTime;
325 }
326
327 if (FixedSetupCost is not null)
328 {
329 yield return FixedSetupCost;
330 }
331
332 if (UnitUsageCost is not null)
333 {
334 yield return UnitUsageCost;
335 }
336 }
337
338 private void OnDecisionParameterPropertyChanged(
339 object? sender,
340 PropertyChangedEventArgs e)
341 {
342 // Forward notification for the specific parameter that changed.
343 if (ReferenceEquals(sender, CapacityConstraint))
344 {
346 }
347 else if (ReferenceEquals(sender, AdditionalCapacity))
348 {
350 }
351 else if (ReferenceEquals(
352 sender,
354 {
356 nameof(AdditionalCapacityCost));
357 }
358 else if (ReferenceEquals(
359 sender,
361 {
364 }
365 else if (ReferenceEquals(sender, SetupTime))
366 {
368 }
369 else if (ReferenceEquals(sender, FixedSetupCost))
370 {
372 }
373 else if (ReferenceEquals(sender, UnitUsageCost))
374 {
376 }
377
378 // Update all computed properties that may be affected.
384 }
385}
Base class for model objects that notify listeners when one of their properties changes.
virtual void OnPropertyChanged([CallerMemberName] string? propertyName=null)
Raises the PropertyChanged event.
Represents the transport characteristics of an item for a specific transport resource.
void ResizeTimeSeries(int periodCount)
Resizes every active period-dependent parameter.
UnitUsageCost? UnitUsageCost
Gets or sets the cost of transporting one unit of the item during each planning period.
FixedSetupCost? FixedSetupCost
Gets or sets the fixed cost incurred when the transport resource is prepared for this item.
int PlanningHorizon
Gets the planning horizon represented by the first active period-dependent parameter.
AdditionalCapacity? AdditionalCapacity
Gets or sets the maximum additional transport capacity available specifically for this item.
SetupTime? SetupTime
Gets or sets the capacity consumed to prepare the transport resource for this item during each planni...
bool HasValidDecisionConfiguration
Gets a value indicating whether the dependencies between the transport parameters are respected.
CapacityConstraint? CapacityConstraint
Gets or sets the maximum transport capacity available specifically for this item during each planning...
void ClearDecisionParameters()
Removes all optional decision-model parameters from this transport characteristic.
UnitCapacityConsumption? UnitCapacityConsumption
Gets or sets the transport capacity consumed by one unit of the item during each planning period.
AdditionalCapacityCost? AdditionalCapacityCost
Gets or sets the unit cost of additional transport capacity allocated to this item.
bool HasConsistentPlanningHorizon
Gets a value indicating whether all active parameters use the same planning horizon.
bool HasDecisionParameters
Gets a value indicating whether at least one decision-model parameter is active.
Defines a model object containing data indexed by planning period.
int PlanningHorizon
Gets the number of planning periods currently represented by the object's time-dependent data.
void ResizeTimeSeries(int periodCount)
Resizes every time-dependent series contained in the object.