Skip to content

Commit e067f91

Browse files
GiggleLiuisPANNclaude
authored
Fix #513: [Model] ProductionPlanning (#761)
* Add plan for #513: [Model] ProductionPlanning * Implement #513: [Model] ProductionPlanning * chore: remove plan file after implementation * fix: update ProductionPlanning to current Problem trait API - Replace deprecated SatisfactionProblem/type Metric with type Value = Or - Fix CLI --cost-budget → --cost-bound to use existing arg field - Update tests to use Or() assertions and find_witness() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Xiwei Pan <xiwei.pan@connect.hkust-gz.edu.cn> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 31a81ad commit e067f91

File tree

9 files changed

+723
-12
lines changed

9 files changed

+723
-12
lines changed

docs/paper/reductions.typ

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
"MultipleCopyFileAllocation": [Multiple Copy File Allocation],
170170
"ExpectedRetrievalCost": [Expected Retrieval Cost],
171171
"MultiprocessorScheduling": [Multiprocessor Scheduling],
172+
"ProductionPlanning": [Production Planning],
172173
"PartitionIntoPathsOfLength2": [Partition into Paths of Length 2],
173174
"PartitionIntoTriangles": [Partition Into Triangles],
174175
"PrecedenceConstrainedScheduling": [Precedence Constrained Scheduling],
@@ -5436,6 +5437,57 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76],
54365437
]
54375438
}
54385439

5440+
#{
5441+
let x = load-model-example("ProductionPlanning")
5442+
let n = x.instance.num_periods
5443+
let demands = x.instance.demands
5444+
let capacities = x.instance.capacities
5445+
let setup-costs = x.instance.setup_costs
5446+
let production-costs = x.instance.production_costs
5447+
let inventory-costs = x.instance.inventory_costs
5448+
let bound = x.instance.cost_bound
5449+
let plan = x.optimal_config
5450+
let prefix-production = range(n).map(i => plan.slice(0, i + 1).sum())
5451+
let prefix-demand = range(n).map(i => demands.slice(0, i + 1).sum())
5452+
let inventory = range(n).map(i => prefix-production.at(i) - prefix-demand.at(i))
5453+
let production-total = range(n).map(i => production-costs.at(i) * plan.at(i)).sum()
5454+
let inventory-total = range(n).map(i => inventory-costs.at(i) * inventory.at(i)).sum()
5455+
let setup-total = range(n).filter(i => plan.at(i) > 0).map(i => setup-costs.at(i)).sum()
5456+
[
5457+
#problem-def("ProductionPlanning")[
5458+
Given a positive integer $n$, period demands $r_1, dots, r_n in ZZ_(>= 0)$, production capacities $c_1, dots, c_n in ZZ_(>= 0)$, setup costs $b_1, dots, b_n in ZZ_(>= 0)$, per-unit production costs $p_1, dots, p_n in ZZ_(>= 0)$, per-unit inventory costs $h_1, dots, h_n in ZZ_(>= 0)$, and a bound $B in ZZ_(>= 0)$, determine whether there exist production quantities $x_1, dots, x_n$ such that $0 <= x_i <= c_i$ for every period $i$, the inventory prefix $I_i = sum_(j=1)^i (x_j - r_j)$ satisfies $I_i >= 0$ for every $i$, and $sum_(i=1)^n (p_i x_i + h_i I_i) + sum_(i: x_i > 0) b_i <= B$.
5459+
][
5460+
Production Planning is the lot-sizing feasibility problem SS21 in Garey & Johnson @garey1979. Florian, Lenstra, and Rinnooy Kan show that the general problem is NP-complete even under strong restrictions, while also giving pseudo-polynomial dynamic-programming algorithms for capacitated variants @florianLenstraRinnooyKan1980. The implementation in this repository uses one bounded integer variable per period, so the registered exact baseline explores the direct witness space $product_i (c_i + 1)$; under the uniform-capacity bound $C = max_i c_i$, this becomes $O^*((C + 1)^n)$#footnote[This is the search bound induced by the configuration space exposed by the implementation, not a literature-best exact algorithm claim.].
5461+
5462+
*Example.* Consider the canonical instance with #n periods, demands $(#demands.map(str).join(", "))$, capacities $(#capacities.map(str).join(", "))$, setup costs $(#setup-costs.map(str).join(", "))$, production costs $(#production-costs.map(str).join(", "))$, inventory costs $(#inventory-costs.map(str).join(", "))$, and budget $B = #bound$. The satisfying production plan $x = (#plan.map(str).join(", "))$ yields prefix inventories $(#inventory.map(str).join(", "))$. The verifier therefore accepts, and its cost breakdown is $#production-total + #inventory-total + #setup-total = #(production-total + inventory-total + setup-total) <= #bound$.
5463+
5464+
#pred-commands(
5465+
"pred create --example " + problem-spec(x) + " -o production-planning.json",
5466+
"pred solve production-planning.json --solver brute-force",
5467+
"pred evaluate production-planning.json --config " + x.optimal_config.map(str).join(","),
5468+
)
5469+
5470+
#figure({
5471+
table(
5472+
columns: n + 1,
5473+
align: center,
5474+
inset: 4pt,
5475+
table.header([*Period*], ..range(n).map(i => [#(i + 1)])),
5476+
[$r_i$], ..range(n).map(i => [#demands.at(i)]),
5477+
[$c_i$], ..range(n).map(i => [#capacities.at(i)]),
5478+
[$b_i$], ..range(n).map(i => [#setup-costs.at(i)]),
5479+
[$p_i$], ..range(n).map(i => [#production-costs.at(i)]),
5480+
[$h_i$], ..range(n).map(i => [#inventory-costs.at(i)]),
5481+
[$x_i$], ..range(n).map(i => [#plan.at(i)]),
5482+
[$I_i$], ..range(n).map(i => [#inventory.at(i)]),
5483+
)
5484+
},
5485+
caption: [Canonical Production Planning instance from the example DB. The documented plan meets every prefix-demand constraint and stays within the budget $B = #bound$.],
5486+
) <fig:production-planning>
5487+
]
5488+
]
5489+
}
5490+
54395491
#{
54405492
let x = load-model-example("CapacityAssignment")
54415493
[

docs/paper/references.bib

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,16 @@ @book{garey1979
180180
year = {1979}
181181
}
182182

183+
@article{florianLenstraRinnooyKan1980,
184+
author = {M. Florian and J. K. Lenstra and A. H. G. Rinnooy Kan},
185+
title = {Deterministic Production Planning: Algorithms and Complexity},
186+
journal = {Management Science},
187+
volume = {26},
188+
number = {7},
189+
pages = {669--679},
190+
year = {1980}
191+
}
192+
183193
@article{busingstiller2011,
184194
author = {Christina Büsing and Sebastian Stiller},
185195
title = {Line planning, path constrained network flow and inapproximability},

problemreductions-cli/src/cli.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ Flags by problem type:
245245
PathConstrainedNetworkFlow --arcs, --capacities, --source, --sink, --paths, --requirement
246246
Factoring --target, --m, --n
247247
BinPacking --sizes, --capacity
248-
CapacityAssignment --capacities, --cost-matrix, --delay-matrix, --delay-budget
248+
CapacityAssignment --capacities, --cost-matrix, --delay-matrix, --cost-budget, --delay-budget
249+
ProductionPlanning --num-periods, --demands, --capacities, --setup-costs, --production-costs, --inventory-costs, --cost-bound
249250
SubsetSum --sizes, --target
250251
ThreePartition --sizes, --bound
251252
SumOfSquaresPartition --sizes, --num-groups
@@ -329,7 +330,8 @@ Examples:
329330
pred create MIS --graph 0-1,1-2,2-3 --weights 1,1,1
330331
pred create SAT --num-vars 3 --clauses \"1,2;-1,3\"
331332
pred create QUBO --matrix \"1,0.5;0.5,2\"
332-
pred create CapacityAssignment --capacities 1,2,3 --cost-matrix \"1,3,6;2,4,7;1,2,5\" --delay-matrix \"8,4,1;7,3,1;6,3,1\" --delay-budget 12
333+
pred create CapacityAssignment --capacities 1,2,3 --cost-matrix \"1,3,6;2,4,7;1,2,5\" --delay-matrix \"8,4,1;7,3,1;6,3,1\" --cost-budget 10 --delay-budget 12
334+
pred create ProductionPlanning --num-periods 6 --demands 5,3,7,2,8,5 --capacities 12,12,12,12,12,12 --setup-costs 10,10,10,10,10,10 --production-costs 1,1,1,1,1,1 --inventory-costs 1,1,1,1,1,1 --cost-bound 80
333335
pred create GeneralizedHex --graph 0-1,0-2,0-3,1-4,2-4,3-4,4-5 --source 0 --sink 5
334336
pred create IntegralFlowWithMultipliers --arcs \"0>1,0>2,1>3,2>3\" --capacities 1,1,2,2 --source 0 --sink 3 --multipliers 1,2,3,1 --requirement 2
335337
pred create MultipleChoiceBranching/i32 --arcs \"0>1,0>2,1>3,2>3,1>4,3>5,4>5,2>4\" --weights 3,2,4,1,2,3,1,3 --partition \"0,1;2,3;4,7;5,6\" --bound 10
@@ -379,6 +381,18 @@ pub struct CreateArgs {
379381
/// Capacities (edge capacities for flow problems, capacity levels for CapacityAssignment)
380382
#[arg(long)]
381383
pub capacities: Option<String>,
384+
/// Demands for ProductionPlanning (comma-separated, e.g., "5,3,7,2,8,5")
385+
#[arg(long)]
386+
pub demands: Option<String>,
387+
/// Setup costs for ProductionPlanning (comma-separated, e.g., "10,10,10,10,10,10")
388+
#[arg(long)]
389+
pub setup_costs: Option<String>,
390+
/// Per-unit production costs for ProductionPlanning (comma-separated, e.g., "1,1,1,1,1,1")
391+
#[arg(long)]
392+
pub production_costs: Option<String>,
393+
/// Per-unit inventory costs for ProductionPlanning (comma-separated, e.g., "1,1,1,1,1,1")
394+
#[arg(long)]
395+
pub inventory_costs: Option<String>,
382396
/// Bundle capacities for IntegralFlowBundles (e.g., 1,1,1)
383397
#[arg(long)]
384398
pub bundle_capacities: Option<String>,

0 commit comments

Comments
 (0)