@ -20,8 +20,8 @@ module rec T : sig
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  type  t  = 
 
			
		
	
		
			
				
					    (*  nary: arithmetic, numeric and pointer  *) 
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset 
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset 
 
			
		
	
		
			
				
					    (*  pointer and memory constants and operations  *) 
 
			
		
	
		
			
				
					    |  Splat  of  { byt :  t ;  siz :  t } 
 
			
		
	
		
			
				
					    |  Memory  of  { siz :  t ;  arr :  t } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -62,7 +62,7 @@ module rec T : sig
 
			
		
	
		
			
				
					    |  Extract  of  { unsigned :  bool ;  bits :  int } 
 
			
		
	
		
			
				
					    |  Convert  of  { unsigned :  bool ;  dst :  Typ . t ;  src :  Typ . t } 
 
			
		
	
		
			
				
					    (*  numeric constants  *) 
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t 
 
			
		
	
		
			
				
					    |  Float  of  { data :  string } 
 
			
		
	
		
			
				
					  [ @@ deriving  compare ,  equal ,  hash ,  sexp ] 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -82,8 +82,8 @@ and T0 : sig
 
			
		
	
		
			
				
					  type  qset  =  Qset . M ( T ) . t  [ @@ deriving  compare ,  equal ,  hash ,  sexp ] 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  type  t  = 
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset 
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset 
 
			
		
	
		
			
				
					    |  Splat  of  { byt :  t ;  siz :  t } 
 
			
		
	
		
			
				
					    |  Memory  of  { siz :  t ;  arr :  t } 
 
			
		
	
		
			
				
					    |  Concat  of  { args :  t  vector } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -114,15 +114,15 @@ and T0 : sig
 
			
		
	
		
			
				
					    |  Struct_rec  of  { elts :  t  vector } 
 
			
		
	
		
			
				
					    |  Extract  of  { unsigned :  bool ;  bits :  int } 
 
			
		
	
		
			
				
					    |  Convert  of  { unsigned :  bool ;  dst :  Typ . t ;  src :  Typ . t } 
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t 
 
			
		
	
		
			
				
					    |  Float  of  { data :  string } 
 
			
		
	
		
			
				
					  [ @@ deriving  compare ,  equal ,  hash ,  sexp ] 
 
			
		
	
		
			
				
					end  =  struct  
			
		
	
		
			
				
					  type  qset  =  Qset . M ( T ) . t  [ @@ deriving  compare ,  equal ,  hash ,  sexp ] 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  type  t  = 
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Add  of  { args :  qset 
 
			
		
	
		
			
				
					    |  Mul  of  { args :  qset 
 
			
		
	
		
			
				
					    |  Splat  of  { byt :  t ;  siz :  t } 
 
			
		
	
		
			
				
					    |  Memory  of  { siz :  t ;  arr :  t } 
 
			
		
	
		
			
				
					    |  Concat  of  { args :  t  vector } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -153,7 +153,7 @@ end = struct
 
			
		
	
		
			
				
					    |  Struct_rec  of  { elts :  t  vector } 
 
			
		
	
		
			
				
					    |  Extract  of  { unsigned :  bool ;  bits :  int } 
 
			
		
	
		
			
				
					    |  Convert  of  { unsigned :  bool ;  dst :  Typ . t ;  src :  Typ . t } 
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t ; typ :  Typ . t  }
 
			
		
	
		
			
				
					    |  Integer  of  { data :  Z . t 
 
			
		
	
		
			
				
					    |  Float  of  { data :  string } 
 
			
		
	
		
			
				
					  [ @@ deriving  compare ,  equal ,  hash ,  sexp ] 
 
			
		
	
		
			
				
					end  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -207,7 +207,6 @@ let rec pp ?is_x fs term =
 
			
		
	
		
			
				
					        Trace . pp_styled  ( get_var_style  var )  " %%%s_%d "  fs  name  id 
 
			
		
	
		
			
				
					    |  Nondet  { msg }  ->  pf  " nondet  \" %s \" "  msg 
 
			
		
	
		
			
				
					    |  Label  { name }  ->  pf  " %s "  name 
 
			
		
	
		
			
				
					    |  Integer  { data ;  typ =  Pointer  _ }  when  Z . equal  Z . zero  data  ->  pf  " null " 
 
			
		
	
		
			
				
					    |  Splat  { byt ;  siz }  ->  pf  " %a^%a "  pp  byt  pp  siz 
 
			
		
	
		
			
				
					    |  Memory  { siz ;  arr }  ->  pf  " @<1>⟨%a,%a@<1>⟩ "  pp  siz  pp  arr 
 
			
		
	
		
			
				
					    |  Concat  { args }  ->  pf  " %a "  ( Vector . pp  " @,^ "  pp )  args 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -308,30 +307,6 @@ let pp = pp_t
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(* *  Invariant  *)  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  typ_of  =  function  
			
		
	
		
			
				
					  |  Add  { typ }  |  Mul  { typ }  |  Integer  { typ }  |  App  { op =  Convert  { dst =  typ } }  -> 
 
			
		
	
		
			
				
					      Some  typ 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  Eq  |  Dq  |  Gt  |  Ge  |  Lt  |  Le } }  ->  Some  Typ . bool 
 
			
		
	
		
			
				
					  |  App 
 
			
		
	
		
			
				
					      {  op =  App  { op =  Div  |  Rem  |  And  |  Or  |  Xor  |  Shl  |  Lshr  |  Ashr ;  arg =  x } 
 
			
		
	
		
			
				
					      ;  arg =  y  }  ->  ( 
 
			
		
	
		
			
				
					    match  typ_of  x  with  Some  _  as  t  ->  t  |  None  ->  typ_of  y  ) 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  App  { op =  Conditional } ;  arg =  thn } ;  arg =  els }  ->  ( 
 
			
		
	
		
			
				
					    match  typ_of  thn  with  Some  _  as  t  ->  t  |  None  ->  typ_of  els  ) 
 
			
		
	
		
			
				
					  |  _  ->  None 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  typ  =  typ_of  
			
		
	
		
			
				
					let  is_boolean  e  =  Option . exists  ~ f : ( Typ . equal  Typ . bool )  ( typ_of  e )  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  type_check  e  typ  =  
			
		
	
		
			
				
					  assert  ( 
 
			
		
	
		
			
				
					    Option . for_all  ~ f : ( Typ . castable  typ )  ( typ_of  e ) 
 
			
		
	
		
			
				
					    | |  fail  " %a@ : %a not <:@ %a "  pp  e  Typ . pp 
 
			
		
	
		
			
				
					         ( Option . value_exn  ( typ_of  e ) ) 
 
			
		
	
		
			
				
					         Typ . pp  typ  ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  type_check2  e  f  typ  =  type_check  e  typ  ;  type_check  f  typ  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(*  an indeterminate  ( factor of a monomial )  is any non-Add/Mul/Integer term  *)  
			
		
	
		
			
				
					let  rec  assert_indeterminate  =  function  
			
		
	
		
			
				
					  |  App  { op }  ->  assert_indeterminate  op 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -342,11 +317,9 @@ let rec assert_indeterminate = function
 
			
		
	
		
			
				
					 *      ∏ ᵢ  x ᵢ ^ n ᵢ 
 
			
		
	
		
			
				
					 *  for  ( non - constant )  indeterminants  x ᵢ  and  positive  integer  exponents  n ᵢ 
 
			
		
	
		
			
				
					 * ) 
 
			
		
	
		
			
				
					let  assert_monomial  add_typ  mono =  
			
		
	
		
			
				
					let  assert_monomial  =  
			
		
	
		
			
				
					  match  mono  with 
 
			
		
	
		
			
				
					  |  Mul  { typ ;  args }  -> 
 
			
		
	
		
			
				
					      assert  ( Typ . castable  add_typ  typ )  ; 
 
			
		
	
		
			
				
					      assert  ( Option . is_some  ( Typ . prim_bit_size_of  typ ) )  ; 
 
			
		
	
		
			
				
					  |  Mul  { args }  -> 
 
			
		
	
		
			
				
					      Qset . iter  args  ~ f : ( fun  factor  exponent  -> 
 
			
		
	
		
			
				
					          assert  ( Q . sign  exponent  >  0 )  ; 
 
			
		
	
		
			
				
					          assert_indeterminate  factor  | >  Fn . id  ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -355,7 +328,7 @@ let assert_monomial add_typ mono =
 
			
		
	
		
			
				
					(*  a polynomial term is a monomial multiplied by a non-zero coefficient  
			
		
	
		
			
				
					 *      c  × ∏ ᵢ  x ᵢ 
 
			
		
	
		
			
				
					 * ) 
 
			
		
	
		
			
				
					let  assert_poly_term  add_typ  mono coeff  =  
			
		
	
		
			
				
					let  assert_poly_term  coeff  =  
			
		
	
		
			
				
					  assert  ( not  ( Q . equal  Q . zero  coeff ) )  ; 
 
			
		
	
		
			
				
					  match  mono  with 
 
			
		
	
		
			
				
					  |  Integer  { data }  ->  assert  ( Z . equal  Z . one  data ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -364,8 +337,8 @@ let assert_poly_term add_typ mono coeff =
 
			
		
	
		
			
				
					      |  None  |  Some  ( Integer  _ ,  _ )  ->  assert  false 
 
			
		
	
		
			
				
					      |  Some  ( _ ,  n )  ->  assert  ( Qset . length  args  >  1  | |  not  ( Q . equal  Q . one  n ) ) 
 
			
		
	
		
			
				
					      )  ; 
 
			
		
	
		
			
				
					      assert_monomial  add_typ  mono | >  Fn . id 
 
			
		
	
		
			
				
					  |  _  ->  assert_monomial  add_typ  mono | >  Fn . id 
 
			
		
	
		
			
				
					      assert_monomial  | >  Fn . id 
 
			
		
	
		
			
				
					  |  _  ->  assert_monomial  | >  Fn . id 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(*  a polynomial is a linear combination of monomials, e.g.  
			
		
	
		
			
				
					 *      ∑ ᵢ  c ᵢ  × ∏ ⱼ  x ᵢ ⱼ 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -374,13 +347,12 @@ let assert_poly_term add_typ mono coeff =
 
			
		
	
		
			
				
					 * ) 
 
			
		
	
		
			
				
					let  assert_polynomial  poly  =  
			
		
	
		
			
				
					  match  poly  with 
 
			
		
	
		
			
				
					  |  Add  { typ;   args}  -> 
 
			
		
	
		
			
				
					  |  Add  { }  -> 
 
			
		
	
		
			
				
					      (  match  Qset . min_elt  args  with 
 
			
		
	
		
			
				
					      |  None  ->  assert  false 
 
			
		
	
		
			
				
					      |  Some  ( Integer  _ ,  _ )  ->  assert  false 
 
			
		
	
		
			
				
					      |  None  |  Some  ( Integer  _ ,  _ )  ->  assert  false 
 
			
		
	
		
			
				
					      |  Some  ( _ ,  k )  ->  assert  ( Qset . length  args  >  1  | |  not  ( Q . equal  Q . one  k ) ) 
 
			
		
	
		
			
				
					      )  ; 
 
			
		
	
		
			
				
					      Qset . iter  args  ~ f : ( fun  m  c  ->  assert_poly_term  typ  m c  | >  Fn . id ) 
 
			
		
	
		
			
				
					      Qset . iter  args  ~ f : ( fun  m  c  ->  assert_poly_term  c  | >  Fn . id ) 
 
			
		
	
		
			
				
					  |  _  ->  assert  false 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  invariant  ? ( partial  =  false )  e  =  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -393,41 +365,23 @@ let invariant ?(partial = false) e =
 
			
		
	
		
			
				
					  in 
 
			
		
	
		
			
				
					  match  op  with 
 
			
		
	
		
			
				
					  |  App  _  ->  fail  " uncurry cannot return App "  () 
 
			
		
	
		
			
				
					  |  Integer  { data ;  typ =  ( Integer  _  |  Pointer  _ )  as  typ }  ->  ( 
 
			
		
	
		
			
				
					    match  Typ . prim_bit_size_of  typ  with 
 
			
		
	
		
			
				
					    |  None  ->  assert  false 
 
			
		
	
		
			
				
					    |  Some  bits  -> 
 
			
		
	
		
			
				
					        assert_arity  0  ; 
 
			
		
	
		
			
				
					        assert  ( Z . numbits  data  < =  bits )  ) 
 
			
		
	
		
			
				
					  |  Integer  _  ->  assert  false 
 
			
		
	
		
			
				
					  |  Integer  _  ->  assert_arity  0 
 
			
		
	
		
			
				
					  |  Var  _  |  Nondet  _  |  Label  _  |  Float  _  ->  assert_arity  0 
 
			
		
	
		
			
				
					  |  Extract  _  ->  assert_arity  1 
 
			
		
	
		
			
				
					  |  Convert  { dst ;  src }  -> 
 
			
		
	
		
			
				
					      (  match  args  with 
 
			
		
	
		
			
				
					      |  [ Integer  { typ =  Integer  _  as  typ } ]  ->  assert  ( Typ . equal  src  typ ) 
 
			
		
	
		
			
				
					      |  [ arg ]  -> 
 
			
		
	
		
			
				
					          assert  ( Option . for_all  ~ f : ( Typ . convertible  src )  ( typ_of  arg ) ) 
 
			
		
	
		
			
				
					      |  _  ->  assert_arity  1  )  ; 
 
			
		
	
		
			
				
					      assert_arity  1  ; 
 
			
		
	
		
			
				
					      assert  ( Typ . convertible  src  dst ) 
 
			
		
	
		
			
				
					  |  Add  _  ->  assert_polynomial  e  | >  Fn . id 
 
			
		
	
		
			
				
					  |  Mul  {typ }  ->  assert_monomial  typ   e  | >  Fn . id 
 
			
		
	
		
			
				
					  |  Mul  _  ->  assert_monomial  e  | >  Fn . id 
 
			
		
	
		
			
				
					  |  Eq  |  Dq  |  Gt  |  Ge  |  Lt  |  Le  |  Div  |  Rem  |  And  |  Or  |  Xor  |  Shl  |  Lshr 
 
			
		
	
		
			
				
					   | Ashr  ->  ( 
 
			
		
	
		
			
				
					    match  args  with 
 
			
		
	
		
			
				
					    |  [ x ;  y ]  ->  ( 
 
			
		
	
		
			
				
					      match  ( typ_of  x ,  typ_of  y )  with 
 
			
		
	
		
			
				
					      |  Some  typ ,  Some  typ'  ->  assert  ( Typ . castable  typ  typ' ) 
 
			
		
	
		
			
				
					      |  _  ->  assert  true  ) 
 
			
		
	
		
			
				
					    |  _  ->  assert_arity  2  ) 
 
			
		
	
		
			
				
					   | Ashr  -> 
 
			
		
	
		
			
				
					      assert_arity  2 
 
			
		
	
		
			
				
					  |  Concat  { args }  ->  assert  ( Vector . length  args  < >  1 ) 
 
			
		
	
		
			
				
					  |  Splat  { byt ;  siz }  ->  ( 
 
			
		
	
		
			
				
					      assert  ( Option . exists  ~ f : ( Typ . convertible  Typ . byt )  ( typ_of  byt ) )  ; 
 
			
		
	
		
			
				
					      assert  ( Option . exists  ~ f : ( Typ . convertible  Typ . siz )  ( typ_of  siz ) )  ; 
 
			
		
	
		
			
				
					  |  Splat  { siz }  ->  ( 
 
			
		
	
		
			
				
					    match  siz  with 
 
			
		
	
		
			
				
					    |  Integer  { data }  ->  assert  ( not  ( Z . equal  Z . zero  data ) ) 
 
			
		
	
		
			
				
					    |  _  ->  ()  ) 
 
			
		
	
		
			
				
					  |  Memory  { siz }  -> 
 
			
		
	
		
			
				
					      assert  ( Option . for_all  ~ f : ( Typ . convertible  Typ . siz )  ( typ_of  siz ) ) 
 
			
		
	
		
			
				
					  |  Memory  _  ->  assert  true 
 
			
		
	
		
			
				
					  |  Ord  |  Uno  |  Select  ->  assert_arity  2 
 
			
		
	
		
			
				
					  |  Conditional  |  Update  ->  assert_arity  3 
 
			
		
	
		
			
				
					  |  Record  ->  assert  ( partial  | |  not  ( List . is_empty  args ) ) 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -581,24 +535,19 @@ let fv e = fold_vars e ~f:Set.add ~init:Var.Set.empty
 
			
		
	
		
			
				
					let  var  x  =  x  
			
		
	
		
			
				
					let  nondet  msg  =  Nondet  { msg }  | >  check  invariant  
			
		
	
		
			
				
					let  label  ~ parent  ~ name  =  Label  { parent ;  name }  | >  check  invariant  
			
		
	
		
			
				
					let  integer  data  typ  =  Integer  { data ;  typ }  | >  check  invariant  
			
		
	
		
			
				
					let  null  =  integer  Z . zero  Typ . ptr  
			
		
	
		
			
				
					let  bool  b  =  integer  ( Z . of_bool  b )  Typ . bool  
			
		
	
		
			
				
					let  integer  data  =  Integer  { data }  | >  check  invariant  
			
		
	
		
			
				
					let  null  =  integer  Z . zero  
			
		
	
		
			
				
					let  zero  =  integer  Z . zero  
			
		
	
		
			
				
					let  one  =  integer  Z . one  
			
		
	
		
			
				
					let  minus_one  =  integer  Z . minus_one  
			
		
	
		
			
				
					let  bool  b  =  integer  ( Z . of_bool  b )  
			
		
	
		
			
				
					let  true _  =  bool  true  
			
		
	
		
			
				
					let  false _  =  bool  false  
			
		
	
		
			
				
					let  float  data  =  Float  { data }  | >  check  invariant  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  zero  ( typ  :  Typ . t )  =  
			
		
	
		
			
				
					  match  typ  with  Float  _  ->  float  " 0 "  |  _  ->  integer  Z . zero  typ 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  one  ( typ  :  Typ . t )  =  
			
		
	
		
			
				
					  match  typ  with  Float  _  ->  float  " 1 "  |  _  ->  integer  Z . one  typ 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  minus_one  ( typ  :  Typ . t )  =  
			
		
	
		
			
				
					  match  typ  with  Float  _  ->  float  " -1 "  |  _  ->  integer  Z . minus_one  typ 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_extract  ~ unsigned  bits  arg  =  
			
		
	
		
			
				
					  match  arg  with 
 
			
		
	
		
			
				
					  |  Integer  { data }  -> 
 
			
		
	
		
			
				
					      integer  ( Z . extract  ~ unsigned  bits  data )  ( Typ . integer  ~ bits ) 
 
			
		
	
		
			
				
					  |  Integer  { data }  ->  integer  ( Z . extract  ~ unsigned  bits  data ) 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  Extract  { unsigned ;  bits } ;  arg } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_convert  ~ unsigned  dst  src  arg  =  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -606,7 +555,7 @@ let simp_convert ~unsigned dst src arg =
 
			
		
	
		
			
				
					  else 
 
			
		
	
		
			
				
					    match  ( dst ,  src ,  arg )  with 
 
			
		
	
		
			
				
					    |  Integer  { bits =  m } ,  Integer  { bits =  n } ,  Integer  { data }  -> 
 
			
		
	
		
			
				
					        integer  ( Z . extract  ~ unsigned  ( min  m  n )  data )  dst  
 
			
		
	
		
			
				
					        integer  ( Z . extract  ~ unsigned  ( min  m  n )  data ) 
 
			
		
	
		
			
				
					    |  _  ->  App  { op =  Convert  { unsigned ;  dst ;  src } ;  arg } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_gt  x  y  =  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -637,37 +586,37 @@ let sum_mul_const const sum =
 
			
		
	
		
			
				
					  if  Q . equal  Q . one  const  then  sum 
 
			
		
	
		
			
				
					  else  Qset . map_counts  ~ f : ( fun  _  ->  Q . mul  const )  sum 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  sum_to_term  typ  sum =  
			
		
	
		
			
				
					let  rec  sum_to_term  =  
			
		
	
		
			
				
					  match  Qset . length  sum  with 
 
			
		
	
		
			
				
					  |  0  ->  zero  typ  
 
			
		
	
		
			
				
					  |  0  ->  zero 
 
			
		
	
		
			
				
					  |  1  ->  ( 
 
			
		
	
		
			
				
					    match  Qset . min_elt  sum  with 
 
			
		
	
		
			
				
					    |  Some  ( Integer  _ ,  q )  ->  rational  q  typ  
 
			
		
	
		
			
				
					    |  Some  ( Integer  _ ,  q )  ->  rational  q 
 
			
		
	
		
			
				
					    |  Some  ( arg ,  q )  when  Q . equal  Q . one  q  ->  arg 
 
			
		
	
		
			
				
					    |  _  ->  Add  { typ;   args=  sum }  ) 
 
			
		
	
		
			
				
					  |  _  ->  Add  { typ;   args=  sum } 
 
			
		
	
		
			
				
					    |  _  ->  Add  { =  sum }  ) 
 
			
		
	
		
			
				
					  |  _  ->  Add  { =  sum } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					and  rational  Q . { num ;  den }  typ  =  simp_div  ( integer  num  typ  )  ( integer  den  typ  )  
			
		
	
		
			
				
					and  rational  Q . { num ;  den }  =  simp_div  ( integer  num )  ( integer  den )  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					and  simp_div  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i / j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  when  not  ( Z . equal  Z . zero  j )  -> 
 
			
		
	
		
			
				
					      integer  ( Z . div  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  when  not  ( Z . equal  Z . zero  j )  -> 
 
			
		
	
		
			
				
					      integer  ( Z . div  i  j ) 
 
			
		
	
		
			
				
					  (*  e / 1 ==> e  *) 
 
			
		
	
		
			
				
					  |  e ,  Integer  { data }  when  Z . equal  Z . one  data  ->  e 
 
			
		
	
		
			
				
					  (*   ( ∑ᵢ cᵢ ×  )  / z ==> ∑ᵢ cᵢ/z ×  *) 
 
			
		
	
		
			
				
					  |  Add  { typ;   args} ,  Integer  { data }  -> 
 
			
		
	
		
			
				
					      sum_to_term  typ  ( sum_mul_const  Q . ( inv  ( of_z  data ) )  args ) 
 
			
		
	
		
			
				
					  |  Add  { } ,  Integer  { data }  -> 
 
			
		
	
		
			
				
					      sum_to_term  ( sum_mul_const  Q . ( inv  ( of_z  data ) )  args ) 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Div ;  arg =  x } ;  arg =  y } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_rem  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i % j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  when  not  ( Z . equal  Z . zero  j )  -> 
 
			
		
	
		
			
				
					      integer  ( Z . rem  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  when  not  ( Z . equal  Z . zero  j )  -> 
 
			
		
	
		
			
				
					      integer  ( Z . rem  i  j ) 
 
			
		
	
		
			
				
					  (*  e % 1 ==> 0  *) 
 
			
		
	
		
			
				
					  |  _ ,  Integer  { data ; typ  } when  Z . equal  Z . one  data  ->  integer Z .  zero typ  
 
			
		
	
		
			
				
					  |  _ ,  Integer  { data when  Z . equal  Z . one  data  ->  
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Rem ;  arg =  x } ;  arg =  y } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(*  Sums of polynomial terms represented by multisets. A sum ∑ᵢ cᵢ ×   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -681,8 +630,7 @@ module Sum = struct
 
			
		
	
		
			
				
					    assert  ( not  ( Q . equal  Q . zero  coeff ) )  ; 
 
			
		
	
		
			
				
					    match  term  with 
 
			
		
	
		
			
				
					    |  Integer  { data }  when  Z . equal  Z . zero  data  ->  sum 
 
			
		
	
		
			
				
					    |  Integer  { data ;  typ }  -> 
 
			
		
	
		
			
				
					        Qset . add  sum  ( integer  Z . one  typ )  Q . ( coeff  *  of_z  data ) 
 
			
		
	
		
			
				
					    |  Integer  { data }  ->  Qset . add  sum  one  Q . ( coeff  *  of_z  data ) 
 
			
		
	
		
			
				
					    |  _  ->  Qset . add  sum  term  coeff 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  let  singleton  ? ( coeff  =  Q . one )  term  =  add  coeff  term  empty 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -694,7 +642,7 @@ module Sum = struct
 
			
		
	
		
			
				
					  let  to_term  =  sum_to_term 
 
			
		
	
		
			
				
					end  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  simp_add_  typ  es poly  =  
			
		
	
		
			
				
					let  rec  simp_add_  poly  =  
			
		
	
		
			
				
					  (*   ( coeff ×  )  + poly  *) 
 
			
		
	
		
			
				
					  let  f  term  coeff  poly  = 
 
			
		
	
		
			
				
					    match  ( term ,  poly )  with 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -704,18 +652,18 @@ let rec simp_add_ typ es poly =
 
			
		
	
		
			
				
					    |  Integer  { data } ,  _  when  Z . equal  Z . zero  data  ->  poly 
 
			
		
	
		
			
				
					    (*   ( c ×  )  + cⱼ ==> c×  *) 
 
			
		
	
		
			
				
					    |  Integer  { data =  i } ,  Integer  { data =  j }  -> 
 
			
		
	
		
			
				
					        rational  Q . ( ( coeff  *  of_z  i )  +  of_z  j )  typ  
 
			
		
	
		
			
				
					        rational  Q . ( ( coeff  *  of_z  i )  +  of_z  j ) 
 
			
		
	
		
			
				
					    (*   ( c × ×  )  + s ==>  ( ∑ᵢ  ( c ×  )  ×  )  + s  *) 
 
			
		
	
		
			
				
					    |  Add  { args } ,  _  ->  simp_add_  typ  ( Sum . mul_const  coeff  args )  poly 
 
			
		
	
		
			
				
					    |  Add  { args } ,  _  ->  simp_add_  ( Sum . mul_const  coeff  args )  poly 
 
			
		
	
		
			
				
					    (*   ( c₀ ×  )  +  ( ∑ᵢ₌₁ⁿ cᵢ ×  )  ==> ∑ᵢ₌₀ⁿ cᵢ ×  *) 
 
			
		
	
		
			
				
					    |  _ ,  Add  { args }  ->  Sum . to_term  typ  ( Sum . add  coeff  term  args ) 
 
			
		
	
		
			
				
					    |  _ ,  Add  { args }  ->  Sum . to_term  ( Sum . add  coeff  term  args ) 
 
			
		
	
		
			
				
					    (*   ( c₁ ×  )  + X₂ ==> ∑ᵢ₌₁² cᵢ ×  *) 
 
			
		
	
		
			
				
					    |  _  ->  Sum . to_term  typ  ( Sum . add  coeff  term  ( Sum . singleton  poly ) ) 
 
			
		
	
		
			
				
					    |  _  ->  Sum . to_term  ( Sum . add  coeff  term  ( Sum . singleton  poly ) ) 
 
			
		
	
		
			
				
					  in 
 
			
		
	
		
			
				
					  Qset . fold  ~ f  es  ~ init : poly 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_add  typ  es =  simp_add_  typ   es  ( zero  typ )   
			
		
	
		
			
				
					let  simp_add2  typ  e f  =  simp_add_  typ   ( Sum . singleton  e )  f  
			
		
	
		
			
				
					let  simp_add  =  simp_add_  es  zero  
			
		
	
		
			
				
					let  simp_add2  f  =  simp_add_  ( Sum . singleton  e )  f  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(*  Products of indeterminants represented by multisets. A product ∏ᵢ xᵢ^nᵢ  
			
		
	
		
			
				
					   of  indeterminates  x ᵢ  is  represented  by  a  multiset  where  the  elements  are 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -731,58 +679,56 @@ module Prod = struct
 
			
		
	
		
			
				
					  let  union  =  Qset . union 
 
			
		
	
		
			
				
					end  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  simp_mul2  typ  e f  =  
			
		
	
		
			
				
					let  rec  simp_mul2  f  =  
			
		
	
		
			
				
					  match  ( e ,  f )  with 
 
			
		
	
		
			
				
					  (*  c₁ × ×  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i } ,  Integer  { data =  j }  ->  integer  ( Z . mul  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i } ,  Integer  { data =  j }  ->  integer  ( Z . mul  i  j ) 
 
			
		
	
		
			
				
					  (*  0 ×  *) 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  _  when  Z . equal  Z . zero  data  ->  e 
 
			
		
	
		
			
				
					  (*  e ×  *) 
 
			
		
	
		
			
				
					  |  _ ,  Integer  { data }  when  Z . equal  Z . zero  data  ->  f 
 
			
		
	
		
			
				
					  (*  c ×  ( ∑ᵤ cᵤ ×  )  ==> ∑ᵤ c × ×  *) 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  Add  { args }  |  Add  { args } ,  Integer  { data }  -> 
 
			
		
	
		
			
				
					      Sum . to_term  typ  ( Sum . mul_const  ( Q . of_z  data )  args ) 
 
			
		
	
		
			
				
					      Sum . to_term  ( Sum . mul_const  ( Q . of_z  data )  args ) 
 
			
		
	
		
			
				
					  (*  c₁ × ×  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  c } ,  x  |  x ,  Integer  { data =  c }  -> 
 
			
		
	
		
			
				
					      Sum . to_term  typ  ( Sum . singleton  ~ coeff : ( Q . of_z  c )  x ) 
 
			
		
	
		
			
				
					      Sum . to_term  ( Sum . singleton  ~ coeff : ( Q . of_z  c )  x ) 
 
			
		
	
		
			
				
					  (*   ( ∏ᵤ₌₀ⁱ xᵤ )  ×  ( ∏ᵥ₌ᵢ₊₁ⁿ xᵥ )  ==> ∏ⱼ₌₀ⁿ xⱼ  *) 
 
			
		
	
		
			
				
					  |  Mul  { args =  xs1 } ,  Mul  { args =  xs2 }  ->  Mul  { typ;   args=  Prod . union  xs1  xs2 } 
 
			
		
	
		
			
				
					  |  Mul  { args =  xs1 } ,  Mul  { args =  xs2 }  ->  Mul  { =  Prod . union  xs1  xs2 } 
 
			
		
	
		
			
				
					  (*   ( ∏ᵢ xᵢ )  ×  ( ∑ᵤ cᵤ ×  )  ==> ∑ᵤ cᵤ × ×  *) 
 
			
		
	
		
			
				
					  |  ( Mul  { args =  prod }  as  m ) ,  Add  { args =  sum } 
 
			
		
	
		
			
				
					   | Add  { args =  sum } ,  ( Mul  { args =  prod }  as  m )  -> 
 
			
		
	
		
			
				
					      Sum . to_term  typ  
 
			
		
	
		
			
				
					      Sum . to_term 
 
			
		
	
		
			
				
					        ( Sum . map  sum  ~ f : ( function 
 
			
		
	
		
			
				
					          |  Mul  { args }  ->  Mul  { typ;   args=  Prod . union  prod  args } 
 
			
		
	
		
			
				
					          |  Integer  _  as  c  ->  simp_mul2  typ  c m 
 
			
		
	
		
			
				
					          |  mono  ->  Mul  { typ;   args=  Prod . add  mono  prod }  ) ) 
 
			
		
	
		
			
				
					          |  Mul  { args }  ->  Mul  { =  Prod . union  prod  args } 
 
			
		
	
		
			
				
					          |  Integer  _  as  c  ->  simp_mul2  m 
 
			
		
	
		
			
				
					          |  mono  ->  Mul  { =  Prod . add  mono  prod }  ) ) 
 
			
		
	
		
			
				
					  (*  x₀ ×  ( ∏ᵢ₌₁ⁿ xᵢ )  ==> ∏ᵢ₌₀ⁿ xᵢ  *) 
 
			
		
	
		
			
				
					  |  Mul  { args =  xs1 } ,  x  |  x ,  Mul  { args =  xs1 }  -> 
 
			
		
	
		
			
				
					      Mul  { typ ;  args =  Prod . add  x  xs1 } 
 
			
		
	
		
			
				
					  |  Mul  { args =  xs1 } ,  x  |  x ,  Mul  { args =  xs1 }  ->  Mul  { args =  Prod . add  x  xs1 } 
 
			
		
	
		
			
				
					  (*  e ×  ( ∑ᵤ cᵤ ×  )  ==> ∑ᵤ e × ×  *) 
 
			
		
	
		
			
				
					  |  Add  { args } ,  e  |  e ,  Add  { args }  -> 
 
			
		
	
		
			
				
					      simp_add  typ  ( Sum . map  ~ f : ( fun  m  ->  simp_mul2  typ   e  m )  args ) 
 
			
		
	
		
			
				
					      simp_add  ( Sum . map  ~ f : ( fun  m  ->  simp_mul2  e  m )  args ) 
 
			
		
	
		
			
				
					  (*  x₁ ×  *) 
 
			
		
	
		
			
				
					  |  _  ->  Mul  { args =  Prod . add  e  ( Prod . singleton  f ) ; typ  }
 
			
		
	
		
			
				
					  |  _  ->  Mul  { args =  Prod . add  e  ( Prod . singleton  f ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_mul  typ  es =  
			
		
	
		
			
				
					let  simp_mul  =  
			
		
	
		
			
				
					  (*   ( bas ^ pwr )  ×  *) 
 
			
		
	
		
			
				
					  let  rec  mul_pwr  bas  pwr  term  = 
 
			
		
	
		
			
				
					    if  Q . equal  Q . zero  pwr  then  term 
 
			
		
	
		
			
				
					    else  mul_pwr  bas  Q . ( pwr  -  one )  ( simp_mul2  typ  bas term ) 
 
			
		
	
		
			
				
					    else  mul_pwr  bas  Q . ( pwr  -  one )  ( simp_mul2  term ) 
 
			
		
	
		
			
				
					  in 
 
			
		
	
		
			
				
					  let  one  =  one  typ  in 
 
			
		
	
		
			
				
					  Qset . fold  es  ~ init : one  ~ f : ( fun  bas  pwr  term  -> 
 
			
		
	
		
			
				
					      if  Q . sign  pwr  > =  0  then  mul_pwr  bas  pwr  term 
 
			
		
	
		
			
				
					      else  simp_div  term  ( mul_pwr  bas  ( Q . neg  pwr )  one )  ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_negate  typ  x =  simp_mul2  typ (  minus_one typ )   x  
			
		
	
		
			
				
					let  simp_negate  =  simp_mul2  x  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_sub  typ  x y  =  
			
		
	
		
			
				
					let  simp_sub  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i - j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i } ,  Integer  { data =  j }  ->  integer  ( Z . sub  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i } ,  Integer  { data =  j }  ->  integer  ( Z . sub  i  j ) 
 
			
		
	
		
			
				
					  (*  x - y ==> x +  ( -1  *  y )   *) 
 
			
		
	
		
			
				
					  |  _  ->  simp_add2  typ  x ( simp_negate  typ   y ) 
 
			
		
	
		
			
				
					  |  _  ->  simp_add2  ( simp_negate  y ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_cond  cnd  thn  els  =  
			
		
	
		
			
				
					  match  cnd  with 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -796,7 +742,7 @@ let simp_cond cnd thn els =
 
			
		
	
		
			
				
					let  rec  simp_and  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i && j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  ->  integer  ( Z . logand  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  ->  integer  ( Z . logand  i  j ) 
 
			
		
	
		
			
				
					  (*  e && true ==> e  *) 
 
			
		
	
		
			
				
					  |  ( Integer  { data } ,  e  |  e ,  Integer  { data } )  when  Z . is_true  data  ->  e 
 
			
		
	
		
			
				
					  (*  e && false ==> 0  *) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -814,7 +760,7 @@ let rec simp_and x y =
 
			
		
	
		
			
				
					let  rec  simp_or  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i || j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  ->  integer  ( Z . logor  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  ->  integer  ( Z . logor  i  j ) 
 
			
		
	
		
			
				
					  (*  e || true ==> true  *) 
 
			
		
	
		
			
				
					  |  ( ( Integer  { data }  as  t ) ,  _  |  _ ,  ( Integer  { data }  as  t ) ) 
 
			
		
	
		
			
				
					    when  Z . is_true  data  -> 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -829,7 +775,18 @@ let rec simp_or x y =
 
			
		
	
		
			
				
					  |  _  when  equal  x  y  ->  x 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Or ;  arg =  x } ;  arg =  y } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  simp_not  ( typ  :  Typ . t )  term  =  
			
		
	
		
			
				
					let  rec  is_boolean  =  function  
			
		
	
		
			
				
					  |  App  { op =  App  { op =  Eq  |  Dq  |  Gt  |  Ge  |  Lt  |  Le } } 
 
			
		
	
		
			
				
					   | App  { op =  Convert  { dst =  Integer  { bits =  1 } } }  -> 
 
			
		
	
		
			
				
					      true 
 
			
		
	
		
			
				
					  |  App 
 
			
		
	
		
			
				
					      {  op =  App  { op =  Div  |  Rem  |  And  |  Or  |  Xor  |  Shl  |  Lshr  |  Ashr ;  arg =  x } 
 
			
		
	
		
			
				
					      ;  arg =  y  } 
 
			
		
	
		
			
				
					   | App  { op =  App  { op =  App  { op =  Conditional } ;  arg =  x } ;  arg =  y }  -> 
 
			
		
	
		
			
				
					      is_boolean  x  | |  is_boolean  y 
 
			
		
	
		
			
				
					  |  _  ->  false 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  simp_not  term  =  
			
		
	
		
			
				
					  match  term  with 
 
			
		
	
		
			
				
					  (*  ¬ ( x = y )  ==> x ≠ y  *) 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  Eq ;  arg =  x } ;  arg =  y }  ->  simp_dq  x  y 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -849,28 +806,26 @@ let rec simp_not (typ : Typ.t) term =
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  Uno ;  arg =  x } ;  arg =  y }  ->  simp_ord  x  y 
 
			
		
	
		
			
				
					  (*  ¬ ( a ∧ b )  ==> ¬a ∨  *) 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  And ;  arg =  x } ;  arg =  y }  -> 
 
			
		
	
		
			
				
					      simp_or  ( simp_not  typ  x)  ( simp_not  typ   y ) 
 
			
		
	
		
			
				
					      simp_or  ( simp_not  )  ( simp_not  y ) 
 
			
		
	
		
			
				
					  (*  ¬ ( a ∨  )  ==> ¬a ∧ ¬b  *) 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  Or ;  arg =  x } ;  arg =  y }  -> 
 
			
		
	
		
			
				
					      simp_and  ( simp_not  typ  x)  ( simp_not  typ   y ) 
 
			
		
	
		
			
				
					      simp_and  ( simp_not  )  ( simp_not  y ) 
 
			
		
	
		
			
				
					  (*  ¬ ( c ? t : e )  ==> c ? ¬t : ¬e  *) 
 
			
		
	
		
			
				
					  |  App  { op =  App  { op =  App  { op =  Conditional ;  arg =  cnd } ;  arg =  thn } ;  arg =  els } 
 
			
		
	
		
			
				
					    -> 
 
			
		
	
		
			
				
					      simp_cond  cnd  ( simp_not  t yp t  hn)  ( simp_not  typ   els ) 
 
			
		
	
		
			
				
					      simp_cond  cnd  ( simp_not  t hn)  ( simp_not  els ) 
 
			
		
	
		
			
				
					  (*  ¬i ==> -i-1  *) 
 
			
		
	
		
			
				
					  |  Integer  { data ; typ  } ->  integer  ( Z . lognot  data )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data ->  integer  ( Z . lognot  data ) 
 
			
		
	
		
			
				
					  (*  ¬e ==> true xor e  *) 
 
			
		
	
		
			
				
					  |  e  ->  App  { op =  App  { op =  Xor ;  arg =  integer  ( Z . of_bool  true )  typ } ;  arg =  e } 
 
			
		
	
		
			
				
					  |  e  ->  App  { op =  App  { op =  Xor ;  arg =  true _ } ;  arg =  e } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					and  simp_eq  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i = j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i } ,  Integer  { data =  j }  ->  bool  ( Z . equal  i  j ) 
 
			
		
	
		
			
				
					  (*  b = false ==> ¬b  *) 
 
			
		
	
		
			
				
					  |  b ,  Integer  { data }  when  Z . is_false  data  &&  is_boolean  b  -> 
 
			
		
	
		
			
				
					      simp_not  Typ . bool  b 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  b  when  Z . is_false  data  &&  is_boolean  b  -> 
 
			
		
	
		
			
				
					      simp_not  Typ . bool  b 
 
			
		
	
		
			
				
					  |  b ,  Integer  { data }  when  Z . is_false  data  &&  is_boolean  b  ->  simp_not  b 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  b  when  Z . is_false  data  &&  is_boolean  b  ->  simp_not  b 
 
			
		
	
		
			
				
					  (*  b = true ==> b  *) 
 
			
		
	
		
			
				
					  |  b ,  Integer  { data }  when  Z . is_true  data  &&  is_boolean  b  ->  b 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  b  when  Z . is_true  data  &&  is_boolean  b  ->  b 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -892,24 +847,22 @@ and simp_dq x y =
 
			
		
	
		
			
				
					    match  simp_eq  x  y  with 
 
			
		
	
		
			
				
					    |  App  { op =  App  { op =  Eq ;  arg =  x } ;  arg =  y }  -> 
 
			
		
	
		
			
				
					        App  { op =  App  { op =  Dq ;  arg =  x } ;  arg =  y } 
 
			
		
	
		
			
				
					    |  b  ->  simp_not  Typ . bool  b  ) 
 
			
		
	
		
			
				
					    |  b  ->  simp_not  b  ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_xor  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i xor j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  ->  integer  ( Z . logxor  i  j )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  ->  integer  ( Z . logxor  i  j ) 
 
			
		
	
		
			
				
					  (*  true xor b ==> ¬b  *) 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  b  when  Z . is_true  data  &&  is_boolean  b  -> 
 
			
		
	
		
			
				
					      simp_not  Typ . bool  b 
 
			
		
	
		
			
				
					  |  b ,  Integer  { data }  when  Z . is_true  data  &&  is_boolean  b  -> 
 
			
		
	
		
			
				
					      simp_not  Typ . bool  b 
 
			
		
	
		
			
				
					  |  Integer  { data } ,  b  when  Z . is_true  data  &&  is_boolean  b  ->  simp_not  b 
 
			
		
	
		
			
				
					  |  b ,  Integer  { data }  when  Z . is_true  data  &&  is_boolean  b  ->  simp_not  b 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Xor ;  arg =  x } ;  arg =  y } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_shl  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i shl j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_left  i  ( Z . to_int  j ) )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_left  i  ( Z . to_int  j ) ) 
 
			
		
	
		
			
				
					  (*  e shl 0 ==> e  *) 
 
			
		
	
		
			
				
					  |  e ,  Integer  { data }  when  Z . equal  Z . zero  data  ->  e 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Shl ;  arg =  x } ;  arg =  y } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -917,8 +870,8 @@ let simp_shl x y =
 
			
		
	
		
			
				
					let  simp_lshr  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i lshr j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_right_trunc  i  ( Z . to_int  j ) )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_right_trunc  i  ( Z . to_int  j ) ) 
 
			
		
	
		
			
				
					  (*  e lshr 0 ==> e  *) 
 
			
		
	
		
			
				
					  |  e ,  Integer  { data }  when  Z . equal  Z . zero  data  ->  e 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Lshr ;  arg =  x } ;  arg =  y } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -926,8 +879,8 @@ let simp_lshr x y =
 
			
		
	
		
			
				
					let  simp_ashr  x  y  =  
			
		
	
		
			
				
					  match  ( x ,  y )  with 
 
			
		
	
		
			
				
					  (*  i ashr j  *) 
 
			
		
	
		
			
				
					  |  Integer  { data =  i ; typ  },  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_right  i  ( Z . to_int  j ) )  typ  
 
			
		
	
		
			
				
					  |  Integer  { data =  i ,  Integer  { data =  j }  when  Z . sign  j  > =  0  -> 
 
			
		
	
		
			
				
					      integer  ( Z . shift_right  i  ( Z . to_int  j ) ) 
 
			
		
	
		
			
				
					  (*  e ashr 0 ==> e  *) 
 
			
		
	
		
			
				
					  |  e ,  Integer  { data }  when  Z . equal  Z . zero  data  ->  e 
 
			
		
	
		
			
				
					  |  _  ->  App  { op =  App  { op =  Ashr ;  arg =  x } ;  arg =  y } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1005,22 +958,10 @@ let app1 ?(partial = false) op arg =
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  app2  op  x  y  =  app1  ( app1  ~ partial : true  op  x )  y  
			
		
	
		
			
				
					let  app3  op  x  y  z  =  app1  ( app1  ~ partial : true  ( app1  ~ partial : true  op  x )  y )  z  
			
		
	
		
			
				
					let  addN  typ  args  =  simp_add  typ  args  | >  check  invariant  
			
		
	
		
			
				
					let  mulN  typ  args  =  simp_mul  typ  args  | >  check  invariant  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  check1  op  typ  x  =  
			
		
	
		
			
				
					  type_check  x  typ  ; 
 
			
		
	
		
			
				
					  op  typ  x  | >  check  invariant 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  check2  op  typ  x  y  =  
			
		
	
		
			
				
					  type_check2  x  y  typ  ; 
 
			
		
	
		
			
				
					  op  typ  x  y  | >  check  invariant 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  addN  args  =  simp_add  args  | >  check  invariant  
			
		
	
		
			
				
					let  mulN  args  =  simp_mul  args  | >  check  invariant  
			
		
	
		
			
				
					let  simp_memory  siz  arr  =  Memory  { siz ;  arr }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  memory  ~ siz  ~ arr  =  
			
		
	
		
			
				
					  type_check  siz  Typ . siz  ; 
 
			
		
	
		
			
				
					  simp_memory  siz  arr  | >  check  invariant 
 
			
		
	
		
			
				
					let  memory  ~ siz  ~ arr  =  simp_memory  siz  arr  | >  check  invariant  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  simp_concat  xs  =  
			
		
	
		
			
				
					  if  Vector . length  xs  =  1  then  Vector . get  xs  0 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1044,11 +985,7 @@ let simp_splat byt siz =
 
			
		
	
		
			
				
					  |  Integer  { data }  when  Z . equal  Z . zero  data  ->  concat  [| |] 
 
			
		
	
		
			
				
					  |  _  ->  Splat  { byt ;  siz } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  splat  ~ byt  ~ siz  =  
			
		
	
		
			
				
					  type_check  byt  Typ . byt  ; 
 
			
		
	
		
			
				
					  type_check  siz  Typ . siz  ; 
 
			
		
	
		
			
				
					  simp_splat  byt  siz  | >  check  invariant 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  splat  ~ byt  ~ siz  =  simp_splat  byt  siz  | >  check  invariant  
			
		
	
		
			
				
					let  eq  =  app2  Eq  
			
		
	
		
			
				
					let  dq  =  app2  Dq  
			
		
	
		
			
				
					let  gt  =  app2  Gt  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1057,16 +994,16 @@ let lt = app2 Lt
 
			
		
	
		
			
				
					let  le  =  app2  Le  
			
		
	
		
			
				
					let  ord  =  app2  Ord  
			
		
	
		
			
				
					let  uno  =  app2  Uno  
			
		
	
		
			
				
					let  neg  =  check1  simp_negate 
			
		
	
		
			
				
					let  add  =  check2  simp_add2 
			
		
	
		
			
				
					let  sub  =  check2  simp_sub 
			
		
	
		
			
				
					let  mul  =  check2  simp_mul2 
			
		
	
		
			
				
					let  neg  =   
			
		
	
		
			
				
					let  add  =   
			
		
	
		
			
				
					let  sub  =   
			
		
	
		
			
				
					let  mul  =   
			
		
	
		
			
				
					let  div  =  app2  Div  
			
		
	
		
			
				
					let  rem  =  app2  Rem  
			
		
	
		
			
				
					let  and_  =  app2  And  
			
		
	
		
			
				
					let  or_  =  app2  Or  
			
		
	
		
			
				
					let  xor  =  app2  Xor  
			
		
	
		
			
				
					let  not_  =  check1  simp_not 
			
		
	
		
			
				
					let  not_  =   
			
		
	
		
			
				
					let  shl  =  app2  Shl  
			
		
	
		
			
				
					let  lshr  =  app2  Lshr  
			
		
	
		
			
				
					let  ashr  =  app2  Ashr  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1103,6 +1040,10 @@ let extract ?(unsigned = false) ~bits term =
 
			
		
	
		
			
				
					let  convert  ? ( unsigned  =  false )  ~ dst  ~ src  term  =  
			
		
	
		
			
				
					  app1  ( Convert  { unsigned ;  dst ;  src } )  term 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  size_of  t  =  
			
		
	
		
			
				
					  Option . bind  ( Typ . prim_bit_size_of  t )  ~ f : ( fun  n  -> 
 
			
		
	
		
			
				
					      if  n  %  8  =  0  then  Some  ( integer  ( Z . of_int  ( n  /  8 ) ) )  else  None  ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  rec  of_exp  ( e  :  Exp . t )  =  
			
		
	
		
			
				
					  let  unsigned  op  typ  x  y  = 
 
			
		
	
		
			
				
					    match  Typ . prim_bit_size_of  typ  with 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1116,14 +1057,12 @@ let rec of_exp (e : Exp.t) =
 
			
		
	
		
			
				
					  |  Reg  { name }  ->  var  ( Var  { id =  0 ;  name } ) 
 
			
		
	
		
			
				
					  |  Nondet  { msg }  ->  nondet  msg 
 
			
		
	
		
			
				
					  |  Label  { parent ;  name }  ->  label  ~ parent  ~ name 
 
			
		
	
		
			
				
					  |  Integer  { data ;  typ =  Integer  { bits }  as  typ }  -> 
 
			
		
	
		
			
				
					      integer  ( Z . signed_extract  data  0  bits )  typ 
 
			
		
	
		
			
				
					  |  Integer  { data ;  typ }  ->  integer  data  typ 
 
			
		
	
		
			
				
					  |  Integer  { data }  ->  integer  data 
 
			
		
	
		
			
				
					  |  Float  { data }  ->  float  data 
 
			
		
	
		
			
				
					  |  Ap1  ( Convert  { unsigned ;  dst } ,  src ,  arg )  -> 
 
			
		
	
		
			
				
					      convert  ~ unsigned  ~ dst  ~ src  ( of_exp  arg ) 
 
			
		
	
		
			
				
					  |  Ap1  ( Select  idx ,  _ ,  arg )  -> 
 
			
		
	
		
			
				
					      select  ~ rcd : ( of_exp  arg )  ~ idx : ( integer  ( Z . of_int  idx )  Typ . siz  ) 
 
			
		
	
		
			
				
					      select  ~ rcd : ( of_exp  arg )  ~ idx : ( integer  ( Z . of_int  idx ) ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Eq ,  _ ,  x ,  y )  ->  eq  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Dq ,  _ ,  x ,  y )  ->  dq  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Gt ,  _ ,  x ,  y )  ->  gt  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1136,9 +1075,9 @@ let rec of_exp (e : Exp.t) =
 
			
		
	
		
			
				
					  |  Ap2  ( Ule ,  typ ,  x ,  y )  ->  unsigned  le  typ  x  y 
 
			
		
	
		
			
				
					  |  Ap2  ( Ord ,  _ ,  x ,  y )  ->  ord  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Uno ,  _ ,  x ,  y )  ->  uno  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Add ,  typ ,  x ,  y )  ->  add  typ   ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Sub ,  typ ,  x ,  y )  ->  sub  typ   ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Mul ,  typ ,  x ,  y )  ->  mul  typ   ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Add ,  _ ,  x ,  y )  ->  add  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Sub ,  _ ,  x ,  y )  ->  sub  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Mul ,  _ ,  x ,  y )  ->  mul  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Div ,  _ ,  x ,  y )  ->  div  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Rem ,  _ ,  x ,  y )  ->  rem  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Udiv ,  typ ,  x ,  y )  ->  unsigned  div  typ  x  y 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1151,7 +1090,7 @@ let rec of_exp (e : Exp.t) =
 
			
		
	
		
			
				
					  |  Ap2  ( Ashr ,  _ ,  x ,  y )  ->  ashr  ( of_exp  x )  ( of_exp  y ) 
 
			
		
	
		
			
				
					  |  Ap2  ( Update  idx ,  _ ,  rcd ,  elt )  -> 
 
			
		
	
		
			
				
					      update  ~ rcd : ( of_exp  rcd )  ~ elt : ( of_exp  elt ) 
 
			
		
	
		
			
				
					        ~ idx : ( integer  ( Z . of_int  idx )  Typ . siz  ) 
 
			
		
	
		
			
				
					        ~ idx : ( integer  ( Z . of_int  idx ) ) 
 
			
		
	
		
			
				
					  |  Ap3  ( Conditional ,  _ ,  cnd ,  thn ,  els )  -> 
 
			
		
	
		
			
				
					      conditional  ~ cnd : ( of_exp  cnd )  ~ thn : ( of_exp  thn )  ~ els : ( of_exp  els ) 
 
			
		
	
		
			
				
					  |  ApN  ( Record ,  _ ,  elts )  -> 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1162,11 +1101,6 @@ let rec of_exp (e : Exp.t) =
 
			
		
	
		
			
				
					        ~ id : e 
 
			
		
	
		
			
				
					        ( Vector . map  elts  ~ f : ( fun  e  ->  lazy  ( of_exp  e ) ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  size_of  t  =  
			
		
	
		
			
				
					  Option . bind  ( Typ . prim_bit_size_of  t )  ~ f : ( fun  n  -> 
 
			
		
	
		
			
				
					      if  n  %  8  =  0  then  Some  ( integer  ( Z . of_int  ( n  /  8 ) )  Typ . siz )  else  None 
 
			
		
	
		
			
				
					  ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					(* *  Transform  *)  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					let  map  e  ~ f  =  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1181,14 +1115,14 @@ let map e ~f =
 
			
		
	
		
			
				
					      let  args'  =  Vector . map_preserving_phys_equal  ~ f  args  in 
 
			
		
	
		
			
				
					      if  args'  = =  args  then  e  else  mk  args' 
 
			
		
	
		
			
				
					    in 
 
			
		
	
		
			
				
					    let  map_qset  mk  typ  ~ f  args  = 
 
			
		
	
		
			
				
					    let  map_qset  mk  ~ f  args  = 
 
			
		
	
		
			
				
					      let  args'  =  Qset . map  ~ f : ( fun  arg  q  ->  ( f  arg ,  q ) )  args  in 
 
			
		
	
		
			
				
					      if  args'  = =  args  then  e  else  mk  typ  args'
 
			
		
	
		
			
				
					      if  args'  = =  args  then  e  else  mk  
 
			
		
	
		
			
				
					    in 
 
			
		
	
		
			
				
					    match  e  with 
 
			
		
	
		
			
				
					    |  App  { op ;  arg }  ->  map_bin  ( app1  ~ partial : true )  ~ f  op  arg 
 
			
		
	
		
			
				
					    |  Add  { args ; typ  } ->  map_qset  addN  typ   ~ f  args 
 
			
		
	
		
			
				
					    |  Mul  { args ; typ  } ->  map_qset  mulN  typ   ~ f  args 
 
			
		
	
		
			
				
					    |  Add  { args ->  map_qset  addN  ~ f  args 
 
			
		
	
		
			
				
					    |  Mul  { args ->  map_qset  mulN  ~ f  args 
 
			
		
	
		
			
				
					    |  Splat  { byt ;  siz }  ->  map_bin  simp_splat  ~ f  byt  siz 
 
			
		
	
		
			
				
					    |  Memory  { siz ;  arr }  ->  map_bin  simp_memory  ~ f  siz  arr 
 
			
		
	
		
			
				
					    |  Concat  { args }  ->  map_vector  simp_concat  ~ f  args 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1246,23 +1180,21 @@ let solve e f =
 
			
		
	
		
			
				
					          Some  ( Map . add_exn  s  ~ key  ~ data ) 
 
			
		
	
		
			
				
					    in 
 
			
		
	
		
			
				
					    let  concat_size  args  = 
 
			
		
	
		
			
				
					      Vector . fold_until  args  ~ init : ( integer  Z . zero  Typ . siz ) 
 
			
		
	
		
			
				
					        ~ f : ( fun  sum  ->  function 
 
			
		
	
		
			
				
					          |  Memory  { siz }  ->  Continue  ( add  Typ . siz  siz  sum )  |  _  ->  Stop  None 
 
			
		
	
		
			
				
					          ) 
 
			
		
	
		
			
				
					      Vector . fold_until  args  ~ init : zero 
 
			
		
	
		
			
				
					        ~ f : ( fun  sum  ->  function  Memory  { siz }  ->  Continue  ( add  siz  sum ) 
 
			
		
	
		
			
				
					          |  _  ->  Stop  None  ) 
 
			
		
	
		
			
				
					        ~ finish : ( fun  _  ->  None ) 
 
			
		
	
		
			
				
					    in 
 
			
		
	
		
			
				
					    match  ( e ,  f )  with 
 
			
		
	
		
			
				
					    |  ( Add  { typ }  |  Mul  { typ }  |  Integer  { typ } ) ,  _ 
 
			
		
	
		
			
				
					     | _ ,  ( Add  { typ }  |  Mul  { typ }  |  Integer  { typ } )  ->  ( 
 
			
		
	
		
			
				
					      match  sub  typ  e  f  with 
 
			
		
	
		
			
				
					    |  ( Add  _  |  Mul  _  |  Integer  _ ) ,  _  |  _ ,  ( Add  _  |  Mul  _  |  Integer  _ )  ->  ( 
 
			
		
	
		
			
				
					      match  sub  e  f  with 
 
			
		
	
		
			
				
					      |  Add  { args }  -> 
 
			
		
	
		
			
				
					          let  c ,  q  =  Qset . min_elt_exn  args  in 
 
			
		
	
		
			
				
					          let  n  =  Sum . to_term  typ  ( Qset . remove  args  c )  in 
 
			
		
	
		
			
				
					          let  d  =  rational  ( Q . neg  q )  typ  in 
 
			
		
	
		
			
				
					          let  n  =  Sum . to_term  ( Qset . remove  args  c )  in 
 
			
		
	
		
			
				
					          let  d  =  rational  ( Q . neg  q )  in 
 
			
		
	
		
			
				
					          let  r  =  div  n  d  in 
 
			
		
	
		
			
				
					          Some  ( Map . add_exn  s  ~ key : c  ~ data : r ) 
 
			
		
	
		
			
				
					      |  e_f  ->  solve_uninterp  e_f  ( zero  typ )   ) 
 
			
		
	
		
			
				
					      |  e_f  ->  solve_uninterp  e_f  zero  ) 
 
			
		
	
		
			
				
					    |  Concat  { args =  ms } ,  Concat  { args =  ns }  ->  ( 
 
			
		
	
		
			
				
					      match  ( concat_size  ms ,  concat_size  ns )  with 
 
			
		
	
		
			
				
					      |  Some  p ,  Some  q  ->  solve_uninterp  e  f  > > =  solve_  p  q