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