rustplex 0.3.0

A linear programming solver based on the Simplex algorithm for Rust
Documentation

Rustplex

Crates.io Version Docs.rs License Downloads

Rustplex is a fast, type-safe, and ergonomic Linear Programming (LP) Solver written in pure Rust.

It uses the Two-Phase Simplex Algorithm to solve optimization problems, featuring a clean builder API that allows you to write mathematical constraints using standard Rust operators.

⚠️ Status: Early Development

This library is currently in version 0.x. The API is subject to breaking changes as we refine the solver core and introduce new features. We recommend pinning the version in your Cargo.toml.


✨ Key Features

  • Ergonomic Modeling: Use standard operators (+, -, *) to build constraints naturally (e.g., 3*x + y <= 10).
  • Type Safety: Strongly typed keys (VariableKey, ConstraintKey) prevent common mistakes, like mixing up variables from different models.
  • Performance Optimized: Internally uses sparse sorted vectors and an efficient slotmap arena for memory management, ensuring fast iteration and low allocation overhead.
  • Robust Solver: Implements the Two-Phase Simplex method to automatically detect and handle infeasible or unbounded problems.
  • Standard Form Conversion: Automatically handles complex variable bounds (e.g., free variables, ranges like [-5, 10]) by compiling them into standard form (x >= 0) behind the scenes.

πŸš€ Installation

Add rustplex to your project via Cargo:

cargo add rustplex


Or add it manually to your Cargo.toml:

[dependencies]

rustplex = "0.3.0"




πŸ’» Usage

Rustplex separates the Model (your problem definition) from the Solver (the math). Here is a complete example:

use rustplex::prelude::*;

fn main() -> Result<(), SolverError> {
    // 1. Initialize the model
    let mut model = Model::new();

    // 2. Define decision variables with custom bounds
    let x1 = model.add_variable().name("x1").bounds(2.0..=5.0).real();
    let x2 = model.add_variable().name("x2").non_negative().real();
    let x3 = model.add_variable().name("x3").upper_bound(1.0).real();
    let x4 = model.add_variable().name("x4").real(); // Unbounded (free)

    // 3. Set the objective function: Maximize x1 + x2 + x3 - x4
    model.set_objective(
        Maximize,
        x1 + x2 + x3 - x4,
    );

    // 4. Add constraints using natural syntax
    //    x1 + x3 <= x2
    model.add_constraint(x1 + x3).le(x2);
    
    //    x2 + x3 == 5.0
    model.add_constraint(x2 + x3).eq(5.0);

    //    x4 + x1 >= 10.0
    model.add_constraint(x4 + x1).ge(10.0);

    // 5. Solve the model
    let solution = model.solve()?;

    // 6. Inspect the results
    if solution.status().is_optimal() {
        println!("Objective Value: {}", solution.objective_value().unwrap());
        
        // Retrieve variable values safely
        println!("x1 = {}", solution[x1]);
        println!("x2 = {}", solution[x2]);
        
        // Print full detailed report
        println!("{}", model.format(&solution));
    } else {
        println!("Solver failed: {}", solution.status());
    }
    
    Ok(())
}

Output:

Objective Value: 5
x1 = 5
x2 = 5
Solver Status: Optimal
Objective Value: 5.00
Variable Values: [
        Variable(x1:cont ∈ [2, 5]): 5.00
        Variable(x2:cont ∈ [0, inf]): 5.00
        Variable(x3:cont ∈ [-inf, 1]): 0.00
        Variable(x4:cont ∈ [-inf, inf]): 5.00
]
Iterations: 8
Solve Time: 30.90Β΅s

βš™οΈ Configuration

You can tune the solver's behavior (tolerances, iteration limits) via SolverConfig:

use rustplex::prelude::*;

let mut model = Model::new()
    .with_config(SolverConfig {
        max_iterations: 10_000,
        tolerance: 1e-8,
        ..Default::default()
    });


πŸ—ΊοΈ Roadmap

We are actively working on the following features:

  • Comprehensive Documentation: Add detailed API references, architectural explanations, and practical examples to improve usability and understanding.
  • Integer Programming (IP): Branch-and-bound support for integer variables.
  • Mixed-Integer Programming (MIP): Hybrid models with both continuous and integer variables.
  • Parallel Solving: Multi-threaded pivoting for massive problems.

🀝 Contributing

Contributions are welcome! Whether it's reporting a bug, improving documentation, or adding a new feature, feel free to open an issue or pull request.

  1. Fork the repository.
  2. Create your feature branch (git checkout -b feature/amazing-feature).
  3. Commit your changes (git commit -m 'Add some amazing feature').
  4. Push to the branch (git push origin feature/amazing-feature).
  5. Open a Pull Request.

πŸ“„ License

This project is licensed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-MIT and LICENSE-APACHE for details.


Developed with ❀️ in Rust.