Expand description
§CSP Solver
A constraint satisfaction problem (CSP) solver library in Rust.
§Safety & Resource Management
All models have automatic memory and timeout limits to prevent system exhaustion:
- Default memory limit: 2GB
- Default timeout: 60000 milliseconds (60 seconds)
- Memory tracking: During variable creation (prevents crashes)
- Early failure: Clear error messages when limits exceeded
use selen::prelude::*;
// Automatic safety limits
let mut m = Model::default(); // 2GB memory, 60000ms (60s) timeout
// Custom limits
let config = SolverConfig::default()
.with_max_memory_mb(512) // 512MB limit
.with_timeout_ms(30000); // 30000ms = 30 second timeout
let mut m = Model::with_config(config);§Variable Types
- Integer variables:
m.int(min, max)- continuous range - Float variables:
m.float(min, max)- continuous range with precision control - Custom domains:
m.intset(vec![values])- specific integer values only - Boolean variables:
m.bool()- equivalent tom.int(0, 1)
§Bulk Variable Creation
- Multiple integers:
m.ints(n, min, max)- create n integer variables with same bounds - Multiple floats:
m.floats(n, min, max)- create n float variables with same bounds - Multiple booleans:
m.bools(n)- create n boolean variables
§Constraint API
use selen::prelude::*;
let mut m = Model::default();
let (x, y, z) = (m.int(0, 10), m.int(0, 10), m.int(0, 10));
// Comparison constraints (via runtime API)
m.new(x.lt(y)); // x < y
m.new(y.le(z)); // y <= z
m.new(z.gt(5)); // z > 5
m.new(x.eq(10)); // x == 10
m.new(x.ne(y)); // x != y
// Arithmetic operations (return new variables)
let sum = m.add(x, y); // sum = x + y
let diff = m.sub(x, y); // diff = x - y
let product = m.mul(x, y); // product = x * y
let quotient = m.div(x, y); // quotient = x / y
let absolute = m.abs(x); // absolute = |x|
// Aggregate operations
let minimum = m.min(&[x, y, z]).unwrap(); // minimum of variables
let maximum = m.max(&[x, y, z]).unwrap(); // maximum of variables
let total = m.sum(&[x, y, z]); // sum of variables
// Global constraints
m.alldiff(&[x, y, z]); // all variables different
m.alleq(&[x, y, z]); // all variables equal
// Boolean operations (return boolean variables)
let (a, b) = (m.bool(), m.bool());
let and_result = m.bool_and(&[a, b]); // a AND b
let or_result = m.bool_or(&[a, b]); // a OR b
let not_result = m.bool_not(a); // NOT a
// Fluent expression building
m.new(x.add(y).le(z)); // x + y <= z
m.new(y.sub(x).ge(0)); // y - x >= 0
// Linear constraints (weighted sums) - generic for int and float
m.lin_eq(&[2, 3], &[x, y], 10); // 2x + 3y == 10
m.lin_le(&[1, -1], &[x, y], 5); // x - y <= 5
m.lin_ne(&[2, 1], &[x, y], 8); // 2x + y != 8
// Reified constraints (with boolean result) - generic for int and float
let b = m.bool();
m.eq_reif(x, y, b); // b ↔ (x == y)
m.ne_reif(x, y, b); // b ↔ (x != y)
m.lt_reif(x, y, b); // b ↔ (x < y)
m.le_reif(x, y, b); // b ↔ (x <= y)
m.gt_reif(x, y, b); // b ↔ (x > y)
m.ge_reif(x, y, b); // b ↔ (x >= y)§Example 1: Basic Integer Problem
use selen::prelude::*;
let mut m = Model::default();
let x = m.int(1, 10);
let y = m.int(1, 10);
let sum = m.add(x, y);
m.new(sum.eq(12));
m.new(x.gt(y));
if let Ok(solution) = m.solve() {
println!("x = {:?}, y = {:?}", solution[x], solution[y]);
}§Example 2: Mixed Integer-Float Optimization
use selen::prelude::*;
let mut m = Model::default();
let items = m.int(1, 100); // Number of items
let cost = m.float(0.0, 1000.0); // Total cost
// Use constraint API methods
m.lin_eq(&vec![1.0, -12.5], &vec![cost, items], 0.0); // cost = items * 12.5
m.new(cost.le(500.0)); // Budget constraint
// Maximize number of items within budget
if let Ok(solution) = m.maximize(items) {
println!("Optimal: {:?} items, cost: {:?}",
solution[items], solution[cost]);
}§Example 3: Custom Domains and Global Constraints
use selen::prelude::*;
let mut m = Model::default();
// Variables with custom domains
let red = m.intset(vec![1, 3, 5, 7]); // Odd numbers
let blue = m.intset(vec![2, 4, 6, 8]); // Even numbers
let green = m.intset(vec![2, 3, 5, 7]); // Prime numbers
// All must be different using constraint API
m.alldiff(&[red, blue, green]);
if let Ok(solution) = m.solve() {
println!("Red: {:?}, Blue: {:?}, Green: {:?}",
solution[red], solution[blue], solution[green]);
}§Example 4: Bulk Variable Creation
Create multiple variables efficiently with the same domain:
use selen::prelude::*;
let mut m = Model::default();
// Create 5 integer variables, each with domain [1, 10]
let vars = m.ints(5, 1, 10);
// Create 3 boolean variables
let flags = m.bools(3);
// Create 4 float variables with same bounds
let weights = m.floats(4, 0.0, 1.0);
// All variables in vars must be different
m.alldiff(&vars);
// First flag must be true
m.new(flags[0].eq(1));
if let Ok(solution) = m.solve() {
println!("Solution found with {} variables!",
vars.len() + flags.len() + weights.len());
}§Example 5: Programmatic API - Basic Constraints
For developers who prefer explicit, method-based constraint building:
use selen::prelude::*;
let mut m = Model::default();
let x = m.int(1, 10);
let y = m.int(1, 10);
// Build constraints programmatically
m.new(x.add(y).eq(12)); // x + y == 12
m.new(x.gt(y)); // x > y
m.new(x.mul(2).le(15)); // x * 2 <= 15
if let Ok(solution) = m.solve() {
println!("x = {:?}, y = {:?}", solution[x], solution[y]);
}§Example 6: Programmatic API - Global Constraints
use selen::prelude::*;
let mut m = Model::default();
let vars = vec![m.int(1, 5), m.int(1, 5), m.int(1, 5)];
// Global constraints using programmatic API
m.alldiff(&vars); // All variables must be different
// Mathematical functions
let sum_result = m.sum(&vars);
m.new(sum_result.le(10)); // sum(vars) <= 10
let max_result = m.max(&vars).expect("non-empty variable list");
m.new(max_result.ge(3)); // max(vars) >= 3
if let Ok(solution) = m.solve() {
println!("Variables: {:?}", vars.iter().map(|&v| solution[v]).collect::<Vec<_>>());
}§Example 7: Programmatic API - Complex Operations
use selen::prelude::*;
let mut m = Model::default();
let x = m.int(-10, 10);
let y = m.int(1, 10);
let z = m.int(1, 20);
// Arithmetic and mathematical functions
let abs_x = m.abs(x);
m.new(abs_x.ge(5)); // abs(x) >= 5
// Modulo operations
let mod_result = m.modulo(z, Val::from(3));
m.new(mod_result.eq(1)); // z % 3 == 1
// Logical operations on constraints
let constraint1 = x.gt(0);
let constraint2 = y.lt(5);
m.new(constraint1.and(constraint2)); // (x > 0) && (y < 5)
if let Ok(solution) = m.solve() {
println!("x = {:?}, y = {:?}, z = {:?}", solution[x], solution[y], solution[z]);
}Modules§
- api
- API module
- core
- Core functionality
- model
- Model core module
- prelude
- Prelude module for CSP solver
- runtime_
api - Runtime Constraint API
- solvers
- Specialized solvers for common problem domains.
Macros§
- lp_
debug - Macro for conditional debug printing