Skip to content

Releases: HansBug/packingsolver3d

v0.0.5

Choose a tag to compare

@HansBug HansBug released this 21 Sep 08:43

Upstream moved to PackingSolver 9ae71316

Five upstream commits since d10db9d7, two of them fixes for crashes reported from this package:

  • Bin weight checks use one absolute tolerance. fontanf/packingsolver#586 (fixes #582) replaces the multiplicative PSTOL slack the branching schemes relaxed against with a tolerance precomputed from the highest bin weight of the instance, applied identically in the search and in Solution::build. The ROADEF 2022 instance X/MA4/MA4_2520 aborted in all four optimisation modes with solution doesn't satisfy bin weight capacity on d10db9d7; it now places its 122 items in 0.8–1.6 s in every mode. Applied to onedimensional, box, rectangle and boxstacks.
  • Sequential value correction no longer aborts on a multi-bin knapsack. #588 (fixes #587) stops dividing by the packed copies of an item type the previous pass left out entirely; such a type keeps its profit instead of poisoning the next pass with Items must have strictly positive profits. Of 36 synthetic multi-bin boxstacks knapsack loads (2–3 containers, 3–12 item types, 1.2–2.0 times the volume), 19 aborted on d10db9d7 and none do now; one improves (118 → 127 items), none worsens. Upstream's regression instance is replayed by this package's upstream-case tests.
  • boxstacks exposes its remaining OptimizeParameters on the command line and drops the unused use_tree_search field (the bridge never set it); the shape and mathoptsolverscmake dependencies are bumped (the stricter convex_hull only affects irregular, which this package does not build).

Algorithm paths and their pacing are unchanged: the three multi-bin bin-packing loads of the SSK path end with the same items, bins and times to the millisecond, so the recommend_time_budget constants measured on d10db9d7 are kept. Data and scripts of the comparison: gist.

Compatibility

  • No API change; calls behave as in 0.0.4, apart from the upstream fixes above. __UPSTREAM_COMMIT__ is 9ae71316e8856c0a312f06b61b536e44f37d0d5d.

Wheels: CPython 3.7 to 3.14 on Linux x86_64 / aarch64, Windows AMD64 / ARM64, macOS arm64 / x86_64, built with PACKINGSOLVER_USE_HIGHS=ON, as before.

v0.0.4

Choose a tag to compare

@HansBug HansBug released this 20 Sep 04:17

Upstream moved to PackingSolver d10db9d7

  • Multi-bin boxstacks bin packing fills bins one at a time. Upstream 9bfb9431 adds a sequential single knapsack path (SSK) next to sequential value correction (SVC), chosen by the same mean-items-per-bin thresholds as box; 63ed7915 (fontanf/packingsolver#584) forwards the timer to the DP pricing subproblem and d10db9d7 enables its pairing heuristic. On 43 container loads with a 60 s limit: loads without a solution 31 → 15 of 43, first solution median 30 s → 0.5 s, no time-limit overrun. Knapsack and variable-sized bin packing with several bins still run SVC.
  • Not included: fontanf/packingsolver#586 (the weight-tolerance abort of #582) is not merged upstream yet.

New API

  • stop_when_unimproved_ratio on box.solve / boxstacks.solve: a relative patience. The solve stops once no improvement has arrived for the larger of stop_when_unimproved_for and ratio times the time of the last improvement, and never before a first solution exists. Upstream's anytime searches double their queues between passes, so a fixed patience either cuts late passes short or wastes most of the budget; the relative one waits for the next pass wherever the search is.
  • recommend_time_budget now returns that ratio (alpha / 2 clamped to 1 … 4: 2 for box, 4 for boxstacks at their default alpha), sets stop_when_unimproved_after to the predicted first-solution latency and stop_when_unimproved_for to a 5 s floor; TimeBudget.as_options() carries all four values. 0.0.3's rule (after = T/2, patience = (T − L)/2) ended solves at 0.5–0.85 of the limit; on the recorded curves the relative rule ends them at 0.7–1.0 of a tighter limit for the balanced alpha and gives back a third of the time at alpha = 8.
  • algorithm_path mirrors the new multi-bin boxstacks selection; the multi-bin boxstacks paths were re-measured on d10db9d7 (122 runs plus 24 multi-bin knapsack loads) and the constants regenerated. Docs: Explanations / Upstream behaviours gains "Multi-bin boxstacks fills bins one at a time"; the time-budget page documents the stall rule with a replay against the previous one.

Compatibility

  • No breaking change; calls without the new keyword argument behave as in 0.0.3, apart from the upstream improvements above.

Wheels: CPython 3.7 to 3.14 on Linux x86_64 / aarch64, Windows AMD64 / ARM64, macOS arm64 / x86_64, built with PACKINGSOLVER_USE_HIGHS=ON, as before.

v0.0.3

Choose a tag to compare

@HansBug HansBug released this 19 Sep 08:18

Upstream moved to PackingSolver 2a598481

  • Anytime single-bin boxstacks. Upstream fontanf/packingsolver#578 turns the sequential onedimensional rectangle algorithm into an anytime variant: under a time limit the solve no longer returns the truncated result of one fixed-size pass but grows its queues level by level and always holds the best complete solution found so far. On the 40' container of the examples the 10 s result went from about half the cargo to 1022 of 1036 items.

New API

  • progress_callback (#2) on box.solve / boxstacks.solve: called on every improvement with an immutable ProgressEvent (time, items, bins, profit, cost, upstream's label); returning False stops the solve (result.run.stop_reason == 'callback'). Exceptions raised in the callback propagate unchanged.
  • stop_when_unimproved_for / stop_when_unimproved_after (#3): end an anytime solve once no improvement has arrived for the given number of seconds, optionally not before a given time; result.run.stop_reason == 'unimproved'.
  • recommend_time_budget(instance, solver, alpha=None, speed=1.0) (#4) returns a TimeBudget — a time_limit that is a loose upper bound plus matching stall-stop knobs — from a model fitted on 3158 recorded anytime curves, one interpretable formula per upstream algorithm path (algorithm_path replicates upstream's automatic selection). alpha weighs quality against waiting (4 balanced, 8 thorough; default 4 for box, 8 for boxstacks), speed rescales for the machine. Also exported: DEFAULT_ALPHA, instance_features, count_stacks. The campaign, its figures and a replay of stopping policies live in experiments/time_budget/; the docs gain Explanations / How the time budget is estimated and a how-to section.

Compatibility

  • No breaking change: calls without the new keyword arguments behave as in 0.0.2, apart from the upstream anytime improvement above.

Wheels: CPython 3.7 to 3.14 on Linux x86_64 / aarch64, Windows AMD64 / ARM64, macOS arm64 / x86_64, built with PACKINGSOLVER_USE_HIGHS=ON, as before.

v0.0.2

Choose a tag to compare

@HansBug HansBug released this 15 Sep 00:40

Upstream moved to PackingSolver 3f4faae1

This release only moves the vendored PackingSolver from a7e53303 to 3f4faae1; the Python API is unchanged.

  • boxstacks no longer returns an empty solution under a time limit. Upstream fontanf/packingsolver#571 (fixes #570) replaced the box tree search that computed the bound before the primal algorithms with closed-form volume bounds, a one-dimensional relaxation and dual feasible functions. Before, on knapsack, bin packing and variable-sized bin packing instances with several item types and more items than fit, that search consumed the whole time_limit and boxstacks.solve came back with no placements.
  • Instance reduction in box and boxstacks (upstream 24decc4c): negative-profit item types are trimmed under knapsack and identical item types are merged; both happen inside optimize() and results are mapped back to the original item types.
  • Multi-bin solutions no longer read past unsized weight vectors. Upstream fontanf/packingsolver#576 (fixes #575): with instance reduction on, every bin packing / variable-sized bin packing solve using two or more bins rebuilt its solution through a path that indexed the still-empty per-group weight vectors of later bins, an access violation with MSVC. This is why 0.0.2 was not published from 24decc4c: its Windows test suite crashed on exactly that case.
  • test/test_upstream_cases.py replays the three upstream reproducer instances of #570 with the same 3 s limit, and the postal-carton instance of #575 without one.

Wheels: CPython 3.7 to 3.14 on Linux x86_64 / aarch64, Windows AMD64 / ARM64, macOS arm64 / x86_64, built with PACKINGSOLVER_USE_HIGHS=ON, as before.

v0.0.1

Choose a tag to compare

@HansBug HansBug released this 10 Sep 01:18

First release of packingsolver3d: Pythonic, in-process bindings for the two three-dimensional solvers of PackingSolver, box and boxstacks. The upstream C++ (commit a7e53303) is compiled together with a pybind11 bridge into one extension module; nothing runs in a subprocess and no C++ object ever reaches Python.

What it does

  • packingsolver3d.box -- 3D bin packing, knapsack, variable-sized bin packing and open-dimension objectives over rectangular boxes: several bin types with copies and costs, item types with copies, profits, weights and any subset of the six rotations, bin weight capacity, and every upstream algorithm switch (tree search, sequential single knapsack, sequential value correction, column generation, dichotomic search, dual feasible functions).
  • packingsolver3d.boxstacks -- the truck-loading engine on top of the same model: stacks with stackability ids, nesting height, maximum stackability, maximum weight above, stack density, semi-trailer truck axle limits, floor defects and unloading constraints.
  • Value in, value out -- frozen dataclasses (Instance, BinType, ItemType, ...) go in, a Result with status, value, bound, bins, stacks and placements comes out; Result.run records the exact upstream options, upstream's log and the wall time.
  • Honest statuses -- OPTIMAL only when the achieved value meets a bound upstream reported for that objective; a good-looking heuristic packing stays FEASIBLE.
  • Guarded inputs -- instances that the chosen solver would silently misread are refused with typed errors (UnsupportedFeatureError, StackSemanticsError, InvalidInstanceError) instead of being solved as a different problem.
  • Budgets -- time_limit and memory_limit go to upstream's own timer and memory check; anytime and deterministic optimisation modes are exposed.
  • Visualisation -- packingsolver3d.visual.plot_result draws any result as an interactive plotly figure (optional plot extra).
  • Concurrency -- the GIL is released while upstream runs and its log is collected through a per-call stream, so several threads may solve at once.

Benchmarks

The documentation carries a reproducible capability study on three public instance families (Egeblad-Pisinger 3D knapsack, Martello-Pisinger-Vigo class 9, Ivancic-Mathur-Mohanty THPACK9; 97 cases) next to py3dbp, jerry800416/3D-bin-packing, gedex/bp3d, the five U-Nesting strategies and two exact reference codes, with every solution re-validated by an independent geometry checker: https://packingsolver3d.readthedocs.io/en/latest/benchmarks/index.html

Wheels

CPython 3.7--3.14 on Linux x86_64 and Windows AMD64, 3.8--3.14 on Linux aarch64 and macOS (x86_64 and arm64, 11.0+), 3.11--3.14 on Windows ARM64; an sdist for everything else (needs a C++17 compiler, git, network access and CMake 3.28+, which pip installs where a cmake wheel exists). The sdist is installed from source in clean Debian, Alpine and Ubuntu containers on every CI run.

Known upstream behaviours

Documented, not papered over -- see https://packingsolver3d.readthedocs.io/en/latest/explanations/upstream_behaviours/index.html: the LP backend is always HiGHS; copies_min defaults to "all copies"; boxstacks groups stacks by (group_id, stackability_id) without checking footprints and keeps items upright; boxstacks accepts floor defects but places stacks over them at the pinned commit; limits are upstream's own checks and the solver runs in-process; unset profit and cost default to geometry; the default objective produces no solution and is refused; anytime runs are not reproducible run to run.

Install

pip install packingsolver3d            # solver only
pip install "packingsolver3d[plot]"    # with plotly for the figures

Documentation: https://packingsolver3d.readthedocs.io/en/latest/ -- Unofficial distribution, not endorsed by the PackingSolver author; upstream is MIT licensed, see NOTICE.md.