Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/DISCUSSION_TEMPLATE/q-a.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ body:
id: package-version
attributes:
label: Package and version
placeholder: "packvium 1.9.0 (Python)"
placeholder: "packvium 1.10.0 (Python)"
validations:
required: true
- type: textarea
Expand Down
2 changes: 1 addition & 1 deletion .github/DISCUSSION_TEMPLATE/show-and-tell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ body:
id: package-version
attributes:
label: Package and version
placeholder: "packvium 1.9.0 (Python)"
placeholder: "packvium 1.10.0 (Python)"
validations:
required: false
- type: textarea
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ body:
id: version
attributes:
label: Package version
description: The exact version installed, for example 1.9.0.
placeholder: "1.9.0"
description: The exact version installed, for example 1.10.0.
placeholder: "1.10.0"
validations:
required: true
- type: input
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ body:
id: version
attributes:
label: Package version
placeholder: "1.9.0"
placeholder: "1.10.0"
validations:
required: true
- type: textarea
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,53 @@ What changed in `packvium` on PyPI, release by release. The format follows
[Keep a Changelog](https://keepachangelog.com/1.1.0/) and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.10.0]

New request fields, a bound under three more objectives, and the intelligence modules join the
frozen API. One stricter refusal: a `units` key other than `length` (see *Changed*).

### Added

- **`container.pallet_overhang_limit`** (`OverhangLimit`): a load may pass the deck by the
stated length at each end and width at each side. Only the deck bears weight, and the packed
pallet reports `achieved_dimensions`.
- **Gusseted bags:** `deformable_boundary.kind: "gusseted_bag"` with `side_gusset_depth`;
`Container` gains `side_gusset_depth` and `side_gusset_ticks`.
- **24 rotations for a `convex_hull` item:** 18 signed codes such as `-L-W+H` beside the six;
`Rotation.every()`, `is_signed`, `is_upright`. `Rotation.all()` and `upright()` are unchanged.
- **`placement_id` on every placement**, which `fixed_placements`, revision events,
`FixedPlacement` and `PlacementLock` may quote; `validate` checks it.
- **`currency`** on the request and `rate_table`, echoed on the result; `PackingRequest`,
`Packer.pack` and `RateTable` take it.
- **`optimality.lower_bound` under `maximum_value`, `open_dimension_height` and
`maximum_volume`**, checked by `validate`.
- **`NestedPacker(level_beam_width=K)`** carries the K best carton sets up a level and lets the
outermost level's score choose; 1 (the default) is the greedy chain, answer for answer.
- **A made-to-measure box may keep a `void_fill_reserve_ratio`.**
- **`packvium.revisions.stock_cut_boxes`.**

### Changed

- **`units` refuses every key but `length`**: `invalid_request` / `not_allowed` at
`/units/<key>`. 1.9 read a bare weight as grams whatever `units.weight` said.
- **`derive_revision` stocks a box already cut to measure** that holds a locked or verified
placement, as `<type>@<revision>#<instance>`; `verify_revision_chain` then needs that
revision's artifact and reports `artifact_required` without it.
- **`packvium.simulation`, `recommendations`, `outcomes`, `holdout`, `pareto` and `locks` are
signature-frozen**, like the packing API.

### Fixed

- **An explicit rotation list emptied by `keep_upright` is refused at `allowed_rotations`**,
with the same named request error the independent validator checks.
- **Stocking cut boxes indexes artifact lookups once** and reports malformed consumed
machine fields as structured `invalid_revision` errors.
- **`resolve_with_locks` reported a held lock as `missing`** when the re-solve opened the same
containers in another order; a lock from `locks_from_plan` is now matched by `placement_id`.
- **An artifact export refuses an integer past `2^53 - 1`** with `number_out_of_range`
rather than printing it.
- **A compressible item no longer joins a rigid item's grid lattice.**

## [1.9.0]

No API change, but admission is stricter: some requests 1.8 accepted are now refused (see the
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type: software
authors:
- name: "Packvium contributors"
website: "https://packvium.com"
version: "1.9.0"
version: "1.10.0"
license: MIT
url: "https://packvium.com"
repository-code: "https://github.com/toxakara/packvium-python"
Expand Down
36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ coordinates and rotations for each item, with a reason for anything that did not
Full documentation, the constraint reference and benchmarks live at
[packvium.com](https://packvium.com).

> **Version 1.9.0 — the public API is frozen.** Field names, status codes and the
> **Version 1.10.0 — the public API is frozen.** Field names, status codes and the
> objective vector do not change without a major version, so any `1.x` is a safe upgrade
> from any earlier `1.x`.
> Read [docs/GUARANTEES.md](https://github.com/toxakara/packvium-python/blob/main/docs/GUARANTEES.md) before relying on a result.
Expand Down Expand Up @@ -72,7 +72,7 @@ Item.create("mug", Dimensions.mm("100", "100", "120"), "12 oz")

A JSON request refuses a float measure rather than rounding it: send `"160.5"`, not
`160.5`. Its `units` sets only the length unit; a weight takes its unit from the measure or is
grams, and `units.weight` is ignored today. See
grams; any other `units` key, `weight` included, is refused. See
[docs/UNITS-AND-NUMERICS.md](https://github.com/toxakara/packvium-python/blob/main/docs/UNITS-AND-NUMERICS.md).

## Getting the same answer every time
Expand Down Expand Up @@ -210,22 +210,22 @@ in `constraints.py` and `limits.py` have failed you.
| File | What it shows |
| --- | --- |
| [`basic.py`](https://github.com/toxakara/packvium-python/blob/main/examples/basic.py) | The smallest useful call: items in, placements out — and the three details in it that are easy to miss. |
| [`objectives.py`](https://github.com/toxakara/packvium-python/blob/main/examples/objectives.py) | Six of the seven objectives (all but `maximum_volume`) on scenes where they genuinely disagree, including the rate card that makes the heavier shipment the cheaper one. |
| [`constraints.py`](https://github.com/toxakara/packvium-python/blob/main/examples/constraints.py) | Upright-only, floor-only, non-stackable, top-load limits, and tags that keep two items out of the same box — plus how to read the reason an item was refused. |
| [`objectives.py`](https://github.com/toxakara/packvium-python/blob/main/examples/objectives.py) | Six of the seven objectives (all but `maximum_volume`) on scenes where they genuinely disagree, including the rate card that makes the heavier shipment the cheaper one, a rate card's `currency`, and the lower bound that proves the value left behind is the least possible. |
| [`constraints.py`](https://github.com/toxakara/packvium-python/blob/main/examples/constraints.py) | Upright-only, floor-only, non-stackable, top-load limits, and tags that keep two items out of the same box — plus how to read the reason an item was refused, and a crate allowed past the pallet deck by `pallet_overhang_limit`. |
| [`limits.py`](https://github.com/toxakara/packvium-python/blob/main/examples/limits.py) | A courier fleet: a van with a fridge unit and wheel arches as obstacles, an item cap per bike, one dangerous-goods item per van, frozen goods only in a refrigerated vehicle, and a cap on vehicles. |
| [`units.py`](https://github.com/toxakara/packvium-python/blob/main/examples/units.py) | Why there are no floats anywhere: fractional inches, exact ticks, and the one-tick difference between a fit and a refusal. |
| [`serialization.py`](https://github.com/toxakara/packvium-python/blob/main/examples/serialization.py) | The same request as JSON, the result in full, and exactly which mistakes are refused and which are silently ignored. |
| [`errors.py`](https://github.com/toxakara/packvium-python/blob/main/examples/errors.py) | A web handler: refused requests turned into a 422 with a pointer and a message a person can act on, fixed placements that cannot hold, and a partial fit that is not an error. |
| [`reproducibility.py`](https://github.com/toxakara/packvium-python/blob/main/examples/reproducibility.py) | Why a clock-limited search answers differently on a busy machine, how an effort budget fixes it, and how to read `termination`. |
| [`trucking.py`](https://github.com/toxakara/packvium-python/blob/main/examples/trucking.py) | A three-stop delivery van within its axle ratings: loading and unloading order, what the driver can reach at each stop, and the same goods packed without a route. |
| [`fixed_placements.py`](https://github.com/toxakara/packvium-python/blob/main/examples/fixed_placements.py) | A trailer that arrives partly loaded: new pallets packed around the ones already on board, and a record of what is on board that cannot be true. |
| [`fixed_placements.py`](https://github.com/toxakara/packvium-python/blob/main/examples/fixed_placements.py) | A trailer that arrives partly loaded: new pallets packed around the ones already on board, a record of what is on board that cannot be true, and a loaded pallet fixed by quoting its `placement_id`. |
| [`rebalancing.py`](https://github.com/toxakara/packvium-python/blob/main/examples/rebalancing.py) | Two pallets of very different weight evened out after packing, one validated move at a time. |
| [`shapes.py`](https://github.com/toxakara/packvium-python/blob/main/examples/shapes.py) | Items that are not their box: complementary wedges sharing one crate as `convex_hull`, and a cushion that compresses under load until the crush limit refuses it. |
| [`nested.py`](https://github.com/toxakara/packvium-python/blob/main/examples/nested.py) | Units into cartons, cartons onto a pallet, in one call. |
| [`shapes.py`](https://github.com/toxakara/packvium-python/blob/main/examples/shapes.py) | Items that are not their box: complementary wedges sharing one crate as `convex_hull`, two copies of one wedge that need a signed rotation such as `-L-W+H`, a cushion that compresses under load until the crush limit refuses it, and a gusseted bag that holds a layer more than a flat one. |
| [`nested.py`](https://github.com/toxakara/packvium-python/blob/main/examples/nested.py) | Units into cartons, cartons onto a pallet, in one call, and `level_beam_width` letting the pallet pick a dearer carton set that packs better. |
| [`commerce.py`](https://github.com/toxakara/packvium-python/blob/main/examples/commerce.py) | Rate a shipment, apply an eligibility rule, and pin a catalog version. |
| [`execution.py`](https://github.com/toxakara/packvium-python/blob/main/examples/execution.py) | Turn a result into dock instructions: solver facts kept apart from screen text, a step order that is injected or honestly absent, and an operator lock that yields a second plan rather than editing the approved one. |
| [`artifacts.py`](https://github.com/toxakara/packvium-python/blob/main/examples/artifacts.py) | Hand a result to a system with no engine: one document with the plan, geometry and the request that produced it, exported as CSV and a printable work order, with an honest replay level. |
| [`revisions.py`](https://github.com/toxakara/packvium-python/blob/main/examples/revisions.py) | Replan a half-loaded job: a missing item and a locked placement recorded against the approved plan, a replan that keeps the locked item in place, and a hash-chained record that notices an edit. |
| [`revisions.py`](https://github.com/toxakara/packvium-python/blob/main/examples/revisions.py) | Replan a half-loaded job: a missing item and a locked placement recorded against the approved plan, a replan that keeps the locked item in place, a hash-chained record that notices an edit, and a box already cut to measure (with a void-fill reserve) stocked for the replan. |
| [`intelligence.py`](https://github.com/toxakara/packvium-python/blob/main/examples/intelligence.py) | Prove a carton change is worth publishing: two scenarios compared order by order, a proposal that refuses to exist on thin evidence, and a replay against held-out history where a cheaper packing your validator rejects still counts as a regression. |
| [`extensions.py`](https://github.com/toxakara/packvium-python/blob/main/examples/extensions.py) | A rule the schema has no field for — and an honest account of what you give up by writing one. |

Expand All @@ -245,20 +245,24 @@ instead: `PYTHONPATH=src python3 examples/trucking.py`.
- **Real constraints.** Weight and payload limits, permitted rotations, keep-upright,
floor-only, non-stackable, top-load limits, minimum support ratio, tag incompatibility,
eligible container tags, per-container item and tag limits, clearance, obstacles, two-axle
load limits and multi-stop route order.
load limits, multi-stop route order, pallet overhang past the deck, and flat or gusseted
bags.
- **A solver portfolio, not one algorithm.** Regular-grid, layer, extreme-point,
maximal-space and bounded exact search, selected by problem shape and profile.
- **Answers you can check.** Every solution is re-validated by logic independent of the
search. Unplaced items come back with a reason code, not silently missing.
- **A proof, or the distance to one.** Under the `default` and `lowest_cost` objectives every
result states `optimality.lower_bound`. A complete result that attains it reports `optimal`,
search. Unplaced items come back with a reason code, not silently missing. Every placement
carries a `placement_id` that a fixed placement, a revision or a lock can quote.
- **A proof, or the distance to one.** Under the `default`, `lowest_cost`, `maximum_value`,
`open_dimension_height` and `maximum_volume` objectives every result states
`optimality.lower_bound`. A complete result that attains it reports `optimal`,
which proves no packing obeying the request's rules scores better; any other carries the gap
to the bound (`gap_key`, `absolute_gap`, `relative_gap`).
- **Deterministic when you ask for it.** The same request with an `effort_budget` gives the
same result on every run and machine. A search stopped by `time_limit_ms` keeps what it
reached, which can differ between runs; `termination` says which happened.
- **Multi-container and nested.** Split across containers, or pack containers into
containers. `rebalance_weight` evens out the payload across containers afterwards.
containers; `NestedPacker(level_beam_width=K)` carries the K best carton sets up a level,
so the pallet decides between them. `rebalance_weight` evens out the payload across containers afterwards.
- **Extensible.** Register your own constraints, item orderings, candidate scorers,
container selectors or complete solvers.
- **Work orders, not just coordinates.** `packvium.execution` turns a validated result
Expand All @@ -279,7 +283,7 @@ instead: `PYTHONPATH=src python3 examples/trucking.py`.
- **Decide before you publish.** `packvium.simulation` and `packvium.recommendations`
compare two catalog scenarios order by order and propose a change only when the paired
cohort supports it; `packvium.holdout` replays that proposal against history it has not
seen. Python-only, and supported but not yet signature-frozen — see
seen. Python-only, and signature-frozen since 1.10.0 like the packing surface — see
[PUBLIC-API.md](https://github.com/toxakara/packvium-python/blob/main/docs/PUBLIC-API.md).

## Documentation
Expand Down Expand Up @@ -310,7 +314,7 @@ Documentation, the constraint reference and the benchmarks are at
| --- | --- | --- |
| Python — [`packvium`](https://pypi.org/project/packvium/) | `pip install packvium` | [packvium-python](https://github.com/toxakara/packvium-python) |
| PHP — [`packvium/packvium`](https://packagist.org/packages/packvium/packvium) | `composer require packvium/packvium` | [packvium-php](https://github.com/toxakara/packvium-php) |
| Rust — [`packvium`](https://crates.io/crates/packvium) | `packvium = "1.9"` | [packvium-rust](https://github.com/toxakara/packvium-rust) |
| Rust — [`packvium`](https://crates.io/crates/packvium) | `packvium = "1.10"` | [packvium-rust](https://github.com/toxakara/packvium-rust) |
| Node.js — [`@packvium/engine`](https://www.npmjs.com/package/@packvium/engine) | `npm install @packvium/engine` | [packvium-node](https://github.com/toxakara/packvium-node) |
| Browser / WebAssembly — [`@packvium/browser`](https://www.npmjs.com/package/@packvium/browser) | `npm install @packvium/browser` | [packvium-wasm](https://github.com/toxakara/packvium-wasm) |
| PHP FFI bridge — [`packvium/native-bridge`](https://packagist.org/packages/packvium/native-bridge) | `composer require packvium/native-bridge` | [packvium-php-bridge](https://github.com/toxakara/packvium-php-bridge) |
Expand All @@ -332,7 +336,7 @@ CodeMeta form.
@software{packvium_python,
author = {{Packvium contributors}},
title = {Packvium for Python},
version = {1.9.0},
version = {1.10.0},
license = {MIT},
url = {https://packvium.com}
}
Expand Down
2 changes: 1 addition & 1 deletion codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"@type": "SoftwareSourceCode",
"name": "Packvium for Python",
"description": "Deterministic 3D bin-packing and cartonization engine for pallets, containers, trucks and shipping cartons. Exact integer geometry, reproducible results.",
"version": "1.9.0",
"version": "1.10.0",
"license": "https://spdx.org/licenses/MIT",
"author": [
{
Expand Down
2 changes: 1 addition & 1 deletion docs/GUARANTEES.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ silently — if you need them, they belong in your own layer above this library.

## Status of this release

Version `1.9.0` freezes the public API. Field names, status codes, the objective
Version `1.10.0` freezes the public API. Field names, status codes, the objective
vector, the numeric policy and the validation rules do not change without a major
version, so any `1.x` is a safe upgrade from any earlier `1.x`. A caret or tilde
constraint on `1.0` is enough; an exact pin is no longer required.
Expand Down
Loading
Loading