///|
pub(all) struct PatternGroup {
stock_id : String
counts : Array[Int32]
repetitions : Int32
remaining_each : Int32
} derive(Debug)
///|
pub extend PatternGroup with @debug.Debug::{to_repr}
///|
/// A compact shop-floor bill of cutting patterns, in first-use order.
pub fn group_patterns(
p : Problem,
plan : Plan,
) -> Result[Array[PatternGroup], String] {
match audit(p, plan) {
Err(e) => return Err(e)
Ok(_) => ()
}
let result : Array[PatternGroup] = []
for a in plan.bars {
let id = p.stocks[a.stock].id
let mut found = -1
for i, g in result {
if g.stock_id == id && g.counts == a.counts {
found = i
break
}
}
if found >= 0 {
let g = result[found]
result[found] = { ..g, repetitions: g.repetitions + 1, }
} else {
result.push({
stock_id: id,
counts: a.counts.copy(),
repetitions: 1,
remaining_each: a.remaining,
})
}
}
Ok(result)
}
///|
/// Read a compact pattern bill; the independent audit still requires exact fulfillment.
pub fn expand_groups(
p : Problem,
groups : Array[PatternGroup],
) -> Result[Plan, String] {
if groups.length() > 128 {
return Err("too many pattern groups")
}
let bars : Array[Pattern] = []
for g in groups {
if g.repetitions < 1 ||
g.repetitions > 128 ||
bars.length() + g.repetitions > 128 {
return Err("pattern repetitions outside plan bound")
}
let mut si = -1
for i, s in p.stocks {
if s.id == g.stock_id {
si = i
break
}
}
let a = match pattern(p, si, g.counts) {
Err(e) => return Err(e)
Ok(v) => v
}
if a.remaining != g.remaining_each {
return Err("group remaining length mismatch")
}
for _ in 0..