94 lines
5.7 KiB
Markdown
94 lines
5.7 KiB
Markdown
# Optimiser measurements
|
||
|
||
Run `npm run benchmark` for **Minimise cuts**, or `npm run benchmark -- --random` for
|
||
**Maximise randomness**. Both are compared with the original stock-first optimiser's
|
||
frozen results in `baseline.json`. The 84 inputs in `cases.ts` cover rectangular
|
||
remainders, fireplaces in both directions, room-order permutations, tight and exact
|
||
stagger limits, fractional stock, large floors, and both supplied angled rooms.
|
||
`--output=/tmp/results.json` saves a run; `--compare=/tmp/results.json` compares
|
||
against a previous iteration. Do not overwrite the baseline to hide regressions.
|
||
|
||
## Fixed metrics
|
||
|
||
- **Saw passes:** crosscuts actually required by the allocation, long-edge rips,
|
||
and additional shaping edges. Skirting includes bevel and coping operations.
|
||
- **Cut difficulty:** shaping passes, then rip passes, used to break equal saw-count
|
||
ties. This is an explicit proxy, not an estimate of minutes or tool-specific effort.
|
||
- **Random appearance:** the existing repetition penalty, evaluated independently
|
||
from the output rows. It penalises nearby repeating joints, similar consecutive
|
||
steps and staircases, including steps that wrap across a board length. Raw repeat,
|
||
similar-step and staircase counts are also reported. A lower score is better.
|
||
- **Waste:** purchased stock minus installed material, including kerf. The report
|
||
gives board counts and waste percentages weighted by purchased stock.
|
||
- **Validity and runtime:** errors, elapsed time, p95 and maximum case time. Tests
|
||
separately verify coverage, non-overlapping row bands, minimum sizes, stagger,
|
||
factory ends, rounded stock consumption, cut accounting, references and input purity.
|
||
|
||
Minimise cuts orders `(passes, shaping, rips, pattern penalty, boards)`.
|
||
Maximise randomness orders `(pattern penalty, passes, shaping, rips, boards)`.
|
||
Validity precedes either objective. Skirting orders `(passes, waste)`.
|
||
|
||
## Measured results
|
||
|
||
Totals across the same 84 cases, September 2026:
|
||
|
||
| Metric | Original | Minimise cuts | Maximise randomness |
|
||
| ------------------- | -------: | ------------: | ------------------: |
|
||
| Flooring saw passes | 2,177 | **1,741** | **1,994** |
|
||
| Shaping passes | 192 | 184 | 185 |
|
||
| Rip passes | 414 | 402 | 405 |
|
||
| Pattern penalty | 265 | 1,349 | **113** |
|
||
| Flooring boards | 3,561 | 3,537 | 3,579 |
|
||
| Flooring waste | 8.20% | 7.57% | 8.66% |
|
||
| Invalid cases | 0 | 0 | 0 |
|
||
|
||
Minimise cuts saves **20.0%** of saw passes. Maximise randomness reduces the pattern
|
||
penalty **57.4%**, while also saving **8.4%** of saw passes. For random flooring in the
|
||
default 4,800 × 3,600 mm room, 38 passes become **24** or **30**, respectively; both options use 76
|
||
boards and have approximately 1.2% waste.
|
||
|
||
Skirting drops from **1,447 to 1,436 passes**. It uses 521 boards instead of 513:
|
||
cutting effort now takes precedence over waste, which rises from 9.28% to 10.68%.
|
||
Eight cases improve and 76 tie.
|
||
For flooring, 78 cut-priority cases improve and six tie. Appearance priority improves
|
||
72, ties 11, and uses one extra cut in `rectangle-38` despite the same zero pattern
|
||
penalty. The bounded search does not establish global optimality.
|
||
|
||
## Iterations retained
|
||
|
||
1. Correct the objective order; measuring stock first contradicted the requested priorities.
|
||
2. Deduplicate the complete relevant state, including recent joint history. Stop
|
||
computing keys once the beam is full; share immutable exhausted stocks and avoid
|
||
searching offcuts for pieces requiring both factory ends.
|
||
3. Repack completed boundary blanks, reserving exact complementary factory ends
|
||
first. Preserve the original placement and cutting order within each source board.
|
||
4. Try bounded swaps of interchangeable rectangular rows. Accept only a lower
|
||
pattern penalty with unchanged cuts, stock and geometry coverage.
|
||
5. Polish all surviving completed candidates, retaining the best result.
|
||
6. Preserve end remnants during search instead of trimming them immediately.
|
||
This alone improves 56 cut-priority cases and saves another 99 passes after the
|
||
earlier improvements. Final packing can still combine non-exact blanks.
|
||
7. When repetition remains, compare an immediate-reuse search as well. This improves
|
||
five appearance-priority cases. All searches share their clipping cache, and the
|
||
two UI choices select from the completed results. Selection itself does not rerun
|
||
the optimiser.
|
||
8. Compare exact three-piece skirting fills with the original packing. This improves
|
||
two cases for a small additional calculation cost.
|
||
|
||
## Experiments rejected
|
||
|
||
Increasing beam widths from 5/2 to 12/4 roughly tripled search time, with regressions
|
||
in both modes. Carrying two room results into the next room worsened two appearance
|
||
cases for a single waste improvement. Expanding the offcut candidate pool with
|
||
distinct remnants had no cut-priority benefit and regressed a large-room result,
|
||
including after the end-preservation change. These variants were removed.
|
||
|
||
The original single-result benchmark took about 1.5 seconds for the corpus. Producing
|
||
both choices, including the conditional extra appearance search, takes about 3 seconds
|
||
on the same machine; p95 is around 110 ms and the most complex case around 0.7 seconds.
|
||
These are indicative timings, not CI thresholds. Ordinary option changes reuse the
|
||
already calculated plans. A separate 500-row, 2,000-board boundary check completes
|
||
without an error; temporary stock is repacked before enforcing the board limit.
|
||
|
||
Tests enforce the retained aggregate improvements as well as physical invariants.
|
||
Metric definitions and input cases stay fixed while search strategies change.
|