CSP Solver

A Constraint Satisfaction Problem (CSP) solver library written in Rust.
We are starting the implementation from scratch.
The new implementation follows the design and implementation of Copper v0.1.0.
Status
The library is currently in active development. Features and APIs may change as we refine the implementation and add new functionality.
Current version is rewritten from scratch and is following the implementation of Cupper with added float type.
Overview
This library provides efficient algorithms and data structures for solving constraint satisfaction problems. CSPs are mathematical problems defined as a set of objects whose state must satisfy a number of constraints or limitations.
Installation
Add this to your Cargo.toml
:
[dependencies]
cspsolver = "0.3.3-alpha"
Quick Start
use csp::*;
fn main() -> CspResult<()> {
let mut solver = CspSolver::new();
let var1 = solver.add_variable("x", vec![1, 2, 3])?;
let var2 = solver.add_variable("y", vec![1, 2, 3])?;
solver.add_constraint(NotEqualConstraint::new(var1, var2))?;
if let Some(solution) = solver.solve()? {
println!("Solution found: {:?}", solution);
} else {
println!("No solution exists");
}
Ok(())
}
Examples
cargo run --example pc_builder
cargo run --example resource_allocation
cargo run --example portfolio_optimization
PC Building Optimizer
A practical example of constraint optimization - finding the best PC build within budget constraints:
use cspsolver::prelude::*;
fn main() {
let mut m = Model::default();
let n_monitors = m.new_var(int(1), int(3)).unwrap();
let monitor_price = int(100);
let monitor_score = int(250);
let gpu_prices = [int(150), int(250), int(500)];
let gpu_scores = [int(100), int(400), int(800)];
let gpus: Vec<_> = m.new_vars_binary(gpu_prices.len()).collect();
let gpu_price = m.sum_iter(
gpus.iter()
.zip(gpu_prices)
.map(|(gpu, price)| gpu.times(price))
);
let gpu_score = m.sum_iter(
gpus.iter()
.zip(gpu_scores)
.map(|(gpu, score)| gpu.times(score))
);
let total_price = m.add(gpu_price, n_monitors.times(monitor_price));
let total_score = m.add(gpu_score, n_monitors.times(monitor_score));
let n_gpus = m.sum(&gpus);
m.equals(n_gpus, int(1)); m.less_than_or_equals(total_price, int(600));
let solution = m.maximize(total_score).unwrap();
println!("Optimal PC Build:");
println!("Monitors: {}", match solution[n_monitors] {
Val::ValI(n) => n,
_ => 0
});
println!("GPU selection: {:?}", solution.get_values_binary(&gpus));
println!("Total score: {}", match solution[total_score] {
Val::ValI(s) => s,
_ => 0
});
println!("Total price: ${}", match solution[total_price] {
Val::ValI(p) => p,
_ => 0
});
}
Resource Allocation Problem
Allocating tasks to workers with skill and capacity constraints:
use cspsolver::prelude::*;
fn main() {
let mut m = Model::default();
let num_workers = 3;
let num_tasks = 4;
let capacities = [int(8), int(6), int(10)];
let task_hours = [int(3), int(4), int(2), int(5)];
let priorities = [int(10), int(15), int(5), int(20)];
let mut assignments = Vec::new();
for i in 0..num_workers {
let mut worker_tasks = Vec::new();
for j in 0..num_tasks {
worker_tasks.push(m.new_var_binary());
}
assignments.push(worker_tasks);
}
for j in 0..num_tasks {
let task_assignments: Vec<_> = assignments
.iter()
.map(|worker| worker[j])
.collect();
m.equals(m.sum(&task_assignments), int(1));
}
for i in 0..num_workers {
let worker_load = m.sum_iter(
assignments[i]
.iter()
.zip(task_hours.iter())
.map(|(assigned, hours)| assigned.times(*hours))
);
m.less_than_or_equals(worker_load, capacities[i]);
}
let total_priority = m.sum_iter(
assignments
.iter()
.flatten()
.zip(priorities.iter().cycle())
.map(|(assigned, priority)| assigned.times(*priority))
);
let solution = m.maximize(total_priority).unwrap();
println!("Optimal Task Assignment:");
for i in 0..num_workers {
print!("Worker {}: ", i + 1);
let worker_assignments = solution.get_values_binary(&assignments[i]);
for (j, &assigned) in worker_assignments.iter().enumerate() {
if assigned {
print!("Task{} ", j + 1);
}
}
println!();
}
println!("Total priority: {}", match solution[total_priority] {
Val::ValI(p) => p,
_ => 0
});
}
License
This project is licensed under the MIT License - see the LICENSE file for details.