{"id":29933994,"url":"https://github.com/rust-or/rust-lp-modeler","last_synced_at":"2026-03-07T20:05:31.275Z","repository":{"id":54256677,"uuid":"67782862","full_name":"rust-or/rust-lp-modeler","owner":"rust-or","description":"Lp modeler written in Rust","archived":false,"fork":false,"pushed_at":"2021-03-01T08:03:03.000Z","size":28226,"stargazers_count":105,"open_issues_count":9,"forks_count":29,"subscribers_count":10,"default_branch":"master","last_synced_at":"2026-02-24T16:40:47.068Z","etag":null,"topics":["formulation","glpk","linear-models","linear-programming","lp-modeler","rust","rust-library","solver"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rust-or.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-09T08:51:29.000Z","updated_at":"2025-11-12T10:51:55.000Z","dependencies_parsed_at":"2022-08-13T10:10:40.866Z","dependency_job_id":null,"html_url":"https://github.com/rust-or/rust-lp-modeler","commit_stats":null,"previous_names":["jcavat/rust-lp-modeler"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/rust-or/rust-lp-modeler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-or%2Frust-lp-modeler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-or%2Frust-lp-modeler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-or%2Frust-lp-modeler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-or%2Frust-lp-modeler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rust-or","download_url":"https://codeload.github.com/rust-or/rust-lp-modeler/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-or%2Frust-lp-modeler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30229590,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T19:01:10.287Z","status":"ssl_error","status_checked_at":"2026-03-07T18:59:58.103Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formulation","glpk","linear-models","linear-programming","lp-modeler","rust","rust-library","solver"],"created_at":"2025-08-02T19:12:47.099Z","updated_at":"2026-03-07T20:05:31.254Z","avatar_url":"https://github.com/rust-or.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lp-modeler\n[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)\n[![Build Status](https://travis-ci.org/jcavat/rust-lp-modeler.svg?branch=master)](https://travis-ci.org/jcavat/rust-lp-modeler)\n[![Gitter](https://badges.gitter.im/rust-lp-modeler/community.svg)](https://gitter.im/rust-lp-modeler/community?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n[![Github Actions](https://github.com/jcavat/rust-lp-modeler/workflows/Rust/badge.svg)](https://github.com/jcavat/rust-lp-modeler/actions)\nThis project provides a mathematical programming modeling library for Rust.\n\nAn optimization problem (e.g. an integer or linear programme) can be formulated using familiar Rust syntax (see examples), and written into a universal [LP model format](https://www.gurobi.com/documentation/8.0/refman/lp_format.html).\nThis can then be processed by a mixed integer programming solver.\nPresently supported solvers that require a [separate installation (see below the examples section)](#installing-external-solvers) to be present at runtime of your `lp_modeler`-based project are:\n* [COIN-OR cbc](https://github.com/coin-or/Cbc)\n* [Gurobi](https://www.gurobi.com/documentation/)\n* [GLPK](https://www.gnu.org/software/glpk/)\n\nPresently supported solvers that you can import as Rust crates (as [optional features](https://doc.rust-lang.org/cargo/reference/features.html)) are:\n* [minilp](https://docs.rs/minilp/latest/minilp/)\n* [coin_cbc](https://docs.rs/coin_cbc/latest/coin_cbc/) (requires the `Cbc` library files to be present at compile time of your `lp_modeler`-based project, see the [`coin_cbc` project README](https://github.com/KardinalAI/coin_cbc) for how to do this)\n\nThis project is inspired by [COIN-OR PuLP](http://www.coin-or.org/PuLP/ \"Coin-Or PuLP website\") which provides\nsuch a library for Python.\n\n## Usage\n\nThese examples present a formulation (in LP model format), and demonstrate the Rust code required to generate this formulation. Code can be found in [tests/problems.rs](tests/problems.rs).\n\n### Example 1 - Simple model\n\n#### Formulation\n```\n\\ One Problem\n\nMaximize\n  10 a + 20 b\n\nSubject To\n  c1: 500 a + 1200 b + 1500 c \u003c= 10000\n  c2: a - b \u003c= 0\n\nGenerals\n  a c b \n\nEnd\n```\n\n#### Rust code\n```rust\nextern crate lp_modeler;\n\nuse lp_modeler::solvers::{CbcSolver, SolverTrait};\nuse lp_modeler::dsl::*;\nuse lp_modeler::constraint;\n\nfn main() {\n    // Define problem variables\n    let ref a = LpInteger::new(\"a\");\n    let ref b = LpInteger::new(\"b\");\n    let ref c = LpInteger::new(\"c\");\n\n    // Define problem and objective sense\n    let mut problem = LpProblem::new(\"One Problem\", LpObjective::Maximize);\n\n    // Objective Function: Maximize 10*a + 20*b\n    problem += 10.0 * a + 20.0 * b;\n\n    // Constraint: 500*a + 1200*b + 1500*c \u003c= 10000\n    problem += constraint!(500*a + 1200*b + 1500*c \u003c= 10000);\n\n    // Constraint: a \u003c= b\n    problem += constraint!(a \u003c= b);\n\n    // Specify solver\n    let solver = CbcSolver::new();\n\n    // Run optimisation and process output hashmap\n    match solver.run(\u0026problem) {\n        Ok(solution) =\u003e {\n            println!(\"Status {:?}\", solution.status);\n            for (name, value) in solution.results.iter() {\n                println!(\"value of {} = {}\", name, value);\n            }\n        },\n        Err(msg) =\u003e println!(\"{}\", msg),\n    }\n}\n```\n\nTo generate the LP file which is shown above:\n```rust\nproblem.write_lp(\"problem.lp\")\n```\n\n### Example 2 - An Assignment model\n\n#### Formulation\n\nThis more complex formulation programmatically generates the expressions for the objective and constraints.\n\nWe wish to maximise the quality of the pairing between a group of men and women, based on their mutual compatibility score. Each man must be assigned to exactly one woman, and vice versa.\n\n###### Compatibility Score Matrix\n\n| | Abe | Ben | Cam |\n| --- | --- | --- | --- |\n| **Deb** | 50 | 60 | 60 |\n| **Eve** | 75 | 95 | 70 |\n| **Fay** | 75 | 80 | 80 |\n\nThis problem is formulated as an [Assignment Problem](https://en.wikipedia.org/wiki/Assignment_problem).\n\n#### Rust code\n```rust\nextern crate lp_modeler;\n\nuse std::collections::HashMap;\n\nuse lp_modeler::dsl::*;\nuse lp_modeler::solvers::{SolverTrait, CbcSolver};\n\nfn main() {\n    // Problem Data\n    let men = vec![\"A\", \"B\", \"C\"];\n    let women = vec![\"D\", \"E\", \"F\"];\n    let compatibility_score: HashMap\u003c(\u0026str, \u0026str),f32\u003e = vec![\n        ((\"A\", \"D\"), 50.0),\n        ((\"A\", \"E\"), 75.0),\n        ((\"A\", \"F\"), 75.0),\n        ((\"B\", \"D\"), 60.0),\n        ((\"B\", \"E\"), 95.0),\n        ((\"B\", \"F\"), 80.0),\n        ((\"C\", \"D\"), 60.0),\n        ((\"C\", \"E\"), 70.0),\n        ((\"C\", \"F\"), 80.0),\n    ].into_iter().collect();\n\n    // Define Problem\n    let mut problem = LpProblem::new(\"Matchmaking\", LpObjective::Maximize);\n\n    // Define Variables\n    let vars: HashMap\u003c(\u0026str,\u0026str), LpBinary\u003e =\n        men.iter()\n            .flat_map(|\u0026m| women.iter()\n            .map(move |\u0026w| {\n                let key = (m,w);\n                let value = LpBinary::new(\u0026format!(\"{}_{}\", m,w));\n                (key, value)\n            }))\n            .collect();\n\n    // Define Objective Function\n    let obj_vec: Vec\u003cLpExpression\u003e = {\n       vars.iter().map( |(\u0026(m,w), bin)| {\n           let \u0026coef = compatibility_score.get(\u0026(m, w)).unwrap();\n           coef * bin\n       } )\n    }.collect();\n    problem += obj_vec.sum();\n\n    // Define Constraints\n    // - constraint 1: Each man must be assigned to exactly one woman\n    for \u0026m in \u0026men{\n        problem += sum(\u0026women, |\u0026w| vars.get(\u0026(m,w)).unwrap() ).equal(1);\n    }\n\n    // - constraint 2: Each woman must be assigned to exactly one man\n    for \u0026w in \u0026women{\n        problem += sum(\u0026men, |\u0026m| vars.get(\u0026(m,w)).unwrap() ).equal(1);\n    }\n\n    // Run Solver\n    let solver = CbcSolver::new();\n    let result = solver.run(\u0026problem);\n\n    // Compute final objective function value\n    // (terminate if error, or assign status \u0026 variable values)\n    assert!(result.is_ok(), result.unwrap_err());\n    let (status, results) = result.unwrap();\n    let mut obj_value = 0f32;\n    for (\u0026(m, w), var) in \u0026vars{\n        let obj_coef = compatibility_score.get(\u0026(m, w)).unwrap();\n        let var_value = results.get(\u0026var.name).unwrap();\n\n        obj_value += obj_coef * var_value;\n    }\n\n    // Print output\n    println!(\"Status: {:?}\", status);\n    println!(\"Objective Value: {}\", obj_value);\n    for (var_name, var_value) in \u0026results{\n        let int_var_value = *var_value as u32;\n        if int_var_value == 1{\n            println!(\"{} = {}\", var_name, int_var_value);\n        }\n    }\n}\n```\n\nThis code computes the objective function value and processes the output to print the chosen pairing of men and women:\n```\nStatus: Optimal\nObjective Value: 230\nB_E = 1\nC_D = 1\nA_F = 1\n```\n\n## installing external solvers\n\n### installing conda (package manager)\n\nIf you want the latest release version of Cbc, Gurobi or GLPK, the easiest cross-platform installation pathway should be via [conda](https://docs.conda.io/en/latest/). \nImportantly, this does not require admin rights on the system you want to install it on.\nAll you need to do is [install conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html).\nOnce this is done, use the respective conda command for the solver you want to use (see below).\n\n### COIN-OR Cbc\n\n#### latest release (via conda)\n\nTo get the latest Cbc release for your system with conda (installation [see above](#installing-conda-package-manager)), use this command:\n```\nconda create -n coin-or-cbc -c conda-forge coin-or-cbc\n```\nThen activating the newly created environment will make the `cbc` executable available:\n```\nconda activate coin-or-cbc\n```\n\n#### latest release (via coinbrew)\n\nTo get the latest Cbc release, including the .\nWe recommend using COIN-OR's `coinbrew`, as described here:\nhttps://coin-or.github.io/user_introduction#building-from-source\n\n#### latest commit (via coinbrew)\n\nTo get the very latest Cbc version, including unreleased bug fixes, you will need to [build it from source](https://coin-or.github.io/user_introduction#building-from-source).\nWe recommend using COIN-OR's `coinbrew`, as described here:\nhttps://coin-or.github.io/user_introduction#building-from-source\n\n\n### GLPK\n\n#### recent release (via conda)\n\nTo get a recent release of GLPK for your system with conda, use this command:\n```\nconda create -n glpk -c conda-forge glpk\n```\nThen activating the newly created environment will make the `glpsol` executable available:\n```\nconda activate glpk\n```\n\n### Gurobi\n\n#### latest release (via conda)\n\nTo use Gurobi, **you need to have a valid [license key](https://www.gurobi.com/downloads/)** and have it in a location that Gurobi can find it.\nOnce you have a valid license, you can get the latest Gurobi release for your system with conda, use this command:\n```\nconda create -n gurobi -c gurobi gurobi\n```\nThen activating the newly created environment will make the `gurobi_cl` executable available:\n```\nconda activate gurobi\n```\n\n## Changelog\n\n### 0.5.0\n\n* Add a native `minilp` impl to call the Rust native solver `minilp`\n* Changed `coin_cbc`-based `NativeCbcSolver` to an optional feature\n* Fix adding upper bounds to `NativeCbc`\n* Add a `coinstraint!()` macro\n* Add `AddAssign`, `SubAssign` and `MulAssign` traits\n* Reworked various internal functions to remove recursions (fixes related stack overflows)\n* Add install infos for the solvers to the docs\n\n### 0.4.3\n\n* Add a native coin-or impl (NativeCBCSolver) to call CoinOR CBC trough the C API.\n\n### 0.4.2\n\n* Fix incorrect simplification of (expr-c1)+c2 \n\n### 0.4.1\n\n* Fix failed cbc parsing on infeasible solution\n\n### 0.4.0\n\n* Improve modules\n  * Remove maplit dependency\n  * All the features to write expressions and constraints are put into `dsl` module\n  * `use lp_modeler::dsl::*` is enough to write a system\n  * `use lp_modeler::solvers::*` is always used to choose a solver\n* Add a `sum()` method for vector of `LpExpression`/`Into\u003cLpExpression\u003e` instead of `lp_sum()` function\n* Add a `sum()` function used in the form:\n  \n  ```rust\n  problem += sum(\u0026vars, |\u0026v| v * 10.0) ).le(10.0);\n  ```\n\n### 0.3.3\n\n* Fix and improve error message for GLPK solution parsing\n* Format code with rust fmt\n\n### 0.3.3\n\n* Add new examples in documentation\n* Improve 0.0 comparison\n\n### 0.3.1\n* Add distributive property (ex: `3 * (a + b + 2) = 3*a + 3*b + 6`)\n* Add trivial rules (ex: `3 * a * 0 = 0` or `3 + 0 = 3`)\n* Add commutative property to simplify some computations\n* Support for GLPK\n\n### 0.3.0\n* Functional lib with simple algebra properties\n\n## Contributors\n\n### Main contributor\n\n* Joel Cavat [(jcavat)](https://github.com/jcavat)\n\n### All contributions :heart:\n\n* Thomas Vincent [(tvincent2)](https://github.com/tvincent2)\n* Antony Phillips [(aphi)](https://github.com/aphi)\n* Florian B. [(Lesstat)](https://github.com/Lesstat)\n* Amila Welihinda [(amilajack)](https://github.com/amilajack)\n* [(zappolowski)](https://github.com/zappolowski)\n* Yisu Rem Wang [(remysucre)](https://github.com/remysucre)\n* Tony Cox [(tony-cox)](https://github.com/tony-cox)\n* [EdorianDark](https://github.com/EdorianDark)\n* Colman Humphrey [(ColmanHumphrey)](https://github.com/ColmanHumphrey)\n* Stephan Beyer [sbeyer](https://github.com/sbeyer)\n* Ophir Lojkine [lovasoa](https://github.com/lovasoa)\n* David Lähnemann [dlaehnemann](https://github.com/dlaehnemann)\n\n## Further work\n\n* Parse and provide the objective value \n* Config for lp_solve and CPLEX\n* It would be great to use some constraint for binary variables such as \n    * a \u0026\u0026 b which is the constraint a + b = 2\n    * a || b which is the constraint a + b \u003e= 1\n    * a \u003c=\u003e b which is the constraint a = b\n    * a =\u003e b which is the constraint a \u003c= b\n    * All these cases are easy with two constraints but more complex with expressions\n    * ...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-or%2Frust-lp-modeler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frust-or%2Frust-lp-modeler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-or%2Frust-lp-modeler/lists"}