23 ArgumentNullException.ThrowIfNull(instance);
28 DetectZeroFullProduction(instance);
30 InitialInventoryDecisionMode[] modes =
34 inventory.InitialInventoryDecisionMode)
45 ProblemVariant = problem,
46 CapacityVariant = DetectCapacityVariant(chain),
47 BucketVariant = DetectBucketVariant(chain),
48 NumberOfMachines = chain.WorkCenters.Count(),
49 NumberOfItems = chain.Items.Count,
50 NumberOfPeriods = chain.PlanningHorizon,
51 NumberOfLevels = DetectNumberOfLevels(chain),
52 HasSalesOption = chain.SalesOptions.Count > 0,
54 chain.ProductionCharacteristics.Any(
56 characteristic.SetupTime is not
null),
57 DeclaredMachineLabel =
67 ArgumentNullException.ThrowIfNull(instance);
69 var issues =
new List<string>();
72 foreach (Inventory inventory
in chain.Inventories)
74 if (!inventory.HasValidInitialInventoryDecisionSemantics)
77 $
"Inventory item {inventory.ItemId} has a non-zero fixed " +
78 "InitialInventory while its mode requires zero.");
82 foreach (SalesOption salesOption
in chain.SalesOptions)
84 if (!salesOption.IsInternallyValid)
87 $
"SalesOption item {salesOption.ItemId} / distribution center " +
88 $
"{salesOption.DistributionCenterId} is internally invalid.");
91 if (!chain.Items.Any(item => item.Id == salesOption.ItemId))
94 $
"SalesOption references unknown item {salesOption.ItemId}.");
97 if (!chain.DistributionCenters.Any(
100 salesOption.DistributionCenterId))
103 "SalesOption references unknown distribution center " +
104 $
"{salesOption.DistributionCenterId}.");
113 IReadOnlyCollection<InitialInventoryDecisionMode> modes)
115 if (!zeroFull || modes.Count != 1)
120 return modes.Single()
switch
122 InitialInventoryDecisionMode.VariableDecision =>
125 InitialInventoryDecisionMode.AbsentFixedZero =>
129 WolseyDetectedProblemVariant.Undetermined
133 private static bool DetectZeroFullProduction(
136 bool schedulingEvidence =
139 workCenter.SchedulingProfile is not
null &&
140 workCenter.SchedulingProfile.SmallBucketProductionMode ==
141 SmallBucketProductionMode.AllOrNothing);
143 if (schedulingEvidence)
151 LotSizingProblemFeatureExtractor.Extract(
154 string[] acceptedPropertyNames =
156 "HasZeroFullProduction",
157 "HasZeroFullCapacityProduction",
158 "UsesZeroFullProduction",
159 "UsesZeroFullCapacityProduction"
162 Type type = features.GetType();
164 foreach (
string propertyName
in acceptedPropertyNames)
166 PropertyInfo?
property =
169 BindingFlags.Instance |
170 BindingFlags.Public);
172 if (property?.PropertyType == typeof(
bool) &&
173 property.GetValue(features) is
true)
186 chain.WorkCenters.ToArray();
188 if (workCenters.Length == 0)
193 CapacityConstraint[] capacities =
197 workCenter.CapacityConstraint)
200 capacity is not
null)
201 .Cast<CapacityConstraint>()
204 if (capacities.Length == 0)
209 if (capacities.Length != workCenters.Length)
214 bool allConstant =
true;
216 foreach (CapacityConstraint capacity
in capacities)
218 if (capacity.PlanningHorizon != chain.PlanningHorizon)
223 if (chain.PlanningHorizon <= 1)
228 double first = capacity[1];
231 period <= chain.PlanningHorizon;
234 if (!capacity[period].Equals(first))
243 ? WolseyDetectedCapacityVariant.CC
251 chain.WorkCenters.ToArray();
256 workCenter.CapacityConstraint is not
null &&
257 CountItemsUsingWorkCenter(
261 ProductionSchedulingProfile[] profiles =
265 workCenter.SchedulingProfile is not
null)
268 workCenter.SchedulingProfile!)
271 if (profiles.Length == 0)
278 profile.BucketMode ==
279 SchedulingBucketMode.SmallBucket) &&
282 profile.MaximumSetupCount is not
null))
284 int maximumSetupCount = 0;
286 foreach (ProductionSchedulingProfile profile
in profiles)
288 if (profile.MaximumSetupCount!.PlanningHorizon !=
289 chain.PlanningHorizon)
295 period <= chain.PlanningHorizon;
301 profile.MaximumSetupCount.GetCount(period));
305 if (maximumSetupCount <= 1)
310 if (maximumSetupCount <= 2)
316 ? WolseyDetectedBucketVariant.BB
322 profile.BucketMode ==
323 SchedulingBucketMode.BigBucket) &&
332 private static int CountItemsUsingWorkCenter(
334 WorkCenter workCenter)
336 return chain.ProductionRoutings
339 routing.WorkCenters.Any(
341 reference.WorkCenterId ==
350 private static int? DetectNumberOfLevels(
353 if (chain.Items.Count == 0)
358 if (chain.ComponentRequirements.Count == 0)
364 chain.ComponentRequirements
367 requirement.ParentItemId)
375 requirement.ComponentItemId)
379 var state =
new Dictionary<int, int>();
380 var memo =
new Dictionary<int, int>();
382 int? Visit(
int itemId)
384 if (memo.TryGetValue(itemId, out
int cached))
389 if (state.TryGetValue(itemId, out
int current) &&
398 if (children.TryGetValue(itemId, out
int[]? childIds))
400 foreach (
int childId
in childIds)
402 int? childDepth = Visit(childId);
404 if (childDepth is
null)
412 1 + childDepth.Value);
417 memo[itemId] = depth;
423 foreach (var item
in chain.Items)
425 int? depth = Visit(item.Id);
432 maximum = Math.Max(maximum, depth.Value);