rpid/
lib.rs

1//! Rust Programmable Interface for Domain-Independent Dynamic Programming (RPID)
2//!
3//! With RPID, you can formulate dynamic programming by implementing traits and
4//! solve it by calling a solver.
5//! You need to implement the [Dp] trait to define a dynamic programming model,
6//! and a solver may require the [Dominance] and [Bound] traits to enable dominance checking and pruning with bounds.
7//!
8//! ## Example
9//!
10//! Solving the traveling salesperson problem (TSP) with the CABS solver.
11//!
12//! ```
13//! use fixedbitset::FixedBitSet;
14//! use rpid::prelude::*;
15//! use rpid::solvers;
16//!
17//! struct Tsp {
18//!     c: Vec<Vec<i32>>,
19//! }
20//!
21//! struct TspState {
22//!     unvisited: FixedBitSet,
23//!     current: usize,
24//! }
25//!
26//! impl Dp for Tsp {
27//!     type State = TspState;
28//!     type CostType = i32;
29//!     type Label = usize;
30//!
31//!     fn get_target(&self) -> Self::State {
32//!         let mut unvisited = FixedBitSet::with_capacity(self.c.len());
33//!         unvisited.insert_range(1..);
34//!
35//!         TspState {
36//!             unvisited,
37//!             current: 0,
38//!         }
39//!     }
40//!
41//!     fn get_successors(
42//!         &self,
43//!         state: &Self::State,
44//!     ) -> impl IntoIterator<Item = (Self::State, Self::CostType, Self::Label)> {
45//!         state.unvisited.ones().map(|next| {
46//!             let mut unvisited = state.unvisited.clone();
47//!             unvisited.remove(next);
48//!
49//!             let successor = TspState {
50//!                 unvisited,
51//!                 current: next,
52//!             };
53//!             let weight = self.c[state.current][next];
54//!
55//!             (successor, weight, next)
56//!         })
57//!     }
58//!
59//!     fn get_base_cost(&self, state: &Self::State) -> Option<Self::CostType> {
60//!         if state.unvisited.is_clear() {
61//!             Some(self.c[state.current][0])
62//!         } else {
63//!             None
64//!         }
65//!     }
66//! }
67//!
68//! impl Dominance for Tsp {
69//!     type State = TspState;
70//!     type Key = (FixedBitSet, usize);
71//!
72//!     fn get_key(&self, state: &Self::State) -> Self::Key {
73//!         (state.unvisited.clone(), state.current)
74//!     }
75//! }
76//!
77//! impl Bound for Tsp {
78//!     type State = TspState;
79//!     type CostType = i32;
80//!
81//!     fn get_dual_bound(&self, _: &Self::State) -> Option<Self::CostType> {
82//!         Some(0)
83//!     }
84//! }
85//!
86//! let tsp = Tsp { c: vec![vec![0, 1, 2], vec![1, 0, 3], vec![2, 3, 0]] };
87//! let mut solver
88//!     = solvers::create_cabs(tsp, SearchParameters::default(), CabsParameters::default());
89//! let solution = solver.search();
90//! assert_eq!(solution.cost, Some(6));
91//! assert_eq!(solution.transitions, vec![1, 2]);
92//! assert!(solution.is_optimal);
93//! assert!(!solution.is_infeasible);
94//! assert_eq!(solution.best_bound, Some(6));
95//! ```
96//!
97//! For more examples, see <https://github.com/Kurorororo/didp-rust-models>.
98//!
99//! ## References
100//!
101//! Ryo Kuroiwa and J. Christopher Beck. RPID: Rust Programmable Interface for Domain-Independent Dynamic Programming.
102//! In *31st International Conference on Principles and Practice of Constraint Programming (CP 2025)*,
103//! volume 340 of Leibniz International Proceedings in Informatics (LIPIcs), pages 23:1-23:21.
104//! Schloss Dagstuhl - Leibniz-Zentrum für Informatik, 2025.
105//! [doi:10.4230/LIPIcs.CP.2025.23](https://doi.org/10.4230/LIPIcs.CP.2025.23)
106
107pub mod algorithms;
108mod dp;
109pub mod io;
110pub mod solvers;
111pub mod timer;
112
113pub use dp::{Bound, BoundMut, Dominance, Dp, DpMut, OptimizationMode};
114pub use solvers::Solution;
115
116pub mod prelude {
117    //! Prelude to import commonly used items.
118    pub use super::solvers::{CabsParameters, Search, SearchParameters};
119    pub use super::{Bound, Dominance, Dp, OptimizationMode, Solution};
120}