FA-95006 / Warehouse slotting and bin packing / Open access
Pallet build: weight limit not applied · case 01
Dense cases are stacked to the height limit and the pallet exceeds its gross weight rating.
ROOT CAUSE
The case count only considers the layer limit and never the weight bound.
VERIFIED REPAIR
Take the minimum of the height-limited and weight-limited case counts.
Unsuccessful approach: Rounding the weight bound down to full layers discards a legal partial top layer.
Case contract
case [l, w, h, kg], pallet [L, W]; cases stay upright but may rotate 90 degrees; all layers share one orientation. Pallet base adds 15 height and 25 kg tare. Cases per pallet are bounded by whole layers within max_h and by max_kg (a partial top layer is allowed). Return [per_layer, layers used, cases, height, weight].
Why this case matters
Pallet build limits govern reserve storage heights and floor loading.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(case, pallet, max_h, max_kg):
l, w, h, kg = case
L, W = pallet
per_layer = max((L // l) * (W // w), (L // w) * (W // l))
if per_layer == 0:
return [0, 0, 0, 15, 25]
layers = (max_h - 15) // h
by_weight = (max_kg - 25) // kg
cases = per_layer * layers
if cases <= 0:
return [per_layer, 0, 0, 15, 25]
full = -(-cases // per_layer)
return [per_layer, full, cases, 15 + full * h, 25 + cases * kg]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['generated mix 1', [[50, 15, 10, 12], [120, 100], 190, 1025], [16, 6, 83, 75, 1021]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 7', [[40, 30, 20, 5], [120, 80], 140, 1025], [8, 6, 48, 135, 265]], ['generated mix 15', [[50, 20, 30, 8], [120, 80], 115, 800], [8, 3, 24, 105, 217]]], [['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['generated mix 9', [[50, 20, 25, 12], [120, 100], 115, 1200], [12, 4, 48, 115, 601]], ['generated mix 17', [[30, 30, 30, 8], [120, 80], 165, 500], [8, 5, 40, 165, 345]], ['generated mix 26', [[25, 30, 25, 12], [120, 80], 140, 1200], [12, 5, 60, 140, 745]]], [['generated mix 34', [[25, 15, 20, 5], [120, 100], 115, 300], [32, 2, 55, 55, 300]], ['generated mix 33', [[40, 30, 10, 20], [120, 80], 165, 800], [8, 5, 38, 65, 785]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['generated mix 28', [[20, 30, 20, 12], [120, 80], 140, 800], [16, 4, 64, 95, 793]]], [['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 38', [[40, 15, 10, 20], [120, 80], 115, 1200], [16, 4, 58, 55, 1185]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 31', [[40, 15, 25, 5], [120, 100], 190, 1025], [18, 7, 126, 190, 655]], ['generated mix 40', [[20, 15, 30, 20], [120, 80], 190, 500], [32, 1, 23, 45, 485]]], [['generated mix 57', [[30, 15, 10, 8], [120, 80], 115, 500], [20, 3, 59, 45, 497]], ['generated mix 44', [[30, 30, 10, 5], [120, 80], 140, 500], [8, 12, 95, 135, 500]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 51', [[25, 15, 10, 8], [120, 80], 165, 500], [24, 3, 59, 45, 497]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| weight bound partial layer | [9, 7, 63, 190, 1285] | [9, 3, 20, 90, 425] | Failed |
| generated mix 1 | [16, 17, 272, 185, 3289] | [16, 6, 83, 75, 1021] | Failed |
| listed orientation wins | [20, 5, 100, 115, 525] | [20, 5, 100, 115, 525] | Passed |
| height exact | [9, 5, 45, 140, 115] | [9, 5, 45, 140, 115] | Passed |
| too heavy for one | [9, 7, 63, 190, 31525] | [9, 0, 0, 15, 25] | Failed |
| rotation wins | [8, 5, 40, 115, 225] | [8, 5, 40, 115, 225] | Passed |
| generated mix 7 | [8, 6, 48, 135, 265] | [8, 6, 48, 135, 265] | Passed |
| generated mix 15 | [8, 3, 24, 105, 217] | [8, 3, 24, 105, 217] | Passed |
SHA-256 / 5aa2f9013467884b5528e91367fedad885fc5e62e5eff8c54b30296d6167ba88
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(case, pallet, max_h, max_kg):
l, w, h, kg = case
L, W = pallet
per_layer = max((L // l) * (W // w), (L // w) * (W // l))
if per_layer == 0:
return [0, 0, 0, 15, 25]
layers = (max_h - 15) // h
by_weight = (max_kg - 25) // kg
cases = min(per_layer * layers, by_weight // per_layer * per_layer)
if cases <= 0:
return [per_layer, 0, 0, 15, 25]
full = -(-cases // per_layer)
return [per_layer, full, cases, 15 + full * h, 25 + cases * kg]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['generated mix 1', [[50, 15, 10, 12], [120, 100], 190, 1025], [16, 6, 83, 75, 1021]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 7', [[40, 30, 20, 5], [120, 80], 140, 1025], [8, 6, 48, 135, 265]], ['generated mix 15', [[50, 20, 30, 8], [120, 80], 115, 800], [8, 3, 24, 105, 217]]], [['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['generated mix 9', [[50, 20, 25, 12], [120, 100], 115, 1200], [12, 4, 48, 115, 601]], ['generated mix 17', [[30, 30, 30, 8], [120, 80], 165, 500], [8, 5, 40, 165, 345]], ['generated mix 26', [[25, 30, 25, 12], [120, 80], 140, 1200], [12, 5, 60, 140, 745]]], [['generated mix 34', [[25, 15, 20, 5], [120, 100], 115, 300], [32, 2, 55, 55, 300]], ['generated mix 33', [[40, 30, 10, 20], [120, 80], 165, 800], [8, 5, 38, 65, 785]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['generated mix 28', [[20, 30, 20, 12], [120, 80], 140, 800], [16, 4, 64, 95, 793]]], [['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 38', [[40, 15, 10, 20], [120, 80], 115, 1200], [16, 4, 58, 55, 1185]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 31', [[40, 15, 25, 5], [120, 100], 190, 1025], [18, 7, 126, 190, 655]], ['generated mix 40', [[20, 15, 30, 20], [120, 80], 190, 500], [32, 1, 23, 45, 485]]], [['generated mix 57', [[30, 15, 10, 8], [120, 80], 115, 500], [20, 3, 59, 45, 497]], ['generated mix 44', [[30, 30, 10, 5], [120, 80], 140, 500], [8, 12, 95, 135, 500]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 51', [[25, 15, 10, 8], [120, 80], 165, 500], [24, 3, 59, 45, 497]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| weight bound partial layer | [9, 2, 18, 65, 385] | [9, 3, 20, 90, 425] | Failed |
| generated mix 1 | [16, 5, 80, 65, 985] | [16, 6, 83, 75, 1021] | Failed |
| listed orientation wins | [20, 5, 100, 115, 525] | [20, 5, 100, 115, 525] | Passed |
| height exact | [9, 5, 45, 140, 115] | [9, 5, 45, 140, 115] | Passed |
| too heavy for one | [9, 0, 0, 15, 25] | [9, 0, 0, 15, 25] | Passed |
| rotation wins | [8, 5, 40, 115, 225] | [8, 5, 40, 115, 225] | Passed |
| generated mix 7 | [8, 6, 48, 135, 265] | [8, 6, 48, 135, 265] | Passed |
| generated mix 15 | [8, 3, 24, 105, 217] | [8, 3, 24, 105, 217] | Passed |
SHA-256 / ba5686298e66049acfca27c99227e6e48fa57e9c9263dcd3a9f3b38eb697d41e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(case, pallet, max_h, max_kg):
l, w, h, kg = case
L, W = pallet
per_layer = max((L // l) * (W // w), (L // w) * (W // l))
if per_layer == 0:
return [0, 0, 0, 15, 25]
layers = (max_h - 15) // h
by_weight = (max_kg - 25) // kg
cases = min(per_layer * layers, by_weight)
if cases <= 0:
return [per_layer, 0, 0, 15, 25]
full = -(-cases // per_layer)
return [per_layer, full, cases, 15 + full * h, 25 + cases * kg]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['generated mix 1', [[50, 15, 10, 12], [120, 100], 190, 1025], [16, 6, 83, 75, 1021]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 7', [[40, 30, 20, 5], [120, 80], 140, 1025], [8, 6, 48, 135, 265]], ['generated mix 15', [[50, 20, 30, 8], [120, 80], 115, 800], [8, 3, 24, 105, 217]]], [['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['generated mix 9', [[50, 20, 25, 12], [120, 100], 115, 1200], [12, 4, 48, 115, 601]], ['generated mix 17', [[30, 30, 30, 8], [120, 80], 165, 500], [8, 5, 40, 165, 345]], ['generated mix 26', [[25, 30, 25, 12], [120, 80], 140, 1200], [12, 5, 60, 140, 745]]], [['generated mix 34', [[25, 15, 20, 5], [120, 100], 115, 300], [32, 2, 55, 55, 300]], ['generated mix 33', [[40, 30, 10, 20], [120, 80], 165, 800], [8, 5, 38, 65, 785]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['weight bound partial layer', [[40, 30, 25, 20], [120, 100], 190, 425], [9, 3, 20, 90, 425]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['generated mix 20', [[20, 20, 25, 20], [120, 100], 115, 1200], [30, 2, 58, 65, 1185]], ['generated mix 28', [[20, 30, 20, 12], [120, 80], 140, 800], [16, 4, 64, 95, 793]]], [['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 38', [[40, 15, 10, 20], [120, 80], 115, 1200], [16, 4, 58, 55, 1185]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['square', [[25, 25, 30, 5], [120, 80], 165, 900], [12, 5, 60, 165, 325]], ['rotation wins', [[50, 30, 20, 5], [120, 100], 115, 1000], [8, 5, 40, 115, 225]], ['generated mix 31', [[40, 15, 25, 5], [120, 100], 190, 1025], [18, 7, 126, 190, 655]], ['generated mix 40', [[20, 15, 30, 20], [120, 80], 190, 500], [32, 1, 23, 45, 485]]], [['generated mix 57', [[30, 15, 10, 8], [120, 80], 115, 500], [20, 3, 59, 45, 497]], ['generated mix 44', [[30, 30, 10, 5], [120, 80], 140, 500], [8, 12, 95, 135, 500]], ['too heavy for one', [[40, 30, 25, 500], [120, 100], 190, 425], [9, 0, 0, 15, 25]], ['listed orientation wins', [[30, 20, 20, 5], [120, 100], 115, 1000], [20, 5, 100, 115, 525]], ['height exact', [[40, 30, 25, 2], [120, 100], 140, 2000], [9, 5, 45, 140, 115]], ['too big', [[130, 30, 25, 2], [120, 100], 190, 425], [0, 0, 0, 15, 25]], ['generated mix 42', [[40, 30, 20, 5], [120, 80], 165, 300], [8, 7, 55, 155, 300]], ['generated mix 51', [[25, 15, 10, 8], [120, 80], 165, 500], [24, 3, 59, 45, 497]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| weight bound partial layer | [9, 3, 20, 90, 425] | [9, 3, 20, 90, 425] | Passed |
| generated mix 1 | [16, 6, 83, 75, 1021] | [16, 6, 83, 75, 1021] | Passed |
| listed orientation wins | [20, 5, 100, 115, 525] | [20, 5, 100, 115, 525] | Passed |
| height exact | [9, 5, 45, 140, 115] | [9, 5, 45, 140, 115] | Passed |
| too heavy for one | [9, 0, 0, 15, 25] | [9, 0, 0, 15, 25] | Passed |
| rotation wins | [8, 5, 40, 115, 225] | [8, 5, 40, 115, 225] | Passed |
| generated mix 7 | [8, 6, 48, 135, 265] | [8, 6, 48, 135, 265] | Passed |
| generated mix 15 | [8, 3, 24, 105, 217] | [8, 3, 24, 105, 217] | Passed |
SHA-256 / d0c4b8dfb0317f795234911bf0ea2fabfc02fbfcc022a3b08a272a679e258cca
Verification & scope
Uniform-case, single-orientation layer model; no interlocking patterns. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:52:09.791086+00:00.
Case digest / d745a906f3d48279ca071da660154e4c215f5dabd0e6a9792c5a9739845a6971