CASOON Open Source
Model constraint problems in Rust. Solve them anytime.
unifier models constraint satisfaction and optimization problems – variables, domains, constraints, weighted objectives – and solves them with interchangeable strategies, from exhaustive search that proves optimality to local search and a parallel portfolio.
cargo add unifierJob shop: 3 jobs, 3 machines, horizon 21
Status: Optimal
Score: Feasible(strong=0, medium=0, weak=-11)
Makespan: 11
01234567890
M0 00011......
M1 2222001111.
M2 .....122200
Digits are job numbers; each row is one machine.- interchangeable solver strategies
- 5
- built-in constraints in 0.3.2, three of them global
- 16
- outcome states: Optimal, Feasible, Infeasible, Aborted
- 4
- runtime dependency (pathwise)
- 1
What it does
Global constraints that propagate
AllDifferent reaches generalized arc consistency with Régin’s matching algorithm; Cumulative and NoOverlap detect overload, and NoOverlap tightens bounds by edge-finding.
Honest results
Optimal only when Branch & Bound has proven it, Infeasible only when the search space is exhausted, Aborted with a reason otherwise – plus a score bound to show how far from proven a result is.
Anytime and cancellable
Time limits, node budgets and a cancellation token stop any solver with the best solution so far. The parallel portfolio shares that incumbent between its workers.
Built for scheduling
Activities, resources and groups compile into Cumulative and NoOverlap constraints, with calendars, optional activities, alternative resources and tardiness objectives.
Generated at build time
All examples →Map of Australia: 7 regions, 9 borders 3 colours: Feasible WA blue NT green SA red Q blue NSW green V blue T red 2 colours: Infeasible No colouring exists: WA, NT and SA border each other.
Every result on this site is printed by an example program in the repository, captured with scripts/regenerate-showcase.sh. The showcase puts each program next to its output.
examples/output/map_coloring.txtQuickstart
From a model to a proven optimum. The full walkthrough lives in the documentation.
- Add the crate with
cargo add unifier. - Declare variables, constraints and objectives with
ModelBuilder. - Validate with
build(), then pass the graph to a solver.
use unifier::dsl::ModelBuilder;
use unifier::solver::{BranchAndBoundSolver, SolverOptions};
let mut model = ModelBuilder::new();
// Three meetings, each in one of the time slots 1 to 4.
let a = model.new_var("a", 1..=4);
let b = model.new_var("b", 1..=4);
let c = model.new_var("c", 1..=4);
// Hard constraints: no shared slot, and a ends before b starts.
model.add_all_different([a, b, c]);
model.add_less_than_or_equal(a, b, -1); // a <= b - 1
// Soft objective: schedule everything as early as possible.
model.add_minimize([a, b, c], 1);
let graph = model.build().expect("valid model");
let outcome = BranchAndBoundSolver::new().solve(&graph, &SolverOptions::default());
println!("{:?}", outcome.status); // Optimal