@@ -363,12 +363,80 @@ fn simplify_bv_or(ctx: &mut Context, a: ExprRef, b: ExprRef) -> Option<ExprRef>
363363 let and = ctx. and ( * a, * b) ;
364364 Some ( ctx. not ( and) )
365365 }
366+ // sum of products form
367+ ( Expr :: BVAnd ( a1, b1, _) , Expr :: BVAnd ( a2, b2, _) ) => {
368+ simplify_sum_of_products ( ctx, * a1, * b1, * a2, * b2)
369+ }
366370 _ => None ,
367371 }
368372 }
369373 }
370374}
371375
376+ // simplifies some sum of products expressions over exactly two products of t variables
377+ fn simplify_sum_of_products (
378+ ctx : & mut Context ,
379+ a1 : ExprRef ,
380+ b1 : ExprRef ,
381+ a2 : ExprRef ,
382+ b2 : ExprRef ,
383+ ) -> Option < ExprRef > {
384+ // recognize a / !a
385+ let mut lits_1 = [ Lit :: from_expr ( ctx, a1) , Lit :: from_expr ( ctx, b1) ] ;
386+ let mut lits_2 = [ Lit :: from_expr ( ctx, a2) , Lit :: from_expr ( ctx, b2) ] ;
387+ // sort by inner expression in order to normalize the order since AND is commutative
388+ lits_1. sort_by_key ( |l| l. get_var ( ) ) ;
389+ lits_2. sort_by_key ( |l| l. get_var ( ) ) ;
390+ // define a and b
391+ let a = lits_1[ 0 ] . get_var ( ) ;
392+ let b = lits_1[ 1 ] . get_var ( ) ;
393+ // check that the second product also is over the same a and b
394+ if a == lits_2[ 0 ] . get_var ( ) && b == lits_2[ 1 ] . get_var ( ) {
395+ let prod_1 = ( lits_1[ 0 ] . is_neg ( ) , lits_1[ 1 ] . is_neg ( ) ) ;
396+ let prod_2 = ( lits_2[ 0 ] . is_neg ( ) , lits_2[ 1 ] . is_neg ( ) ) ;
397+ // sort products
398+ let mut prods = [ prod_1, prod_2] ;
399+ prods. sort ( ) ;
400+
401+ match ( prods[ 0 ] , prods[ 1 ] ) {
402+ // !a & b | a & !b
403+ ( ( false , true ) , ( true , false ) ) => Some ( ctx. xor ( a, b) ) ,
404+ // !a & !b | a & b
405+ // TODO: this currently cannot be triggered, because !a & !b gets converted with demorgan first!
406+ ( ( false , false ) , ( true , true ) ) => Some ( ctx. equal ( a, b) ) ,
407+ _ => None ,
408+ }
409+ } else {
410+ None
411+ }
412+ }
413+
414+ #[ derive( Debug , Copy , Clone ) ]
415+ enum Lit {
416+ Pos ( ExprRef ) ,
417+ Neg ( ExprRef ) ,
418+ }
419+
420+ impl Lit {
421+ fn from_expr ( ctx : & Context , e : ExprRef ) -> Self {
422+ if let Expr :: BVNot ( a, _) = & ctx[ e] {
423+ Lit :: Neg ( * a)
424+ } else {
425+ Lit :: Pos ( e)
426+ }
427+ }
428+ fn get_var ( & self ) -> ExprRef {
429+ match self {
430+ Lit :: Pos ( e) => * e,
431+ Lit :: Neg ( e) => * e,
432+ }
433+ }
434+
435+ fn is_neg ( & self ) -> bool {
436+ matches ! ( self , Lit :: Neg ( _) )
437+ }
438+ }
439+
372440fn simplify_bv_xor ( ctx : & mut Context , a : ExprRef , b : ExprRef ) -> Option < ExprRef > {
373441 // a xor a -> 0
374442 if a == b {
0 commit comments