Portfolio arrangement for sequential printing (20 strategies in parallel) #170

Open
opened 2026-04-05 16:18:46 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @Wachhund on 3/25/2026

Summary

This PR implements a portfolio-based arrangement optimization for sequential printing (By Object mode). Instead of using a single arrangement strategy, it evaluates 20 different strategies in parallel (5 placement tactics × 4 object orderings) and automatically selects the best result — the one requiring the fewest printing plates.

References

Based on two papers by Pavel Surynek et al.:

  1. P. Surynek, V. Bubník, L. Matěna, P. Kubiš"Object Packing and Scheduling for Sequential 3D Printing: a Linear Arithmetic Model and a CEGAR-inspired Optimal Solver", arXiv:2503.05071 [cs.CG], 2025. doi:10.48550/arXiv.2503.05071
    — Formalizes the SEQ-PACK+S problem and introduces the CEGAR-SEQ algorithm with Z3 SMT solver.

  2. P. Surynek"Portfolio of Solving Strategies in CEGAR-based Object Packing and Scheduling for Sequential 3D Printing", arXiv:2603.12224 [cs.AI], 2026. doi:10.48550/arXiv.2603.12224
    — Extends CEGAR-SEQ with a portfolio of 5 placement tactics × 4 object orderings = 20 strategies evaluated in parallel.

This PR implements the portfolio approach from paper (2) using the existing libnest2d NFP engine instead of the Z3 SMT solver, requiring no new dependencies.

Key changes

  • PlacementTactic enum (5 values): Center, MaxXMinY, MinXMaxY, MinXMinY, MaxXMaxY — maps directly to libnest2d NfpPConfig::Alignment values
  • ObjectOrdering enum (4 values): HeightMinToMax, HeightMaxToMin, HeightRandom, HeightInput — controls item sort order before packing
  • ArrangeStrategy struct: Combines a tactic + ordering as a composite strategy
  • portfolio_arrange() function: Runs all 20 strategies in parallel via TBB, selects the result with fewest plates (tiebreaker: smallest bounding box area)
  • get_origin_for_alignment() helper: Correctly maps all 5 alignment values to bin corner/center points for the NFP optimizer
  • ArrangeJob integration: Automatically activates portfolio mode when print_sequence == ByObject. Shows a toast notification with the winning strategy and plate count
  • Comprehensive tests: 15+ Catch2 tests including strategy validation, regression tests, and benchmarks with real printer part polygons

Design decisions

  • No new config setting — Portfolio activates automatically for sequential printing. It is strictly equal or better than single-strategy arrangement, so there is no reason to disable it. A config toggle can be added as a follow-up if needed.
  • No new dependencies — Uses only existing libnest2d, TBB, and NLopt. All 5 alignment values and custom sort functions are already supported by libnest2d.
  • Backward compatible — Without the strategy field set (default std::nullopt), behavior is 100% identical to current code. The arrange() function signature is unchanged.
  • Thread-safe — Each parallel strategy runs on its own copy of the items list. No shared mutable state. stopcondition (cancel) propagates to all parallel runs.

How it works

  1. When the user clicks "Arrange" in By Object mode, portfolio_arrange() generates 20 strategy combinations
  2. All 20 run in parallel via tbb::parallel_for, each calling the existing arrange() with a different strategy
  3. Each result is scored: primary = number of plates used, secondary = total bounding box area
  4. The best result is applied to the model
  5. A toast notification shows: "Portfolio Arrange: MinXMaxY + HeightMaxToMin — 3 plate(s) (best of 20 strategies)"

Files changed

File Change
src/libslic3r/Arrange.hpp New enums, structs, portfolio_arrange() declaration
src/libslic3r/Arrange.cpp Strategy mapping, sort function dispatch, portfolio runner, get_origin_for_alignment()
src/slic3r/GUI/Jobs/ArrangeJob.hpp m_portfolio_result member
src/slic3r/GUI/Jobs/ArrangeJob.cpp Portfolio call + toast notification
tests/libslic3r/test_arrange_strategy.cpp 15+ tests
tests/libslic3r/CMakeLists.txt Test registration

Build verification

  • Linux (Docker/Ubuntu 24.04): Full build successful — 640/640 compile units, no errors. GUI tested in VM.
  • Windows (VS2022): All source files compile successfully. Linker issues with GMP/MPFR (pre-existing dependency problem, unrelated to this PR)

Test plan

  • All 5 PlacementTactics produce valid arrangement results
  • All 4 ObjectOrderings produce valid arrangement results
  • All 20 strategy combinations work without crashes
  • Default strategy matches original arrange behavior (regression test)
  • Portfolio uses same or fewer plates than single strategy (3 benchmark testsets)
  • Stopcondition (cancel) works correctly
  • Non-sequential print mode falls back to single arrange
  • Empty items list handled gracefully
  • Toast notification shows winning strategy and plate count
  • Different object layouts produce different winning strategies
  • Hardware validation print on Bambu X1 Carbon (pending)
*Originally created by @Wachhund on 3/25/2026* ## Summary This PR implements a **portfolio-based arrangement optimization** for sequential printing (By Object mode). Instead of using a single arrangement strategy, it evaluates **20 different strategies in parallel** (5 placement tactics × 4 object orderings) and automatically selects the best result — the one requiring the fewest printing plates. ### References Based on two papers by Pavel Surynek et al.: 1. **P. Surynek, V. Bubník, L. Matěna, P. Kubiš** — *"Object Packing and Scheduling for Sequential 3D Printing: a Linear Arithmetic Model and a CEGAR-inspired Optimal Solver"*, arXiv:2503.05071 [cs.CG], 2025. [doi:10.48550/arXiv.2503.05071](https://doi.org/10.48550/arXiv.2503.05071) — Formalizes the SEQ-PACK+S problem and introduces the CEGAR-SEQ algorithm with Z3 SMT solver. 2. **P. Surynek** — *"Portfolio of Solving Strategies in CEGAR-based Object Packing and Scheduling for Sequential 3D Printing"*, arXiv:2603.12224 [cs.AI], 2026. [doi:10.48550/arXiv.2603.12224](https://doi.org/10.48550/arXiv.2603.12224) — Extends CEGAR-SEQ with a portfolio of 5 placement tactics × 4 object orderings = 20 strategies evaluated in parallel. This PR implements the portfolio approach from paper (2) using the existing libnest2d NFP engine instead of the Z3 SMT solver, requiring no new dependencies. ### Key changes - **`PlacementTactic` enum** (5 values): Center, MaxXMinY, MinXMaxY, MinXMinY, MaxXMaxY — maps directly to libnest2d `NfpPConfig::Alignment` values - **`ObjectOrdering` enum** (4 values): HeightMinToMax, HeightMaxToMin, HeightRandom, HeightInput — controls item sort order before packing - **`ArrangeStrategy` struct**: Combines a tactic + ordering as a composite strategy - **`portfolio_arrange()` function**: Runs all 20 strategies in parallel via TBB, selects the result with fewest plates (tiebreaker: smallest bounding box area) - **`get_origin_for_alignment()` helper**: Correctly maps all 5 alignment values to bin corner/center points for the NFP optimizer - **ArrangeJob integration**: Automatically activates portfolio mode when `print_sequence == ByObject`. Shows a toast notification with the winning strategy and plate count - **Comprehensive tests**: 15+ Catch2 tests including strategy validation, regression tests, and benchmarks with real printer part polygons ### Design decisions - **No new config setting** — Portfolio activates automatically for sequential printing. It is strictly equal or better than single-strategy arrangement, so there is no reason to disable it. A config toggle can be added as a follow-up if needed. - **No new dependencies** — Uses only existing libnest2d, TBB, and NLopt. All 5 alignment values and custom sort functions are already supported by libnest2d. - **Backward compatible** — Without the strategy field set (default `std::nullopt`), behavior is 100% identical to current code. The `arrange()` function signature is unchanged. - **Thread-safe** — Each parallel strategy runs on its own copy of the items list. No shared mutable state. stopcondition (cancel) propagates to all parallel runs. ### How it works 1. When the user clicks "Arrange" in By Object mode, `portfolio_arrange()` generates 20 strategy combinations 2. All 20 run in parallel via `tbb::parallel_for`, each calling the existing `arrange()` with a different strategy 3. Each result is scored: primary = number of plates used, secondary = total bounding box area 4. The best result is applied to the model 5. A toast notification shows: `"Portfolio Arrange: MinXMaxY + HeightMaxToMin — 3 plate(s) (best of 20 strategies)"` ### Files changed | File | Change | |------|--------| | `src/libslic3r/Arrange.hpp` | New enums, structs, `portfolio_arrange()` declaration | | `src/libslic3r/Arrange.cpp` | Strategy mapping, sort function dispatch, portfolio runner, `get_origin_for_alignment()` | | `src/slic3r/GUI/Jobs/ArrangeJob.hpp` | `m_portfolio_result` member | | `src/slic3r/GUI/Jobs/ArrangeJob.cpp` | Portfolio call + toast notification | | `tests/libslic3r/test_arrange_strategy.cpp` | 15+ tests | | `tests/libslic3r/CMakeLists.txt` | Test registration | ### Build verification - **Linux (Docker/Ubuntu 24.04)**: Full build successful — 640/640 compile units, no errors. GUI tested in VM. - **Windows (VS2022)**: All source files compile successfully. Linker issues with GMP/MPFR (pre-existing dependency problem, unrelated to this PR) ## Test plan - [x] All 5 PlacementTactics produce valid arrangement results - [x] All 4 ObjectOrderings produce valid arrangement results - [x] All 20 strategy combinations work without crashes - [x] Default strategy matches original arrange behavior (regression test) - [x] Portfolio uses same or fewer plates than single strategy (3 benchmark testsets) - [x] Stopcondition (cancel) works correctly - [x] Non-sequential print mode falls back to single arrange - [x] Empty items list handled gracefully - [x] Toast notification shows winning strategy and plate count - [x] Different object layouts produce different winning strategies - [ ] Hardware validation print on Bambu X1 Carbon (pending)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/OrcaSlicer#170