@@ -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) ]
228244mod 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