diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 380237d..4001083 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -64,7 +64,7 @@ jobs: - name: Test run: | rustup toolchain install nightly - RUSTFLAGS=-Zsanitizer=leak cargo +nightly test --features raw + RUSTFLAGS=-Zsanitizer=leak cargo +nightly test linux-bundled-test: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 9d994e4..193f36e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" exclude = ["data/test/*"] [features] -raw = [] bundled = ["scip-sys/bundled"] from-source = ["scip-sys/from-source"] diff --git a/README.md b/README.md index 31423b5..dcbe8f8 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,106 @@ # russcip + [![tests](https://github.com/mmghannam/russcip/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/mmghannam/russcip/actions/workflows/build_and_test.yml) [![coverage](https://img.shields.io/codecov/c/github/scipopt/russcip)](https://app.codecov.io/gh/scipopt/russcip/) -[![][img_crates]][crates] [![][img_doc]][doc] - - - +[![][img_crates]][crates] [![][img_doc]][doc] [img_crates]: https://img.shields.io/crates/v/russcip.svg + [crates]: https://crates.io/crates/russcip + [img_doc]: https://img.shields.io/badge/rust-documentation-blue.svg + [doc]: https://docs.rs/russcip/ + [img_coverage]: https://img.shields.io/codecov/c/github/scipopt/russcip -A safe Rust interface for [SCIP](https://www.scipopt.org/index.php#download). This crate also exposes access to the SCIP's C-API through the `ffi` module. +A safe Rust interface for [SCIP](https://www.scipopt.org/index.php#download). This crate also exposes access to the +SCIP's C-API through the `ffi` module. The project is currently actively developed, issues/pull-requests are very welcome. ## Installation By running + ```bash cargo add russcip --features bundled ``` The `bundled` feature will download a precompiled SCIP as part of the build process. -This is the easiest to get started with russcip, instead you could try the [from-source](#from-source-feature) +This is the easiest to get started with russcip, instead you could try the [from-source](#from-source-feature) or if you want to link against your custom SCIP installation check the [section](#custom-scip-installation) below. ### `from-source` feature -To build SCIP from source, you can enable the `from-source` feature. This will download the SCIP source code and build it as part of the build process. + +To build SCIP from source, you can enable the `from-source` feature. This will download the SCIP source code and build +it as part of the build process. + ```bash cargo add russcip --features from-source ``` -This is currently the most relaiable way to get a statically-linked build of SCIP. However, it only includes SCIP with SoPlex so can only handle linear constraints. + +This is currently the most relaiable way to get a statically-linked build of SCIP. However, it only includes SCIP with +SoPlex so can only handle linear constraints. ### Custom SCIP installation + If no feature is not enabled, `russcip` will look for a scip installation in the current conda environment, to install SCIP using conda run the following command + ```bash conda install --channel conda-forge scip ``` -Alternatively, you can specify the installation directory through the `SCIPOPTDIR` environment variable. -*russcip* is tested against SCIP 9.0.0 but it might work for other versions depending on which functionality you use. +Alternatively, you can specify the installation directory through the `SCIPOPTDIR` environment variable. +*russcip* is tested against SCIP 9.0.0 but it might work for other versions depending on which functionality you use. ### Examples -An [example](examples/create_and_solve.rs) on how to model and solve an integer program can be found in the [examples](examples) directory. + +An [example](examples/create_and_solve.rs) on how to model and solve an integer program can be found in +the [examples](examples) directory. To run the example, you can use the following command + ```bash cargo run --example create_and_solve ``` +## Accessing unsafe functions -## The `raw` feature -You can enable this feature by specifying the feature in your `Cargo.toml` -```toml -[dependencies] -russcip = { features = ["raw"] } -``` -This enables access to the `scip_ptr` unsafe function in the `Model` struct, which gives you access to the underlying SCIP raw pointer. This is can be used in combination with the `ffi` module to call SCIP functions that are not wrapped yet in the safe interface. +The `ffi` module provides access to the raw C-API of SCIP. This can be used to call functions that are not wrapped in +the safe interface yet. +The `scip_ptr` unsafe function in the `Model` struct, which gives you access to the underlying SCIP raw pointer. +Each other wrapper struct has a similar function named `inner`, e.g. `Variable::inner` or `Constraint::inner` gives you +a `*mut ffi::SCIP_VAR` or `*mut ffi::SCIP_CONS` respectively. ## Implementing Custom Plugins -Some of SCIP's plugins are imported to the rust interface as traits. Currently the implemented plugins are: -| **Name** | **File** | **Docs** | -|---------------|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Branching rule| [branchrule.rs](https://github.com/scipopt/russcip/blob/main/src/branchrule.rs) | [docs](https://docs.rs/russcip/latest/russcip/branchrule/trait.BranchRule.html) | -| Variable Pricer| [pricer.rs](https://github.com/scipopt/russcip/blob/main/src/pricer.rs) | [docs](https://docs.rs/russcip/latest/russcip/pricer/trait.Pricer.html) | -| Event Handler | [eventhdlr.rs](https://github.com/scipopt/russcip/blob/main/src/eventhdlr.rs) | [docs](https://docs.rs/russcip/latest/russcip/eventhdlr/trait.Eventhdlr.html) | -| Primal Heuristic | [heuristic.rs](https://github.com/scipopt/russcip/blob/main/src/heuristic.rs) | [docs](https://docs.rs/russcip/latest/russcip/eventhdlr/trait.Heuristic.html) | +Some of SCIP's plugins are imported to the rust interface as traits. Currently the implemented plugins are: -To add a custom plugin to a SCIP `Model` instance, you should implement its trait and call the corresponding `include_{PLUGIN_NAME}` method. For examples on implementing the specific plugin trait you can check the tests in the corresponding files. +| **Name** | **File** | **Docs** | +|------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------| +| Branching rule | [branchrule.rs](https://github.com/scipopt/russcip/blob/main/src/branchrule.rs) | [docs](https://docs.rs/russcip/latest/russcip/branchrule/trait.BranchRule.html) | +| Variable Pricer | [pricer.rs](https://github.com/scipopt/russcip/blob/main/src/pricer.rs) | [docs](https://docs.rs/russcip/latest/russcip/pricer/trait.Pricer.html) | +| Event Handler | [eventhdlr.rs](https://github.com/scipopt/russcip/blob/main/src/eventhdlr.rs) | [docs](https://docs.rs/russcip/latest/russcip/eventhdlr/trait.Eventhdlr.html) | +| Primal Heuristic | [heuristic.rs](https://github.com/scipopt/russcip/blob/main/src/heuristic.rs) | [docs](https://docs.rs/russcip/latest/russcip/eventhdlr/trait.Heuristic.html) | + +To add a custom plugin to a SCIP `Model` instance, you should implement its trait and call the corresponding +`include_{PLUGIN_NAME}` method. For examples on implementing the specific plugin trait you can check the tests in the +corresponding files. ## Contributing -Thinking about contributing to _russcip_? First of all thank you! You can check our issues [page](https://github.com/scipopt/russcip/issues), there's a bunch of [_good_first_issues_](https://github.com/scipopt/russcip/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22), or you can check our contribution [guide](CONTRIBUTING.md). If you'd like to contribute and unsure what to do, or thinking about a big feature and want to discuss if it makes sense and what is the best way to do it? you could open a new [issue](https://github.com/scipopt/russcip/issues/new/choose)/[discussion](https://github.com/scipopt/russcip/discussions/new/choose) or send me a quick email [@mmghannam](https://github.com/mmghannam). + +Thinking about contributing to _russcip_? First of all thank you! You can check our +issues [page](https://github.com/scipopt/russcip/issues), there's a bunch of [ +_good_first_issues_](https://github.com/scipopt/russcip/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22), +or you can check our contribution [guide](CONTRIBUTING.md). If you'd like to contribute and unsure what to do, or +thinking about a big feature and want to discuss if it makes sense and what is the best way to do it? you could open a +new [issue](https://github.com/scipopt/russcip/issues/new/choose)/[discussion](https://github.com/scipopt/russcip/discussions/new/choose) +or send me a quick email [@mmghannam](https://github.com/mmghannam). ## About SCIP -SCIP is currently one of the fastest non-commercial solvers for mixed integer programming (MIP) and mixed integer nonlinear programming (MINLP). It is also a framework for constraint integer programming and branch-cut-and-price. It allows for total control of the solution process and the access of detailed information down to the guts of the solver. +SCIP is currently one of the fastest non-commercial solvers for mixed integer programming (MIP) and mixed integer +nonlinear programming (MINLP). It is also a framework for constraint integer programming and branch-cut-and-price. It +allows for total control of the solution process and the access of detailed information down to the guts of the solver. diff --git a/src/branchrule.rs b/src/branchrule.rs index 7106dc6..9b96719 100644 --- a/src/branchrule.rs +++ b/src/branchrule.rs @@ -69,6 +69,11 @@ pub struct SCIPBranchRule { } impl SCIPBranchRule { + /// Returns the internal raw pointer of the branch rule. + pub fn inner(&self) -> *mut ffi::SCIP_BRANCHRULE { + self.raw + } + /// Returns the name of the branch rule. pub fn name(&self) -> String { unsafe { diff --git a/src/col.rs b/src/col.rs index bb6f6ce..65e019e 100644 --- a/src/col.rs +++ b/src/col.rs @@ -11,7 +11,6 @@ pub struct Col { } impl Col { - #[cfg(feature = "raw")] /// Returns a raw pointer to the underlying `ffi::SCIP_COL` struct. pub fn inner(&self) -> *mut ffi::SCIP_COL { self.raw diff --git a/src/constraint.rs b/src/constraint.rs index a5c270f..60326a2 100644 --- a/src/constraint.rs +++ b/src/constraint.rs @@ -14,7 +14,6 @@ pub struct Constraint { impl Constraint { /// Returns a pointer to the underlying `SCIP_CONS` C struct. - #[cfg(feature = "raw")] pub fn inner(&self) -> *mut ffi::SCIP_CONS { self.raw } diff --git a/src/eventhdlr.rs b/src/eventhdlr.rs index b5b9bff..8e56873 100644 --- a/src/eventhdlr.rs +++ b/src/eventhdlr.rs @@ -182,6 +182,11 @@ pub struct SCIPEventhdlr { } impl SCIPEventhdlr { + /// Returns the internal raw pointer of the event handler. + pub fn inner(&self) -> *mut ffi::SCIP_EVENTHDLR { + self.raw + } + /// Returns the name of the event handler. pub fn name(&self) -> String { unsafe { diff --git a/src/model.rs b/src/model.rs index 0f3afa4..105e586 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use crate::constraint::Constraint; use crate::eventhdlr::Eventhdlr; use crate::node::Node; @@ -10,6 +8,8 @@ use crate::status::Status; use crate::variable::{VarId, VarType, Variable}; use crate::{ffi, Row, Separator}; use crate::{BranchRule, HeurTiming, Heuristic, Pricer}; +use scip_sys::SCIP; +use std::rc::Rc; /// Represents an optimization model. #[non_exhaustive] @@ -1195,6 +1195,11 @@ pub fn minimal_model() -> Model { } impl Model { + /// Returns a pointer to the SCIP instance. This is useful for passing to functions in the `ffi` module. + pub fn scip_ptr(&self) -> *mut SCIP { + self.scip.raw + } + /// Returns the status of the optimization model. pub fn status(&self) -> Status { self.scip.status() @@ -1566,7 +1571,6 @@ mod tests { assert!(sol.is_none()); } - #[cfg(feature = "raw")] #[test] fn scip_ptr() { let mut model = Model::new() diff --git a/src/node.rs b/src/node.rs index 2e2c9a7..d8ce4bc 100644 --- a/src/node.rs +++ b/src/node.rs @@ -6,7 +6,6 @@ pub struct Node { } impl Node { - #[cfg(feature = "raw")] /// Returns a raw pointer to the underlying `ffi::SCIP_NODE` struct. pub fn inner(&self) -> *mut ffi::SCIP_NODE { self.raw diff --git a/src/pricer.rs b/src/pricer.rs index f176130..4cab13c 100644 --- a/src/pricer.rs +++ b/src/pricer.rs @@ -56,6 +56,11 @@ pub struct SCIPPricer { } impl SCIPPricer { + /// Returns the internal raw pointer of the pricer. + pub fn inner(&self) -> *mut ffi::SCIP_PRICER { + self.raw + } + /// Returns the name of the pricer. pub fn name(&self) -> String { unsafe { diff --git a/src/row.rs b/src/row.rs index eb101d0..efc4281 100644 --- a/src/row.rs +++ b/src/row.rs @@ -10,7 +10,6 @@ pub struct Row { } impl Row { - #[cfg(feature = "raw")] /// Returns a raw pointer to the underlying `ffi::SCIP_ROW` struct. pub fn inner(&self) -> *mut ffi::SCIP_ROW { self.raw diff --git a/src/separator.rs b/src/separator.rs index cad8409..062e4a6 100644 --- a/src/separator.rs +++ b/src/separator.rs @@ -71,6 +71,11 @@ pub struct SCIPSeparator { } impl SCIPSeparator { + /// Returns the internal raw pointer of the separator. + pub fn inner(&self) -> *mut ffi::SCIP_SEPA { + self.raw + } + /// Returns the name of the separator. pub fn name(&self) -> String { unsafe { diff --git a/src/variable.rs b/src/variable.rs index ebc3101..392e7f7 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -24,7 +24,6 @@ impl PartialEq for Variable { impl Eq for Variable {} impl Variable { - #[cfg(feature = "raw")] /// Returns a raw pointer to the underlying `ffi::SCIP_VAR` struct. pub fn inner(&self) -> *mut ffi::SCIP_VAR { self.raw @@ -179,7 +178,6 @@ mod tests { assert_eq!(var.var_type(), VarType::ImplInt); assert_eq!(var.status(), VarStatus::Original); - #[cfg(feature = "raw")] assert!(!var.inner().is_null()); }