Skip to content

Commit 286d041

Browse files
committed
add: add method for getting reduced cost from variable + tests
1 parent 1dfd6a4 commit 286d041

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

src/variable.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ impl Variable {
152152
};
153153
Some(var)
154154
}
155+
156+
/// Gets the reduced costs of the variable in the current node's LP relaxation; the current node has to have a feasible LP.
157+
///
158+
/// * Returns:
159+
/// `None` - if the variable is active but not in the current LP
160+
/// `Some(0.0)` - if the variable has been aggregated out or fixed in presolving.
161+
/// `Some(f64)` - the reduced cost of the variable
162+
///
163+
pub fn get_redcost(&self) -> Option<f64> {
164+
let rc = unsafe { ffi::SCIPgetVarRedcost(self.scip.raw, self.raw) };
165+
// ? scip invalid
166+
if rc == 1e100 {
167+
return None;
168+
}
169+
Some(rc)
170+
}
155171
}
156172

157173
/// The type of variable in an optimization problem.
@@ -227,7 +243,10 @@ impl From<SCIP_Status> for VarStatus {
227243
#[cfg(test)]
228244
mod tests {
229245
use super::*;
230-
use crate::{Model, ObjSense, ProblemOrSolving, minimal_model};
246+
use crate::{
247+
Model, ModelWithProblem, ObjSense, Pricer, ProblemOrSolving, minimal_model,
248+
prelude::{cons, pricer},
249+
};
231250

232251
#[test]
233252
fn var_data() {
@@ -278,4 +297,64 @@ mod tests {
278297

279298
assert_eq!(x.sol_val(), 1.0);
280299
}
300+
301+
struct PricerRedcost;
302+
impl Pricer for PricerRedcost {
303+
fn generate_columns(
304+
&mut self,
305+
mut model: Model<crate::Solving>,
306+
_pricer: crate::SCIPPricer,
307+
_farkas: bool,
308+
) -> crate::PricerResult {
309+
if model.vars().len() > 3 {
310+
// initial call, no vars yet
311+
return crate::PricerResult {
312+
state: crate::PricerResultState::NoColumns,
313+
lower_bound: None,
314+
};
315+
}
316+
let conss = model.conss();
317+
let cons1 = &conss[0];
318+
let cons2 = &conss[1];
319+
let dual1 = cons1.dual_sol().unwrap();
320+
let dual2 = cons2.dual_sol().unwrap();
321+
// coeff
322+
let c = 1.0;
323+
// rc
324+
let rc = c - dual1 - dual2;
325+
// make var
326+
let var_obj = model.add_priced_var(0.0, 1.0, c, "testvar", VarType::Continuous);
327+
model.add_cons_coef(cons1, &var_obj, 1.0);
328+
model.add_cons_coef(cons2, &var_obj, 1.0);
329+
// check if calculated rc matches get_redcost
330+
assert_eq!(rc, var_obj.get_redcost().unwrap());
331+
332+
crate::PricerResult {
333+
state: crate::PricerResultState::FoundColumns,
334+
lower_bound: None,
335+
}
336+
}
337+
}
338+
339+
#[test]
340+
fn var_redcost() {
341+
let mut model = minimal_model()
342+
.set_longint_param("limits/nodes", 3)
343+
.unwrap()
344+
.minimize();
345+
let x = model.add_var(0.0, 1.0, 10.3, "x", VarType::Binary);
346+
let y = model.add_var(0.0, 1.0, 5.5, "y", VarType::Binary);
347+
let cons1 = model.add(cons().modifiable(true).ge(5.0));
348+
let cons2 = model.add(cons().modifiable(true).ge(10.0));
349+
model.add_cons_coef(&cons1, &y, 10.0);
350+
model.add_cons_coef(&cons2, &x, 10.0);
351+
352+
let pricer_obj = PricerRedcost;
353+
354+
model.add(pricer(pricer_obj));
355+
356+
model.solve();
357+
let redcost = x.get_redcost().unwrap();
358+
println!("Reduced cost of x: {}", redcost);
359+
}
281360
}

0 commit comments

Comments
 (0)