[sledge] Switch Fol.Context from using Ses.Equality to Context

Summary:
The implementation in Context, in terms of Fol.Term and Fol.Formula,
can now be used instead of Ses.Equality, implemented using
Ses.Term. The Ses modules can now be removed.

Reviewed By: jvillard

Differential Revision: D24532362

fbshipit-source-id: cee9791b7
master
Josh Berdine 4 years ago committed by Facebook GitHub Bot
parent ca9acdb915
commit 03c2a6f118

@ -79,7 +79,7 @@ let term_eq_class_has_only_vars_in fvs ctx term =
Context.pp ctx Term.pp term]
;
let term_has_only_vars_in fvs term =
Var.Set.subset (Term.fv term) ~of_:fvs
Var.Set.subset (Trm.fv term) ~of_:fvs
in
let term_eq_class = Context.class_of ctx term in
List.exists ~f:(term_has_only_vars_in fvs) term_eq_class
@ -98,7 +98,7 @@ let garbage_collect (q : t) ~wrt =
List.fold q.heap current ~f:(fun seg current ->
if term_eq_class_has_only_vars_in current q.ctx seg.loc then
List.fold (Context.class_of q.ctx seg.seq) current
~f:(fun e c -> Var.Set.union c (Term.fv e))
~f:(fun e c -> Var.Set.union c (Trm.fv e))
else current )
in
all_reachable_vars current new_set q

@ -60,17 +60,6 @@ let _Ite cnd thn els =
| _ when Fml.is_negative cnd -> `Ite (Fml.not_ cnd, els, thn)
| _ -> `Ite (cnd, thn, els)
(** Map a unary function on terms over the leaves of a conditional term,
rebuilding the tree of conditionals with the supplied ite construction
function. *)
let rec map_cnd : (fml -> 'a -> 'a -> 'a) -> (trm -> 'a) -> cnd -> 'a =
fun f_ite f_trm -> function
| `Trm trm -> f_trm trm
| `Ite (cnd, thn, els) ->
let thn' = map_cnd f_ite f_trm thn in
let els' = map_cnd f_ite f_trm els in
f_ite cnd thn' els'
(** Embed a formula into a conditional term (associating true with 1 and
false with 0), identity on conditional terms. *)
let embed_into_cnd : exp -> cnd = function
@ -101,23 +90,16 @@ let ite : fml -> exp -> exp -> exp =
let c = _Ite cnd (embed_into_cnd thn) (embed_into_cnd els) in
match project_out_fml c with Some f -> `Fml f | None -> (c :> exp) )
(** Embed a conditional term into a formula (associating 0 with false and
non-0 with true, lifted over the tree mapping conditional terms to
conditional formulas), identity on formulas.
- [embed_into_fml] is left inverse to [embed_into_cnd] in the sense that
[embed_into_fml ((embed_into_cnd (`Fml f)) :> exp) = f].
- [embed_into_fml] is not right inverse to [embed_into_cnd] since
[embed_into_fml] can only preserve one bit of information from its
argument. So in general
[(embed_into_cnd (`Fml (embed_into_fml x)) :> exp)] is not equivalent
to [x].
- The weaker condition that
[0 (embed_into_cnd (`Fml (embed_into_fml x)) :> exp)] iff
[0 x] holds. *)
let embed_into_fml : exp -> fml = function
| `Fml fml -> fml
| #cnd as c -> map_cnd cond (fun e -> Fml.not_ (Fml.eq0 e)) c
(** Map a unary function on terms over the leaves of a conditional term,
rebuilding the tree of conditionals with the supplied ite construction
function. *)
let rec map_cnd : (fml -> 'a -> 'a -> 'a) -> (trm -> 'a) -> cnd -> 'a =
fun f_ite f_trm -> function
| `Trm trm -> f_trm trm
| `Ite (cnd, thn, els) ->
let thn' = map_cnd f_ite f_trm thn in
let els' = map_cnd f_ite f_trm els in
f_ite cnd thn' els'
(** Map a unary function on terms over an expression. *)
let ap1 : (trm -> exp) -> exp -> exp =
@ -448,461 +430,3 @@ module Formula = struct
let rename s e = map_vars ~f:(Var.Subst.apply s) e
end
(*
* Convert to Ses
*)
let v_to_ses : var -> Ses.Var.t =
fun v -> Ses.Var.identified ~id:(Var.id v) ~name:(Var.name v)
let vs_to_ses : Var.Set.t -> Ses.Var.Set.t =
fun vs -> Ses.Var.Set.of_iter (Iter.map ~f:v_to_ses (Var.Set.to_iter vs))
let rec arith_to_ses poly =
Trm.Arith.fold_monomials poly Ses.Term.zero ~f:(fun mono coeff e ->
Ses.Term.add e
(Ses.Term.mulq coeff
(Trm.Arith.fold_factors mono Ses.Term.one ~f:(fun trm pow f ->
let rec exp b i =
assert (i > 0) ;
if i = 1 then b else Ses.Term.mul b (exp f (i - 1))
in
Ses.Term.mul f (exp (t_to_ses trm) pow) ))) )
and t_to_ses : trm -> Ses.Term.t = function
| Var {name; id} -> Ses.Term.var (Ses.Var.identified ~name ~id)
| Z z -> Ses.Term.integer z
| Q q -> Ses.Term.rational q
| Arith a -> arith_to_ses a
| Splat x -> Ses.Term.splat (t_to_ses x)
| Sized {seq; siz} ->
Ses.Term.sized ~seq:(t_to_ses seq) ~siz:(t_to_ses siz)
| Extract {seq; off; len} ->
Ses.Term.extract ~seq:(t_to_ses seq) ~off:(t_to_ses off)
~len:(t_to_ses len)
| Concat es -> Ses.Term.concat (Array.map ~f:t_to_ses es)
| Select {idx; rcd} -> Ses.Term.select ~rcd:(t_to_ses rcd) ~idx
| Update {idx; rcd; elt} ->
Ses.Term.update ~rcd:(t_to_ses rcd) ~idx ~elt:(t_to_ses elt)
| Record es ->
Ses.Term.record (IArray.of_array (Array.map ~f:t_to_ses es))
| Ancestor i -> Ses.Term.rec_record i
| Apply (Rem, [|x; y|]) -> Ses.Term.rem (t_to_ses x) (t_to_ses y)
| Apply (BitAnd, [|x; y|]) -> Ses.Term.and_ (t_to_ses x) (t_to_ses y)
| Apply (BitOr, [|x; y|]) -> Ses.Term.or_ (t_to_ses x) (t_to_ses y)
| Apply (BitXor, [|x; y|]) -> Ses.Term.dq (t_to_ses x) (t_to_ses y)
| Apply (BitShl, [|x; y|]) -> Ses.Term.shl (t_to_ses x) (t_to_ses y)
| Apply (BitLshr, [|x; y|]) -> Ses.Term.lshr (t_to_ses x) (t_to_ses y)
| Apply (BitAshr, [|x; y|]) -> Ses.Term.ashr (t_to_ses x) (t_to_ses y)
| Apply (Signed n, [|x|]) -> Ses.Term.signed n (t_to_ses x)
| Apply (Unsigned n, [|x|]) -> Ses.Term.unsigned n (t_to_ses x)
| Apply (sym, xs) ->
Ses.Term.apply sym (IArray.of_array (Array.map ~f:t_to_ses xs))
let rec f_to_ses : fml -> Ses.Term.t = function
| Tt -> Ses.Term.true_
| Not Tt -> Ses.Term.false_
| Eq (x, y) -> Ses.Term.eq (t_to_ses x) (t_to_ses y)
| Eq0 x -> Ses.Term.eq Ses.Term.zero (t_to_ses x)
| Pos x -> Ses.Term.lt Ses.Term.zero (t_to_ses x)
| Not p -> Ses.Term.not_ (f_to_ses p)
| And {pos; neg} ->
Formula.fold_pos_neg
~f:(fun f p -> Ses.Term.and_ p (f_to_ses f))
~pos ~neg Ses.Term.true_
| Or {pos; neg} ->
Formula.fold_pos_neg
~f:(fun f p -> Ses.Term.or_ p (f_to_ses f))
~pos ~neg Ses.Term.false_
| Iff (p, q) -> Ses.Term.eq (f_to_ses p) (f_to_ses q)
| Cond {cnd; pos; neg} ->
Ses.Term.conditional ~cnd:(f_to_ses cnd) ~thn:(f_to_ses pos)
~els:(f_to_ses neg)
| Lit (sym, args) ->
Ses.Term.poslit sym (IArray.of_array (Array.map ~f:t_to_ses args))
let rec to_ses : exp -> Ses.Term.t = function
| `Ite (cnd, thn, els) ->
Ses.Term.conditional ~cnd:(f_to_ses cnd)
~thn:(to_ses (thn :> exp))
~els:(to_ses (els :> exp))
| `Trm t -> t_to_ses t
| `Fml f -> f_to_ses f
(*
* Convert from Ses
*)
let v_of_ses : Ses.Var.t -> var =
fun v -> Var.identified ~id:(Ses.Var.id v) ~name:(Ses.Var.name v)
let vs_of_ses : Ses.Var.Set.t -> Var.Set.t =
fun vs -> Var.Set.of_iter (Iter.map ~f:v_of_ses (Ses.Var.Set.to_iter vs))
let uap1 f = ap1t (fun x -> Trm.apply f [|x|])
let uap2 f = ap2t (fun x y -> Trm.apply f [|x; y|])
let litN p = apNf (Fml.lit p)
let rec uap_tt f a = uap1 f (of_ses a)
and uap_ttt f a b = uap2 f (of_ses a) (of_ses b)
and ap2 mk_f mk_t a b =
match (of_ses a, of_ses b) with
| `Fml p, `Fml q -> `Fml (mk_f p q)
| x, y -> mk_t x y
and ap2_f mk_f mk_t a b = ap2 mk_f (fun x y -> `Fml (mk_t x y)) a b
and apN mk_f mk_t mk_unit es =
match
Ses.Term.Set.fold es (None, None) ~f:(fun e (fs, ts) ->
match of_ses e with
| `Fml f ->
(Some (match fs with None -> f | Some g -> mk_f f g), ts)
| t -> (fs, Some (match ts with None -> t | Some u -> mk_t t u)) )
with
| Some f, Some t -> mk_t t (Formula.inject f)
| Some f, None -> `Fml f
| None, Some t -> t
| None, None -> `Fml mk_unit
and of_ses : Ses.Term.t -> exp =
fun t ->
let open Term in
let open Formula in
match t with
| Var {id; name} -> var (Var.identified ~id ~name)
| Integer {data} -> integer data
| Rational {data} -> rational data
| Ap1 (Signed {bits}, e) -> uap_tt (Signed bits) e
| Ap1 (Unsigned {bits}, e) -> uap_tt (Unsigned bits) e
| Ap2 (Eq, d, e) -> ap2_f iff eq d e
| Ap2 (Dq, d, e) -> ap2_f xor dq d e
| Ap2 (Lt, d, e) -> ap2_f (fun p q -> and_ (not_ p) q) lt d e
| Ap2 (Le, d, e) -> ap2_f (fun p q -> or_ (not_ p) q) le d e
| PosLit (p, es) ->
`Fml (litN p (IArray.to_array (IArray.map ~f:of_ses es)))
| NegLit (p, es) ->
`Fml (not_ (litN p (IArray.to_array (IArray.map ~f:of_ses es))))
| Add sum -> (
match Ses.Term.Qset.pop_min_elt sum with
| None -> zero
| Some (e, q, sum) ->
let mul e q =
if Q.equal Q.one q then of_ses e
else
match of_ses e with
| `Trm (Z z) -> rational (Q.mul q (Q.of_z z))
| `Trm (Q r) -> rational (Q.mul q r)
| t -> mulq q t
in
Ses.Term.Qset.fold ~f:(fun e q -> add (mul e q)) sum (mul e q) )
| Mul prod -> (
match Ses.Term.Qset.pop_min_elt prod with
| None -> one
| Some (e, q, prod) ->
let rec expn e n =
let p = Z.pred n in
if Z.sign p = 0 then e else mul e (expn e p)
in
let exp e q =
let n = Q.num q in
let sn = Z.sign n in
if sn = 0 then of_ses e
else if sn > 0 then expn (of_ses e) n
else div one (expn (of_ses e) (Z.neg n))
in
Ses.Term.Qset.fold ~f:(fun e q -> mul (exp e q)) prod (exp e q) )
| Ap2 (Div, d, e) -> div (of_ses d) (of_ses e)
| Ap2 (Rem, d, e) -> uap_ttt Rem d e
| And es -> apN and_ (uap2 BitAnd) tt es
| Or es -> apN or_ (uap2 BitOr) ff es
| Ap2 (Xor, d, e) -> ap2 xor (uap2 BitXor) d e
| Ap2 (Shl, d, e) -> uap_ttt BitShl d e
| Ap2 (Lshr, d, e) -> uap_ttt BitLshr d e
| Ap2 (Ashr, d, e) -> uap_ttt BitAshr d e
| Ap3 (Conditional, cnd, thn, els) -> (
let cnd = embed_into_fml (of_ses cnd) in
match (of_ses thn, of_ses els) with
| `Fml pos, `Fml neg -> `Fml (cond ~cnd ~pos ~neg)
| thn, els -> ite ~cnd ~thn ~els )
| Ap1 (Splat, byt) -> splat (of_ses byt)
| Ap3 (Extract, seq, off, len) ->
extract ~seq:(of_ses seq) ~off:(of_ses off) ~len:(of_ses len)
| Ap2 (Sized, siz, seq) -> sized ~seq:(of_ses seq) ~siz:(of_ses siz)
| ApN (Concat, args) ->
concat (Array.map ~f:of_ses (IArray.to_array args))
| Ap1 (Select idx, rcd) -> select ~rcd:(of_ses rcd) ~idx
| Ap2 (Update idx, rcd, elt) ->
update ~rcd:(of_ses rcd) ~idx ~elt:(of_ses elt)
| ApN (Record, elts) ->
record (Array.map ~f:of_ses (IArray.to_array elts))
| RecRecord i -> ancestor i
| Apply (sym, args) ->
apply sym (Array.map ~f:of_ses (IArray.to_array args))
let f_of_ses e = embed_into_fml (of_ses e)
let v_map_ses : (var -> var) -> Ses.Var.t -> Ses.Var.t =
fun f x ->
let v = v_of_ses x in
let v' = f v in
if v' == v then x else v_to_ses v'
let ses_map : (Ses.Term.t -> Ses.Term.t) -> exp -> exp =
fun f x -> of_ses (f (to_ses x))
let f_ses_map : (Ses.Term.t -> Ses.Term.t) -> fml -> fml =
fun f x -> f_of_ses (f (f_to_ses x))
(*
* Contexts
*)
module Context = struct
type t = Ses.Equality.t [@@deriving sexp]
let invariant = Ses.Equality.invariant
(* Query *)
let vars x =
Iter.from_iter (fun f ->
Ses.Equality.fold_vars ~f:(fun v () -> f (v_of_ses v)) x () )
let fv x = Var.Set.of_iter (vars x)
let is_empty x = Ses.Equality.is_true x
let is_unsat x = Ses.Equality.is_false x
let implies x b = Ses.Equality.implies x (f_to_ses b)
let refutes x b =
Ses.Term.is_false (Ses.Equality.normalize x (f_to_ses b))
let normalize x e = ses_map (Ses.Equality.normalize x) e
(* Classes *)
let class_of x e = List.map ~f:of_ses (Ses.Equality.class_of x (to_ses e))
let classes x =
Ses.Term.Map.fold (Ses.Equality.classes x) Term.Map.empty
~f:(fun ~key:rep ~data:cls clss ->
let rep' = of_ses rep in
let cls' = List.map ~f:of_ses cls in
Term.Map.add ~key:rep' ~data:cls' clss )
let diff_classes r s =
Term.Map.filter_mapi (classes r) ~f:(fun ~key:rep ~data:cls ->
match
List.filter cls ~f:(fun exp ->
not (implies s (Formula.eq rep exp)) )
with
| [] -> None
| cls -> Some cls )
(* Pretty printing *)
let pp_raw = Ses.Equality.pp
let ppx_cls x = List.pp "@ = " (Term.ppx x)
let ppx_classes x fs clss =
List.pp "@ @<2>∧ "
(fun fs (rep, cls) ->
Format.fprintf fs "@[%a@ = %a@]" (Term.ppx x) rep (ppx_cls x)
(List.sort ~cmp:Term.compare cls) )
fs
(Iter.to_list (Term.Map.to_iter clss))
let pp fs r = ppx_classes (fun _ -> None) fs (classes r)
let ppx var_strength fs clss noneqs =
let first = Term.Map.is_empty clss in
if not first then Format.fprintf fs " " ;
ppx_classes var_strength fs clss ;
List.pp
~pre:(if first then "@[ " else "@ @[@<2>∧ ")
"@ @<2>∧ "
(Formula.ppx var_strength)
fs noneqs ~suf:"@]" ;
first && List.is_empty noneqs
let ppx_diff var_strength fs parent_ctx fml ctx =
let fml' = f_ses_map (Ses.Equality.normalize ctx) fml in
ppx var_strength fs
(diff_classes ctx parent_ctx)
(if Formula.(equal tt fml') then [] else [fml'])
(* Construct *)
let empty = Ses.Equality.true_
let add vs f x =
let vs', x' = Ses.Equality.and_term (vs_to_ses vs) (f_to_ses f) x in
(vs_of_ses vs', x')
let union vs x y =
let vs', z = Ses.Equality.and_ (vs_to_ses vs) x y in
(vs_of_ses vs', z)
let inter vs x y =
let vs', z = Ses.Equality.or_ (vs_to_ses vs) x y in
(vs_of_ses vs', z)
let interN vs xs =
let vs', z = Ses.Equality.orN (vs_to_ses vs) xs in
(vs_of_ses vs', z)
let dnf f =
let meet1 a (vs, p, x) =
let vs, x = add vs a x in
(vs, Formula.and_ p a, x)
in
let join1 = Iter.cons in
let top = (Var.Set.empty, Formula.tt, empty) in
let bot = Iter.empty in
Formula.fold_dnf ~meet1 ~join1 ~top ~bot f
let rename x sub = Ses.Equality.rename x (v_map_ses (Var.Subst.apply sub))
(* Substs *)
module Subst = struct
type t = Ses.Equality.Subst.t [@@deriving sexp]
let pp = Ses.Equality.Subst.pp
let is_empty = Ses.Equality.Subst.is_empty
let fold s z ~f =
Ses.Equality.Subst.fold s z ~f:(fun ~key ~data ->
f ~key:(of_ses key) ~data:(of_ses data) )
let subst s = ses_map (Ses.Equality.Subst.subst s)
let partition_valid vs s =
let t, ks, u = Ses.Equality.Subst.partition_valid (vs_to_ses vs) s in
(t, vs_of_ses ks, u)
end
let apply_subst vs s x =
let vs', x' = Ses.Equality.apply_subst (vs_to_ses vs) s x in
(vs_of_ses vs', x')
let solve_for_vars vss x =
Ses.Equality.solve_for_vars (List.map ~f:vs_to_ses vss) x
let elim vs x = Ses.Equality.elim (vs_to_ses vs) x
(* Replay debugging *)
type call =
| Add of Var.Set.t * fml * t
| Union of Var.Set.t * t * t
| Inter of Var.Set.t * t * t
| InterN of Var.Set.t * t list
| Rename of t * Var.Subst.t
| Is_unsat of t
| Implies of t * fml
| Refutes of t * fml
| Normalize of t * exp
| Apply_subst of Var.Set.t * Subst.t * t
| Solve_for_vars of Var.Set.t list * t
| Elim of Var.Set.t * t
[@@deriving sexp]
let replay c =
match call_of_sexp (Sexp.of_string c) with
| Add (us, e, r) -> add us e r |> ignore
| Union (us, r, s) -> union us r s |> ignore
| Inter (us, r, s) -> inter us r s |> ignore
| InterN (us, rs) -> interN us rs |> ignore
| Rename (r, s) -> rename r s |> ignore
| Is_unsat r -> is_unsat r |> ignore
| Implies (r, f) -> implies r f |> ignore
| Refutes (r, f) -> refutes r f |> ignore
| Normalize (r, e) -> normalize r e |> ignore
| Apply_subst (us, s, r) -> apply_subst us s r |> ignore
| Solve_for_vars (vss, r) -> solve_for_vars vss r |> ignore
| Elim (ks, r) -> elim ks r |> ignore
(* Debug wrappers *)
let report ~name ~elapsed ~aggregate ~count =
Format.eprintf "%15s time: %12.3f ms %12.3f ms %12d calls@." name
elapsed aggregate count
let dump_threshold = ref 1000.
let wrap tmr f call =
let f () =
Timer.start tmr ;
let r = f () in
Timer.stop_report tmr (fun ~name ~elapsed ~aggregate ~count ->
report ~name ~elapsed ~aggregate ~count ;
if Float.(elapsed > !dump_threshold) then (
dump_threshold := 2. *. !dump_threshold ;
Format.eprintf "@\n%a@\n@." Sexp.pp_hum (sexp_of_call (call ()))
) ) ;
r
in
if not [%debug] then f ()
else
try f ()
with exn ->
let bt = Printexc.get_raw_backtrace () in
let sexp = sexp_of_call (call ()) in
raise (Replay (exn, bt, sexp))
let add_tmr = Timer.create "add" ~at_exit:report
let union_tmr = Timer.create "union" ~at_exit:report
let inter_tmr = Timer.create "inter" ~at_exit:report
let interN_tmr = Timer.create "interN" ~at_exit:report
let rename_tmr = Timer.create "rename" ~at_exit:report
let is_unsat_tmr = Timer.create "is_unsat" ~at_exit:report
let implies_tmr = Timer.create "implies" ~at_exit:report
let refutes_tmr = Timer.create "refutes" ~at_exit:report
let normalize_tmr = Timer.create "normalize" ~at_exit:report
let apply_subst_tmr = Timer.create "apply_subst" ~at_exit:report
let solve_for_vars_tmr = Timer.create "solve_for_vars" ~at_exit:report
let elim_tmr = Timer.create "elim" ~at_exit:report
let add us e r =
wrap add_tmr (fun () -> add us e r) (fun () -> Add (us, e, r))
let union us r s =
wrap union_tmr (fun () -> union us r s) (fun () -> Union (us, r, s))
let inter us r s =
wrap inter_tmr (fun () -> inter us r s) (fun () -> Inter (us, r, s))
let interN us rs =
wrap interN_tmr (fun () -> interN us rs) (fun () -> InterN (us, rs))
let rename r s =
wrap rename_tmr (fun () -> rename r s) (fun () -> Rename (r, s))
let is_unsat r =
wrap is_unsat_tmr (fun () -> is_unsat r) (fun () -> Is_unsat r)
let implies r f =
wrap implies_tmr (fun () -> implies r f) (fun () -> Implies (r, f))
let refutes r f =
wrap refutes_tmr (fun () -> refutes r f) (fun () -> Refutes (r, f))
let normalize r e =
wrap normalize_tmr (fun () -> normalize r e) (fun () -> Normalize (r, e))
let apply_subst us s r =
wrap apply_subst_tmr
(fun () -> apply_subst us s r)
(fun () -> Apply_subst (us, s, r))
let solve_for_vars vss r =
wrap solve_for_vars_tmr
(fun () -> solve_for_vars vss r)
(fun () -> Solve_for_vars (vss, r))
let elim ks r =
wrap elim_tmr (fun () -> elim ks r) (fun () -> Elim (ks, r))
end

@ -141,108 +141,3 @@ and Formula : sig
val fold_map_vars : t -> 's -> f:(Var.t -> 's -> Var.t * 's) -> t * 's
val rename : Var.Subst.t -> t -> t
end
(** Sets of assumptions, interpreted as conjunction, plus reasoning about
their logical consequences. *)
module Context : sig
type t [@@deriving sexp]
val pp : t pp
val ppx_diff :
Var.strength -> Format.formatter -> t -> Formula.t -> t -> bool
include Invariant.S with type t := t
val empty : t
(** The empty context of assumptions. *)
val add : Var.Set.t -> Formula.t -> t -> Var.Set.t * t
(** Add (that is, conjoin) an assumption to a context. *)
val union : Var.Set.t -> t -> t -> Var.Set.t * t
(** Union (that is, conjoin) two contexts of assumptions. *)
val inter : Var.Set.t -> t -> t -> Var.Set.t * t
(** Intersect (that is, disjoin) contexts of assumptions. *)
val interN : Var.Set.t -> t list -> Var.Set.t * t
(** Intersect contexts of assumptions. Possibly weaker than logical
disjunction. *)
val dnf : Formula.t -> (Var.Set.t * Formula.t * t) iter
(** Disjunctive-normal form expansion. *)
val rename : t -> Var.Subst.t -> t
(** Apply a renaming substitution to the context. *)
val is_empty : t -> bool
(** Test if the context of assumptions is empty. *)
val is_unsat : t -> bool
(** Test if the context of assumptions is inconsistent. *)
val implies : t -> Formula.t -> bool
(** Holds only if a formula is a logical consequence of a context of
assumptions. This only checks if the formula is valid in the current
state of the context, without doing any further logical reasoning or
propagation. *)
val refutes : t -> Formula.t -> bool
(** Holds only if a formula is inconsistent with a context of assumptions,
that is, conjoining the formula to the assumptions is unsatisfiable. *)
val normalize : t -> Term.t -> Term.t
(** Normalize a term [e] to [e'] such that [e = e'] is implied by the
assumptions, where [e'] and its subterms are expressed in terms of the
canonical representatives of each equivalence class. *)
val class_of : t -> Term.t -> Term.t list
(** Equivalence class of [e]: all the terms [f] in the context such that
[e = f] is implied by the assumptions. *)
val vars : t -> Var.t iter
(** Enumerate the variables occurring in the terms of the context. *)
val fv : t -> Var.Set.t
(** The variables occurring in the terms of the context. *)
(** Solution Substitutions *)
module Subst : sig
type t
val pp : t pp
val is_empty : t -> bool
val fold : t -> 's -> f:(key:Term.t -> data:Term.t -> 's -> 's) -> 's
val subst : t -> Term.t -> Term.t
(** Apply a substitution recursively to subterms. *)
val partition_valid : Var.Set.t -> t -> t * Var.Set.t * t
(** Partition ∃xs. σ into equivalent ∃xs. τ ∧ ∃ks. ν where ks
and ν are maximal where ks. ν is universally valid, xs ks
and ks fv(τ) = . *)
end
val apply_subst : Var.Set.t -> Subst.t -> t -> Var.Set.t * t
(** Context induced by applying a solution substitution to a set of
equations generating the argument context. *)
val solve_for_vars : Var.Set.t list -> t -> Subst.t
(** [solve_for_vars vss x] is a solution substitution that is implied by
[x] and consists of oriented equalities [v e] that map terms [v]
with free variables contained in (the union of) a prefix [uss] of
[vss] to terms [e] with free variables contained in as short a prefix
of [uss] as possible. *)
val elim : Var.Set.t -> t -> t
(** [elim ks x] is [x] weakened by removing oriented equations [k ↦ _]
for [k] in [ks]. *)
(**/**)
val pp_raw : t pp
val replay : string -> unit
(** Replay debugging *)
end

@ -7,8 +7,6 @@
(** Propositional formulas *)
open Ses
module type TERM = sig
type t [@@deriving compare, equal, sexp]
end
@ -35,7 +33,7 @@ module type FORMULA = sig
| Iff of t * t
| Cond of {cnd: t; pos: t; neg: t}
(* uninterpreted literals *)
| Lit of Predsym.t * trm array
| Lit of Ses.Predsym.t * trm array
[@@deriving compare, equal, sexp]
val mk_Tt : unit -> t
@ -47,7 +45,7 @@ module type FORMULA = sig
val _Or : pos:set -> neg:set -> t
val _Iff : t -> t -> t
val _Cond : t -> t -> t -> t
val _Lit : Predsym.t -> trm array -> t
val _Lit : Ses.Predsym.t -> trm array -> t
val and_ : t -> t -> t
val or_ : t -> t -> t
val is_negative : t -> bool

File diff suppressed because it is too large Load Diff

@ -1,100 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** Constraints representing equivalence relations over uninterpreted
functions and linear rational arithmetic.
Functions that return relations that might be stronger than their
argument relations accept and return a set of variables. The input set
is the variables with which any generated variables must be chosen
fresh, and the output set is the variables that have been generated. *)
type t [@@deriving compare, equal, sexp]
type classes = Term.t list Term.Map.t
val classes : t -> classes
(** [classes r] maps each equivalence class representative to the other
terms [r] proves equal to it. *)
val pp : t pp
val pp_classes : t pp
val ppx_classes : Var.strength -> classes pp
include Invariant.S with type t := t
val true_ : t
(** The diagonal relation, which only equates each term with itself. *)
val and_eq : Var.Set.t -> Term.t -> Term.t -> t -> Var.Set.t * t
(** Conjoin an equation to a relation. *)
val and_term : Var.Set.t -> Term.t -> t -> Var.Set.t * t
(** Conjoin a (Boolean) term to a relation. *)
val and_ : Var.Set.t -> t -> t -> Var.Set.t * t
(** Conjunction. *)
val or_ : Var.Set.t -> t -> t -> Var.Set.t * t
(** Disjunction. *)
val orN : Var.Set.t -> t list -> Var.Set.t * t
(** Nary disjunction. *)
val rename : t -> (Var.t -> Var.t) -> t
(** Apply a renaming substitution to the relation. *)
val is_true : t -> bool
(** Test if the relation is diagonal. *)
val is_false : t -> bool
(** Test if the relation is empty / inconsistent. *)
val implies : t -> Term.t -> bool
(** Test if a term is implied by a relation. *)
val class_of : t -> Term.t -> Term.t list
(** Equivalence class of [e]: all the terms [f] in the relation such that
[e = f] is implied by the relation. *)
val normalize : t -> Term.t -> Term.t
(** Normalize a term [e] to [e'] such that [e = e'] is implied by the
relation, where [e'] and its subterms are expressed in terms of the
relation's canonical representatives of each equivalence class. *)
val fold_vars : t -> 's -> f:(Var.t -> 's -> 's) -> 's
(** Solution Substitutions *)
module Subst : sig
type t [@@deriving compare, equal, sexp]
val pp : t pp
val is_empty : t -> bool
val fold : t -> 's -> f:(key:Term.t -> data:Term.t -> 's -> 's) -> 's
val subst : t -> Term.t -> Term.t
(** Apply a substitution recursively to subterms. *)
val partition_valid : Var.Set.t -> t -> t * Var.Set.t * t
(** Partition ∃xs. σ into equivalent ∃xs. τ ∧ ∃ks. ν where ks
and ν are maximal where ks. ν is universally valid, xs ks and
ks fv(τ) = . *)
end
val apply_subst : Var.Set.t -> Subst.t -> t -> Var.Set.t * t
(** Relation induced by applying a substitution to a set of equations
generating the argument relation. *)
val solve_for_vars : Var.Set.t list -> t -> Subst.t
(** [solve_for_vars vss r] is a solution substitution that is entailed by
[r] and consists of oriented equalities [x e] that map terms [x]
with free variables contained in (the union of) a prefix [uss] of [vss]
to terms [e] with free variables contained in as short a prefix of [uss]
as possible. *)
val elim : Var.Set.t -> t -> t
(** Weaken relation by removing oriented equations [k ↦ _] for [k] in
[ks]. *)

File diff suppressed because it is too large Load Diff

@ -1,231 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** Terms
Pure (heap-independent) terms are arithmetic, bitwise-logical, etc.
operations over literal values and variables. *)
type op1 =
| Signed of {bits: int}
(** [Ap1 (Signed {bits= n}, arg)] is [arg] interpreted as an [n]-bit
signed integer. That is, it two's-complement--decodes the low [n]
bits of the infinite two's-complement encoding of [arg]. *)
| Unsigned of {bits: int}
(** [Ap1 (Unsigned {bits= n}, arg)] is [arg] interpreted as an [n]-bit
unsigned integer. That is, it unsigned-binary--decodes the low [n]
bits of the infinite two's-complement encoding of [arg]. *)
| Splat (** Iterated concatenation of a single byte *)
| Select of int (** Select an index from a record *)
[@@deriving compare, equal, sexp]
type op2 =
| Eq (** Equal test *)
| Dq (** Disequal test *)
| Lt (** Less-than test *)
| Le (** Less-than-or-equal test *)
| Div (** Division, for integers result is truncated toward zero *)
| Rem
(** Remainder of division, satisfies [a = b * div a b + rem a b] and
for integers [rem a b] has same sign as [a], and [|rem a b| < |b|] *)
| Xor (** Exclusive-or, bitwise *)
| Shl (** Shift left, bitwise *)
| Lshr (** Logical shift right, bitwise *)
| Ashr (** Arithmetic shift right, bitwise *)
| Sized (** Size-tagged sequence *)
| Update of int (** Constant record with updated index *)
[@@deriving compare, equal, sexp]
type op3 =
| Conditional (** If-then-else *)
| Extract (** Extract a slice of an sequence value *)
[@@deriving compare, equal, sexp]
type opN =
| Concat (** Byte-array concatenation *)
| Record (** Record (array / struct) constant *)
[@@deriving compare, equal, sexp]
module rec Set : sig
include NS.Set.S with type elt := T.t
val t_of_sexp : Sexp.t -> t
end
and Qset : sig
include NS.Multiset.S with type mul := Q.t with type elt := T.t
val t_of_sexp : Sexp.t -> t
end
and T : sig
type set = Set.t [@@deriving compare, equal, sexp]
type qset = Qset.t [@@deriving compare, equal, sexp]
and t = private
| Var of {id: int; name: string}
(** Local variable / virtual register *)
| Ap1 of op1 * t (** Unary application *)
| Ap2 of op2 * t * t (** Binary application *)
| Ap3 of op3 * t * t * t (** Ternary application *)
| ApN of opN * t iarray (** N-ary application *)
| And of set (** Conjunction, boolean or bitwise *)
| Or of set (** Disjunction, boolean or bitwise *)
| Add of qset (** Sum of terms with rational coefficients *)
| Mul of qset (** Product of terms with rational exponents *)
| Integer of {data: Z.t} (** Integer constant *)
| Rational of {data: Q.t} (** Rational constant *)
| RecRecord of int (** Reference to ancestor recursive record *)
| Apply of Funsym.t * t iarray
(** Uninterpreted function application *)
| PosLit of Predsym.t * t iarray
| NegLit of Predsym.t * t iarray
[@@deriving compare, equal, sexp]
end
include module type of T with type t = T.t
(** Term.Var is re-exported as Var *)
module Var : sig
include Var_intf.VAR with type t = private T.t
val of_ : T.t -> t
(** [var (of_ e)] = [e] if [e] matches [Var _], otherwise undefined *)
val of_term : T.t -> t option
end
module Map : sig
include Map.S with type key := t
val t_of_sexp : (Sexp.t -> 'a) -> Sexp.t -> 'a t
end
val ppx : Var.strength -> t pp
val pp : t pp
val pp_diff : (t * t) pp
val invariant : t -> unit
(** Construct *)
(* variables *)
val var : Var.t -> t
(* constants *)
val bool : bool -> t
val true_ : t
val false_ : t
val integer : Z.t -> t
val zero : t
val one : t
val minus_one : t
val rational : Q.t -> t
(* type conversions *)
val signed : int -> t -> t
val unsigned : int -> t -> t
(* comparisons *)
val eq : t -> t -> t
val dq : t -> t -> t
val lt : t -> t -> t
val le : t -> t -> t
(* arithmetic *)
val neg : t -> t
val add : t -> t -> t
val sub : t -> t -> t
val mulq : Q.t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
val rem : t -> t -> t
(* boolean / bitwise *)
val and_ : t -> t -> t
val or_ : t -> t -> t
val not_ : t -> t
(* bitwise *)
val xor : t -> t -> t
val shl : t -> t -> t
val lshr : t -> t -> t
val ashr : t -> t -> t
(* if-then-else *)
val conditional : cnd:t -> thn:t -> els:t -> t
(* sequence sizes *)
val seq_size_exn : t -> t
val seq_size : t -> t option
(* sequences *)
val splat : t -> t
val sized : seq:t -> siz:t -> t
val extract : seq:t -> off:t -> len:t -> t
val concat : t array -> t
(* records (struct / array values) *)
val record : t iarray -> t
val select : rcd:t -> idx:int -> t
val update : rcd:t -> idx:int -> elt:t -> t
val rec_record : int -> t
(* uninterpreted *)
val apply : Funsym.t -> t iarray -> t
val poslit : Predsym.t -> t iarray -> t
val neglit : Predsym.t -> t iarray -> t
(** Destruct *)
val d_int : t -> Z.t option
(** Access *)
val const_of : t -> Q.t option
(** Transform *)
val map : t -> f:(t -> t) -> t
val map_rec_pre : t -> f:(t -> t option) -> t
(** Pre-order transformation. Each subterm [x] from root to leaves is
presented to [f]. If [f x = Some x'] then the subterms of [x] are not
traversed and [x] is transformed to [x']. Otherwise traversal proceeds
to the subterms of [x], followed by rebuilding the term structure on the
transformed subterms. *)
val fold_map : t -> 's -> f:(t -> 's -> t * 's) -> t * 's
val fold_map_rec_pre : t -> 's -> f:(t -> 's -> (t * 's) option) -> t * 's
val disjuncts : t -> t list
val rename : (Var.t -> Var.t) -> t -> t
(** Traverse *)
val iter : t -> f:(t -> unit) -> unit
val exists : t -> f:(t -> bool) -> bool
val fold : t -> 'a -> f:(t -> 'a -> 'a) -> 'a
val fold_vars : t -> 'a -> f:(Var.t -> 'a -> 'a) -> 'a
val fold_terms : t -> 'a -> f:(t -> 'a -> 'a) -> 'a
(** Query *)
val fv : t -> Var.Set.t
val is_true : t -> bool
val is_false : t -> bool
val is_constant : t -> bool
(** Test if a term's semantics is independent of the values of variables. *)
val height : t -> int
(** Solve *)
val solve_zero_eq : ?for_:t -> t -> (t * t) option
(** [solve_zero_eq d] is [Some (e, f)] if [d = 0] can be equivalently
expressed as [e = f] for some monomial subterm [e] of [d]. If [for_] is
passed, then the subterm [e] must be [for_]. *)

@ -1,10 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** Variables *)
include Term.Var

@ -1,10 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** Variables *)
include module type of Term.Var

@ -531,9 +531,7 @@ let and_ e q = star (pure e) q
let and_subst subst q =
[%Trace.call fun {pf} -> pf "%a@ %a" Context.Subst.pp subst pp q]
;
Context.Subst.fold
~f:(fun ~key ~data -> and_ (Formula.eq key data))
subst q
Context.Subst.fold_eqs ~f:and_ subst q
|>
[%Trace.retn fun {pf} q ->
pf "%a" pp q ;

@ -5,11 +5,12 @@
* LICENSE file in the root directory of this source tree.
*)
open Ses
open Sledge
open Fol
let%test_module _ =
( module struct
open Equality
open Context
let () = Trace.init ~margin:68 ()
@ -21,10 +22,10 @@ let%test_module _ =
* [@@@warning "-32"] *)
let printf pp = Format.printf "@\n%a@." pp
let pp = printf pp
let pp_classes = Format.printf "@\n@[<hv> %a@]@." pp_classes
let pp = printf Context.pp_raw
let pp_classes = Format.printf "@\n@[<hv> %a@]@." Context.pp
let ( ! ) i = Term.integer (Z.of_int i)
let g = Term.rem
let g x y = Term.apply (Uninterp "g") [|x; y|]
let wrt = Var.Set.empty
let t_, wrt = Var.fresh "t" ~wrt
let u_, wrt = Var.fresh "u" ~wrt
@ -42,10 +43,12 @@ let%test_module _ =
let z = Term.var z_
let of_eqs l =
List.fold ~f:(fun (a, b) (us, r) -> and_eq us a b r) l (wrt, true_)
List.fold
~f:(fun (a, b) (us, r) -> add us (Formula.eq a b) r)
l (wrt, empty)
|> snd
let implies_eq r a b = implies r (Term.eq a b)
let implies_eq r a b = implies r (Formula.eq a b)
(* tests *)
@ -56,8 +59,8 @@ let%test_module _ =
pp r3 ;
[%expect
{|
%t_1 = %u_2 = %v_3 = %w_4 = %x_5 = %z_7 = (%y_6 rem %t_1)
= (%y_6 rem %t_1)
%t_1 = %u_2 = %v_3 = %w_4 = %x_5 = %z_7 = g(%y_6, %t_1)
= g(%y_6, %t_1)
{sat= true;
rep= [[%t_1 ];
@ -67,22 +70,19 @@ let%test_module _ =
[%x_5 %t_1];
[%y_6 ];
[%z_7 %t_1];
[(%y_6 rem %v_3) %t_1];
[(%y_6 rem %z_7) %t_1];
[-1 ];
[0 ]]} |}]
[g(%y_6, %v_3) %t_1];
[g(%y_6, %z_7) %t_1]]} |}]
let%test _ = implies_eq r3 t z
let b = Term.dq x !0
let b = Formula.inject (Formula.dq x !0)
let r15 = of_eqs [(b, b); (x, !1)]
let%expect_test _ =
pp r15 ;
[%expect
{|
{sat= true; rep= [[%x_5 1]; [(%x_5 0) -1]; [-1 ]; [0 ]]} |}]
[%expect {|
{sat= true; rep= [[%x_5 1]]} |}]
let%test _ = implies_eq r15 b (Term.signed 1 !1)
let%test _ = implies_eq r15 (Term.unsigned 1 b) !1
let%test _ = implies_eq r15 (Term.neg b) (Term.apply (Signed 1) [|!1|])
let%test _ = implies_eq r15 (Term.apply (Unsigned 1) [|b|]) !1
end )

@ -16,7 +16,7 @@ let%test_module _ =
(* let () =
* Trace.init ~margin:160
* ~config:(Result.get_ok (Trace.parse "+Fol"))
* ~config:(Result.get_ok (Trace.parse "+Fol+Context+Arithmetic"))
* () *)
[@@@warning "-32"]
@ -43,8 +43,8 @@ let%test_module _ =
let x = Term.var x_
let y = Term.var y_
let z = Term.var z_
let f = Term.splat
let g = Term.mul
let f x = Term.apply (Uninterp "f") [|x|]
let g x y = Term.apply (Uninterp "g") [|x; y|]
let of_eqs l =
List.fold
@ -66,7 +66,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw f1 ;
[%expect {| {sat= false; rep= [[-1 ]; [0 ]]} |}]
[%expect {| {sat= false; rep= []} |}]
let%test _ = is_unsat (add_eq !1 !1 f1)
@ -76,7 +76,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw f2 ;
[%expect {| {sat= false; rep= [[-1 ]; [0 ]]} |}]
[%expect {| {sat= false; rep= []} |}]
let f3 = of_eqs [(x + !0, x + !1)]
@ -84,7 +84,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw f3 ;
[%expect {| {sat= false; rep= [[-1 ]; [0 ]]} |}]
[%expect {| {sat= false; rep= []} |}]
let f4 = of_eqs [(x, y); (x + !0, y + !1)]
@ -92,8 +92,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw f4 ;
[%expect
{| {sat= false; rep= [[%x_5 ]; [%y_6 %x_5]; [-1 ]; [0 ]]} |}]
[%expect {| {sat= false; rep= [[%x_5 ]; [%y_6 %x_5]]} |}]
let t1 = of_eqs [(!1, !1)]
@ -109,7 +108,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw r0 ;
[%expect {| {sat= true; rep= [[-1 ]; [0 ]]} |}]
[%expect {| {sat= true; rep= []} |}]
let%expect_test _ =
pp r0 ;
@ -128,7 +127,7 @@ let%test_module _ =
%x_5 = %y_6
{sat= true; rep= [[%x_5 ]; [%y_6 %x_5]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%x_5 ]; [%y_6 %x_5]]} |}]
let%test _ = implies_eq r1 x y
@ -139,15 +138,10 @@ let%test_module _ =
pp_raw r2 ;
[%expect
{|
%x_5 = %y_6 = %z_7 = %x_5^
%x_5 = %y_6 = %z_7 = f(%x_5)
{sat= true;
rep= [[%x_5 ];
[%y_6 %x_5];
[%z_7 %x_5];
[%x_5^ %x_5];
[-1 ];
[0 ]]} |}]
rep= [[%x_5 ]; [%y_6 %x_5]; [%z_7 %x_5]; [f(%x_5) %x_5]]} |}]
let%test _ = implies_eq r2 x z
let%test _ = implies_eq (inter r1 r2) x y
@ -168,13 +162,11 @@ let%test_module _ =
pp_raw rs ;
[%expect
{|
{sat= true;
rep= [[%w_4 ]; [%y_6 %w_4]; [%z_7 %w_4]; [-1 ]; [0 ]]}
{sat= true; rep= [[%w_4 ]; [%y_6 %w_4]; [%z_7 %w_4]]}
{sat= true;
rep= [[%x_5 ]; [%y_6 %x_5]; [%z_7 %x_5]; [-1 ]; [0 ]]}
{sat= true; rep= [[%x_5 ]; [%y_6 %x_5]; [%z_7 %x_5]]}
{sat= true; rep= [[%y_6 ]; [%z_7 %y_6]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%y_6 ]; [%z_7 %y_6]]} |}]
let%test _ =
let r = of_eqs [(w, y); (y, z)] in
@ -189,23 +181,21 @@ let%test_module _ =
pp_raw r3 ;
[%expect
{|
%z_7 = %u_2 = %v_3 = %w_4 = %x_5 = (%y_6 × %z_7)
(%y_6^2 × %z_7) = %t_1
%t_1 = %u_2 = %v_3 = %w_4 = %x_5 = %z_7 = g(%y_6, %t_1)
= g(%y_6, %t_1)
{sat= true;
rep= [[%t_1 (%y_6^2 × %z_7)];
[%u_2 %z_7];
[%v_3 %z_7];
[%w_4 %z_7];
[%x_5 %z_7];
rep= [[%t_1 ];
[%u_2 %t_1];
[%v_3 %t_1];
[%w_4 %t_1];
[%x_5 %t_1];
[%y_6 ];
[%z_7 ];
[(%y_6 × %z_7) %z_7];
[(%y_6^2 × %z_7) ];
[-1 ];
[0 ]]} |}]
[%z_7 %t_1];
[g(%y_6, %v_3) %t_1];
[g(%y_6, %z_7) %t_1]]} |}]
let%test _ = not (implies_eq r3 t z) (* incomplete *)
let%test _ = implies_eq r3 t z
let%test _ = implies_eq r3 x z
let%test _ = implies_eq (union r2 r3) x z
@ -219,12 +209,10 @@ let%test_module _ =
(-4 + %z_7) = %y_6 (3 + %z_7) = %w_4 (8 + %z_7) = %x_5
{sat= true;
rep= [[%w_4 (%z_7 + 3)];
[%x_5 (%z_7 + 8)];
[%y_6 (%z_7 + -4)];
[%z_7 ];
[-1 ];
[0 ]]} |}]
rep= [[%w_4 (3 + %z_7)];
[%x_5 (8 + %z_7)];
[%y_6 (-4 + %z_7)];
[%z_7 ]]} |}]
let%test _ = implies_eq r4 x (w + !5)
let%test _ = difference r4 x w |> Poly.equal (Some (Z.of_int 5))
@ -242,7 +230,7 @@ let%test_module _ =
{|
1 = %x_5 = %y_6
{sat= true; rep= [[%x_5 1]; [%y_6 1]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%x_5 1]; [%y_6 1]]} |}]
let%test _ = implies_eq r6 x y
@ -251,8 +239,6 @@ let%test_module _ =
let%expect_test _ =
pp r7 ;
pp_raw r7 ;
pp_raw (add_eq x z r7) ;
pp (add_eq x z r7) ;
[%expect
{|
%v_3 = %x_5 %w_4 = %y_6 = %z_7
@ -262,32 +248,7 @@ let%test_module _ =
[%w_4 ];
[%x_5 %v_3];
[%y_6 %w_4];
[%z_7 %w_4];
[-1 ];
[0 ]]}
{sat= true;
rep= [[%v_3 ];
[%w_4 %v_3];
[%x_5 %v_3];
[%y_6 %v_3];
[%z_7 %v_3];
[-1 ];
[0 ]]}
%v_3 = %w_4 = %x_5 = %y_6 = %z_7 |}]
let%expect_test _ =
printf (List.pp " , " Term.pp) (class_of r7 t) ;
printf (List.pp " , " Term.pp) (class_of r7 x) ;
printf (List.pp " , " Term.pp) (class_of r7 z) ;
[%expect
{|
%t_1
%v_3 , %x_5
%w_4 , %z_7 , %y_6 |}]
[%z_7 %w_4]]} |}]
let r7' = add_eq x z r7
@ -303,9 +264,7 @@ let%test_module _ =
[%w_4 %v_3];
[%x_5 %v_3];
[%y_6 %v_3];
[%z_7 %v_3];
[-1 ];
[0 ]]} |}]
[%z_7 %v_3]]} |}]
let%test _ = normalize r7' w |> Term.equal v
@ -324,8 +283,7 @@ let%test_module _ =
{|
14 = %y_6 13×%z_7 = %x_5
{sat= true;
rep= [[%x_5 (13 × %z_7)]; [%y_6 14]; [%z_7 ]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%x_5 13×%z_7]; [%y_6 14]; [%z_7 ]]} |}]
let%test _ = implies_eq r8 y !14
@ -336,11 +294,9 @@ let%test_module _ =
pp_raw r9 ;
[%expect
{|
{sat= true;
rep= [[%x_5 (%z_7 + -16)]; [%z_7 ]; [-1 ]; [0 ]]}
{sat= true; rep= [[%x_5 (-16 + %z_7)]; [%z_7 ]]}
{sat= true;
rep= [[%x_5 (%z_7 + -16)]; [%z_7 ]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%x_5 (-16 + %z_7)]; [%z_7 ]]} |}]
let%test _ = difference r9 z (x + !8) |> Poly.equal (Some (Z.of_int 8))
@ -355,11 +311,9 @@ let%test_module _ =
Format.printf "@.%a@." Term.pp (normalize r10 (x + !8 - z)) ;
[%expect
{|
{sat= true;
rep= [[%x_5 (%z_7 + -16)]; [%z_7 ]; [-1 ]; [0 ]]}
{sat= true; rep= [[%x_5 (-16 + %z_7)]; [%z_7 ]]}
{sat= true;
rep= [[%x_5 (%z_7 + -16)]; [%z_7 ]; [-1 ]; [0 ]]}
{sat= true; rep= [[%x_5 (-16 + %z_7)]; [%z_7 ]]}
(-8 + -1×%x_5 + %z_7)
@ -394,8 +348,7 @@ let%test_module _ =
let%expect_test _ =
pp_raw r13 ;
[%expect
{| {sat= true; rep= [[%y_6 ]; [%z_7 %y_6]; [-1 ]; [0 ]]} |}]
[%expect {| {sat= true; rep= [[%y_6 ]; [%z_7 %y_6]]} |}]
let%test _ = not (is_unsat r13) (* incomplete *)
@ -404,9 +357,8 @@ let%test_module _ =
let%expect_test _ =
pp_raw r14 ;
[%expect
{|
{sat= true; rep= [[%x_5 1]; [-1 ]; [0 ]]} |}]
[%expect {|
{sat= true; rep= [[%x_5 1]]} |}]
let%test _ = implies_eq r14 a (Formula.inject Formula.tt)
@ -415,15 +367,8 @@ let%test_module _ =
let%expect_test _ =
pp_raw r14 ;
[%expect
{|
{sat= true;
rep= [[%x_5 1];
[%y_6 ];
[(%x_5 = 0) 0];
[(%y_6 = 0) 0];
[-1 ];
[0 ]]} |}]
[%expect {|
{sat= true; rep= [[%x_5 1]]} |}]
let%test _ = implies_eq r14 a (Formula.inject Formula.tt)
(* incomplete *)
@ -434,9 +379,8 @@ let%test_module _ =
let%expect_test _ =
pp_raw r15 ;
[%expect
{|
{sat= true; rep= [[%x_5 1]; [-1 ]; [0 ]]} |}]
[%expect {|
{sat= true; rep= [[%x_5 1]]} |}]
(* f(x1)1=x+1, f(y)+1=y1, y+1=x ⊢ false *)
let r16 =
@ -447,12 +391,10 @@ let%test_module _ =
[%expect
{|
{sat= false;
rep= [[%x_5 (%y_6 + 1)];
rep= [[%x_5 (1 + %y_6)];
[%y_6 ];
[%y_6^ (%y_6 + -2)];
[(%x_5 + -1)^ (%y_6 + 3)];
[-1 ];
[0 ]]} |}]
[f(%y_6) (-2 + %y_6)];
[f((-1 + %x_5)) (3 + %y_6)]]} |}]
let%test _ = is_unsat r16
@ -466,10 +408,8 @@ let%test_module _ =
{sat= false;
rep= [[%x_5 ];
[%y_6 %x_5];
[%x_5^ %x_5];
[%y_6^ (%x_5 + -1)];
[-1 ];
[0 ]]} |}]
[f(%x_5) %x_5];
[f(%y_6) (-1 + %x_5)]]} |}]
let%test _ = is_unsat r17
@ -482,12 +422,10 @@ let%test_module _ =
{sat= true;
rep= [[%x_5 ];
[%y_6 ];
[%x_5^ %x_5];
[%y_6^ (%y_6 + -1)];
[-1 ];
[0 ]]}
[f(%x_5) %x_5];
[f(%y_6) (-1 + %y_6)]]}
%x_5 = %x_5^ (-1 + %y_6) = %y_6^ |}]
%x_5 = f(%x_5) (-1 + %y_6) = f(%y_6) |}]
let r19 = of_eqs [(x, y + z); (x, !0); (y, !0)]
@ -495,9 +433,10 @@ let%test_module _ =
pp_raw r19 ;
[%expect
{|
{sat= true;
rep= [[%x_5 0]; [%y_6 0]; [%z_7 0]; [-1 ]; [0 ]]} |}]
{sat= true; rep= [[%x_5 0]; [%y_6 0]; [%z_7 0]]} |}]
let%test _ = implies_eq r19 x !0
let%test _ = implies_eq r19 y !0
let%test _ = implies_eq r19 z !0
let%expect_test _ =

@ -15,9 +15,11 @@ let%test_module _ =
let () = Trace.init ~margin:68 ()
(* let () =
* Trace.init ~margin:160 ~config:(Result.get_ok (Trace.parse "+Sh")) ()
*
* [@@@warning "-32"] *)
* Trace.init ~margin:160
* ~config:(Result.get_ok (Trace.parse "+Sh+Context+Arithmetic"))
* () *)
[@@@warning "-32"]
let pp = Format.printf "@\n%a@." pp
let pp_raw = Format.printf "@\n%a@." pp_raw

@ -19,9 +19,9 @@ let%test_module _ =
* Trace.init ~margin:160
* ~config:
* (Result.get_ok (Trace.parse "+Solver.infer_frame+Solver.excise"))
* ()
*
* [@@@warning "-32"] *)
* () *)
[@@@warning "-32"]
let infer_frame p xs q =
Solver.infer_frame p (Var.Set.of_list xs) q

@ -5,7 +5,10 @@
* LICENSE file in the root directory of this source tree.
*)
open Ses
open Sledge
open Fol
module T = Term
module F = Formula
(* [@@@warning "-32"] *)
@ -15,46 +18,48 @@ let%test_module _ =
(* let () = Trace.init ~margin:68 ~config:Trace.all () *)
open Term
let pp = Format.printf "@\n%a@." pp
let ( ! ) i = integer (Z.of_int i)
let ( + ) = add
let ( - ) = sub
let ( * ) = mul
let ( = ) = eq
let ( != ) = dq
let ( < ) = lt
let ( <= ) = le
let ( && ) = and_
let ( || ) = or_
let ( ~~ ) = not_
let pp = Format.printf "@\n%a@." T.pp
let ppf = Format.printf "@\n%a@." F.pp
let ( ! ) i = T.integer (Z.of_int i)
let ( + ) = T.add
let ( - ) = T.sub
let ( * ) = T.mul
let ( = ) = F.eq
let ( != ) = F.dq
let ( < ) = F.lt
let ( <= ) = F.le
let ( && ) = F.and_
let ( || ) = F.or_
let ( ~~ ) = F.not_
let wrt = Var.Set.empty
let y_, wrt = Var.fresh "y" ~wrt
let z_, _ = Var.fresh "z" ~wrt
let y = var y_
let z = var z_
let y = T.var y_
let z = T.var z_
let%test "booleans distinct" = is_false (true_ = false_)
let%test "u1 values distinct" = is_false (one = zero)
let%test "boolean overflow" = is_true (minus_one = signed 1 one)
let%test _ = is_true (one = unsigned 1 minus_one)
let%test "booleans distinct" = F.equal F.ff (F.iff F.tt F.ff)
let%test "u1 values distinct" = F.equal F.ff (T.one = T.zero)
let%test "boolean overflow" =
F.equal F.tt (!(-1) = T.apply (Signed 1) [|!1|])
let%test _ = F.equal F.tt (T.one = T.apply (Unsigned 1) [|!(-1)|])
let%expect_test _ =
pp (!42 + !13) ;
[%expect {| 55 |}]
let%expect_test _ =
pp (!(-128) && !127) ;
pp (T.apply BitAnd [|!(-128); !127|]) ;
[%expect {| 0 |}]
let%expect_test _ =
pp (!(-128) || !127) ;
pp (T.apply BitOr [|!(-128); !127|]) ;
[%expect {| -1 |}]
let%expect_test _ =
pp (z + !42 + !13) ;
[%expect {| (%z_2 + 55) |}]
[%expect {| (55 + %z_2) |}]
let%expect_test _ =
pp (z + !42 + !(-42)) ;
@ -70,7 +75,7 @@ let%test_module _ =
let%expect_test _ =
pp ((!2 * z * z) + (!3 * z) + !4) ;
[%expect {| (3 × %z_2 + 2 × (%z_2^2) + 4) |}]
[%expect {| (4 + 3×%z_2 + 2×%z_2^2) |}]
let%expect_test _ =
pp
@ -85,9 +90,8 @@ let%test_module _ =
+ (!9 * z * z * z) ) ;
[%expect
{|
(3 × %y_1 + 2 × %z_2 + 6 × (%y_1 × %z_2) + 8 × (%y_1 × %z_2^2)
+ 5 × (%y_1^2) + 7 × (%y_1^2 × %z_2) + 4 × (%z_2^2) + 9 × (%z_2^3)
+ 1) |}]
(1 + 3×%y_1 + 6×(%y_1 × %z_2) + 8×(%y_1 × %z_2^2) + 5×%y_1^2
+ 7×(%y_1^2 × %z_2) + 2×%z_2 + 4×%z_2^2 + 9×%z_2^3) |}]
let%expect_test _ =
pp (!0 * z * y) ;
@ -99,15 +103,15 @@ let%test_module _ =
let%expect_test _ =
pp (!7 * z * (!2 * y)) ;
[%expect {| (14 × (%y_1 × %z_2)) |}]
[%expect {| 14×(%y_1 × %z_2) |}]
let%expect_test _ =
pp (!13 + (!42 * z)) ;
[%expect {| (42 × %z_2 + 13) |}]
[%expect {| (13 + 42×%z_2) |}]
let%expect_test _ =
pp ((!13 * z) + !42) ;
[%expect {| (13 × %z_2 + 42) |}]
[%expect {| (42 + 13×%z_2) |}]
let%expect_test _ =
pp ((!2 * z) - !3 + ((!(-2) * z) + !3)) ;
@ -115,23 +119,23 @@ let%test_module _ =
let%expect_test _ =
pp ((!3 * y) + (!13 * z) + !42) ;
[%expect {| (3 × %y_1 + 13 × %z_2 + 42) |}]
[%expect {| (42 + 3×%y_1 + 13×%z_2) |}]
let%expect_test _ =
pp ((!13 * z) + !42 + (!3 * y)) ;
[%expect {| (3 × %y_1 + 13 × %z_2 + 42) |}]
[%expect {| (42 + 3×%y_1 + 13×%z_2) |}]
let%expect_test _ =
pp ((!13 * z) + !42 + (!3 * y) + (!2 * z)) ;
[%expect {| (3 × %y_1 + 15 × %z_2 + 42) |}]
[%expect {| (42 + 3×%y_1 + 15×%z_2) |}]
let%expect_test _ =
pp ((!13 * z) + !42 + (!3 * y) + (!(-13) * z)) ;
[%expect {| (3 × %y_1 + 42) |}]
[%expect {| (42 + 3×%y_1) |}]
let%expect_test _ =
pp (z + !42 + ((!3 * y) + (!(-1) * z))) ;
[%expect {| (3 × %y_1 + 42) |}]
[%expect {| (42 + 3×%y_1) |}]
let%expect_test _ =
pp (!(-1) * (z + (!(-1) * y))) ;
@ -139,7 +143,7 @@ let%test_module _ =
let%expect_test _ =
pp (((!3 * y) + !2) * (!4 + (!5 * z))) ;
[%expect {| (12 × %y_1 + 10 × %z_2 + 15 × (%y_1 × %z_2) + 8) |}]
[%expect {| ((2 + 3×%y_1) × (4 + 5×%z_2)) |}]
let%expect_test _ =
pp (((!2 * z) - !3 + ((!(-2) * z) + !3)) * (!4 + (!5 * z))) ;
@ -147,112 +151,111 @@ let%test_module _ =
let%expect_test _ =
pp ((!13 * z) + !42 - ((!3 * y) + (!13 * z))) ;
[%expect {| (-3 × %y_1 + 42) |}]
[%expect {| (42 + -3×%y_1) |}]
let%expect_test _ =
pp (z = y) ;
ppf (z = y) ;
[%expect {| (%y_1 = %z_2) |}]
let%expect_test _ =
pp (z = z) ;
[%expect {| -1 |}]
ppf (z = z) ;
[%expect {| tt |}]
let%expect_test _ =
pp (z != z) ;
[%expect {| 0 |}]
ppf (z != z) ;
[%expect {| ff |}]
let%expect_test _ =
pp (!1 = !0) ;
[%expect {| 0 |}]
ppf (!1 = !0) ;
[%expect {| ff |}]
let%expect_test _ =
pp (!3 * y = z = true_) ;
[%expect {| (%z_2 = (3 × %y_1)) |}]
ppf (F.iff (!3 * y = z) F.tt) ;
[%expect {| (3×%y_1 = %z_2) |}]
let%expect_test _ =
pp (true_ = (!3 * y = z)) ;
[%expect {| (%z_2 = (3 × %y_1)) |}]
ppf (F.iff F.tt (!3 * y = z)) ;
[%expect {| (3×%y_1 = %z_2) |}]
let%expect_test _ =
pp (!3 * y = z = false_) ;
[%expect {| (%z_2 (3 × %y_1)) |}]
ppf (F.iff (!3 * y = z) F.ff) ;
[%expect {| (3×%y_1 %z_2) |}]
let%expect_test _ =
pp (false_ = (!3 * y = z)) ;
[%expect {| (%z_2 (3 × %y_1)) |}]
ppf (F.iff F.ff (!3 * y = z)) ;
[%expect {| (3×%y_1 %z_2) |}]
let%expect_test _ =
pp (y - (!(-3) * y) + !4) ;
[%expect {| (4 × %y_1 + 4) |}]
[%expect {| (4 + 4×%y_1) |}]
let%expect_test _ =
pp ((!(-3) * y) + !4 - y) ;
[%expect {| (-4 × %y_1 + 4) |}]
[%expect {| (4 + -4×%y_1) |}]
let%expect_test _ =
pp (y = (!(-3) * y) + !4) ;
[%expect {| (%y_1 = (-3 × %y_1 + 4)) |}]
ppf (y = (!(-3) * y) + !4) ;
[%expect {| (4 = 4×%y_1) |}]
let%expect_test _ =
pp ((!(-3) * y) + !4 = y) ;
[%expect {| (%y_1 = (-3 × %y_1 + 4)) |}]
ppf ((!(-3) * y) + !4 = y) ;
[%expect {| (4 = 4×%y_1) |}]
let%expect_test _ =
pp (sub true_ (z = !4)) ;
[%expect {| (-1 × (%z_2 = 4) + -1) |}]
pp (T.sub (F.inject F.tt) (F.inject (z = !4))) ;
[%expect {| ((4 = %z_2) ? 0 : 1) |}]
let%expect_test _ =
pp (add true_ (z = !4) = (z = !4)) ;
[%expect {| ((%z_2 = 4) = ((%z_2 = 4) + -1)) |}]
pp (T.add (F.inject F.tt) (F.inject (F.iff (z = !4) (z = !4)))) ;
[%expect {| 2 |}]
let%expect_test _ =
pp ((!13 * z) + !42 = (!3 * y) + (!13 * z)) ;
[%expect {| ((3 × %y_1 + 13 × %z_2) = (13 × %z_2 + 42)) |}]
ppf ((!13 * z) + !42 = (!3 * y) + (!13 * z)) ;
[%expect {| (42 = 3×%y_1) |}]
let%expect_test _ =
pp ((!13 * z) + !(-42) = (!3 * y) + (!13 * z)) ;
[%expect {| ((3 × %y_1 + 13 × %z_2) = (13 × %z_2 + -42)) |}]
ppf ((!13 * z) + !(-42) = (!3 * y) + (!13 * z)) ;
[%expect {| (-42 = 3×%y_1) |}]
let%expect_test _ =
pp ((!13 * z) + !42 = (!(-3) * y) + (!13 * z)) ;
[%expect {| ((-3 × %y_1 + 13 × %z_2) = (13 × %z_2 + 42)) |}]
ppf ((!13 * z) + !42 = (!(-3) * y) + (!13 * z)) ;
[%expect {| (-42 = 3×%y_1) |}]
let%expect_test _ =
pp ((!10 * z) + !42 = (!(-3) * y) + (!13 * z)) ;
[%expect {| ((-3 × %y_1 + 13 × %z_2) = (10 × %z_2 + 42)) |}]
ppf ((!10 * z) + !42 = (!(-3) * y) + (!13 * z)) ;
[%expect {| ((42 + 3×%y_1) = 3×%z_2) |}]
let%expect_test _ =
pp ~~((!13 * z) + !(-42) != (!3 * y) + (!13 * z)) ;
[%expect {| ((3 × %y_1 + 13 × %z_2) = (13 × %z_2 + -42)) |}]
ppf ~~((!13 * z) + !(-42) != (!3 * y) + (!13 * z)) ;
[%expect {| (-42 = 3×%y_1) |}]
let%expect_test _ =
pp ~~(!2 < y && z <= !3) ;
[%expect {| ((3 < %z_2) || (%y_1 2)) |}]
ppf ~~(!2 < y && z <= !3) ;
[%expect {| ((3 < %z_2) (2 %y_1)) |}]
let%expect_test _ =
pp ~~(!2 <= y || z < !3) ;
[%expect {| ((%y_1 < 2) && (3 %z_2)) |}]
ppf ~~(!2 <= y || z < !3) ;
[%expect {| ((2 > %y_1) (3 %z_2)) |}]
let%expect_test _ =
pp (eq z zero) ;
pp (eq zero z) ;
pp (dq (eq zero z) false_) ;
ppf (F.eq z T.zero) ;
ppf (F.eq T.zero z) ;
ppf (F.xor (F.eq T.zero z) F.ff) ;
[%expect
{|
(%z_2 = 0)
(0 = %z_2)
(%z_2 = 0)
(0 = %z_2)
(%z_2 = 0) |}]
(0 = %z_2) |}]
let%expect_test _ =
let z1 = z + !1 in
let z1_2 = z1 * z1 in
pp z1_2 ;
pp (z1_2 * z1_2) ;
[%expect
{|
(2 × %z_2 + (%z_2^2) + 1)
[%expect {|
(1 + %z_2)^2
(4 × %z_2 + 6 × (%z_2^2) + 4 × (%z_2^3) + (%z_2^4) + 1) |}]
(1 + %z_2)^4 |}]
end )

Loading…
Cancel
Save