aboutsummaryrefslogtreecommitdiffstats
path: root/src/lfsc/converter.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/lfsc/converter.ml')
-rw-r--r--src/lfsc/converter.ml1302
1 files changed, 1302 insertions, 0 deletions
diff --git a/src/lfsc/converter.ml b/src/lfsc/converter.ml
new file mode 100644
index 0000000..d586e37
--- /dev/null
+++ b/src/lfsc/converter.ml
@@ -0,0 +1,1302 @@
+(**************************************************************************)
+(* *)
+(* SMTCoq *)
+(* Copyright (C) 2011 - 2019 *)
+(* *)
+(* See file "AUTHORS" for the list of authors *)
+(* *)
+(* This file is distributed under the terms of the CeCILL-C licence *)
+(* *)
+(**************************************************************************)
+
+
+open Ast
+open Builtin
+open Format
+open Translator_sig
+
+
+module Make (T : Translator_sig.S) = struct
+
+ open T
+
+ module MTerm = Map.Make (Term)
+
+
+ (** Environment for {!lem} *)
+ type env = {
+ clauses : int list; (** Accumulated clauses *)
+ ax : bool; (** Force use of axiomatic rules? *)
+ mpred : bool MTerm.t; (** map for positivity of predicates in cong *)
+ assum : Hstring.t list; (** Assumptions that were not used *)
+ }
+
+
+ (** Empty environment *)
+ let empty = {
+ clauses = [];
+ ax = false;
+ mpred = MTerm.empty;
+ assum = [];
+ }
+
+
+ (** Returns the formula of which p is a proof of *)
+ let th_res p = match app_name (deref p).ttype with
+ | Some (n, [r]) when n == H.th_holds -> r
+ | _ -> assert false
+
+
+ (** Ignore declarations at begining of proof *)
+ let rec ignore_all_decls p = match value p with
+ | Lambda (s, p) -> ignore_all_decls p
+ | _ -> p
+
+
+ (** Ignore declarations but keep assumptions *)
+ let rec ignore_decls p = match value p with
+ | Lambda (s, pr) ->
+ (match s.sname with
+ | Name n when (Hstring.view n).[0] = 'A' -> p
+ | _ -> ignore_decls pr
+ )
+ | _ -> p
+
+
+ (** Ignore result of preprocessing *)
+ let rec ignore_preproc p = match app_name p with
+ | Some (n, [_; _; p]) when n == H.th_let_pf ->
+ begin match value p with
+ | Lambda (_, p) -> ignore_preproc p
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+ (** Produce input clauses from the result of CVC4's pre-processing. This may
+ not match the actual inputs in the original SMT2 file but they correspond
+ to what the proof uses. *)
+ let rec produce_inputs_preproc p = match app_name p with
+ | Some (n, [_; _; p]) when n == H.th_let_pf ->
+ begin match value p with
+ | Lambda ({sname = Name h; stype}, p) ->
+ begin match app_name stype with
+ | Some (n, [formula]) when n == H.th_holds ->
+ mk_input h formula;
+ produce_inputs_preproc p
+ | _ -> assert false
+ end
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+ (** Produce inputs from the assumptions *)
+ let rec produce_inputs p = match value p with
+ | Lambda ({sname = Name h; stype}, p) ->
+ begin match app_name stype with
+ | Some (n, [formula])
+ when n == H.th_holds &&
+ (match name formula with
+ | Some f when f == H.ttrue -> false | _ -> true)
+ ->
+ mk_input h formula;
+ produce_inputs p
+ | _ -> produce_inputs p
+ end
+ | _ -> p
+
+
+ let dvar_of_v t = match app_name t with
+ | Some (n, [_; v]) when n == H.a_var_bv -> v
+ | _ -> t
+
+
+ let trust_vareq_as_alias formula = match app_name formula with
+ | Some (n, [ty; alias; t]) when n == H.eq ->
+ (match name (dvar_of_v alias) with
+ | Some n -> register_alias n t; true
+ | None -> false)
+ | _ -> false
+
+
+ let rec admit_preproc p = match app_name p with
+ | Some (n, [_; tr; p]) when n == H.th_let_pf ->
+ begin match app_name tr with
+ | Some (n, _) when n == H.trust_f ->
+ eprintf "Warning: hole for trust_f.@."
+ | Some (rule, _) ->
+ eprintf "Warning: hole for unsupported rule %a.@." Hstring.print rule
+ | None -> eprintf "Warning: hole@."
+ end;
+ let formula = th_res tr in
+ begin match value p with
+ | Lambda ({sname = Name h}, p) ->
+ if not (trust_vareq_as_alias formula) then
+ mk_admit_preproc h formula;
+ admit_preproc p
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+
+ (** Handle deferred declarations in LFSC (for extensionality rule atm.) *)
+ let rec deferred p = match app_name p with
+ | Some (n, [ty_i; ty_e; a; b; p]) when n == H.ext ->
+ begin match value p with
+ | Lambda ({sname = Name index_diff}, p) ->
+ begin match value p with
+ | Lambda ({sname = Name h}, p) ->
+ let diff_a_b = (apply_diff ty_i ty_e a b) in
+ register_alias index_diff diff_a_b;
+ let f =
+ or_ (eq (array ty_i ty_e) a b)
+ (not_ (eq ty_e
+ (apply_read ty_i ty_e a diff_a_b)
+ (apply_read ty_i ty_e b diff_a_b))) in
+ let cid = mk_clause_cl Exte [f] [] in
+ register_decl_id h cid;
+ deferred p
+ | _ -> assert false
+ end
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+
+ (** Registers a propositional variable as an abstraction for a
+ formula. Proofs in SMTCoq have to be given in terms of formulas. *)
+ let rec register_prop_vars p = match app_name p with
+ | Some (n, [formula; p]) when n == H.decl_atom ->
+ begin match value p with
+ | Lambda (v, p) ->
+ let vt = (symbol_to_const v) in
+ (* eprintf "register prop var: %a@." print_term_type vt; *)
+ register_prop_abstr vt formula;
+ begin match value p with
+ | Lambda (_, p) -> register_prop_vars p
+ | _ -> assert false
+ end
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+ (** Returns the name of the local assumptions made in [satlem] *)
+ let rec get_assumptions acc p = match app_name p with
+ | Some (n, [_; _; _; _; p]) when n == H.ast || n == H.asf ->
+ begin match value p with
+ | Lambda ({sname = Name n}, p) -> get_assumptions (n :: acc) p
+ | _ -> assert false
+ end
+ | _ -> acc, p
+
+
+
+ let rec rm_used' assumptions t = match name t with
+ | Some x -> List.filter (fun y -> y != x) assumptions
+ | None -> match app_name t with
+ | Some (_, l) -> List.fold_left rm_used' assumptions l
+ | None -> assumptions
+
+ (** Remove used assumptions from the environment *)
+ let rm_used env t = { env with assum = rm_used' env.assum t }
+
+
+ let rm_duplicates eq l =
+ let rec aux acc = function
+ | x :: r -> if List.exists (eq x) acc then aux acc r else aux (x :: acc) r
+ | [] -> acc in
+ aux [] (List.rev l)
+
+ (** Create an intermediate resolution step in [satlem] with the accumulated
+ clauses. {!Reso} ignores the resulting clause so we can just give the
+ empty clause here. *)
+ let mk_inter_resolution clauses = match clauses with
+ | [] -> (* not false *)
+ mk_clause_cl Fals [not_ tfalse] []
+ (* assert false *)
+ | [id] -> id
+ | _ -> mk_clause ~reuse:false Reso [] clauses
+
+
+
+ let is_ty_Bool ty = match name ty with
+ | Some n -> n == H.tBool
+ | _ -> false
+
+
+ (** Accumulates equalities for congruence. This is useful for when [f] takes
+ multiples arguments. *)
+ let rec cong neqs env p = match app_name p with
+ | Some (n, [ty; rty; f; f'; x; y; p_f_eq_f'; r]) when n == H.cong ->
+
+ let ne = not_ (eq ty x y) in
+ let neqs, env =
+ if List.exists (Term.equal ne) neqs then neqs, env
+ else ne :: neqs, lem env r in
+
+ begin match name f, name f' with
+ | Some n, Some n' when n == n' -> neqs, env
+ | None, None -> cong neqs env p_f_eq_f'
+ | _ -> assert false
+ end
+
+ | Some (n, [_; _; _; r])
+ when n == H.symm || n == H.negsymm ->
+ cong neqs (rm_used env r) r
+
+ (* | Some (n, [t; x; y; z; r1; r2]) when n == H.trans *)
+ (* | Some (n, [t; x; z; y; r1; r2]) when n == H.negtrans || n == H.negtrans1 *)
+ (* | Some (n, [t; y; x; z; r1; r2]) when n == H.negtrans2 *)
+
+ | Some (n, [t; x1; x2; x3; r1; r2])
+ when n == H.trans || n == H.negtrans ||
+ n == H.negtrans1 || n == H.negtrans2 ->
+
+ let x, y, z =
+ if n == H.trans then x1, x2, x3
+ else if n == H.negtrans || n == H.negtrans1 then x1, x3, x2
+ else if n == H.negtrans2 then x2, x1, x3
+ else assert false
+ in
+
+ (* ignore useless transitivity *)
+ if term_equal x z then
+ match app_name x with
+ | Some (n, [t; _; _; x]) when n == H.apply ->
+ let x_x = eq t x x in
+ not_ x_x :: neqs,
+ { env with clauses = mk_clause_cl Eqre [x_x] [] :: env.clauses }
+ | _ ->
+ let x_x = eq t x x in
+ not_ x_x :: neqs,
+ { env with clauses = mk_clause_cl Eqre [x_x] [] :: env.clauses }
+ else if term_equal x y then cong neqs (rm_used env r2) r2
+ else if term_equal y z then cong neqs (rm_used env r1) r1
+ else
+ let neqs1, env1 = cong neqs (rm_used env r1) r1 in
+ cong neqs1 (rm_used env1 r2) r2
+
+ (* | Some ("refl", [_; r]) -> neqs, rm_used env r *)
+
+ | _ -> neqs, env
+ (* eprintf "something went wrong in congruence@."; *)
+ (* neqs, lem env p (\* env *\) *)
+
+
+ (** Accumulates equalities for transitivity to chain them together. *)
+ and trans neqs env p = match app_name p with
+
+ | Some (n, [ty; x; y; z; p1; p2]) when n == H.trans ->
+ (* | Some (("negtrans"|"negtrans1") as r, [ty; x; z; y; p1; p2]) *)
+ (* | Some ("negtrans2" as r, [ty; y; x; z; p1; p2]) *)
+
+ let merge = true in
+
+ (* let clauses = lem mpred assum (lem mpred assum clauses p1) p2 in *)
+
+ (* let x_y = th_res p1 in *)
+ (* let y_z = th_res p2 in *)
+ (* let x_y = match r with "negtrans2" -> eq ty y x | _ -> eq ty x y in *)
+ (* let y_z = match r with "negtrans"|"negtrans1" -> eq ty z y | _ -> eq ty y z in *)
+ let n_x_y = not_ (eq ty x y) in
+ let n_y_z = not_ (eq ty y z) in
+
+ let neqs2, env = if merge then trans neqs env p2 else [], lem env p2 in
+ let neqs1, env = if merge then trans neqs env p1 else [], lem env p1 in
+
+ let neqs = match neqs1, neqs2 with
+ | [], [] -> [n_x_y; n_y_z]
+ | [], _ -> n_x_y :: neqs2
+ | _, [] -> neqs1 @ [n_y_z]
+ | _, _ -> neqs1 @ neqs2
+ in
+
+ (* rm_duplicates Term.equal neqs *)
+ neqs, env
+
+ | Some (n, [_; _; _; r]) when n == H.symm || n == H.negsymm ->
+ let neqs, env = trans neqs (rm_used env r) r in
+ List.rev neqs, env
+
+ | Some (n, [_; r]) when n == H.refl -> neqs, rm_used env r
+
+ | _ -> neqs, lem env p
+
+
+
+
+ (** Convert the local proof of a [satlem]. We use decductive style rules when
+ possible but revert to axiomatic ones when the context forces us to. *)
+ and lem ?(toplevel=false) env p = match app_name p with
+ | Some (n, [l1; l2; x; r])
+ when (n == H.or_elim_1 || n == H.or_elim_2) &&
+ (match app_name r with
+ | Some (n, _) -> n == H.iff_elim_1 || n == H.iff_elim_2
+ | _ -> false)
+ ->
+
+ let el, rem = if n == H.or_elim_1 then l1, l2 else l2, l1 in
+
+ let env = lem env r in
+ let env = lem env x in
+ (match env.clauses with
+ | ci1 :: ci2 :: cls ->
+ { env with clauses = mk_clause_cl Reso [rem] [ci1; ci2] :: cls }
+ | _ -> env
+ )
+
+ | Some (n, [_; _; x; r])
+ when (n == H.or_elim_1 || n == H.or_elim_2) &&
+ (match app_name r with
+ | Some (n, _) -> n == H.impl_elim ||
+ n == H.not_and_elim ||
+ n == H.iff_elim_1 ||
+ n == H.iff_elim_2 ||
+ n == H.xor_elim_1 ||
+ n == H.xor_elim_2 ||
+ n == H.ite_elim_1 ||
+ n == H.ite_elim_2 ||
+ n == H.ite_elim_3 ||
+ n == H.not_ite_elim_1 ||
+ n == H.not_ite_elim_2 ||
+ n == H.not_ite_elim_3
+ | _ -> false)
+ ->
+ let env = rm_used env x in
+ let env = lem env r in
+ { env with ax = true }
+
+ | Some (n, [a; b; x; r]) when n == H.or_elim_1 || n == H.or_elim_2 ->
+ let env = rm_used env x in
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax -> mk_clause_cl Or [a; b] env.clauses :: []
+ | _ ->
+ let a_or_b = th_res r in
+ mk_clause_cl Orp [not_ a_or_b; a; b] [] :: env.clauses
+ in
+ { env with clauses; ax = true }
+
+ | Some (n, [a; b; r]) when n == H.impl_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax -> mk_clause_cl Imp [not_ a; b] env.clauses :: []
+ | _ ->
+ let a_impl_b = th_res r in
+ mk_clause_cl Impp [not_ a_impl_b; not_ a; b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; r]) when n == H.xor_elim_1 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Xor2 [not_ a; not_ b] env.clauses :: []
+ | _ ->
+ let a_xor_b = xor_ a b in
+ mk_clause_cl Xorp2 [not_ a_xor_b; not_ a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; r]) when n == H.xor_elim_2 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Xor1 [a; b] env.clauses :: []
+ | _ ->
+ let a_xor_b = xor_ a b in
+ mk_clause_cl Xorp1 [not_ a_xor_b; a; b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; c; r]) when n == H.ite_elim_1 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Ite2 [not_ a; b] env.clauses :: []
+ | _ ->
+ let ite_a_b_c = ifte_ a b c in
+ mk_clause_cl Itep2 [not_ ite_a_b_c; not_ a; b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; c; r]) when n == H.ite_elim_2 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Ite1 [a; c] env.clauses :: []
+ | _ ->
+ let ite_a_b_c = ifte_ a b c in
+ mk_clause_cl Itep1 [not_ ite_a_b_c; a; c] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; c; r]) when n == H.not_ite_elim_1 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nite2 [not_ a; not_ b] env.clauses :: []
+ | _ ->
+ let ite_a_b_c = ifte_ a b c in
+ mk_clause_cl Iten2 [ite_a_b_c; not_ a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; c; r]) when n == H.not_ite_elim_2 ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nite1 [a; not_ c] env.clauses :: []
+ | _ ->
+ let ite_a_b_c = ifte_ a b c in
+ mk_clause_cl Iten1 [ite_a_b_c; a; not_ c] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; c; r]) when n == H.ite_elim_3 ->
+ let env = lem env r in
+ let ite_a_b_c = ifte_ a b c in
+ { env with
+ clauses =
+ mk_clause_cl Itep1 [not_ ite_a_b_c; a; c] [] ::
+ mk_clause_cl Itep2 [not_ ite_a_b_c; not_ a; b] [] ::
+ env.clauses;
+ ax = true }
+
+ | Some (n, [a; b; c; r]) when n == H.not_ite_elim_3 ->
+ let env = lem env r in
+ let ite_a_b_c = ifte_ a b c in
+ { env with
+ clauses =
+ mk_clause_cl Iten1 [ite_a_b_c; a; not_ c] [] ::
+ mk_clause_cl Iten2 [ite_a_b_c; not_ a; not_ b] [] ::
+ env.clauses;
+ ax = true }
+
+ | Some (n, [a; b; r]) when n == H.iff_elim_1 ->
+ begin match app_name r with
+ | Some (n, [a; b; r]) when n == H.not_iff_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nequ2 [not_ a; not_ b] env.clauses :: []
+ | _ ->
+ let a_iff_b = iff_ a b in
+ mk_clause_cl Equn1 [a_iff_b; not_ a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+ | Some (n, [a; b; r]) when n == H.not_xor_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nxor2 [not_ a; b] env.clauses :: []
+ | _ ->
+ let a_xor_b = xor_ a b in
+ mk_clause_cl Xorn2 [a_xor_b; not_ a; b] [] :: env.clauses
+ in
+ { env with clauses }
+ | _ ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Equ1 [not_ a; b] env.clauses :: []
+ | _ ->
+ let a_iff_b = th_res r in
+ mk_clause_cl Equp2 [not_ a_iff_b; not_ a; b] [] :: env.clauses
+ in
+ { env with clauses }
+ end
+
+ | Some (n, [a; b; r]) when n == H.iff_elim_2 ->
+ begin match app_name r with
+ | Some (n, [a; b; r]) when n == H.not_iff_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nequ1 [a; b] env.clauses :: []
+ | _ ->
+ let a_iff_b = iff_ a b in
+ mk_clause_cl Equn2 [a_iff_b; a; b] [] :: env.clauses
+ in
+ { env with clauses }
+ | Some (n, [a; b; r]) when n == H.not_xor_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nxor1 [a; not_ b] env.clauses :: []
+ | _ ->
+ let a_xor_b = xor_ a b in
+ mk_clause_cl Xorn1 [a_xor_b; a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+ | _ ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Equ2 [a; not_ b] env.clauses :: []
+ | _ ->
+ let a_iff_b = th_res r in
+ mk_clause_cl Equp1 [not_ a_iff_b; a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+ end
+
+ | Some (n, [a; b; r]) when n == H.not_and_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nand [not_ a; not_ b] env.clauses :: []
+ | _ ->
+ let a_and_b = and_ a b in
+ mk_clause_cl Andn [a_and_b; not_ a; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; _; r]) when n == H.and_elim_1 ->
+ begin match app_name r with
+ | Some (n, [a; b; r]) when n == H.not_impl_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax -> mk_clause_cl Nimp1 [a] env.clauses :: []
+ | _ ->
+ let a_impl_b = impl_ a b in
+ mk_clause_cl Impn1 [a_impl_b; a] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; r]) when n == H.not_or_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [id] when not env.ax -> mk_clause_cl Nor [not_ a] [id; 0] :: []
+ | _ ->
+ let a_or_b = or_ a b in
+ mk_clause_cl Orn [a_or_b; not_ a] [0] :: env.clauses
+ in
+ { env with clauses }
+
+ | _ ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [id] when not env.ax -> mk_clause_cl And [a] [id; 0] :: []
+ | _ ->
+ let a_and_b = th_res r in
+ mk_clause_cl Andp [not_ a_and_b; a] [0] :: env.clauses
+ in
+ { env with clauses }
+ end
+
+ | Some (n, [a; b; r]) when n == H.and_elim_2 ->
+ begin match app_name r with
+ | Some (n, [a; b; r]) when n == H.not_impl_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [_] when not env.ax ->
+ mk_clause_cl Nimp2 [not_ b] env.clauses :: []
+ | _ ->
+ let a_impl_b = impl_ a b in
+ mk_clause_cl Impn2 [a_impl_b; not_ b] [] :: env.clauses
+ in
+ { env with clauses }
+
+ | Some (n, [a; b; r]) when n == H.not_or_elim ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [id] when not env.ax -> mk_clause_cl Nor [not_ b] [id; 1] :: []
+ | _ ->
+ let a_or_b = or_ a b in
+ mk_clause_cl Orn [a_or_b; not_ b] [1] :: env.clauses
+ in
+ { env with clauses }
+
+ | _ ->
+ let env = lem env r in
+ let clauses = match env.clauses with
+ | [id] when not env.ax -> mk_clause_cl And [b] [id; 1] :: []
+ | _ ->
+ let a_and_b = th_res r in
+ mk_clause_cl Andp [not_ a_and_b; b] [1] :: env.clauses
+ in
+ { env with clauses }
+ end
+
+ (* Only handle symmetry rules when they are the only rule of the lemma *)
+
+ | Some (n, [ty; a; b; r])
+ when n == H.symm && toplevel && name r <> None ->
+ let env = lem env r in
+ let a_b = eq ty a b in
+ let b_a = eq ty b a in
+
+ { env with
+ clauses = mk_clause_cl Eqtr [not_ a_b; b_a] [] :: env.clauses;
+ ax = true }
+
+ | Some (n, [ty; a; b; r])
+ when n == H.negsymm && toplevel && name r <> None ->
+ let env = lem env r in
+ let a_b = eq ty a b in
+ let b_a = eq ty b a in
+
+ { env with
+ clauses = mk_clause_cl Eqtr [a_b; not_ b_a] [] :: env.clauses;
+ ax = true }
+
+ (* Ignore other symmetry of equlity rules *)
+ | Some (n, [_; _; _; r]) when n == H.symm || n == H.negsymm ->
+ lem (rm_used env r) r
+
+ (* Ignore double negation *)
+ | Some (n, [_; r]) when n == H.not_not_elim || n == H.not_not_intro ->
+ lem env r
+
+ (* Should not be traversed anyway *)
+ | Some (n, [_; r]) when n == H.pred_eq_t || n == H.pred_eq_f ->
+ lem env r
+
+
+ | Some (n, [f]) when n == H.trust_f ->
+ begin match app_name f with
+ | Some (n, ty :: _)
+ when n == H.eq &&
+ (match name ty with Some i -> i == H.tInt | None -> false) ->
+ (* trust are for lia lemma if equality between integers *)
+ { env with clauses = mk_clause_cl Lage [f] [] :: env.clauses }
+ | Some (n, [x]) when n == H.not_ ->
+ begin match app_name x with
+ | Some (n, ty :: _)
+ when n == H.eq &&
+ (match name ty with Some i -> i == H.tInt | None -> false) ->
+ (* trust are for lia lemma if disequality between integers *)
+ { env with clauses = mk_clause_cl Lage [f] [] :: env.clauses }
+ | _ -> { env with clauses = mk_clause_cl Hole [f] [] :: env.clauses }
+ end
+ | _ -> { env with clauses = mk_clause_cl Hole [f] [] :: env.clauses }
+ end
+
+ | Some (n, [_; _; _; _; r; w])
+ when n == H.trans &&
+ (match app_name w with
+ | Some (n, _) -> n == H.pred_eq_t || n == H.pred_eq_f
+ | _ -> false)
+ ->
+ (* Remember which direction of the implication we want for congruence over
+ predicates *)
+ let env = match app_name w with
+ | Some (n, [pt; x]) when n == H.pred_eq_t ->
+ let env = rm_used env x in
+ { env with mpred = MTerm.add pt false env.mpred }
+ | Some (n, [pt; x]) when n == H.pred_eq_f ->
+ let env = rm_used env x in
+ { env with mpred = MTerm.add pt true env.mpred }
+ | _ -> assert false
+ in
+
+ lem env r
+
+
+ | Some (n, [ty; x; y; z; p1; p2])
+ when n == H.negtrans || n == H.negtrans1 ->
+
+ if term_equal x y || term_equal x z || term_equal y z then env
+ else
+ let env = lem env p2 in
+ let env = lem env p1 in
+
+ let x_y = eq ty x y in
+ let y_z = eq ty y z in
+ let x_z = eq ty x z in
+
+ { env with
+ clauses = mk_clause_cl Eqtr [x_y; not_ y_z; not_ x_z] [] :: env.clauses;
+ ax = true }
+
+ | Some (n, [ty; x; y; z; p1; p2]) when n == H.negtrans2 ->
+
+ if term_equal x y || term_equal x z || term_equal y z then env
+ else
+ let env = lem env p2 in
+ let env = lem env p1 in
+
+ let x_y = eq ty x y in
+ let y_z = eq ty y z in
+ let x_z = eq ty x z in
+
+ { env with
+ clauses = mk_clause_cl Eqtr [not_ x_y; y_z; not_ x_z] [] :: env.clauses;
+ ax = true }
+
+ | Some (n, [ty; x; y; z; p1; p2]) when n == H.trans ->
+ (* | Some (("negtrans"|"negtrans1"), [ty; x; z; y; p1; p2]) *)
+ (* | Some ("negtrans2", [ty; y; x; z; p1; p2]) *)
+
+ (* if Term.equal x y || Term.equal x z || Term.equal y z then env *)
+ (* else *)
+
+ let neqs, env = trans [] env p in
+ let x_z = eq ty x z in
+ let cl = (neqs @ [x_z]) in
+ let id = mk_clause_cl Eqtr cl [] in
+ let id = mk_clause_cl ~reuse:false Weak cl [id] in
+ { env with
+ clauses = id :: env.clauses;
+ ax = true }
+
+ (* | Some ("trans", [ty; x; y; z; p1; p2]) ->
+
+ (* let clauses1 = lem mpred assum clauses p1 in *)
+ (* let clauses2 = lem mpred assum clauses p2 in *)
+
+ (* TODO: intermediate resolution step *)
+ let clauses = lem mpred assum (lem mpred assum clauses p1) p2 in
+
+ let x_y = th_res p1 in
+ let y_z = th_res p2 in
+ let x_z = eq ty x z in
+ let clauses = mk_clause_cl "eq_transitive" [not_ x_y; not_ y_z; x_z] [] :: clauses in
+
+
+ (* let cl1 = [th_res p1] in *)
+ (* let cl2 = [th_res p2] in *)
+ (* let clauses = [ *)
+ (* mk_inter_resolution cl1 clauses1; *)
+ (* mk_inter_resolution cl2 clauses2] *)
+ (* in *)
+ clauses
+ *)
+
+ (* Congruence with predicates *)
+ | Some (n, [_; rty; pp; _; x; y; _; _])
+ when n == H.cong && is_ty_Bool rty ->
+
+ let neqs, env = cong [] env p in
+ let cptr, cpfa = match app_name (th_res p) with
+ | Some (n, [_; apx; apy]) when n == H.eq ->
+ (match MTerm.find apx env.mpred, MTerm.find apy env.mpred with
+ | true, false -> p_app apx, not_ (p_app apy)
+ | false, true -> p_app apy, not_ (p_app apx)
+ | true, true -> p_app apx, p_app apy
+ | false, false -> not_ (p_app apx), not_ (p_app apy)
+ )
+ | _ -> assert false
+ in
+ let cl = neqs @ [cpfa; cptr] in
+ { env with
+ clauses = mk_clause_cl Eqcp cl [] :: env.clauses;
+ ax = true }
+
+ (* Congruence *)
+ | Some (n, [_; _; _; _; _; _; _; _]) when n == H.cong ->
+ let neqs, env = cong [] env p in
+ let fx_fy = th_res p in
+ let cl = neqs @ [fx_fy] in
+ { env with
+ clauses = mk_clause_cl Eqco cl [] :: env.clauses;
+ ax = true }
+
+ | Some (n, [_; _]) when n == H.refl ->
+ let x_x = th_res p in
+ { env with clauses = mk_clause_cl Eqre [x_x] [] :: env.clauses }
+
+ | Some (n, [_; _; a; i; v]) when n == H.row1 ->
+ let raiwaiv = th_res p in
+ { env with clauses = mk_clause_cl Row1 [raiwaiv] [] :: env.clauses }
+
+ | Some (n, [ti; _; i; j; a; v; r]) when n == H.row ->
+ let env = lem env r in
+ let i_eq_j = eq ti i j in
+ let pr1 = th_res p in
+ { env with
+ clauses = mk_clause_cl Row2 [i_eq_j; pr1] [] :: env.clauses;
+ ax = true}
+
+ | Some (n, [ti; _; i; j; a; v; npr1]) when n == H.negativerow ->
+ let env = lem env npr1 in
+ let i_eq_j = eq ti i j in
+ let pr1 = match app_name (th_res p) with
+ | Some (n, [pr1]) when n == H.not_ -> pr1
+ | _ -> assert false
+ in
+ { env with clauses = mk_clause_cl Row2 [i_eq_j; pr1] [] :: env.clauses }
+
+ | Some (n, [_; x; y]) when n == H.bv_disequal_constants ->
+ { env with clauses = mk_clause_cl Bbdis [th_res p] [] :: env.clauses }
+
+ | Some (rule, args) ->
+ eprintf "Warning: Introducing hole for unsupported rule %a@."
+ Hstring.print rule;
+ { env with clauses = mk_clause_cl Hole [th_res p] [] :: env.clauses }
+
+ | None ->
+
+ match name p with
+
+ | Some n when n == H.truth ->
+ { env with clauses = mk_clause_cl True [ttrue] [] :: env.clauses }
+
+ | Some h ->
+ (* should be an input clause *)
+ (try { env with clauses = get_input_id h :: env.clauses }
+ with Not_found ->
+ { env with
+ ax = true;
+ assum = List.filter (fun a -> a <> h) env.assum }
+ )
+
+ | None -> { env with ax = true }
+
+
+
+ (** Returns the name given to this lemma, its type and the continuation. *)
+ let result_satlem p = match value p with
+ | Lambda ({sname=Name n} as s, r) ->
+
+ begin match app_name s.stype with
+ | Some (n, [cl]) when n == H.holds -> n, cl, r
+ | _ -> assert false
+ end
+
+ | _ -> assert false
+
+
+ (** Returns the clause used in a resolution step *)
+ let clause_qr p =
+ try match name p with
+ | Some n -> get_input_id n
+ | _ -> raise Not_found
+ with Not_found -> match app_name (deref p).ttype with
+ | Some (n, [cl]) when n == H.holds ->
+ (* eprintf "get_clause id : %a@." print_term cl; *)
+ get_clause_id (to_clause cl)
+ | _ -> raise Not_found
+
+
+ let rec reso_of_QR acc qr = match app_name qr with
+ | Some (n, [_; _; u1; u2; _]) when n == H.q || n == H.r ->
+ reso_of_QR (reso_of_QR acc u1) u2
+ | _ -> clause_qr qr :: acc
+
+ (** Returns clauses used in a linear resolution chain *)
+ let reso_of_QR qr = reso_of_QR [] qr |> List.rev
+
+
+ let rec reso_of_QR qr = match app_name qr with
+ | Some (n, [_; _; u1; u2; _]) when n == H.q || n == H.r ->
+ reso_of_QR u1 @ reso_of_QR u2
+ | _ -> [clause_qr qr]
+
+ let rec reso_of_QR depth acc qr = match app_name qr with
+ | Some (n, [_; _; u1; u2; _]) when n == H.q || n == H.r ->
+ let depth = depth + 1 in
+ reso_of_QR depth (reso_of_QR depth acc u1) u2
+ | _ -> (depth, clause_qr qr) :: acc
+
+ (** Returns clauses used in a linear resolution chain *)
+ let reso_of_QR qr =
+ reso_of_QR 0 [] qr
+ |> List.rev
+ |> List.stable_sort (fun (d1, _) (d2, _) -> d2 - d1)
+ |> List.map snd
+
+
+ (** convert resolution proofs of [satlem_simplify] *)
+ let satlem_simplify p = match app_name p with
+ | Some (n, [_; _; _; qr; p]) when n == H.satlem_simplify ->
+ let clauses = reso_of_QR qr in
+ let lem_name, res, p = result_satlem p in
+ let cl_res = to_clause res in
+ let id = mk_clause ~reuse:false Reso cl_res clauses in
+ register_clause_id cl_res id;
+ register_decl_id lem_name id;
+ Some id, p
+ | _ -> raise Exit
+
+
+ let rec many_satlem_simplify lastid p =
+ try
+ let lastid, p = satlem_simplify p in
+ many_satlem_simplify lastid p
+ with Exit -> lastid, p
+
+
+ (* can be empty, returns continuation *)
+ let satlem_simplifies_c p =
+ many_satlem_simplify None p |> snd
+
+
+ (* There must be at least one, returns id of last deduced clause *)
+ let reso_of_satlem_simplify p =
+ match many_satlem_simplify None p with
+ | Some id, _ -> id
+ | _ -> assert false
+
+
+ let rec bb_trim_intro_unit env p = match app_name p with
+ | Some (n, [_; _; _; ullit; _; l])
+ when n == H.intro_assump_f || n == H.intro_assump_t ->
+ let env = rm_used env ullit in
+ (match value l with
+ | Lambda (_, p) -> bb_trim_intro_unit env p
+ | _ -> assert false)
+ | _ -> env, p
+
+
+ let is_last_bbres p = match app_name p with
+ | Some (n, [_; _; _; _; l]) when n == H.satlem_simplify ->
+ (match value l with
+ | Lambda ({sname=Name e}, pe) ->
+ (match name pe with Some ne -> ne = e | None -> false)
+ | _ -> false)
+ | _ -> false
+
+
+ let rec bb_lem_res lastid p =
+ try
+ if is_last_bbres p then raise Exit;
+ let lastid, p = satlem_simplify p in
+ bb_lem_res lastid p
+ with Exit -> match lastid with
+ | Some id -> id
+ | None -> assert false
+
+
+ let rec bb_lem env p =
+ let env, p = bb_trim_intro_unit env p in
+ let id = bb_lem_res None p in
+ { env with clauses = id :: env.clauses }
+
+
+
+ exception ArithLemma
+
+ (** Remove superfluous applications at the top of [satlem] and returns a list
+ of proofs whose resulting clauses need to be resolved.
+
+ @raises {!ArithLemma} if the proof is a trust statement (we assume it is
+ the case for now). *)
+ let rec trim_junk_satlem p = match app_name p with
+ | Some (n, [p]) when n == H.clausify_false ->
+ (match name p with
+ | Some n when n == H.trust -> raise ArithLemma
+ | _ -> trim_junk_satlem p
+ )
+ | Some (n, [_; p1; p2]) when n == H.contra ->
+ trim_junk_satlem p1 @ trim_junk_satlem p2
+ | _ -> [p]
+
+
+ (** Returns the continuation of a [satlem]. *)
+ let continuation_satlem p = match value p with
+ | Lambda ({sname=Name n}, r) -> n, r
+ | _ -> assert false
+
+
+ let is_bbr_satlem_lam p = match value p with
+ | Lambda ({sname = Name h}, _) ->
+ (try String.sub (Hstring.view h) 0 5 = "bb.cl"
+ with Invalid_argument _ -> false)
+ | _ -> false
+
+ let has_intro_bv p = match app_name p with
+ | Some (n, _) when n == H.intro_assump_f || n == H.intro_assump_t -> true
+ | _ -> false
+
+
+ let has_prefix p s =
+ try
+ for i = 0 to String.length p - 1 do
+ if p.[i] <> s.[i] then raise Exit
+ done;
+ true
+ with Exit | Invalid_argument _ -> false
+
+
+ (** Convert [satlem]. Clauses are chained together with an intermediate
+ resolution step when needed, and when CVC4 uses superfluous local
+ assumption, the clause is weakened. *)
+ let rec satlem ?(prefix_cont) p =
+ let old_p = p in
+ match app_name p with
+
+ | Some (n, [c; _; l; p]) when n == H.satlem ->
+ (* eprintf "SATLEM ---@."; *)
+ let lem_name, lem_cont = continuation_satlem p in
+ begin match prefix_cont with
+ | Some pref when not (has_prefix pref (Hstring.view lem_name)) -> old_p
+ | _ ->
+ let cl = to_clause c in
+ (try
+ let assumptions, l = get_assumptions [] l in
+ let l = trim_junk_satlem l in
+ let env = { empty with assum = assumptions } in
+ let lem =
+ if is_bbr_satlem_lam p || List.exists has_intro_bv l then bb_lem
+ else lem ~toplevel:true in
+ let env =
+ List.fold_left (fun env p ->
+ let local_env =
+ { env with
+ clauses = [];
+ ax = false;
+ mpred = MTerm.empty;
+ } in
+ let local_env = lem local_env p in
+ { env with
+ clauses = List.rev_append local_env.clauses env.clauses;
+ assum = local_env.assum
+ }
+ ) env l
+ in
+ let clauses = List.rev env.clauses in
+ let id = mk_inter_resolution clauses in
+ (* eprintf "remaining assumptions:"; *)
+ (* List.iter (eprintf "%s, ") env.assu; *)
+ (* eprintf "@."; *)
+ (* if env.assum = [] then id else *)
+ let satlem_id = mk_clause Weak cl [id] in
+ register_clause_id cl satlem_id;
+ register_decl_id lem_name satlem_id;
+ (* eprintf "--- SATLEM@."; *)
+
+ with ArithLemma ->
+ let satlem_id = mk_clause Lage cl [] in
+ register_clause_id cl satlem_id
+
+ );
+
+ satlem ?prefix_cont lem_cont
+ end
+
+ | Some (n, [_; _; _; _; l]) when n == H.satlem_simplify ->
+ (match value l with
+ | Lambda ({sname=Name _}, r) ->
+ (match name r with
+ | Some _ -> p
+ | None -> match app_name r with
+ | Some (n, _) when n == H.satlem_simplify -> p
+ | _ ->
+ (* Intermediate satlem_simplify *)
+ (* eprintf ">>>>>> intermediate satlemsimplify@."; *)
+ snd (satlem_simplify p) |> satlem ?prefix_cont
+ )
+ | _ -> p)
+
+ | _ -> p
+
+
+ let rec bbt p = match app_name p with
+ | Some (b, [n; v; bb]) when b == H.bv_bbl_var ->
+ let res = bblast_term n (a_var_bv n v) bb in
+ Some (mk_clause_cl Bbva [res] [])
+ | Some (b, [n; bb; bv]) when b == H.bv_bbl_const ->
+ let res = bblast_term n (a_bv n bv) bb in
+ Some (mk_clause_cl Bbconst [res] [])
+ | Some (rop, [n; x; y; _; _; rb; xbb; ybb])
+ when rop == H.bv_bbl_bvand ||
+ rop == H.bv_bbl_bvor ||
+ rop == H.bv_bbl_bvxor ||
+ rop == H.bv_bbl_bvadd ||
+ rop == H.bv_bbl_bvmul ||
+ rop == H.bv_bbl_bvult ||
+ rop == H.bv_bbl_bvslt
+ ->
+ let bvop, rule =
+ if rop == H.bv_bbl_bvand then bvand, Bbop
+ else if rop == H.bv_bbl_bvor then bvor, Bbop
+ else if rop == H.bv_bbl_bvxor then bvxor, Bbop
+ else if rop == H.bv_bbl_bvadd then bvadd, Bbadd
+ else if rop == H.bv_bbl_bvmul then bvmul, Bbmul
+ else if rop == H.bv_bbl_bvult then bvult, Bbult
+ else if rop == H.bv_bbl_bvslt then bvslt, Bbslt
+ else assert false
+ in
+ let res = bblast_term n (bvop n x y) rb in
+ (match bbt xbb, bbt ybb with
+ | Some idx, Some idy ->
+ Some (mk_clause_cl rule [res] [idx; idy])
+ | _ -> assert false
+ )
+
+ | Some (c, [n; x; _; rb; xbb]) when c == H.bv_bbl_bvnot ->
+ let res = bblast_term n (bvnot n x) rb in
+ (match bbt xbb with
+ | Some idx ->
+ Some (mk_clause_cl Bbnot [res] [idx])
+ | _ -> assert false
+ )
+ | Some (c, [n; x; _; rb; xbb]) when c == H.bv_bbl_bvneg ->
+ let res = bblast_term n (bvneg n x) rb in
+ (match bbt xbb with
+ | Some idx ->
+ Some (mk_clause_cl Bbneg [res] [idx])
+ | _ -> assert false
+ )
+
+ | Some (c, [n; m; m'; x; y; _; _; rb; xbb; ybb])
+ when c == H.bv_bbl_concat ->
+ let res = bblast_term n (concat n m m' x y) rb in
+ (match bbt xbb, bbt ybb with
+ | Some idx, Some idy ->
+ Some (mk_clause_cl Bbconc [res] [idx; idy])
+ | _ -> assert false
+ )
+
+ | Some (c, [n; i; j; m; x; _; rb; xbb])
+ when c == H.bv_bbl_extract ->
+ let res = bblast_term n (extract n i j m x) rb in
+ (match bbt xbb with
+ | Some idx ->
+ Some (mk_clause_cl Bbextr [res] [idx])
+ | _ -> assert false
+ )
+
+ | Some (c, [n; k; m; x; _; rb; xbb])
+ when c == H.bv_bbl_zero_extend ->
+ let res = bblast_term n (zero_extend n k m x) rb in
+ (match bbt xbb with
+ | Some idx ->
+ Some (mk_clause_cl Bbzext [res] [idx])
+ | _ -> assert false
+ )
+
+ | Some (c, [n; k; m; x; _; rb; xbb])
+ when c == H.bv_bbl_sign_extend ->
+ let res = bblast_term n (sign_extend n k m x) rb in
+ (match bbt xbb with
+ | Some idx ->
+ Some (mk_clause_cl Bbsext [res] [idx])
+ | _ -> assert false
+ )
+
+ | None ->
+ begin match name p with
+ | Some h -> (* should be an declared clause *)
+ Some (try get_input_id h with Not_found -> assert false)
+ | None -> assert false
+ end
+
+ | Some (rule, args) ->
+ eprintf "Warning: Introducing hole for unsupported rule %a@."
+ Hstring.print rule;
+ Some (mk_clause_cl Hole [ttype p] [])
+
+
+
+ let rec bblast_decls p = match app_name p with
+ | Some (d, [n; b; t; bb; l]) when d == H.decl_bblast ->
+ (* let res = bblast_term n t b in *)
+ let id = match bbt bb with Some id -> id | None -> assert false in
+ begin match value l with
+ | Lambda ({sname = Name h}, p) ->
+ register_decl_id h id;
+ bblast_decls p
+ | _ -> assert false
+ end
+
+ | Some (d, [n; b; t; a; bb; _; l]) when d == H.decl_bblast_with_alias ->
+ (* register_termalias a t; *)
+ (* begin match name a with *)
+ (* | Some n -> register_alias n t *)
+ (* | None -> () *)
+ (* end; *)
+ let id = match bbt bb with Some id -> id | None -> assert false in
+ begin match value l with
+ | Lambda ({sname = Name h}, p) ->
+ register_decl_id h id;
+ bblast_decls p
+ | _ -> assert false
+ end
+
+ | _ -> p
+
+
+ let bv_pred n =
+ if n == H.bv_bbl_eq then Bbeq
+ else if n == H.bv_bbl_eq_swap then Bbeq
+ else if n == H.bv_bbl_bvult then Bbult
+ else if n == H.bv_bbl_bvslt then Bbslt
+ else assert false
+
+
+ let rec bblast_eqs p = match app_name p with
+ | Some (n, [f; pf; l]) when n == H.th_let_pf ->
+ begin match app_name pf with
+ | Some (rule_name, [_; _; _; _; _; _; a; b]) ->
+ begin match name a, name b with
+ | Some na, Some nb ->
+ let id1, id2 =
+ try get_input_id na, get_input_id nb
+ with Not_found -> assert false in
+ let clid = mk_clause_cl (bv_pred rule_name) [f] [id1; id2] in
+ begin match value l with
+ | Lambda ({sname = Name h}, p) ->
+ register_decl_id h clid;
+ bblast_eqs p
+ | _ -> assert false
+ end
+ | _ -> assert false
+ end
+
+ | _ -> assert false
+ end
+ | _ -> p
+
+
+ (** Bit-blasting and bitvector proof conversion (returns rest of the sat
+ proof) *)
+ let bb_proof p = match app_name p with
+ | Some (n, _) when n == H.decl_bblast || n == H.decl_bblast_with_alias ->
+ p
+ |> bblast_decls
+ |> bblast_eqs
+ |> register_prop_vars
+ |> satlem ~prefix_cont:"bb."
+ |> satlem_simplifies_c
+ |> satlem
+
+ | _ -> p
+
+
+ (** Convert an LFSC proof (this is the entry point) *)
+ let convert p =
+ p
+
+ (* |> ignore_all_decls *)
+ (* |> produce_inputs_preproc *)
+
+ |> ignore_decls
+ |> produce_inputs
+
+ |> deferred
+
+ |> admit_preproc
+
+ |> register_prop_vars
+ |> satlem
+
+ |> bb_proof
+
+ |> reso_of_satlem_simplify
+
+
+
+ let convert_pt p =
+ eprintf "Converting LFSC proof to SMTCoq...@?";
+ let t0 = Sys.time () in
+ let r = convert p in
+ let t1 = Sys.time () in
+ eprintf " Done [%.3f s]@." (t1 -. t0);
+ r
+
+
+
+ (** Clean global environments *)
+ let clear () =
+ Ast.clear_sc ();
+ T.clear ()
+
+
+end