diff --git a/CHANGELOG.md b/CHANGELOG.md index ebaeacd..6957f50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## unreleased ### Added +### Fixed +### Changed +- Free sol after adding in `ScipPtr::add_sol()`. +- Allow adding a var in `Solving` mode. +### Removed + +## 0.2.5 +### Added - Primal heuristic plugin. - Solving Model state, to represent methods accessible when during solving. - Moved solution query methods to its own trait. diff --git a/Cargo.toml b/Cargo.toml index 5d89f7d..bdaed39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ authors = ["Mohammad Ghannam "] description = "Rust interface for SCIP" license = "Apache-2.0" repository = "https://github.com/scipopt/russcip" -version = "0.2.4" +version = "0.2.5" edition = "2021" exclude = ["data/test/*"] diff --git a/src/model.rs b/src/model.rs index d5b2982..f436b2e 100644 --- a/src/model.rs +++ b/src/model.rs @@ -397,6 +397,43 @@ impl Model { } impl Model { + /// Adds a new variable to the model with the given lower bound, upper bound, objective coefficient, name, and type. + /// + /// # Arguments + /// + /// * `lb` - The lower bound of the variable. + /// * `ub` - The upper bound of the variable. + /// * `obj` - The objective coefficient of the variable. + /// * `name` - The name of the variable. + /// * `var_type` - The type of the variable. + /// + /// # Returns + /// + /// A reference-counted pointer to the new variable. + /// + /// # Panics + /// + /// This method panics if the variable cannot be created in the current state. + pub fn add_var( + &mut self, + lb: f64, + ub: f64, + obj: f64, + name: &str, + var_type: VarType, + ) -> Rc { + let var = self + .scip + .create_var_solving(lb, ub, obj, name, var_type) + .expect("Failed to create variable in state ProblemCreated"); + let var_id = var.index(); + let var = Rc::new(var); + self.state.vars.borrow_mut().insert(var_id, var.clone()); + var + } + + /// Adds a new priced variable to the SCIP data structure. + /// Returns the current node of the model. /// /// # Panics diff --git a/src/scip.rs b/src/scip.rs index 35ab9cb..6623822 100644 --- a/src/scip.rs +++ b/src/scip.rs @@ -16,6 +16,7 @@ use std::rc::Rc; pub(crate) struct ScipPtr { pub(crate) raw: *mut ffi::SCIP, consumed: bool, + vars_added_in_solving: Vec<*mut ffi::SCIP_VAR> } impl ScipPtr { @@ -26,6 +27,7 @@ impl ScipPtr { ScipPtr { raw: scip_ptr, consumed: false, + vars_added_in_solving: Vec::new(), } } @@ -33,6 +35,7 @@ impl ScipPtr { ScipPtr { raw: self.raw, consumed: true, + vars_added_in_solving: Vec::new(), } } @@ -209,6 +212,34 @@ impl ScipPtr { Ok(Variable { raw: var_ptr }) } + pub(crate) fn create_var_solving( + &mut self, + lb: f64, + ub: f64, + obj: f64, + name: &str, + var_type: VarType, + ) -> Result { + let name = CString::new(name).unwrap(); + let mut var_ptr = MaybeUninit::uninit(); + scip_call! { ffi::SCIPcreateVarBasic( + self.raw, + var_ptr.as_mut_ptr(), + name.as_ptr(), + lb, + ub, + obj, + var_type.into(), + ) }; + let mut var_ptr = unsafe { var_ptr.assume_init() }; + scip_call! { ffi::SCIPaddVar(self.raw, var_ptr) } + let mut transformed_var = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetTransformedVar(self.raw, var_ptr, transformed_var.as_mut_ptr()) }; + let trans_var_ptr = unsafe { transformed_var.assume_init() }; + scip_call! { ffi::SCIPreleaseVar(self.raw, &mut var_ptr) }; + Ok(Variable { raw: trans_var_ptr }) + } + pub(crate) fn create_priced_var( &mut self, lb: f64, @@ -879,9 +910,9 @@ impl ScipPtr { Ok(Node { raw: node_ptr }) } - pub(crate) fn add_sol(&self, sol: Solution) -> Result { + pub(crate) fn add_sol(&self, mut sol: Solution) -> Result { let mut stored = MaybeUninit::uninit(); - scip_call!(ffi::SCIPaddSol(self.raw, sol.raw, stored.as_mut_ptr())); + scip_call!(ffi::SCIPaddSolFree(self.raw, &mut sol.raw, stored.as_mut_ptr())); let stored = unsafe { stored.assume_init() }; Ok(stored != 0) } @@ -916,6 +947,11 @@ impl Drop for ScipPtr { scip_call_panic!(ffi::SCIPreleaseVar(self.raw, &mut var)); } + // release vars added in solving + for var_ptr in self.vars_added_in_solving.iter_mut() { + scip_call_panic!(ffi::SCIPreleaseVar(self.raw, var_ptr)); + } + // release constraints let n_conss = unsafe { ffi::SCIPgetNOrigConss(self.raw) }; let conss = unsafe { ffi::SCIPgetOrigConss(self.raw) };