selen

Crates.ioselen
lib.rsselen
version0.8.1
created_at2025-09-23 09:50:23.92716+00
updated_at2025-09-25 08:24:18.72759+00
descriptionConstraint Satisfaction Problem (CSP) solver
homepagehttps://github.com/radevgit/selen
repositoryhttps://github.com/radevgit/selen
max_upload_size
id1851245
size1,895,354
(radevgit)

documentation

https://docs.rs/selen

README

Selen - CSP Solver

Crates.io Documentation License: MIT

A Constraint Satisfaction Problem (CSP) solver library written in Rust with zero external dependencies.

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.

Variable Types: int, float, mixed constraints

Constraint Categories:

  • Mathematical: +, -, *, /, %, abs(), min(), max(), sum()
  • Comparison: ==, !=, <, <=, >, >= (natural syntax)
  • Boolean Logic: and(), or(), not() with array syntax and([a,b,c]) and variadic syntax and(a,b,c,d)
  • Global: alldiff(), allequal(), element x[y] = z, count(vars, value, count), table(vars, tuples)
  • Ordering: a <= b <= c, a < b < c, a >= b >= c, a > b > c (natural between constraints)
  • Cardinality: at_least(vars, value, count), at_most(vars, value, count), exactly(vars, value, count)
  • Conditional: if_then(condition, constraint), if_then_else(condition, then_constraint, else_constraint)

Programmatic version of constraints

m.post(x.lt(y));                        // x < y
m.post(y.le(z));                        // y <= z
m.post(z.gt(5));                        // z > 5
m.post(x.add(y).le(z));                 // x + y <= z
m.post(y.sub(x).ge(0));                 // y - x >= 0
m.post(x.mul(y).eq(12));                // x * y == 12
m.post(z.div(y).ne(0));                 // z / y != 0

Mathematical syntax with post! macro

post!(m, x < y);                        // x < y
post!(m, y <= z);                       // y <= z
post!(m, z > int(5));                   // z > 5
post!(m, x + y <= z);                   // x + y <= z
post!(m, y - x >= int(0));              // y - x >= 0
post!(m, x * y == int(12));             // x * y == 12
post!(m, z / y != int(0));              // z / y != 0

Installation

Add this to your Cargo.toml:

[dependencies]
selen = "0.8.1"
๐Ÿงฉ Solving Platinum Blonde puzzle:
๐Ÿ“Š Puzzle stats: 17 clues given, 64 empty cells

Puzzle:                                 Solution:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ยท ยท ยท โ”‚ ยท ยท ยท โ”‚ ยท ยท ยท โ”‚               โ”‚ 9 8 7 โ”‚ 6 5 4 โ”‚ 3 2 1 โ”‚
โ”‚ ยท ยท ยท โ”‚ ยท ยท 3 โ”‚ ยท 8 5 โ”‚               โ”‚ 2 4 6 โ”‚ 1 7 3 โ”‚ 9 8 5 โ”‚
โ”‚ ยท ยท 1 โ”‚ ยท 2 ยท โ”‚ ยท ยท ยท โ”‚               โ”‚ 3 5 1 โ”‚ 9 2 8 โ”‚ 7 4 6 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค               โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ยท ยท ยท โ”‚ 5 ยท 7 โ”‚ ยท ยท ยท โ”‚               โ”‚ 1 2 8 โ”‚ 5 3 7 โ”‚ 6 9 4 โ”‚
โ”‚ ยท ยท 4 โ”‚ ยท ยท ยท โ”‚ 1 ยท ยท โ”‚               โ”‚ 6 3 4 โ”‚ 8 9 2 โ”‚ 1 5 7 โ”‚
โ”‚ ยท 9 ยท โ”‚ ยท ยท ยท โ”‚ ยท ยท ยท โ”‚               โ”‚ 7 9 5 โ”‚ 4 6 1 โ”‚ 8 3 2 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค               โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 5 ยท ยท โ”‚ ยท ยท ยท โ”‚ ยท 7 3 โ”‚               โ”‚ 5 1 9 โ”‚ 2 8 6 โ”‚ 4 7 3 โ”‚
โ”‚ ยท ยท 2 โ”‚ ยท 1 ยท โ”‚ ยท ยท ยท โ”‚               โ”‚ 4 7 2 โ”‚ 3 1 9 โ”‚ 5 6 8 โ”‚
โ”‚ ยท ยท ยท โ”‚ ยท 4 ยท โ”‚ ยท ยท 9 โ”‚               โ”‚ 8 6 3 โ”‚ 7 4 5 โ”‚ 2 1 9 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โœ… Solution found in 3020.832ms!
๐Ÿ“Š Statistics: 499 propagations, 22 nodes explored
๐Ÿ” Efficiency: 22.7 propagations/node

Examples

Core Problems

cargo run --release --example sudoku                 # Classic 9x9 Sudoku solver
cargo run --release --example n_queens               # N-Queens backtracking
cargo run --release --example send_more_money        # Cryptarithmetic puzzle
cargo run --release --example graph_coloring         # Graph constraint problems
cargo run --release --example zebra_puzzle           # Logic puzzle solving

Constraint Types

cargo run --release --example constraint_global      # AllEqual, Count, AllDiff
cargo run --release --example constraint_element     # Element constraint usage
cargo run --release --example constraint_table       # Table constraints
cargo run --release --example constraint_boolean     # Boolean arrays and logic

Advanced Features

cargo run --release --example advanced_runtime_api   # Dynamic constraint building
cargo run --release --example advanced_memory_limits # Memory management demo
cargo run --release --example advanced_timeout       # Timeout handling

Real Applications

cargo run --release --example app_manufacturing      # Industrial optimization
cargo run --release --example app_portfolio          # Financial modeling
cargo run --release --example app_resource_allocation # Resource planning

Basic Usage

use selen::prelude::*;

fn main() {
    let mut m = Model::default();

    // Create variables
    let x = m.int(1, 10);       // Integer variable from 1 to 10
    let y = m.int(5, 15);       // Integer variable from 5 to 15

    // Add constraints
    post!(m, x < y);            // x must be less than y
    post!(m, x + y == int(12)); // x + y must equal 12
    
    // Solve the problem
    if let Ok(solution) = m.solve() {
        println!("x = {:?}", solution[x]);  // x = ValI(1)  
        println!("y = {:?}", solution[y]);  // y = ValI(11)
    }
}

Programmatic API Example

For developers who prefer a more explicit, programmatic approach, the same constraints can be built using the runtime API:

use selen::prelude::*;

fn main() {
    let mut m = Model::default();

    // Create variables
    let x = m.int(1, 10);
    let y = m.int(5, 15);

    // Add constraints using programmatic API
    m.post(x.lt(y));                    // x < y
    m.post(x.add(y).eq(12));            // x + y == 12

    // Global constraints
    let vars = vec![m.int(1, 5), m.int(1, 5), m.int(1, 5)];
    m.alldiff(&vars);                   // All different
    
    // Mathematical functions
    let abs_result = m.abs(x);
    m.post(abs_result.ge(1));           // abs(x) >= 1
    
    // Solve the problem
    if let Ok(solution) = m.solve() {
        println!("x = {:?}", solution[x]);
        println!("y = {:?}", solution[y]);
    }
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Commit count: 213

cargo fmt