Skip to content

Commit 2622e5e

Browse files
authored
Merge pull request #269 from HunkBenny/variable
Added `redcost` method to Variable.rs
2 parents 00dbcd5 + 5d93897 commit 2622e5e

File tree

2 files changed

+85
-2
lines changed

2 files changed

+85
-2
lines changed

src/col.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ impl Col {
169169
assert!(age >= 0);
170170
age as usize
171171
}
172+
173+
/// Returns the reduced cost of the column.
174+
pub fn redcost(&self) -> f64 {
175+
unsafe { ffi::SCIPgetColRedcost(self.scip.raw, self.raw) }
176+
}
172177
}
173178

174179
impl PartialEq for Col {

src/variable.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ impl Variable {
8282

8383
/// Returns the column associated with the variable.
8484
pub fn col(&self) -> Option<Col> {
85-
if self.is_in_lp() {
85+
if self.status() == VarStatus::Column {
8686
let col_ptr = unsafe { ffi::SCIPvarGetCol(self.raw) };
8787
let col = Col {
8888
raw: col_ptr,
@@ -152,6 +152,21 @@ 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+
pub fn redcost(&self) -> Option<f64> {
163+
let rc = unsafe { ffi::SCIPgetVarRedcost(self.scip.raw, self.raw) };
164+
// SCIP can return SCIP_INVALID. In this case, we return None.
165+
if rc == ffi::SCIP_INVALID {
166+
return None;
167+
}
168+
Some(rc)
169+
}
155170
}
156171

157172
/// The type of variable in an optimization problem.
@@ -227,7 +242,10 @@ impl From<SCIP_Status> for VarStatus {
227242
#[cfg(test)]
228243
mod tests {
229244
use super::*;
230-
use crate::{Model, ObjSense, ProblemOrSolving, minimal_model};
245+
use crate::{
246+
Model, ModelWithProblem, ObjSense, Pricer, ProblemOrSolving, minimal_model,
247+
prelude::{cons, pricer},
248+
};
231249

232250
#[test]
233251
fn var_data() {
@@ -278,4 +296,64 @@ mod tests {
278296

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

0 commit comments

Comments
 (0)