@@ -59,13 +59,20 @@ impl Engine {
5959 index
6060 }
6161
62+ pub fn add_lin_var ( & mut self , lin : Lin ) -> usize {
63+ let index = self . add_var ( ) ;
64+ self . assignments [ index] = self . lin_val ( & lin) ;
65+ self . new_row ( index, lin) ;
66+ index
67+ }
68+
6269 pub fn add_constraint ( & mut self ) -> usize {
6370 let index = self . constraints . len ( ) ;
6471 self . constraints . push ( Constraint { lbs : HashMap :: new ( ) , ubs : HashMap :: new ( ) } ) ;
6572 index
6673 }
6774
68- pub fn value ( & self , var : usize ) -> & InfRational {
75+ pub fn val ( & self , var : usize ) -> & InfRational {
6976 & self . assignments [ var]
7077 }
7178
@@ -80,7 +87,7 @@ impl Engine {
8087 pub fn lin_val ( & self , lin : & Lin ) -> InfRational {
8188 let mut result = i_rat ( lin. known_term ) ;
8289 for ( & var, & coeff) in & lin. vars {
83- result += coeff * self . value ( var) ;
90+ result += coeff * self . val ( var) ;
8491 }
8592 result
8693 }
@@ -141,7 +148,7 @@ impl Engine {
141148 if let Some ( reason) = reason {
142149 entry. insert ( reason) ;
143150 }
144- if self . value ( var) < & lb && !self . is_basic ( var) {
151+ if self . val ( var) < & lb && !self . is_basic ( var) {
145152 self . update ( var, lb) ;
146153 }
147154
@@ -176,7 +183,7 @@ impl Engine {
176183 if let Some ( reason) = reason {
177184 entry. insert ( reason) ;
178185 }
179- if self . value ( var) > & ub && !self . is_basic ( var) {
186+ if self . val ( var) > & ub && !self . is_basic ( var) {
180187 self . update ( var, ub) ;
181188 }
182189
@@ -206,9 +213,7 @@ impl Engine {
206213 _ => {
207214 // More than one variable, need to add a new tableau row
208215 let val = inf ( -std:: mem:: take ( & mut expr. known_term ) , if strict { r ( -1 ) } else { Rational :: ZERO } ) ;
209- let slack = self . add_var ( ) ;
210- self . assignments [ slack] = self . lin_val ( & expr) ;
211- self . new_row ( slack, expr) ;
216+ let slack = self . add_lin_var ( expr) ;
212217 self . set_ub ( slack, val, reason)
213218 }
214219 }
@@ -241,9 +246,7 @@ impl Engine {
241246 _ => {
242247 // More than one variable, need to add a new tableau row
243248 let val = i_rat ( -std:: mem:: take ( & mut expr. known_term ) ) ;
244- let slack = self . add_var ( ) ;
245- self . assignments [ slack] = self . lin_val ( & expr) ;
246- self . new_row ( slack, expr) ;
249+ let slack = self . add_lin_var ( expr) ;
247250 self . set_lb ( slack, val, reason) && self . set_ub ( slack, val, reason)
248251 }
249252 }
@@ -266,7 +269,7 @@ impl Engine {
266269 assert ! ( & new_value >= self . lb( var) && & new_value <= self . ub( var) , "New value must be within bounds" ) ;
267270
268271 for & watch in & self . t_watches [ var] {
269- let delta = self . tableau [ & watch] . vars [ & var] * ( new_value - self . value ( var) ) ;
272+ let delta = self . tableau [ & watch] . vars [ & var] * ( new_value - self . val ( var) ) ;
270273 self . assignments [ watch] += delta;
271274 self . notify ( watch) ;
272275 }
@@ -279,18 +282,18 @@ impl Engine {
279282 loop {
280283 // we search for a basic variable whose value is not within its bounds..
281284 let var = self . tableau . iter ( ) . find_map ( |( & var, _) | {
282- if self . value ( var) < self . lb ( var) {
285+ if self . val ( var) < self . lb ( var) {
283286 Some ( ( var, * self . lb ( var) ) )
284- } else if self . value ( var) > self . ub ( var) {
287+ } else if self . val ( var) > self . ub ( var) {
285288 Some ( ( var, * self . ub ( var) ) )
286289 } else {
287290 None
288291 }
289292 } ) ;
290293 if let Some ( ( leaving, val) ) = var {
291294 // .. if we find one, we try to pivot it with a non-basic variable that can take it back within bounds
292- if self . value ( leaving) < & val {
293- let entering = self . tableau [ & leaving] . vars . iter ( ) . find_map ( |( & v, & coeff) | if coeff. is_positive ( ) && self . value ( v) < self . ub ( v) || coeff. is_negative ( ) && self . value ( v) > self . lb ( v) { Some ( v) } else { None } ) ;
295+ if self . val ( leaving) < & val {
296+ let entering = self . tableau [ & leaving] . vars . iter ( ) . find_map ( |( & v, & coeff) | if coeff. is_positive ( ) && self . val ( v) < self . ub ( v) || coeff. is_negative ( ) && self . val ( v) > self . lb ( v) { Some ( v) } else { None } ) ;
294297 if let Some ( entering) = entering {
295298 self . pivot_and_update ( entering, leaving, val) ;
296299 } else {
@@ -311,8 +314,8 @@ impl Engine {
311314 return false ;
312315 }
313316 }
314- if self . value ( leaving) > & val {
315- let entering = self . tableau [ & leaving] . vars . iter ( ) . find_map ( |( & v, & coeff) | if coeff. is_positive ( ) && self . value ( v) > self . lb ( v) || coeff. is_negative ( ) && self . value ( v) < self . ub ( v) { Some ( v) } else { None } ) ;
317+ if self . val ( leaving) > & val {
318+ let entering = self . tableau [ & leaving] . vars . iter ( ) . find_map ( |( & v, & coeff) | if coeff. is_positive ( ) && self . val ( v) > self . lb ( v) || coeff. is_negative ( ) && self . val ( v) < self . ub ( v) { Some ( v) } else { None } ) ;
316319 if let Some ( entering) = entering {
317320 self . pivot_and_update ( entering, leaving, val) ;
318321 } else {
@@ -343,7 +346,7 @@ impl Engine {
343346 assert ! ( self . is_basic( leaving) , "Leaving variable must be basic" ) ;
344347 assert ! ( !self . is_basic( entering) , "Entering variable must be non-basic" ) ;
345348
346- let theta = ( new_value - self . value ( leaving) ) / & self . tableau [ & leaving] . vars [ & entering] ;
349+ let theta = ( new_value - self . val ( leaving) ) / & self . tableau [ & leaving] . vars [ & entering] ;
347350 self . assignments [ leaving] = new_value;
348351 self . notify ( leaving) ;
349352 self . assignments [ entering] += theta;
@@ -454,7 +457,7 @@ impl Engine {
454457impl Display for Engine {
455458 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
456459 for i in 0 ..self . assignments . len ( ) {
457- writeln ! ( f, "x{} = {}, [{}, {}]" , i, self . value ( i) , self . lb( i) , self . ub( i) ) ?;
460+ writeln ! ( f, "x{} = {}, [{}, {}]" , i, self . val ( i) , self . lb( i) , self . ub( i) ) ?;
458461 }
459462 for ( var, lin) in & self . tableau {
460463 writeln ! ( f, "x{} = {}" , var, lin) ?;
@@ -476,7 +479,7 @@ mod tests {
476479 let y = e. add_var ( ) ;
477480 assert_eq ! ( x, 0 ) ;
478481 assert_eq ! ( y, 1 ) ;
479- assert_eq ! ( e. value ( x) , & InfRational :: ZERO ) ;
482+ assert_eq ! ( e. val ( x) , & InfRational :: ZERO ) ;
480483 assert_eq ! ( e. lb( x) , & InfRational :: NEGATIVE_INFINITY ) ;
481484 assert_eq ! ( e. ub( x) , & InfRational :: POSITIVE_INFINITY ) ;
482485 }
@@ -542,7 +545,7 @@ mod tests {
542545 let x = e. add_var ( ) ;
543546 assert ! ( e. new_eq( & v( x) , & c( 42 ) , None ) ) ;
544547 assert_eq ! ( e. lb( x) , e. ub( x) ) ;
545- assert_eq ! ( e. value ( x) , & i_rat( r( 42 ) ) ) ;
548+ assert_eq ! ( e. val ( x) , & i_rat( r( 42 ) ) ) ;
546549 }
547550
548551 #[ test]
@@ -623,7 +626,7 @@ mod tests {
623626
624627 engine. set_listener ( a, move |e, var| {
625628 assert_eq ! ( var, a) ;
626- assert_eq ! ( e. value ( var) , & i_rat( r( 5 ) ) ) ;
629+ assert_eq ! ( e. val ( var) , & i_rat( r( 5 ) ) ) ;
627630 * called_clone. lock ( ) . unwrap ( ) = true ;
628631 } ) ;
629632
@@ -725,6 +728,32 @@ mod tests {
725728 assert ! ( conflict. contains( & c2) ) ;
726729 }
727730
731+ #[ test]
732+ fn complex_conflict_explanation_generation ( ) {
733+ let mut e = Engine :: new ( ) ;
734+ let x = e. add_var ( ) ;
735+ let y = e. add_var ( ) ;
736+ let s1 = e. add_lin_var ( vc ( x, -1 ) + vc ( y, 1 ) ) ; // s1 = y - x
737+ let s2 = e. add_lin_var ( vc ( x, 1 ) + vc ( y, 1 ) ) ; // s2 = x + y
738+
739+ let c0 = e. add_constraint ( ) ;
740+ assert ! ( e. new_le( & v( x) , & c( -4 ) , Some ( c0) ) ) ; // x <= -4
741+ assert ! ( e. check( ) ) ;
742+ let c1 = e. add_constraint ( ) ;
743+ assert ! ( e. new_ge( & v( x) , & c( -8 ) , Some ( c1) ) ) ; // x >= -8
744+ assert ! ( e. check( ) ) ;
745+ let c2 = e. add_constraint ( ) ;
746+ assert ! ( e. new_le( & v( s1) , & c( 1 ) , Some ( c2) ) ) ; // s1 <= 1
747+ assert ! ( e. check( ) ) ;
748+ let c3 = e. add_constraint ( ) ;
749+ assert ! ( e. new_ge( & v( s2) , & c( -3 ) , Some ( c3) ) ) ; // s2 >= -3
750+ assert ! ( !e. check( ) ) ;
751+ let conflict = e. get_conflict_explanation ( ) . unwrap ( ) ;
752+ assert ! ( conflict. contains( & c0) ) ;
753+ assert ! ( conflict. contains( & c2) ) ;
754+ assert ! ( conflict. contains( & c3) ) ;
755+ }
756+
728757 #[ test]
729758 fn add_retract_readd ( ) {
730759 let mut e = Engine :: new ( ) ;
@@ -735,7 +764,7 @@ mod tests {
735764 assert ! ( e. check( ) ) ;
736765 assert ! ( e. lb( x) == & i_rat( r( 5 ) ) ) ;
737766 assert ! ( e. ub( x) == & InfRational :: POSITIVE_INFINITY ) ;
738- assert ! ( e. value ( x) >= & i_rat( r( 5 ) ) ) ;
767+ assert ! ( e. val ( x) >= & i_rat( r( 5 ) ) ) ;
739768
740769 // Retract constraint
741770 e. retract ( c0) ;
@@ -748,7 +777,7 @@ mod tests {
748777 assert ! ( e. check( ) ) ;
749778 assert ! ( e. lb( x) == & i_rat( r( 5 ) ) ) ;
750779 assert ! ( e. ub( x) == & InfRational :: POSITIVE_INFINITY ) ;
751- assert ! ( e. value ( x) >= & i_rat( r( 5 ) ) ) ;
780+ assert ! ( e. val ( x) >= & i_rat( r( 5 ) ) ) ;
752781 }
753782
754783 #[ test]
0 commit comments