From 04090f2ebebc3eef4b3cc0e548cb41d7434beee2 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Tue, 14 Jan 2025 09:07:17 +0100 Subject: [PATCH 1/6] Use &Variable instead of Rc --- examples/create_and_solve.rs | 6 +- src/col.rs | 2 +- src/constraint.rs | 4 +- src/heuristic.rs | 2 +- src/model.rs | 134 +++++++++++++++++------------------ src/pricer.rs | 2 +- src/row.rs | 2 +- src/scip.rs | 26 +++---- src/separator.rs | 11 ++- src/solution.rs | 8 +-- src/variable.rs | 4 +- 11 files changed, 99 insertions(+), 102 deletions(-) diff --git a/examples/create_and_solve.rs b/examples/create_and_solve.rs index cbe1b98..a70f4f8 100644 --- a/examples/create_and_solve.rs +++ b/examples/create_and_solve.rs @@ -14,14 +14,14 @@ fn main() { // Add constraints model.add_cons( - vec![x1.clone(), x2.clone()], + vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1", ); model.add_cons( - vec![x1.clone(), x2.clone()], + vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., @@ -40,6 +40,6 @@ fn main() { let vars = solved_model.vars(); for var in vars { - println!("{} = {}", &var.name(), sol.val(var)); + println!("{} = {}", var.name(), sol.val(&var)); } } diff --git a/src/col.rs b/src/col.rs index 65e019e..4d4b81b 100644 --- a/src/col.rs +++ b/src/col.rs @@ -239,7 +239,7 @@ mod tests { let mut model = minimal_model(); let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); - let cons = model.add_cons(vec![x], &[1.0], 1.0, 1.0, "cons1"); + let cons = model.add_cons(vec![&x], &[1.0], 1.0, 1.0, "cons1"); model.set_cons_modifiable(cons, true); let eventhdlr = Box::new(ColTesterEventHandler); diff --git a/src/constraint.rs b/src/constraint.rs index 60326a2..32628bc 100644 --- a/src/constraint.rs +++ b/src/constraint.rs @@ -3,7 +3,7 @@ use crate::{ffi, Row}; use std::rc::Rc; /// A constraint in an optimization problem. -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(dead_code)] pub struct Constraint { /// A pointer to the underlying `SCIP_CONS` C struct. @@ -54,7 +54,7 @@ mod tests { .set_obj_sense(ObjSense::Maximize); let x1 = model.add_var(0., f64::INFINITY, 3., "x1", VarType::Integer); - let cons = model.add_cons(vec![x1], &[1.], 4., 4., "cons"); + let cons = model.add_cons(vec![&x1], &[1.], 4., 4., "cons"); drop(model); assert_eq!(cons.name(), "cons"); diff --git a/src/heuristic.rs b/src/heuristic.rs index 20769b6..bbd1390 100644 --- a/src/heuristic.rs +++ b/src/heuristic.rs @@ -272,7 +272,7 @@ mod tests { ) -> HeurResult { let sol = model.create_sol(); for var in model.vars() { - sol.set_val(var, 1.0); + sol.set_val(&var, 1.0); } assert_eq!(sol.obj_val(), 7.0); assert_eq!(model.add_sol(sol), Ok(())); diff --git a/src/model.rs b/src/model.rs index 105e586..c64a463 100644 --- a/src/model.rs +++ b/src/model.rs @@ -158,17 +158,16 @@ impl Model { obj: f64, name: &str, var_type: VarType, - ) -> Rc { + ) -> Variable { let var = self .scip .create_var(lb, ub, obj, name, var_type) .expect("Failed to create variable in state ProblemCreated"); - let var = Variable { + + Variable { raw: var, scip: self.scip.clone(), - }; - - Rc::new(var) + } } /// Includes a new branch rule in the model with the given name, description, priority, maximum depth, maximum bound distance, and implementation. @@ -523,10 +522,10 @@ impl Model { /// A trait for optimization models with a problem created. pub trait ModelWithProblem { /// Returns a vector of all variables in the optimization model. - fn vars(&self) -> Vec>; + fn vars(&self) -> Vec; /// Returns the variable with the given ID, if it exists. - fn var(&self, var_id: VarId) -> Option>; + fn var(&self, var_id: VarId) -> Option; /// Returns the number of variables in the optimization model. fn n_vars(&self) -> usize; @@ -548,7 +547,7 @@ impl ModelStageWithProblem for Solving {} impl ModelWithProblem for Model { /// Returns a vector of all variables in the optimization model. - fn vars(&self) -> Vec> { + fn vars(&self) -> Vec { let scip_vars = self.scip.vars(false); scip_vars .into_values() @@ -556,19 +555,18 @@ impl ModelWithProblem for Model { raw: v, scip: self.scip.clone(), }) - .map(Rc::new) .collect() } /// Returns the variable with the given ID, if it exists. - fn var(&self, var_id: VarId) -> Option> { + fn var(&self, var_id: VarId) -> Option { let vars = self.scip.vars(false); for (i, v) in vars { if i == var_id { - return Some(Rc::new(Variable { + return Some(Variable { raw: v, scip: self.scip.clone(), - })); + }); } } @@ -626,7 +624,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the variable cannot be added in the current state, or if the variable is not binary. - fn add_cons_coef_setppc(&mut self, cons: Rc, var: Rc); + fn add_cons_coef_setppc(&mut self, cons: Rc, var: &Variable); /// Adds a coefficient to the given constraint for the given variable and coefficient value. /// @@ -639,7 +637,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the coefficient cannot be added in the current state. - fn add_cons_coef(&mut self, cons: Rc, var: Rc, coef: f64); + fn add_cons_coef(&mut self, cons: Rc, var: &Variable, coef: f64); /// Adds a new quadratic constraint to the model with the given variables, coefficients, left-hand side, right-hand side, and name. /// @@ -663,10 +661,10 @@ pub trait ProblemOrSolving { /// This method panics if the constraint cannot be created in the current state. fn add_cons_quadratic( &mut self, - lin_vars: Vec>, + lin_vars: Vec<&Variable>, lin_coefs: &mut [f64], - quad_vars_1: Vec>, - quad_vars_2: Vec>, + quad_vars_1: Vec<&Variable>, + quad_vars_2: Vec<&Variable>, quad_coefs: &mut [f64], lhs: f64, rhs: f64, @@ -692,7 +690,7 @@ pub trait ProblemOrSolving { /// This method panics if the constraint cannot be created in the current state. fn add_cons( &mut self, - vars: Vec>, + vars: Vec<&Variable>, coefs: &[f64], lhs: f64, rhs: f64, @@ -713,7 +711,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_part(&mut self, vars: Vec>, name: &str) -> Rc; + fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; /// Adds a new set cover constraint to the model with the given variables and name. /// @@ -729,7 +727,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_cover(&mut self, vars: Vec>, name: &str) -> Rc; + fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; /// Adds a new set packing constraint to the model with the given variables and name. /// @@ -745,7 +743,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_pack(&mut self, vars: Vec>, name: &str) -> Rc; + fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; /// Adds a new cardinality constraint to the model with the given variables, cardinality limit, and name. /// @@ -764,7 +762,7 @@ pub trait ProblemOrSolving { /// This method panics if the constraint cannot be created in the current state. fn add_cons_cardinality( &mut self, - vars: Vec>, + vars: Vec<&Variable>, cardinality: usize, name: &str, ) -> Rc; @@ -788,8 +786,8 @@ pub trait ProblemOrSolving { /// This method panics if the constraint cannot be created in the current state. fn add_cons_indicator( &mut self, - bin_var: Rc, - vars: Vec>, + bin_var: &Variable, + vars: Vec<&Variable>, coefs: &mut [f64], rhs: f64, name: &str, @@ -835,7 +833,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the variable cannot be added in the current state, or if the variable is not binary. - fn add_cons_coef_setppc(&mut self, cons: Rc, var: Rc) { + fn add_cons_coef_setppc(&mut self, cons: Rc, var: &Variable) { assert_eq!(var.var_type(), VarType::Binary); self.scip .add_cons_coef_setppc(cons, var) @@ -853,7 +851,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the coefficient cannot be added in the current state. - fn add_cons_coef(&mut self, cons: Rc, var: Rc, coef: f64) { + fn add_cons_coef(&mut self, cons: Rc, var: &Variable, coef: f64) { self.scip .add_cons_coef(cons, var, coef) .expect("Failed to add constraint coefficient in state ProblemCreated"); @@ -881,10 +879,10 @@ impl ProblemOrSolving for Model { /// This method panics if the constraint cannot be created in the current state. fn add_cons_quadratic( &mut self, - lin_vars: Vec>, + lin_vars: Vec<&Variable>, lin_coefs: &mut [f64], - quad_vars_1: Vec>, - quad_vars_2: Vec>, + quad_vars_1: Vec<&Variable>, + quad_vars_2: Vec<&Variable>, quad_coefs: &mut [f64], lhs: f64, rhs: f64, @@ -932,7 +930,7 @@ impl ProblemOrSolving for Model { /// This method panics if the constraint cannot be created in the current state. fn add_cons( &mut self, - vars: Vec>, + vars: Vec<&Variable>, coefs: &[f64], lhs: f64, rhs: f64, @@ -964,7 +962,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_part(&mut self, vars: Vec>, name: &str) -> Rc { + fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip @@ -991,7 +989,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_cover(&mut self, vars: Vec>, name: &str) -> Rc { + fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip @@ -1018,7 +1016,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_pack(&mut self, vars: Vec>, name: &str) -> Rc { + fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip @@ -1048,7 +1046,7 @@ impl ProblemOrSolving for Model { /// This method panics if the constraint cannot be created in the current state. fn add_cons_cardinality( &mut self, - vars: Vec>, + vars: Vec<&Variable>, cardinality: usize, name: &str, ) -> Rc { @@ -1082,8 +1080,8 @@ impl ProblemOrSolving for Model { /// This method panics if the constraint cannot be created in the current state. fn add_cons_indicator( &mut self, - bin_var: Rc, - vars: Vec>, + bin_var: &Variable, + vars: Vec<&Variable>, coefs: &mut [f64], rhs: f64, name: &str, @@ -1406,8 +1404,8 @@ mod tests { let sol = model.best_sol().unwrap(); let vars = model.vars(); assert_eq!(vars.len(), 2); - assert_eq!(sol.val(vars[0].clone()), 40.); - assert_eq!(sol.val(vars[1].clone()), 20.); + assert_eq!(sol.val(&vars[0]), 40.); + assert_eq!(sol.val(&vars[1]), 20.); assert_eq!(sol.obj_val(), model.obj_val()); } @@ -1496,13 +1494,13 @@ mod tests { let x1 = model.add_var(0., f64::INFINITY, 3., "x1", VarType::Integer); let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); model.add_cons( - vec![x1.clone(), x2.clone()], + vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1", ); - model.add_cons(vec![x1, x2], &[1., 2.], -f64::INFINITY, 80., "c2"); + model.add_cons(vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., "c2"); model } @@ -1529,8 +1527,8 @@ mod tests { let sol = solved_model.best_sol().unwrap(); let vars = solved_model.vars(); assert_eq!(vars.len(), 2); - assert_eq!(sol.val(vars[0].clone()), 40.); - assert_eq!(sol.val(vars[1].clone()), 20.); + assert_eq!(sol.val(&vars[0]), 40.); + assert_eq!(sol.val(&vars[1]), 20.); } #[test] @@ -1559,7 +1557,7 @@ mod tests { let var = model.add_var(0., 1., 1., "x1", VarType::Integer); - model.add_cons(vec![var], &[1.], -f64::INFINITY, -1., "c1"); + model.add_cons(vec![&var], &[1.], -f64::INFINITY, -1., "c1"); let solved_model = model.solve(); @@ -1582,14 +1580,14 @@ mod tests { let x1 = model.add_var(0., f64::INFINITY, 3., "x1", VarType::Integer); let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); model.add_cons( - vec![x1.clone(), x2.clone()], + vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1", ); model.add_cons( - vec![x1.clone(), x2.clone()], + vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., @@ -1612,8 +1610,8 @@ mod tests { let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); let cons = model.add_cons(vec![], &[], -f64::INFINITY, 10., "c1"); - model.add_cons_coef(cons.clone(), x1, 0.); // x1 is unconstrained - model.add_cons_coef(cons, x2, 10.); // x2 can't be be used + model.add_cons_coef(cons.clone(), &x1, 0.); // x1 is unconstrained + model.add_cons_coef(cons, &x2, 10.); // x2 can't be used let solved_model = model.solve(); let status = solved_model.status(); @@ -1631,10 +1629,10 @@ mod tests { let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); let cons1 = model.add_cons_set_part(vec![], "c"); - model.add_cons_coef_setppc(cons1, x1); + model.add_cons_coef_setppc(cons1, &x1); - model.add_cons_set_cover(vec![x2.clone()], "c"); - model.add_cons_set_pack(vec![x2], "c"); + model.add_cons_set_cover(vec![&x2], "c"); + model.add_cons_set_pack(vec![&x2], "c"); let solved_model = model.solve(); let status = solved_model.status(); @@ -1656,7 +1654,7 @@ mod tests { let x3 = model.add_var(0., 10., 3., "x3", VarType::Integer); // cardinality constraint allows just two variables to be non-zero - model.add_cons_cardinality(vec![x1.clone(), x2.clone(), x3.clone()], 2, "cardinality"); + model.add_cons_cardinality(vec![&x1, &x2, &x3], 2, "cardinality"); let solved_model = model.solve(); let status = solved_model.status(); @@ -1664,9 +1662,9 @@ mod tests { assert_eq!(solved_model.obj_val(), 70.); let solution = solved_model.best_sol().unwrap(); - assert_eq!(solution.val(x1), 10.); - assert_eq!(solution.val(x2), 0.); - assert_eq!(solution.val(x3), 10.); + assert_eq!(solution.val(&x1), 10.); + assert_eq!(solution.val(&x2), 0.); + assert_eq!(solution.val(&x3), 10.); } #[test] @@ -1684,8 +1682,8 @@ mod tests { // Indicator constraint: `b == 1` implies `x1 - x2 <= -1` model.add_cons_indicator( - b.clone(), - vec![x1.clone(), x2.clone()], + &b, + vec![&x1, &x2], &mut [1., -1.], -1., "indicator", @@ -1693,7 +1691,7 @@ mod tests { // Force `b` to be exactly 1 and later make sure that the constraint `x1 - x2 <= -1` is // indeed active - model.add_cons(vec![b.clone()], &[1.], 1., 1., "c1"); + model.add_cons(vec![&b], &[1.], 1., 1., "c1"); let solved_model = model.solve(); let status = solved_model.status(); @@ -1703,9 +1701,9 @@ mod tests { let solution = solved_model.best_sol().unwrap(); // Indeed `x1 - x2 <= -1` when `b == 1` - assert_eq!(solution.val(x1), 9.); - assert_eq!(solution.val(x2), 10.); - assert_eq!(solution.val(b), 1.); + assert_eq!(solution.val(&x1), 9.); + assert_eq!(solution.val(&x2), 10.); + assert_eq!(solution.val(&b), 1.); } #[test] @@ -1719,15 +1717,15 @@ mod tests { let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); let cons1 = model.add_cons_set_part(vec![], "c"); - model.add_cons_coef_setppc(cons1, x1.clone()); + model.add_cons_coef_setppc(cons1, &x1); - model.add_cons_set_pack(vec![x2.clone()], "c"); + model.add_cons_set_pack(vec![&x2], "c"); let sol = model.create_sol(); assert_eq!(sol.obj_val(), 0.); - sol.set_val(x1, 1.); - sol.set_val(x2, 1.); + sol.set_val(&x1, 1.); + sol.set_val(&x2, 1.); assert_eq!(sol.obj_val(), 7.); assert!(model.add_sol(sol).is_ok()); @@ -1752,8 +1750,8 @@ mod tests { let _cons = model.add_cons_quadratic( vec![], &mut [], - vec![x1.clone(), x2.clone()], - vec![x1, x2], + vec![&x1, &x2], + vec![&x1, &x2], &mut [1., 1.], 0., 1., @@ -1780,7 +1778,7 @@ mod tests { let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); - model.add_cons_set_part(vec![x1, x2], "c"); + model.add_cons_set_part(vec![&x1, &x2], "c"); let solved_model = model.solve(); let status = solved_model.status(); @@ -1907,7 +1905,7 @@ mod tests { let x3 = second_model.add_var(0.0, f64::INFINITY, 1.0, "x3", VarType::Integer); let bound = 2.0; - second_model.add_cons(vec![x3], &[1.0], 0.0, bound, "x3-cons"); + second_model.add_cons(vec![&x3], &[1.0], 0.0, bound, "x3-cons"); let second_solved = second_model.solve(); let expected_obj = obj_val + bound; diff --git a/src/pricer.rs b/src/pricer.rs index 4cab13c..99591b8 100644 --- a/src/pricer.rs +++ b/src/pricer.rs @@ -230,7 +230,7 @@ mod tests { let var = model.add_priced_var(0.0, 1.0, 1.0, "x", VarType::Binary); let conss = model.conss(); for cons in conss { - model.add_cons_coef(cons, var.clone(), 1.0); + model.add_cons_coef(cons, &var, 1.0); } let nvars_after = model.n_vars(); assert_eq!(nvars_before + 1, nvars_after); diff --git a/src/row.rs b/src/row.rs index c274a1e..d1e5a5d 100644 --- a/src/row.rs +++ b/src/row.rs @@ -284,7 +284,7 @@ mod tests { let mut model = minimal_model(); let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); - let cons = model.add_cons(vec![x], &[1.0], 1.0, 1.0, "cons1"); + let cons = model.add_cons(vec![&x], &[1.0], 1.0, 1.0, "cons1"); model.set_cons_modifiable(cons, true); let eventhdlr = Box::new(RowTesterEventHandler); diff --git a/src/scip.rs b/src/scip.rs index 6897cc5..c12c24c 100644 --- a/src/scip.rs +++ b/src/scip.rs @@ -295,7 +295,7 @@ impl ScipPtr { pub(crate) fn create_cons( &self, - vars: Vec>, + vars: Vec<&Variable>, coefs: &[f64], lhs: f64, rhs: f64, @@ -329,7 +329,7 @@ impl ScipPtr { /// Create set partitioning constraint pub(crate) fn create_cons_set_part( &self, - vars: Vec>, + vars: Vec<&Variable>, name: &str, ) -> Result<*mut SCIP_Cons, Retcode> { let c_name = CString::new(name).unwrap(); @@ -352,7 +352,7 @@ impl ScipPtr { /// Create set cover constraint pub(crate) fn create_cons_set_cover( &self, - vars: Vec>, + vars: Vec<&Variable>, name: &str, ) -> Result<*mut SCIP_Cons, Retcode> { let c_name = CString::new(name).unwrap(); @@ -374,10 +374,10 @@ impl ScipPtr { pub(crate) fn create_cons_quadratic( &self, - lin_vars: Vec>, + lin_vars: Vec<&Variable>, lin_coefs: &mut [f64], - quad_vars_1: Vec>, - quad_vars_2: Vec>, + quad_vars_1: Vec<&Variable>, + quad_vars_2: Vec<&Variable>, quad_coefs: &mut [f64], lhs: f64, rhs: f64, @@ -398,7 +398,7 @@ impl ScipPtr { let c_name = CString::new(name).unwrap(); let mut scip_cons = MaybeUninit::uninit(); - let get_ptrs = |vars: Vec>| { + let get_ptrs = |vars: Vec<&Variable>| { vars.into_iter() .map(|var_rc| var_rc.raw) .collect::>() @@ -429,7 +429,7 @@ impl ScipPtr { /// Create set packing constraint pub(crate) fn create_cons_set_pack( &self, - vars: Vec>, + vars: Vec<&Variable>, name: &str, ) -> Result<*mut SCIP_Cons, Retcode> { let c_name = CString::new(name).unwrap(); @@ -452,7 +452,7 @@ impl ScipPtr { /// Create cardinality constraint pub(crate) fn create_cons_cardinality( &self, - vars: Vec>, + vars: Vec<&Variable>, cardinality: usize, name: &str, ) -> Result<*mut SCIP_Cons, Retcode> { @@ -488,8 +488,8 @@ impl ScipPtr { } pub(crate) fn create_cons_indicator( &self, - bin_var: Rc, - vars: Vec>, + bin_var: &Variable, + vars: Vec<&Variable>, coefs: &mut [f64], rhs: f64, name: &str, @@ -528,7 +528,7 @@ impl ScipPtr { pub(crate) fn add_cons_coef_setppc( &self, cons: Rc, - var: Rc, + var: &Variable, ) -> Result<(), Retcode> { scip_call! { ffi::SCIPaddCoefSetppc(self.raw, cons.raw, var.raw) }; Ok(()) @@ -1053,7 +1053,7 @@ impl ScipPtr { pub(crate) fn add_cons_coef( &self, cons: Rc, - var: Rc, + var: &Variable, coef: f64, ) -> Result<(), Retcode> { let cons_is_transformed = unsafe { ffi::SCIPconsIsTransformed(cons.raw) } == 1; diff --git a/src/separator.rs b/src/separator.rs index 723ddf4..b8959b0 100644 --- a/src/separator.rs +++ b/src/separator.rs @@ -148,9 +148,7 @@ impl SCIPSeparator { #[cfg(test)] mod tests { use super::*; - use crate::{ - minimal_model, Model, ModelWithProblem, ObjSense, ProblemOrSolving, Solving, VarType, - }; + use crate::{minimal_model, Model, ModelWithProblem, ObjSense, ProblemOrSolving, Solving, VarType, Variable}; struct NotRunningSeparator; @@ -196,9 +194,10 @@ mod tests { ) -> SeparationResult { // adds a row representing the sum of all variables >= 1 let vars = model.vars(); + let var_refs: Vec<&Variable> = vars.iter().collect(); let varlen = vars.len(); - model.add_cons(vars, &vec![1.0; varlen], 5.0, 5.0, "cons_added"); + model.add_cons(var_refs, &vec![1.0; varlen], 5.0, 5.0, "cons_added"); SeparationResult::ConsAdded } } @@ -212,7 +211,7 @@ mod tests { let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); let y = model.add_var(0.0, 1.0, 1.0, "y", VarType::Binary); - model.add_cons(vec![x, y], &[1.0, 1.0], 1.0, 1.0, "cons1"); + model.add_cons(vec![&x, &y], &[1.0, 1.0], 1.0, 1.0, "cons1"); let sep = ConsAddingSeparator {}; @@ -313,7 +312,7 @@ mod tests { let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); let y = model.add_var(0.0, 1.0, 1.0, "y", VarType::Binary); - model.add_cons(vec![x, y], &[1.0, 1.0], 1.0, 1.0, "cons1"); + model.add_cons(vec![&x, &y], &[1.0, 1.0], 1.0, 1.0, "cons1"); let sep = CutsAddingSeparator {}; diff --git a/src/solution.rs b/src/solution.rs index 2a04036..600cbf9 100644 --- a/src/solution.rs +++ b/src/solution.rs @@ -18,12 +18,12 @@ impl Solution { } /// Returns the value of a variable in the solution. - pub fn val(&self, var: Rc) -> f64 { + pub fn val(&self, var: &Variable) -> f64 { unsafe { ffi::SCIPgetSolVal(self.scip_ptr.raw, self.raw, var.raw) } } /// Sets the value of a variable in the solution. - pub fn set_val(&self, var: Rc, val: f64) { + pub fn set_val(&self, var: &Variable, val: f64) { scip_call_panic!(ffi::SCIPsetSolVal( self.scip_ptr.raw, self.raw, @@ -123,8 +123,8 @@ mod tests { assert!(debug_str.contains("Var t_x2=20")); let vars = model.vars(); - assert_eq!(sol.val(vars[0].clone()), 40.); - assert_eq!(sol.val(vars[1].clone()), 20.); + assert_eq!(sol.val(&vars[0]), 40.); + assert_eq!(sol.val(&vars[1]), 20.); assert_eq!(sol.obj_val(), model.obj_val()); diff --git a/src/variable.rs b/src/variable.rs index 7036cdd..e70481e 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -8,7 +8,7 @@ use std::rc::Rc; pub type VarId = usize; /// A wrapper for a mutable reference to a SCIP variable. -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(dead_code)] pub struct Variable { pub(crate) raw: *mut ffi::SCIP_VAR, @@ -204,7 +204,7 @@ mod tests { fn var_sol_val() { let mut model = minimal_model(); let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); - let _cons = model.add_cons(vec![x.clone()], &[1.0], 1.0, 1.0, "cons1"); + let _cons = model.add_cons(vec![&x], &[1.0], 1.0, 1.0, "cons1"); model.solve(); From 156e3b574ad501aabecb81cd4bef85f790274f8c Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Tue, 14 Jan 2025 09:12:03 +0100 Subject: [PATCH 2/6] Use &Constraint instead of Rc --- src/col.rs | 2 +- src/model.rs | 79 +++++++++++++++++++++++++-------------------------- src/pricer.rs | 4 +-- src/row.rs | 2 +- src/scip.rs | 6 ++-- 5 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/col.rs b/src/col.rs index 4d4b81b..efcc078 100644 --- a/src/col.rs +++ b/src/col.rs @@ -240,7 +240,7 @@ mod tests { let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); let cons = model.add_cons(vec![&x], &[1.0], 1.0, 1.0, "cons1"); - model.set_cons_modifiable(cons, true); + model.set_cons_modifiable(&cons, true); let eventhdlr = Box::new(ColTesterEventHandler); model = model.include_eventhdlr("ColTesterEventHandler", "", eventhdlr); diff --git a/src/model.rs b/src/model.rs index c64a463..da6d2c7 100644 --- a/src/model.rs +++ b/src/model.rs @@ -119,7 +119,7 @@ impl Model { } /// Sets the constraint as modifiable or not. - pub fn set_cons_modifiable(&mut self, cons: Rc, modifiable: bool) { + pub fn set_cons_modifiable(&mut self, cons: &Constraint, modifiable: bool) { self.scip .set_cons_modifiable(cons, modifiable) .expect("Failed to set constraint modifiable"); @@ -534,7 +534,7 @@ pub trait ModelWithProblem { fn n_conss(&self) -> usize; /// Returns a vector of all constraints in the optimization model. - fn conss(&self) -> Vec>; + fn conss(&self) -> Vec; /// Writes the optimization model to a file with the given path and extension. fn write(&self, path: &str, ext: &str) -> Result<(), Retcode>; @@ -584,7 +584,7 @@ impl ModelWithProblem for Model { } /// Returns a vector of all constraints in the optimization model. - fn conss(&self) -> Vec> { + fn conss(&self) -> Vec { let scip_conss = self.scip.conss(false); scip_conss .into_iter() @@ -592,7 +592,6 @@ impl ModelWithProblem for Model { raw: c, scip: self.scip.clone(), }) - .map(Rc::new) .collect() } @@ -624,7 +623,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the variable cannot be added in the current state, or if the variable is not binary. - fn add_cons_coef_setppc(&mut self, cons: Rc, var: &Variable); + fn add_cons_coef_setppc(&mut self, cons: &Constraint, var: &Variable); /// Adds a coefficient to the given constraint for the given variable and coefficient value. /// @@ -637,7 +636,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the coefficient cannot be added in the current state. - fn add_cons_coef(&mut self, cons: Rc, var: &Variable, coef: f64); + fn add_cons_coef(&mut self, cons: &Constraint, var: &Variable, coef: f64); /// Adds a new quadratic constraint to the model with the given variables, coefficients, left-hand side, right-hand side, and name. /// @@ -669,7 +668,7 @@ pub trait ProblemOrSolving { lhs: f64, rhs: f64, name: &str, - ) -> Rc; + ) -> Constraint; /// Adds a new constraint to the model with the given variables, coefficients, left-hand side, right-hand side, and name. /// @@ -695,7 +694,7 @@ pub trait ProblemOrSolving { lhs: f64, rhs: f64, name: &str, - ) -> Rc; + ) -> Constraint; /// Adds a new set partitioning constraint to the model with the given variables and name. /// @@ -711,7 +710,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; + fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint; /// Adds a new set cover constraint to the model with the given variables and name. /// @@ -727,7 +726,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; + fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint; /// Adds a new set packing constraint to the model with the given variables and name. /// @@ -743,7 +742,7 @@ pub trait ProblemOrSolving { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Rc; + fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint; /// Adds a new cardinality constraint to the model with the given variables, cardinality limit, and name. /// @@ -765,7 +764,7 @@ pub trait ProblemOrSolving { vars: Vec<&Variable>, cardinality: usize, name: &str, - ) -> Rc; + ) -> Constraint; /// Adds a new indicator constraint to the model with the given variables, coefficients, right-hand side, and name. /// @@ -791,7 +790,7 @@ pub trait ProblemOrSolving { coefs: &mut [f64], rhs: f64, name: &str, - ) -> Rc; + ) -> Constraint; } trait ModelStageProblemOrSolving {} impl ModelStageProblemOrSolving for ProblemCreated {} @@ -833,7 +832,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the variable cannot be added in the current state, or if the variable is not binary. - fn add_cons_coef_setppc(&mut self, cons: Rc, var: &Variable) { + fn add_cons_coef_setppc(&mut self, cons: &Constraint, var: &Variable) { assert_eq!(var.var_type(), VarType::Binary); self.scip .add_cons_coef_setppc(cons, var) @@ -851,7 +850,7 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the coefficient cannot be added in the current state. - fn add_cons_coef(&mut self, cons: Rc, var: &Variable, coef: f64) { + fn add_cons_coef(&mut self, cons: &Constraint, var: &Variable, coef: f64) { self.scip .add_cons_coef(cons, var, coef) .expect("Failed to add constraint coefficient in state ProblemCreated"); @@ -887,7 +886,7 @@ impl ProblemOrSolving for Model { lhs: f64, rhs: f64, name: &str, - ) -> Rc { + ) -> Constraint { assert_eq!(lin_vars.len(), lin_coefs.len()); assert_eq!(quad_vars_1.len(), quad_vars_2.len()); assert_eq!(quad_vars_1.len(), quad_coefs.len()); @@ -905,10 +904,10 @@ impl ProblemOrSolving for Model { ) .expect("Failed to create constraint in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new constraint to the model with the given variables, coefficients, left-hand side, right-hand side, and name. @@ -935,17 +934,17 @@ impl ProblemOrSolving for Model { lhs: f64, rhs: f64, name: &str, - ) -> Rc { + ) -> Constraint { assert_eq!(vars.len(), coefs.len()); let cons = self .scip .create_cons(vars, coefs, lhs, rhs, name) .expect("Failed to create constraint in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new set partitioning constraint to the model with the given variables and name. @@ -962,17 +961,17 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { + fn add_cons_set_part(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip .create_cons_set_part(vars, name) .expect("Failed to add constraint set partition in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new set cover constraint to the model with the given variables and name. @@ -989,17 +988,17 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { + fn add_cons_set_cover(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip .create_cons_set_cover(vars, name) .expect("Failed to add constraint set cover in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new set packing constraint to the model with the given variables and name. @@ -1016,17 +1015,17 @@ impl ProblemOrSolving for Model { /// # Panics /// /// This method panics if the constraint cannot be created in the current state, or if any of the variables are not binary. - fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Rc { + fn add_cons_set_pack(&mut self, vars: Vec<&Variable>, name: &str) -> Constraint { assert!(vars.iter().all(|v| v.var_type() == VarType::Binary)); let cons = self .scip .create_cons_set_pack(vars, name) .expect("Failed to add constraint set packing in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new cardinality constraint to the model with the given variables, cardinality limit, and name. @@ -1049,16 +1048,16 @@ impl ProblemOrSolving for Model { vars: Vec<&Variable>, cardinality: usize, name: &str, - ) -> Rc { + ) -> Constraint { let cons = self .scip .create_cons_cardinality(vars, cardinality, name) .expect("Failed to add cardinality constraint"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } /// Adds a new indicator constraint to the model with the given variables, coefficients, right-hand side, and name. @@ -1085,7 +1084,7 @@ impl ProblemOrSolving for Model { coefs: &mut [f64], rhs: f64, name: &str, - ) -> Rc { + ) -> Constraint { assert_eq!(vars.len(), coefs.len()); assert_eq!(bin_var.var_type(), VarType::Binary); let cons = self @@ -1093,10 +1092,10 @@ impl ProblemOrSolving for Model { .create_cons_indicator(bin_var, vars, coefs, rhs, name) .expect("Failed to create constraint in state ProblemCreated"); - Rc::new(Constraint { + Constraint { raw: cons, scip: self.scip.clone(), - }) + } } } @@ -1610,8 +1609,8 @@ mod tests { let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); let cons = model.add_cons(vec![], &[], -f64::INFINITY, 10., "c1"); - model.add_cons_coef(cons.clone(), &x1, 0.); // x1 is unconstrained - model.add_cons_coef(cons, &x2, 10.); // x2 can't be used + model.add_cons_coef(&cons, &x1, 0.); // x1 is unconstrained + model.add_cons_coef(&cons, &x2, 10.); // x2 can't be used let solved_model = model.solve(); let status = solved_model.status(); @@ -1629,7 +1628,7 @@ mod tests { let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); let cons1 = model.add_cons_set_part(vec![], "c"); - model.add_cons_coef_setppc(cons1, &x1); + model.add_cons_coef_setppc(&cons1, &x1); model.add_cons_set_cover(vec![&x2], "c"); model.add_cons_set_pack(vec![&x2], "c"); @@ -1717,7 +1716,7 @@ mod tests { let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); let cons1 = model.add_cons_set_part(vec![], "c"); - model.add_cons_coef_setppc(cons1, &x1); + model.add_cons_coef_setppc(&cons1, &x1); model.add_cons_set_pack(vec![&x2], "c"); diff --git a/src/pricer.rs b/src/pricer.rs index 99591b8..090d695 100644 --- a/src/pricer.rs +++ b/src/pricer.rs @@ -230,7 +230,7 @@ mod tests { let var = model.add_priced_var(0.0, 1.0, 1.0, "x", VarType::Binary); let conss = model.conss(); for cons in conss { - model.add_cons_coef(cons, &var, 1.0); + model.add_cons_coef(&cons, &var, 1.0); } let nvars_after = model.n_vars(); assert_eq!(nvars_before + 1, nvars_after); @@ -252,7 +252,7 @@ mod tests { let conss = model.conss(); for c in conss { - model.set_cons_modifiable(c, true); + model.set_cons_modifiable(&c, true); } let pricer = AddSameColumnPricer { diff --git a/src/row.rs b/src/row.rs index d1e5a5d..f9c9b40 100644 --- a/src/row.rs +++ b/src/row.rs @@ -285,7 +285,7 @@ mod tests { let x = model.add_var(0.0, 1.0, 1.0, "x", VarType::Binary); let cons = model.add_cons(vec![&x], &[1.0], 1.0, 1.0, "cons1"); - model.set_cons_modifiable(cons, true); + model.set_cons_modifiable(&cons, true); let eventhdlr = Box::new(RowTesterEventHandler); model = model.include_eventhdlr("ColTesterEventHandler", "", eventhdlr); diff --git a/src/scip.rs b/src/scip.rs index c12c24c..210778c 100644 --- a/src/scip.rs +++ b/src/scip.rs @@ -527,7 +527,7 @@ impl ScipPtr { /// Add coefficient to set packing/partitioning/covering constraint pub(crate) fn add_cons_coef_setppc( &self, - cons: Rc, + cons: &Constraint, var: &Variable, ) -> Result<(), Retcode> { scip_call! { ffi::SCIPaddCoefSetppc(self.raw, cons.raw, var.raw) }; @@ -1052,7 +1052,7 @@ impl ScipPtr { pub(crate) fn add_cons_coef( &self, - cons: Rc, + cons: &Constraint, var: &Variable, coef: f64, ) -> Result<(), Retcode> { @@ -1089,7 +1089,7 @@ impl ScipPtr { pub(crate) fn set_cons_modifiable( &self, - cons: Rc, + cons: &Constraint, modifiable: bool, ) -> Result<(), Retcode> { scip_call!(ffi::SCIPsetConsModifiable( From 9a434f2eb74883895f145b3d1d33383692887e2a Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Tue, 14 Jan 2025 09:13:04 +0100 Subject: [PATCH 3/6] Implement clone for Solution --- src/solution.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/solution.rs b/src/solution.rs index 600cbf9..072a6b6 100644 --- a/src/solution.rs +++ b/src/solution.rs @@ -6,9 +6,10 @@ use crate::variable::Variable; use crate::{ffi, scip_call_panic}; /// A wrapper for a SCIP solution. +#[derive(Clone)] pub struct Solution { - pub(crate) scip_ptr: Rc, pub(crate) raw: *mut ffi::SCIP_SOL, + pub(crate) scip_ptr: Rc, } impl Solution { From bde32d43b5f9e46befe20ad4c3428d93f0733415 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Tue, 14 Jan 2025 09:14:26 +0100 Subject: [PATCH 4/6] Cargo fmt --- examples/create_and_solve.rs | 16 ++-------------- src/model.rs | 32 ++++---------------------------- src/separator.rs | 5 ++++- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/examples/create_and_solve.rs b/examples/create_and_solve.rs index a70f4f8..179f9b4 100644 --- a/examples/create_and_solve.rs +++ b/examples/create_and_solve.rs @@ -13,20 +13,8 @@ fn main() { let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); // Add constraints - model.add_cons( - vec![&x1, &x2], - &[2., 1.], - -f64::INFINITY, - 100., - "c1", - ); - model.add_cons( - vec![&x1, &x2], - &[1., 2.], - -f64::INFINITY, - 80., - "c2", - ); + model.add_cons(vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1"); + model.add_cons(vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., "c2"); let solved_model = model.solve(); diff --git a/src/model.rs b/src/model.rs index da6d2c7..62d3c83 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1492,13 +1492,7 @@ mod tests { let x1 = model.add_var(0., f64::INFINITY, 3., "x1", VarType::Integer); let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); - model.add_cons( - vec![&x1, &x2], - &[2., 1.], - -f64::INFINITY, - 100., - "c1", - ); + model.add_cons(vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1"); model.add_cons(vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., "c2"); model @@ -1578,20 +1572,8 @@ mod tests { let x1 = model.add_var(0., f64::INFINITY, 3., "x1", VarType::Integer); let x2 = model.add_var(0., f64::INFINITY, 4., "x2", VarType::Integer); - model.add_cons( - vec![&x1, &x2], - &[2., 1.], - -f64::INFINITY, - 100., - "c1", - ); - model.add_cons( - vec![&x1, &x2], - &[1., 2.], - -f64::INFINITY, - 80., - "c2", - ); + model.add_cons(vec![&x1, &x2], &[2., 1.], -f64::INFINITY, 100., "c1"); + model.add_cons(vec![&x1, &x2], &[1., 2.], -f64::INFINITY, 80., "c2"); let scip_ptr = model.scip.raw; assert!(!scip_ptr.is_null()); @@ -1680,13 +1662,7 @@ mod tests { let b = model.add_var(0., 1., 0., "b", VarType::Binary); // Indicator constraint: `b == 1` implies `x1 - x2 <= -1` - model.add_cons_indicator( - &b, - vec![&x1, &x2], - &mut [1., -1.], - -1., - "indicator", - ); + model.add_cons_indicator(&b, vec![&x1, &x2], &mut [1., -1.], -1., "indicator"); // Force `b` to be exactly 1 and later make sure that the constraint `x1 - x2 <= -1` is // indeed active diff --git a/src/separator.rs b/src/separator.rs index b8959b0..110baf1 100644 --- a/src/separator.rs +++ b/src/separator.rs @@ -148,7 +148,10 @@ impl SCIPSeparator { #[cfg(test)] mod tests { use super::*; - use crate::{minimal_model, Model, ModelWithProblem, ObjSense, ProblemOrSolving, Solving, VarType, Variable}; + use crate::{ + minimal_model, Model, ModelWithProblem, ObjSense, ProblemOrSolving, Solving, VarType, + Variable, + }; struct NotRunningSeparator; From c543b2f1130228013782ab0b2cd61572335de227 Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Wed, 15 Jan 2025 09:31:49 +0100 Subject: [PATCH 5/6] Add getter methods for params and improve tests --- src/model.rs | 65 ++++++++++++++++++++++++++++++---------------------- src/scip.rs | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/model.rs b/src/model.rs index 62d3c83..a0297e7 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1289,6 +1289,34 @@ impl Model { Ok(self) } + /// Returns the value of a SCIP string parameter. + pub fn str_param(&self, param: &str) -> String { + self.scip + .str_param(param) + .expect("Failed to get string parameter") + .to_string() + } + + /// Returns the value of a SCIP boolean parameter. + pub fn bool_param(&self, param: &str) -> bool { + self.scip.bool_param(param).expect("Failed to get boolean parameter") + } + + /// Returns the value of a SCIP integer parameter. + pub fn int_param(&self, param: &str) -> i32 { + self.scip.int_param(param).expect("Failed to get integer parameter") + } + + /// Returns the value of a SCIP long integer parameter. + pub fn longint_param(&self, param: &str) -> i64 { + self.scip.longint_param(param).expect("Failed to get long integer parameter") + } + + /// Returns the value of a SCIP real parameter. + pub fn real_param(&self, param: &str) -> f64 { + self.scip.real_param(param).expect("Failed to get real parameter") + } + /// Sets the presolving parameter of the SCIP instance and returns the same `Model` instance. #[allow(unused_mut)] pub fn set_presolving(mut self, presolving: ParamSetting) -> Self { @@ -1376,7 +1404,6 @@ mod tests { use crate::status::Status; use rayon::prelude::*; use std::fs; - use std::path::Path; use super::*; @@ -1743,28 +1770,12 @@ mod tests { #[test] fn set_str_param() { let output_path = "data/ignored/test.vbc"; - let mut model = Model::new() + let model = Model::new() .hide_output() .set_str_param("visual/vbcfilename", output_path) - .unwrap() - .include_default_plugins() - .create_prob("test") - .set_obj_sense(ObjSense::Minimize); - - let x1 = model.add_var(0., 1., 3., "x1", VarType::Binary); - let x2 = model.add_var(0., 1., 4., "x2", VarType::Binary); - model.add_cons_set_part(vec![&x1, &x2], "c"); - - let solved_model = model.solve(); - let status = solved_model.status(); - assert_eq!(status, Status::Optimal); - assert_eq!(solved_model.obj_val(), 3.); - - assert!(Path::new(output_path).exists()); - - // drop model so the file is closed and it can be removed - drop(solved_model); - fs::remove_file(output_path).unwrap(); + .unwrap(); + + assert_eq!(model.str_param("visual/vbcfilename"), output_path); } #[test] @@ -1809,10 +1820,12 @@ mod tests { #[test] fn set_bool_param() { - Model::new() + let model = Model::new() .hide_output() .set_bool_param("display/allviols", true) .unwrap(); + + assert!(model.bool_param("display/allviols")); } #[test] @@ -1830,13 +1843,9 @@ mod tests { let model = Model::new() .hide_output() .set_real_param("limits/time", 0.) - .unwrap() - .include_default_plugins() - .read_prob("data/test/simple.lp") - .unwrap() - .solve(); + .unwrap(); - assert_eq!(model.status(), Status::TimeLimit); + assert_eq!(model.real_param("limits/time"), 0.); } #[test] diff --git a/src/scip.rs b/src/scip.rs index 210778c..86cedce 100644 --- a/src/scip.rs +++ b/src/scip.rs @@ -51,29 +51,70 @@ impl ScipPtr { Ok(()) } + pub(crate) fn str_param(&self, param: &str) -> Result<&str, Retcode> { + let param = CString::new(param).unwrap(); + let mut value_ptr = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetStringParam(self.raw, param.as_ptr(), value_ptr.as_mut_ptr()) }; + let value_ptr = unsafe { value_ptr.assume_init() }; + let value = unsafe { CStr::from_ptr(value_ptr) }; + Ok(value.to_str().unwrap()) + } + pub(crate) fn set_bool_param(&self, param: &str, value: bool) -> Result<(), Retcode> { let param = CString::new(param).unwrap(); scip_call! { ffi::SCIPsetBoolParam(self.raw, param.as_ptr(), if value { 1u32 } else { 0u32 }) }; Ok(()) } + + pub(crate) fn bool_param(&self, param: &str) -> Result { + let param = CString::new(param).unwrap(); + let mut value = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetBoolParam(self.raw, param.as_ptr(), value.as_mut_ptr()) }; + let value = unsafe { value.assume_init() }; + Ok(value != 0) + } pub(crate) fn set_int_param(&self, param: &str, value: i32) -> Result<(), Retcode> { let param = CString::new(param).unwrap(); scip_call! { ffi::SCIPsetIntParam(self.raw, param.as_ptr(), value) }; Ok(()) } + + pub(crate) fn int_param(&self, param: &str) -> Result { + let param = CString::new(param).unwrap(); + let mut value = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetIntParam(self.raw, param.as_ptr(), value.as_mut_ptr()) }; + let value = unsafe { value.assume_init() }; + Ok(value) + } pub(crate) fn set_longint_param(&self, param: &str, value: i64) -> Result<(), Retcode> { let param = CString::new(param).unwrap(); scip_call! { ffi::SCIPsetLongintParam(self.raw, param.as_ptr(), value) }; Ok(()) } + + pub(crate) fn longint_param(&self, param: &str) -> Result { + let param = CString::new(param).unwrap(); + let mut value = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetLongintParam(self.raw, param.as_ptr(), value.as_mut_ptr()) }; + let value = unsafe { value.assume_init() }; + Ok(value) + } pub(crate) fn set_real_param(&self, param: &str, value: f64) -> Result<(), Retcode> { let param = CString::new(param).unwrap(); scip_call! { ffi::SCIPsetRealParam(self.raw, param.as_ptr(), value) }; Ok(()) } + + pub(crate) fn real_param(&self, param: &str) -> Result { + let param = CString::new(param).unwrap(); + let mut value = MaybeUninit::uninit(); + scip_call! { ffi::SCIPgetRealParam(self.raw, param.as_ptr(), value.as_mut_ptr()) }; + let value = unsafe { value.assume_init() }; + Ok(value) + } pub(crate) fn set_presolving(&self, presolving: ParamSetting) -> Result<(), Retcode> { scip_call! { ffi::SCIPsetPresolving(self.raw, presolving.into(), true.into()) }; From 36f063052fb6009684618d87748f1cf4cfc6035a Mon Sep 17 00:00:00 2001 From: Mohammed Ghannam Date: Wed, 15 Jan 2025 09:32:23 +0100 Subject: [PATCH 6/6] Cargo fmt --- src/model.rs | 18 +++++++++++++----- src/scip.rs | 8 ++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/model.rs b/src/model.rs index a0297e7..afda280 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1299,22 +1299,30 @@ impl Model { /// Returns the value of a SCIP boolean parameter. pub fn bool_param(&self, param: &str) -> bool { - self.scip.bool_param(param).expect("Failed to get boolean parameter") + self.scip + .bool_param(param) + .expect("Failed to get boolean parameter") } /// Returns the value of a SCIP integer parameter. pub fn int_param(&self, param: &str) -> i32 { - self.scip.int_param(param).expect("Failed to get integer parameter") + self.scip + .int_param(param) + .expect("Failed to get integer parameter") } /// Returns the value of a SCIP long integer parameter. pub fn longint_param(&self, param: &str) -> i64 { - self.scip.longint_param(param).expect("Failed to get long integer parameter") + self.scip + .longint_param(param) + .expect("Failed to get long integer parameter") } /// Returns the value of a SCIP real parameter. pub fn real_param(&self, param: &str) -> f64 { - self.scip.real_param(param).expect("Failed to get real parameter") + self.scip + .real_param(param) + .expect("Failed to get real parameter") } /// Sets the presolving parameter of the SCIP instance and returns the same `Model` instance. @@ -1774,7 +1782,7 @@ mod tests { .hide_output() .set_str_param("visual/vbcfilename", output_path) .unwrap(); - + assert_eq!(model.str_param("visual/vbcfilename"), output_path); } diff --git a/src/scip.rs b/src/scip.rs index 86cedce..a19144c 100644 --- a/src/scip.rs +++ b/src/scip.rs @@ -65,7 +65,7 @@ impl ScipPtr { scip_call! { ffi::SCIPsetBoolParam(self.raw, param.as_ptr(), if value { 1u32 } else { 0u32 }) }; Ok(()) } - + pub(crate) fn bool_param(&self, param: &str) -> Result { let param = CString::new(param).unwrap(); let mut value = MaybeUninit::uninit(); @@ -79,7 +79,7 @@ impl ScipPtr { scip_call! { ffi::SCIPsetIntParam(self.raw, param.as_ptr(), value) }; Ok(()) } - + pub(crate) fn int_param(&self, param: &str) -> Result { let param = CString::new(param).unwrap(); let mut value = MaybeUninit::uninit(); @@ -93,7 +93,7 @@ impl ScipPtr { scip_call! { ffi::SCIPsetLongintParam(self.raw, param.as_ptr(), value) }; Ok(()) } - + pub(crate) fn longint_param(&self, param: &str) -> Result { let param = CString::new(param).unwrap(); let mut value = MaybeUninit::uninit(); @@ -107,7 +107,7 @@ impl ScipPtr { scip_call! { ffi::SCIPsetRealParam(self.raw, param.as_ptr(), value) }; Ok(()) } - + pub(crate) fn real_param(&self, param: &str) -> Result { let param = CString::new(param).unwrap(); let mut value = MaybeUninit::uninit();