Benchmark of the “Optimal” Algorithm

Every cutting optimizer calls itself “optimal”. We publish the numbers: three sets of test instances, an independent oracle for the small ones, provable lower bounds for the shop-floor ones, and the raw JSON with every parameter of the run. Last run: 2026-09-17, engine 6edd4c42bb6b.

▶ Open the calculator

What “Optimal” actually is

Not one formula but a multi-strategy search over the same job: the fast heuristics (FFD, BFD, FFI, quantity ordering), pattern-based dynamic programming, shuffled FFD and GRASP with a fixed seed, look-ahead, and two bounded exact searches — one for few distinct lengths, one for short lists. Every candidate goes through local improvement (emptying bars and swaps), then the solution with the least material wins, fewest bars second. Budgets are counted in operations, not seconds — the result is identical on a fast or a slow server. We display it as the “best solution found”; we say “proven optimal” only when it meets the mathematical lower bound for the job.

Methodology

Three sets of synthetic instances with a fixed seed (20260917), generated by tests/benchmark_optimal.py. (A) Exact-verifiable: 200 small instances (2–4 stock bars 60–130, 2–7 parts 10–65, kerf 0/1/3) with an independent oracle — full enumeration of every assignment. (B) Steel shop: 300 cut lists — 6000 mm stock (90 of them with a 6000 + 12000 mix), 8–30 distinct lengths 250–5800 mm at 1–20 pieces each, kerf 3 mm, min remnant 300 mm; 204 parts per job on average (from 55 to 393). (C) Scaling: 50, 200, 500, 1000, 2000 parts × 3 jobs. All modes run in a single process on one machine; time is time.perf_counter around the engine call itself.

(A) Agreement with the proven optimum

On the small instances the oracle knows the true optimum. “Full match” also requires the same distribution of remnants across bars; “material + bars” is what you actually pay for; “min. bars” — whether the smallest possible number of bars was reached.

AlgorithmFull match with oracleOptimal material + barsMin. barsMedian time (s)
Optimal100%100%100%<0.01
FFD42.5%74.5%84%<0.01
BFD42.5%74.5%84%<0.01
FFI32.5%62.5%76.5%<0.01
LOOK63%80.5%88.5%<0.01
GRASP64%79.5%88%<0.01
SFFD65.5%80.5%88.5%<0.01
Seq31%59.5%59.5%<0.01

(B) Steel shop: 300 cut lists

Here the true optimum is unknown — we compare against a lower bound: L1 = ⌈Σ(length + kerf) / (6000 + kerf)⌉ and the stronger Martello–Toth L2, which counts the parts above 3000 mm that cannot share a bar. “Proven optimal” = the solution meets the bound. With the mixed 6000 + 12000 stock we count in 6 m equivalents (a 12 m bar = 2) and only L1 applies, so the bound is looser there. “Optimal” is strictly better than FFD on 38.3% of the jobs, equal on 61.7% and worse on 0%; versus BFD it is better on 39.3%. Bars saved over FFD across the whole set: 973. Single-stock jobs only (210 of them): proven optimal 31.4%, average gap to the bound 1.67 bars, maximum 8.

AlgorithmAvg bars (6 m eq.)Avg wasteProven optimalAvg gap (bars)Max gapMedian time (s)95th pct (s)
Optimal110.77.7%26.3%1.79123.8511.34
FFD114.010.4%21.3%5.04470.030.08
BFD114.010.5%21.3%5.05470.030.08
FFI114.310.7%20.7%5.35470.040.11
GRASP114.010.4%21.3%5.02470.230.66
SFFD114.010.4%20.7%5.06470.150.47
Seq120.315.2%6.3%11.35490.010.02

(C) Scaling: time by job size

Median time in seconds over 3 jobs per size (single 6000 stock, same parameters as in B). The engine has built-in gates: look-ahead runs up to 240 parts, the exact searches up to 600, which is why time does not grow linearly with size. Sizes where “Optimal” exceeds 10 s: —.

PartsOptimalFFDBFDFFILOOKGRASPSFFDSeq
500.21<0.01<0.01<0.010.100.020.01<0.01
2006.740.010.030.022.900.260.160.01
5004.020.240.250.250.171.490.940.03
10005.860.280.240.300.311.521.420.08
20007.610.310.680.310.384.173.690.44

Honest caveats

The instances are random and synthetic. Uniformly distributed lengths of 250–5800 mm are harsher than a typical cut list — most parts above 3 m cannot share a bar, so waste is high for every algorithm; what matters is the difference between them, not the absolute value. A gap to the lower bound is not proven sub-optimality — the true optimum lies somewhere between the bound and the solution found. Timings come from one machine (Python 3.14.0); the server may be faster or slower. Real jobs differ — the surest test is your own cut list.

Raw data and reproducibility

The script tests/benchmark_optimal.py (standard library + the engine only) is part of the application code, which is not public — we run the test ourselves. What is public is the raw result: benchmark-results.json (backend/benchmark_results.json in the code); the page reads its numbers from that file at start-up — nothing is typed in by hand. It records seed 20260917, the instance-generator parameters, the limits and the engine SHA-256 6edd4c42bb6b7ba0b5f9ee2f6d1b5f11e054c90d2c972b9a961082d945c91f4c. The full run (py -3 tests/benchmark_optimal.py) takes about 30 minutes. The “Optimal” algorithm is available on the Hobby and Pro plans; the free plan uses FFD and BFD from the same tables.

Frequently asked questions

Why isn't “proven optimal” 100% on the steel-shop set?

Because the lower bound is not the optimum itself. On a job with many parts above 3 m the bound underestimates the bars needed, so a solution can be optimal without us being able to prove it. On set A, where the optimum is known exactly, agreement is 100%.

Why are FFD and BFD so close?

With random lengths most bars fill up in an obvious way and any reasonable heuristic finds them. The difference comes on “tight” jobs with 2–3-part combinations that single-pass algorithms never see — that is where “Optimal” wins a bar or two, and per ton of steel that is real money.

Can I run the test myself?

No — the script and the engine are part of the application code and are not publicly available. What is public is the raw JSON at /benchmark-results.json with the seed, the generator parameters and the per-instance results; every number in the tables comes from it. The surest check is your own cut list: compare “Optimal” (Hobby/Pro) with FFD/BFD in the calculator.

▶ Open the calculator

More on cutting optimization