@ -56,11 +56,14 @@ module Subst : sig
 
			
		
	
		
		
			
				
					
					  val  compose  :  t  ->  t  ->  t 
  val  compose  :  t  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					  val  compose1  :  key : Trm . t  ->  data : Trm . t  ->  t  ->  t 
  val  compose1  :  key : Trm . t  ->  data : Trm . t  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					  val  extend  :  Trm . t  ->  t  ->  t  option 
  val  extend  :  Trm . t  ->  t  ->  t  option 
 
			
		
	
		
		
			
				
					
					  val  remove  :  Var . Set . t  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					  val  map_entries  :  f : ( Trm . t  ->  Trm . t )  ->  t  ->  t 
  val  map_entries  :  f : ( Trm . t  ->  Trm . t )  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					  val  to_iter  :  t  ->  ( Trm . t  *  Trm . t )  iter 
  val  to_iter  :  t  ->  ( Trm . t  *  Trm . t )  iter 
 
			
		
	
		
		
			
				
					
					  val  fv  :  t  ->  Var . Set . t 
  val  fv  :  t  ->  Var . Set . t 
 
			
		
	
		
		
			
				
					
					  val  partition_valid  :  Var . Set . t  ->  t  ->  t  *  Var . Set . t  *  t 
  val  partition_valid  :  Var . Set . t  ->  t  ->  t  *  Var . Set . t  *  t 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  (*  direct representation manipulation  *) 
 
			
		
	
		
		
			
				
					
					  val  add  :  key : Trm . t  ->  data : Trm . t  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					  val  remove  :  Trm . t  ->  t  ->  t 
 
			
		
	
		
		
			
				
					
					end  =  struct end  =  struct  
			
		
	
		
		
			
				
					
					  type  t  =  Trm . t  Trm . Map . t  [ @@ deriving  compare ,  equal ,  sexp_of ] 
  type  t  =  Trm . t  Trm . Map . t  [ @@ deriving  compare ,  equal ,  sexp_of ] 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -139,10 +142,6 @@ end = struct
 
			
		
	
		
		
			
				
					
					    |  exception  Found  ->  None 
    |  exception  Found  ->  None 
 
			
		
	
		
		
			
				
					
					    |  s  ->  Some  s 
    |  s  ->  Some  s 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  (* *  remove entries for vars  *) 
 
			
		
	
		
		
			
				
					
					  let  remove  xs  s  = 
 
			
		
	
		
		
			
				
					
					    Var . Set . fold  ~ f : ( fun  x  ->  Trm . Map . remove  ( Trm . var  x ) )  xs  s 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  (* *  map over a subst, applying [f] to both domain and range, requires that 
  (* *  map over a subst, applying [f] to both domain and range, requires that 
 
			
		
	
		
		
			
				
					
					      [ f ]  is  injective  and  for  any  set  of  terms  [ E ] ,  [ f \ [ E \ ] ]  is  disjoint 
      [ f ]  is  injective  and  for  any  set  of  terms  [ E ] ,  [ f \ [ E \ ] ]  is  disjoint 
 
			
		
	
		
		
			
				
					
					      from  [ E ]  * ) 
      from  [ E ]  * ) 
 
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -200,6 +199,11 @@ end = struct
 
			
		
	
		
		
			
				
					
					      if  s'  !=  s  then  partition_valid_  t'  ks'  s'  else  ( t' ,  ks' ,  s' ) 
      if  s'  !=  s  then  partition_valid_  t'  ks'  s'  else  ( t' ,  ks' ,  s' ) 
 
			
		
	
		
		
			
				
					
					    in 
    in 
 
			
		
	
		
		
			
				
					
					    partition_valid_  empty  xs  s 
    partition_valid_  empty  xs  s 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  (*  direct representation manipulation  *) 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  let  add  =  Trm . Map . add 
 
			
		
	
		
		
			
				
					
					  let  remove  =  Trm . Map . remove 
 
			
		
	
		
		
			
				
					
					end end  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					(* *  Theory Solver  *) (* *  Theory Solver  *)  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -1175,7 +1179,96 @@ let solve_for_vars vss r =
 
			
		
	
		
		
			
				
					
					              else  ` Continue  us_xs  ) 
              else  ` Continue  us_xs  ) 
 
			
		
	
		
		
			
				
					
					            ~ finish : ( fun  _  ->  false )  )  ) ] 
            ~ finish : ( fun  _  ->  false )  )  ) ] 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					let  elim  xs  r  =  { r  with  rep =  Subst . remove  xs  r . rep } (*  [elim] removes variables from a context by rearranging the existing  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					   equality  classes .  Non - representative  terms  that  contain  a  variable  to 
 
			
		
	
		
		
			
				
					
					   eliminate  can  be  simply  dropped .  If  a  representative  needs  to  be  removed , 
 
			
		
	
		
		
			
				
					
					   a  new  representative  is  chosen .  This  basic  approach  is  insufficient  if 
 
			
		
	
		
		
			
				
					
					   interpreted  terms  are  to  be  removed .  For  example ,  eliminating  x  from  x  + 
 
			
		
	
		
		
			
				
					
					   1  =  y  =  z  ∧  w  =  x  by  just  preserving  the  existing  classes  between  terms 
 
			
		
	
		
		
			
				
					
					   that  do  not  mention  x  would  yield  y  =  z .  This  would  lose  provability  of 
 
			
		
	
		
		
			
				
					
					   the  equality  w  =  y  -  1 .  So  variables  with  interpreted  uses  are  not 
 
			
		
	
		
		
			
				
					
					   eliminated .  * ) 
 
			
		
	
		
		
			
				
					
					let  elim  xs  r  =  
			
		
	
		
		
			
				
					
					  [ % trace ] 
 
			
		
	
		
		
			
				
					
					    ~ call : ( fun  { pf }  ->  pf  " %a@ %a "  Var . Set . pp_xs  xs  pp_raw  r ) 
 
			
		
	
		
		
			
				
					
					    ~ retn : ( fun  { pf }  ( ks ,  r' )  -> 
 
			
		
	
		
		
			
				
					
					      pf  " %a@ %a "  Var . Set . pp_xs  ks  pp_raw  r'  ; 
 
			
		
	
		
		
			
				
					
					      assert  ( Var . Set . subset  ks  ~ of_ : xs )  ; 
 
			
		
	
		
		
			
				
					
					      assert  ( Var . Set . disjoint  ks  ( fv  r' ) )  ) 
 
			
		
	
		
		
			
				
					
					  @@  fun  ()  -> 
 
			
		
	
		
		
			
				
					
					  (*  add the uninterpreted uses of terms in delta to approx, and the 
 
			
		
	
		
		
			
				
					
					     interpreted  uses  to  interp  * ) 
 
			
		
	
		
		
			
				
					
					  let  rec  add_uninterp_uses  approx  interp  delta  = 
 
			
		
	
		
		
			
				
					
					    if  not  ( Trm . Set . is_empty  delta )  then 
 
			
		
	
		
		
			
				
					
					      let  approx  =  Trm . Set . union  approx  delta  in 
 
			
		
	
		
		
			
				
					
					      let  delta ,  interp  = 
 
			
		
	
		
		
			
				
					
					        Trm . Set . fold  delta 
 
			
		
	
		
		
			
				
					
					          ( Trm . Set . empty ,  Trm . Set . empty ) 
 
			
		
	
		
		
			
				
					
					          ~ f : 
 
			
		
	
		
		
			
				
					
					            ( fold_uses_of  r  ~ f : ( fun  use  ( delta ,  interp )  -> 
 
			
		
	
		
		
			
				
					
					                 if  is_interpreted  use  then  ( delta ,  Trm . Set . add  use  interp ) 
 
			
		
	
		
		
			
				
					
					                 else  ( Trm . Set . add  use  delta ,  interp )  ) ) 
 
			
		
	
		
		
			
				
					
					      in 
 
			
		
	
		
		
			
				
					
					      add_uninterp_uses  approx  interp  delta 
 
			
		
	
		
		
			
				
					
					    else 
 
			
		
	
		
		
			
				
					
					      (*  remove the subterms of interpreted uses from approx  *) 
 
			
		
	
		
		
			
				
					
					      let  rec  remove_subtrms  misses  approx  = 
 
			
		
	
		
		
			
				
					
					        if  not  ( Trm . Set . is_empty  misses )  then 
 
			
		
	
		
		
			
				
					
					          let  approx  =  Trm . Set . diff  approx  misses  in 
 
			
		
	
		
		
			
				
					
					          let  misses  = 
 
			
		
	
		
		
			
				
					
					            Trm . Set . of_iter 
 
			
		
	
		
		
			
				
					
					              ( Iter . flat_map  ~ f : Trm . trms  ( Trm . Set . to_iter  misses ) ) 
 
			
		
	
		
		
			
				
					
					          in 
 
			
		
	
		
		
			
				
					
					          remove_subtrms  misses  approx 
 
			
		
	
		
		
			
				
					
					        else  approx 
 
			
		
	
		
		
			
				
					
					      in 
 
			
		
	
		
		
			
				
					
					      remove_subtrms  interp  approx 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  (*  compute terms in relation mentioning vars to eliminate  *) 
 
			
		
	
		
		
			
				
					
					  let  kills  = 
 
			
		
	
		
		
			
				
					
					    add_uninterp_uses  Trm . Set . empty  Trm . Set . empty 
 
			
		
	
		
		
			
				
					
					      ( Trm . Set . of_iter  ( Iter . map  ~ f : Trm . var  ( Var . Set . to_iter  xs ) ) ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  let  ks  = 
 
			
		
	
		
		
			
				
					
					    Trm . Set . fold  kills  Var . Set . empty  ~ f : ( fun  kill  ks  -> 
 
			
		
	
		
		
			
				
					
					        match  Var . of_trm  kill  with  Some  k  ->  Var . Set . add  k  ks  |  None  ->  ks  ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  (*  compute classes including reps  *) 
 
			
		
	
		
		
			
				
					
					  let  reps  = 
 
			
		
	
		
		
			
				
					
					    Subst . fold  r . rep  Trm . Set . empty  ~ f : ( fun  ~ key : _  ~ data : rep  reps  -> 
 
			
		
	
		
		
			
				
					
					        Trm . Set . add  rep  reps  ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  let  clss  = 
 
			
		
	
		
		
			
				
					
					    Trm . Set . fold  reps  ( classes  r )  ~ f : ( fun  rep  clss  -> 
 
			
		
	
		
		
			
				
					
					        Trm . Map . add_multi  ~ key : rep  ~ data : rep  clss  ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  (*  trim classes to those that intersect kills  *) 
 
			
		
	
		
		
			
				
					
					  let  clss  = 
 
			
		
	
		
		
			
				
					
					    Trm . Map . filter_mapi  clss  ~ f : ( fun  ~ key : _  ~ data : cls  -> 
 
			
		
	
		
		
			
				
					
					        let  cls  =  Trm . Set . of_list  cls  in 
 
			
		
	
		
		
			
				
					
					        if  Trm . Set . disjoint  kills  cls  then  None  else  Some  cls  ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  (*  enumerate affected classes and update solution subst  *) 
 
			
		
	
		
		
			
				
					
					  let  rep  = 
 
			
		
	
		
		
			
				
					
					    Trm . Map . fold  clss  r . rep  ~ f : ( fun  ~ key : rep  ~ data : cls  s  -> 
 
			
		
	
		
		
			
				
					
					        (*  remove mappings for non-rep class elements to kill  *) 
 
			
		
	
		
		
			
				
					
					        let  drop  =  Trm . Set . inter  cls  kills  in 
 
			
		
	
		
		
			
				
					
					        let  s  =  Trm . Set . fold  ~ f : Subst . remove  drop  s  in 
 
			
		
	
		
		
			
				
					
					        if  not  ( Trm . Set . mem  rep  kills )  then  s 
 
			
		
	
		
		
			
				
					
					        else 
 
			
		
	
		
		
			
				
					
					          (*  if rep is to be removed, choose new one from the keepers  *) 
 
			
		
	
		
		
			
				
					
					          let  keep  =  Trm . Set . diff  cls  drop  in 
 
			
		
	
		
		
			
				
					
					          match 
 
			
		
	
		
		
			
				
					
					            Trm . Set . reduce  keep  ~ f : ( fun  x  y  -> 
 
			
		
	
		
		
			
				
					
					                if  prefer  x  y  <  0  then  x  else  y  ) 
 
			
		
	
		
		
			
				
					
					          with 
 
			
		
	
		
		
			
				
					
					          |  Some  rep'  -> 
 
			
		
	
		
		
			
				
					
					              (*  add mappings from each keeper to the new representative  *) 
 
			
		
	
		
		
			
				
					
					              Trm . Set . fold  keep  s  ~ f : ( fun  elt  s  -> 
 
			
		
	
		
		
			
				
					
					                  Subst . add  ~ key : elt  ~ data : rep'  s  ) 
 
			
		
	
		
		
			
				
					
					          |  None  ->  s  ) 
 
			
		
	
		
		
			
				
					
					  in 
 
			
		
	
		
		
			
				
					
					  ( ks ,  { r  with  rep } ) 
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					(* (*  
			
		
	
		
		
			
				
					
					 *  Replay  debugging 
 *  Replay  debugging