Skip to main content

bin_packing/
lib.rs

1//! Cut list optimization and bin packing for 1D (linear stock), 2D (sheet
2//! stock), and 3D (box) problems.
3//!
4//! The crate exposes three shipping entry points by default:
5//!
6//! - [`one_d::solve_1d`] — cutting stock / linear bin packing. Supports first-fit
7//!   decreasing, best-fit decreasing, multistart local search, and an exact
8//!   column-generation backend that reports an LP lower bound.
9//! - [`two_d::solve_2d`] — rectangular sheet packing. Supports the MaxRects family
10//!   (best-area, best-short-side-fit, best-long-side-fit, bottom-left, contact-point),
11//!   the Skyline family (default and minimum-waste), Guillotine beam search with
12//!   configurable ranking and split rules (best-short-side-fit, best-long-side-fit,
13//!   shorter- and longer-leftover-axis, min- and max-area splits), shelf heuristics
14//!   (NFDH, FFDH, BFDH), and a multistart meta-strategy.
15//! - [`three_d::solve_3d`] — rectangular box packing. Supports Extreme Points,
16//!   Guillotine 3D, layer/wall/column builders, DBLF, volume-sorted baselines,
17//!   randomized meta-strategies, and a restricted exact backend.
18//!
19//! The `three-d` feature (enabled by default) provides the 3D rectangular box
20//! packing module with a 29-algorithm catalog. The legacy `three-d-preview`
21//! alias remains available as a compatibility shim.
22//!
23//! The 1D and 2D entry points ship an `Auto` mode that runs multiple strategies and
24//! returns the best candidate, ranked lexicographically by unplaced count, stock /
25//! sheet count, waste, and cost (with `exact` as a secondary tiebreaker for 1D).
26//!
27//! Additional capabilities:
28//!
29//! - Multiple stock / sheet types per problem, each with its own cost and optional
30//!   inventory cap. When 1D inventory caps are present, [`one_d::solve_1d`] also
31//!   reports a relaxed-inventory procurement estimate per stock type.
32//! - Per-item rotation control for 2D demands, plus a `guillotine_required` flag
33//!   that restricts the solver to guillotine-compatible layouts.
34//! - Kerf and trim modeling for 1D cuts so layouts match physical cut lists.
35//! - Reproducible randomized search via an optional `seed`.
36//! - Structured [`BinPackingError`] variants for input validation, infeasible
37//!   demands (1D, 2D, and 3D), and unsupported solver configurations.
38//! - `metrics` blocks with iteration counts, explored states, and diagnostic notes.
39//!
40//! All problem, option, solution, and metrics types derive [`serde::Serialize`] and
41//! [`serde::Deserialize`] so they can flow through JSON APIs or other wire formats
42//! without wrapping.
43//!
44//! # Example: 1D cutting stock
45//!
46//! ```no_run
47//! # #[cfg(feature = "one-d")]
48//! # {
49//! use bin_packing::one_d::{CutDemand1D, OneDOptions, OneDProblem, Stock1D, solve_1d};
50//!
51//! let problem = OneDProblem {
52//!     stock: vec![Stock1D {
53//!         name: "bar".into(),
54//!         length: 96,
55//!         kerf: 1,
56//!         trim: 0,
57//!         cost: 1.0,
58//!         available: None,
59//!     }],
60//!     demands: vec![
61//!         CutDemand1D { name: "rail".into(), length: 45, quantity: 2 },
62//!         CutDemand1D { name: "brace".into(), length: 30, quantity: 2 },
63//!     ],
64//! };
65//! let solution = solve_1d(problem, OneDOptions::default())?;
66//! println!("stock used: {}", solution.stock_count);
67//! # Ok::<(), bin_packing::BinPackingError>(())
68//! # }
69//! # #[cfg(not(feature = "one-d"))]
70//! # Ok::<(), bin_packing::BinPackingError>(())
71//! ```
72//!
73//! # Example: 2D rectangular packing
74//!
75//! ```no_run
76//! # #[cfg(feature = "two-d")]
77//! # {
78//! use bin_packing::two_d::{RectDemand2D, Sheet2D, TwoDOptions, TwoDProblem, solve_2d};
79//!
80//! let problem = TwoDProblem {
81//!     sheets: vec![Sheet2D {
82//!         name: "plywood".into(),
83//!         width: 96,
84//!         height: 48,
85//!         cost: 1.0,
86//!         quantity: None,
87//!     }],
88//!     demands: vec![RectDemand2D {
89//!         name: "panel".into(),
90//!         width: 24,
91//!         height: 18,
92//!         quantity: 4,
93//!         can_rotate: true,
94//!     }],
95//! };
96//! let solution = solve_2d(problem, TwoDOptions::default())?;
97//! println!("sheets used: {}", solution.sheet_count);
98//! # Ok::<(), bin_packing::BinPackingError>(())
99//! # }
100//! # #[cfg(not(feature = "two-d"))]
101//! # Ok::<(), bin_packing::BinPackingError>(())
102//! ```
103
104#![forbid(unsafe_code)]
105#![warn(missing_docs)]
106#![deny(rustdoc::broken_intra_doc_links)]
107
108mod error;
109#[cfg(feature = "one-d")]
110pub mod one_d;
111#[cfg(feature = "two-d")]
112pub mod two_d;
113
114#[cfg(feature = "three-d")]
115pub mod three_d;
116
117pub use error::{BinPackingError, Result};