Skip to content

Commit

Permalink
add support for clarabel (#48)
Browse files Browse the repository at this point in the history
* add support for clarabel

closes #27

* test clarabel

* fmt
  • Loading branch information
lovasoa authored Apr 4, 2024
1 parent 82b218a commit 98eb303
Show file tree
Hide file tree
Showing 15 changed files with 360 additions and 43 deletions.
18 changes: 6 additions & 12 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ on:

env:
CARGO_TERM_COLOR: always
# 'lpsolve' and 'cplex-rs' features are incompatible
ALL_FEATURES_EXCEPT_CPLEX: "scip,singlethread-cbc,coin_cbc,highs,lp-solvers,minilp,russcip,lpsolve"
ALL_FEATURES_EXCEPT_LPSOLVE: "scip,singlethread-cbc,coin_cbc,highs,lp-solvers,minilp,russcip,cplex-rs"

jobs:
build:
Expand Down Expand Up @@ -41,16 +38,11 @@ jobs:
curl -LO https://github.com/rust-or/good_lp/releases/download/cplex/cplex.bin
chmod u+x cplex.bin
./cplex.bin -f ./.github/cplex/response.properties
- name: Build with all features except cplex-rs
run: cargo build --features ${{ env.ALL_FEATURES_EXCEPT_CPLEX }} --tests
- name: Run tests with all features except cplex-rs
- name: Build with all default solvers (no cplex)
run: cargo build --features all_default_solvers --tests
- name: Run tests with all default solvers (no cplex)
# test on a single thread. See: https://github.com/KardinalAI/coin_cbc/issues/9
run: cargo test --features ${{ env.ALL_FEATURES_EXCEPT_CPLEX }} -- --test-threads=1
- name: Build with all features except lpsolve
run: cargo build --features ${{ env.ALL_FEATURES_EXCEPT_LPSOLVE }} --tests
- name: Run tests with all features except lpsolve
# test on a single thread. See: https://github.com/KardinalAI/coin_cbc/issues/9
run: cargo test --features ${{ env.ALL_FEATURES_EXCEPT_LPSOLVE }} -- --test-threads=1
run: cargo test --features all_default_solvers -- --test-threads=1
- name: Run tests with minilp
run: cargo test --no-default-features --features minilp
- name: Run tests with lpsolve
Expand All @@ -63,4 +55,6 @@ jobs:
run: cargo test --no-default-features --features scip
- name: Run tests with CPLEX
run: cargo test --no-default-features --features cplex-rs
- name: Run tests with Clarabel
run: cargo test --no-default-features --features clarabel
- run: cargo bench
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
],
"rust-analyzer.cargo.features": [
"all_default_solvers"
]
}
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Adding a new solver should not take more than a few hundred lines of code, tests
You can generally reuse data structures provided by the library for which you are creating a wrapper.
- implement a function named after your solver that takes an [`UnsolvedProblem`](https://docs.rs/good_lp/latest/good_lp/variable/struct.UnsolvedProblem.html) and returns the struct you defined above.
- implement the [`SolverModel`](https://docs.rs/good_lp/latest/good_lp/index.html#reexport.SolverModel) trait for your new problem type.
- add your solver to `lib.rs` and to the `all_default_solvers` feature in Cargo.toml.
- open a [pull request](https://github.com/rust-or/good_lp/pulls)
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ categories = ["mathematics", "algorithms", "science", "api-bindings", "data-stru
default = ["coin_cbc", "singlethread-cbc"]
singlethread-cbc = ["coin_cbc?/singlethread-cbc"]
scip = ["russcip"]
all_default_solvers = ["coin_cbc", "minilp", "lpsolve", "highs", "russcip", "lp-solvers", "clarabel"] # cplex-rs is not included because it is incompatible with lpsolve

[dependencies]
coin_cbc = { version = "0.1", optional = true, default-features = false }
Expand All @@ -24,6 +25,7 @@ highs = { version = "1.5.0", optional = true }
russcip = { version = "0.3.4", optional = true }
lp-solvers = { version = "1.0.0", features = ["cplex"], optional = true }
cplex-rs = { version = "0.1", optional = true }
clarabel = { version = "0.7.1", optional = true, features=[] }
fnv = "1.0.5"

[dev-dependencies]
Expand All @@ -36,7 +38,8 @@ harness = false

[package.metadata.docs.rs]
# Display the documentation for all solvers on docs.rs
all-features = true
all-features = false
features = [ "all_default_solvers" ]
default-target = "x86_64-unknown-linux-gnu"
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--cfg", "docsrs"]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ you can also activate other solvers using cargo features.
| [`lp-solvers`][lps] |||||
| [`scip`][scip] |||||
| [`cplex-rs`][cplex] |||\+\+ ||
| [`clarabel`][clarabel] |||||

- \* no C compiler: builds with only cargo, without requiring you to install a C compiler
- \*\* no additional libs: works without additional libraries at runtime, all the dependencies are statically linked
Expand Down Expand Up @@ -190,6 +191,13 @@ Since cplex-rs-sys uses [bindgen](https://github.com/rust-lang/rust-bindgen) to

[cplex]: https://www.ibm.com/products/ilog-cplex-optimization-studio/cplex-optimizer

### [clarabel][clarabel]

[Clarabel](https://github.com/oxfordcontrol/Clarabel.rs) is a free
([Apache 2.0](https://github.com/oxfordcontrol/Clarabel.rs/blob/main/LICENSE.md))
linear programming solver written in Rust by the
[Oxford Control group](https://eng.ox.ac.uk/control/).

## Variable types

`good_lp` internally represents all [variable](https://docs.rs/good_lp/1.4.0/good_lp/variable/struct.Variable.html) values and coefficients as `f64`.
Expand Down
2 changes: 1 addition & 1 deletion src/affine_expression_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub trait IntoAffineExpression {
/// ```
///
/// ### Evaluate an expression with a HashMap
/// A [HashMap] is a valid [Solution]
/// A [std::collections::HashMap] is a valid [Solution]
///
/// ```rust
/// use std::collections::HashMap;
Expand Down
8 changes: 3 additions & 5 deletions src/constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ impl_shifts!(Expression Variable);
/// ## Full example
///
/// ```
/// # fn assert_float_eq(a:f64, b:f64) {
/// # assert!((a-b).abs() <= 16. * f64::EPSILON, "{} != {}", a, b);
/// # }
/// # use float_eq::assert_float_eq;
/// use good_lp::*;
///
/// let mut vars = variables!();
Expand All @@ -116,8 +114,8 @@ impl_shifts!(Expression Variable);
/// .with(constraint!(a - 5 <= b / 2))
/// .with(constraint!(b == a))
/// .solve().unwrap();
/// assert_float_eq(10., solution.value(a));
/// assert_float_eq(10., solution.value(b));
/// assert_float_eq!(10., solution.value(a), abs<=1e-8);
/// assert_float_eq!(10., solution.value(b), abs<=1e-8);
/// ```
#[macro_export]
macro_rules! constraint {
Expand Down
20 changes: 17 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
//! .with(1 + a >> 4. - b)
//! .solve()?;
//!
//! assert_eq!(solution.value(a), 1.);
//! assert_eq!(solution.value(b), 3.);
//! # use float_eq::assert_float_eq;
//! assert_float_eq!(solution.value(a), 1., abs <= 1e-8);
//! assert_float_eq!(solution.value(b), 3., abs <= 1e-8);
//! # Ok::<_, good_lp::ResolutionError>(())
//! ```
//!
Expand Down Expand Up @@ -68,6 +69,18 @@ pub use affine_expression_trait::IntoAffineExpression;
pub use cardinality_constraint_solver_trait::CardinalityConstraintSolver;
pub use constraint::Constraint;
pub use expression::Expression;
#[cfg(not(any(
feature = "coin_cbc",
feature = "minilp",
feature = "lpsolve",
feature = "highs",
feature = "scip",
feature = "cplex-rs",
)))]
#[cfg(feature = "clarabel")]
pub use solvers::clarabel::clarabel as default_solver;
#[cfg(feature = "clarabel")]
pub use solvers::clarabel::clarabel;
#[cfg_attr(docsrs, doc(cfg(feature = "coin_cbc")))]
#[cfg(feature = "coin_cbc")]
pub use solvers::coin_cbc::coin_cbc;
Expand Down Expand Up @@ -146,6 +159,7 @@ pub const default_solver: LpSolver<
feature = "lp-solvers",
feature = "scip",
feature = "cplex-rs",
feature = "clarabel",
)))]
compile_error!(
"No solver available. \
Expand All @@ -162,7 +176,7 @@ good_lp = { version = \"*\", features = [\"minilp\"] }
#[cfg(all(feature = "lpsolve", feature = "cplex-rs",))]
compile_error!(
"'lpsolve' and 'cplex-rs' features are incompatible. \
Please select just one of the two.
Please select just one of the two. If you need all compatible solvers, use the 'all_deafult_solvers' feature. \
"
);

Expand Down
Loading

0 comments on commit 98eb303

Please sign in to comment.