aboutsummaryrefslogtreecommitdiffstats
path: root/src/trace/smtTrace.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/trace/smtTrace.ml')
-rw-r--r--src/trace/smtTrace.ml465
1 files changed, 465 insertions, 0 deletions
diff --git a/src/trace/smtTrace.ml b/src/trace/smtTrace.ml
new file mode 100644
index 0000000..8420ca1
--- /dev/null
+++ b/src/trace/smtTrace.ml
@@ -0,0 +1,465 @@
+(**************************************************************************)
+(* *)
+(* SMTCoq *)
+(* Copyright (C) 2011 - 2015 *)
+(* *)
+(* Michaël Armand *)
+(* Benjamin Grégoire *)
+(* Chantal Keller *)
+(* *)
+(* Inria - École Polytechnique - MSR-Inria Joint Lab *)
+(* *)
+(* This file is distributed under the terms of the CeCILL-C licence *)
+(* *)
+(**************************************************************************)
+open SmtMisc
+open CoqTerms
+open SmtCertif
+
+let notUsed = 0
+
+let next_id = ref 0
+
+let clear () = next_id := 0
+
+let next_id () =
+ let id = !next_id in
+ incr next_id;
+ id
+
+(** Basic functions over small certificates *)
+
+let mk_scertif kind ov =
+ {
+ id = next_id ();
+ kind = kind;
+ pos = None;
+ used = notUsed;
+ prev = None;
+ next = None;
+ value = ov
+ }
+
+(** Roots *)
+
+
+let mkRootGen ov =
+ let pos = next_id () in
+ {
+ id = pos;
+ kind = Root;
+ pos = Some pos;
+ used = notUsed;
+ prev = None;
+ next = None;
+ value = ov
+ }
+
+(* let mkRoot = mkRootGen None *)
+let mkRootV v = mkRootGen (Some v)
+
+let isRoot k = k == Root
+
+(** Resolutions *)
+
+let mkRes c1 c2 tl =
+ mk_scertif (Res { rc1 = c1; rc2 = c2; rtail = tl }) None
+
+let isRes k =
+ match k with
+ | Res _ -> true
+ | _ -> false
+
+
+(** Other *)
+
+let mkOther r ov = mk_scertif (Other r) ov
+
+
+(** Moving into the trace *)
+let next c =
+ match c.next with
+ | Some c1 -> c1
+ | None -> assert false
+
+let has_prev c =
+ match c.prev with
+ | Some _ -> true
+ | None -> false
+
+let prev c =
+ match c.prev with
+ | Some c1 -> c1
+ | None -> Printf.printf "prev %i\n" c.id;flush stdout;assert false
+
+let link c1 c2 =
+ c1.next <- Some c2;
+ c2.prev <- Some c1
+
+let clear_links c =
+ c.prev <- None;
+ c.next <- None
+
+let skip c =
+ link (prev c) (next c);
+ clear_links c
+
+let insert_before c cprev =
+ link (prev c) cprev;
+ link cprev c
+
+let get_res c s =
+ match c.kind with
+ | Res res -> res
+ | _ -> Printf.printf "get_res %s\n" s; assert false
+
+let get_other c s =
+ match c.kind with
+ | Other res -> res
+ | _ -> Printf.printf "get_other %s\n" s; assert false
+
+let get_val c =
+ match c.value with
+ | None -> assert false
+ | Some cl -> cl
+
+let rec repr c =
+ match c.kind with
+ | Root | Res _ | Other _ -> c
+ | Same c -> repr c
+
+let set_same c nc =
+ c.kind <- Same (repr nc);
+ skip c
+
+let rec get_pos c =
+ match c.kind with
+ | Root | Res _ | Other _ ->
+ begin match c.pos with
+ | Some n -> n
+ | _ -> assert false
+ end
+ | Same c -> get_pos c
+
+let eq_clause c1 c2 = (repr c1).id = (repr c2).id
+
+(* Selection of useful rules *)
+let select c =
+ let mark c =
+ if not (isRoot c.kind) then c.used <- 1 in
+ mark c;
+ let r = ref c in
+ while not (isRoot !r.kind) do
+ let p = prev !r in
+ (match !r.kind with
+ | Res res ->
+ if !r.used == 1 then begin
+ !r.used <- notUsed;
+ (* let res = get_res !r "select" in *)
+ mark res.rc1; mark res.rc2;
+ List.iter mark res.rtail
+ end else
+ skip !r;
+ | Same _ ->
+ skip !r
+ | _ ->
+ if !r.used == 1 then
+ begin
+ !r.used <- notUsed;
+ let rl = get_other !r "select" in
+ List.iter mark (used_clauses rl)
+ end
+ else skip !r;
+ );
+ r := p
+ done
+
+
+
+
+(* Compute the number of occurence of each_clause *)
+
+let rec occur c =
+ match c.kind with
+ | Root -> c.used <- c.used + 1
+ | Res res ->
+ if c.used == notUsed then
+ begin occur res.rc1; occur res.rc2; List.iter occur res.rtail end;
+ c.used <- c.used + 1
+ | Other res ->
+ if c.used == notUsed then List.iter occur (used_clauses res);
+ c.used <- c.used + 1;
+ | Same c' ->
+ occur c';
+ c.used <- c.used + 1
+
+(* Allocate clause *)
+
+let alloc c =
+ let free_pos = ref [] in
+
+ (* free the unused roots *)
+
+ let r = ref c in
+ while isRoot !r.kind do
+ if !r.used == notUsed then begin
+ free_pos := get_pos !r :: !free_pos;
+ end;
+ r := next !r;
+ done;
+
+ (* r is the first clause defined by resolution or another rule,
+ normaly the first used *)
+ let last_set = ref (get_pos (prev !r)) in
+
+ let decr_clause c =
+ let rc = repr c in
+ assert (rc.used > notUsed);
+ rc.used <- rc.used - 1;
+ if rc.used = notUsed then
+ free_pos := get_pos rc :: !free_pos in
+
+ let decr_res res =
+ decr_clause res.rc1;
+ decr_clause res.rc2;
+ List.iter decr_clause res.rtail in
+
+ let decr_other o =
+ List.iter decr_clause (used_clauses o) in
+
+ while !r.next <> None do
+ let n = next !r in
+ assert (!r.used <> notUsed);
+ if isRes !r.kind then
+ decr_res (get_res !r "alloc")
+ else
+ decr_other (get_other !r "alloc");
+ begin match !free_pos with
+ | p::free -> free_pos := free; !r.pos <- Some p
+ | _ -> incr last_set; !r.pos <- Some !last_set
+ end;
+ r := n
+ done;
+ begin match !free_pos with
+ | p::free -> free_pos := free; !r.pos <- Some p
+ | _ -> incr last_set; !r.pos <- Some !last_set
+ end;
+ !last_set
+
+
+(* A naive allocation for debugging *)
+
+let naive_alloc c =
+ let r = ref c in
+ while isRoot !r.kind do
+ r := next !r
+ done;
+ let last_set = ref (get_pos (prev !r)) in
+ while !r.next <> None do
+ let n = next !r in
+ incr last_set; !r.pos <- Some !last_set;
+ r := n
+ done;
+ incr last_set; !r.pos <- Some !last_set;
+ !last_set
+
+
+(* This function is currently inlined in verit/verit.ml and zchaff/zchaff.ml *)
+
+let build_certif first_root confl =
+ select confl;
+ occur confl;
+ alloc first_root
+
+
+let to_coq to_lit (cstep,
+ cRes, cImmFlatten,
+ cTrue, cFalse, cBuildDef, cBuildDef2, cBuildProj,
+ cImmBuildProj,cImmBuildDef,cImmBuildDef2,
+ cEqTr, cEqCgr, cEqCgrP,
+ cLiaMicromega, cLiaDiseq, cSplArith, cSplDistinctElim) confl =
+ let out_f f = to_lit f in
+ let out_c c = mkInt (get_pos c) in
+ let step_to_coq c =
+ match c.kind with
+ | Res res ->
+ let size = List.length res.rtail + 3 in
+ let args = Array.make size (mkInt 0) in
+ args.(0) <- mkInt (get_pos res.rc1);
+ args.(1) <- mkInt (get_pos res.rc2);
+ let l = ref res.rtail in
+ for i = 2 to size - 2 do
+ match !l with
+ | c::tl ->
+ args.(i) <- mkInt (get_pos c);
+ l := tl
+ | _ -> assert false
+ done;
+ mklApp cRes [|mkInt (get_pos c); Term.mkArray (Lazy.force cint, args)|]
+ | Other other ->
+ begin match other with
+ | ImmFlatten (c',f) -> mklApp cImmFlatten [|out_c c;out_c c'; out_f f|]
+ | True -> mklApp cTrue [|out_c c|]
+ | False -> mklApp cFalse [|out_c c|]
+ | BuildDef f -> mklApp cBuildDef [|out_c c; out_f f|]
+ | BuildDef2 f -> mklApp cBuildDef2 [|out_c c;out_f f|]
+ | BuildProj (f, i) -> mklApp cBuildProj [|out_c c; out_f f;mkInt i|]
+ | ImmBuildDef c' -> mklApp cImmBuildDef [|out_c c; out_c c'|]
+ | ImmBuildDef2 c' -> mklApp cImmBuildDef2 [|out_c c;out_c c'|]
+ | ImmBuildProj(c', i) -> mklApp cImmBuildProj [|out_c c; out_c c';mkInt i|]
+ | EqTr (f, fl) ->
+ let res = List.fold_right (fun f l -> mklApp ccons [|Lazy.force cint; out_f f; l|]) fl (mklApp cnil [|Lazy.force cint|]) in
+ mklApp cEqTr [|out_c c; out_f f; res|]
+ | EqCgr (f, fl) ->
+ let res = List.fold_right (fun f l -> mklApp ccons [|mklApp coption [|Lazy.force cint|]; (match f with | Some f -> mklApp cSome [|Lazy.force cint; out_f f|] | None -> mklApp cNone [|Lazy.force cint|]); l|]) fl (mklApp cnil [|mklApp coption [|Lazy.force cint|]|]) in
+ mklApp cEqCgr [|out_c c; out_f f; res|]
+ | EqCgrP (f1, f2, fl) ->
+ let res = List.fold_right (fun f l -> mklApp ccons [|mklApp coption [|Lazy.force cint|]; (match f with | Some f -> mklApp cSome [|Lazy.force cint; out_f f|] | None -> mklApp cNone [|Lazy.force cint|]); l|]) fl (mklApp cnil [|mklApp coption [|Lazy.force cint|]|]) in
+ mklApp cEqCgrP [|out_c c; out_f f1; out_f f2; res|]
+ | LiaMicromega (cl,d) ->
+ let cl' = List.fold_right (fun f l -> mklApp ccons [|Lazy.force cint; out_f f; l|]) cl (mklApp cnil [|Lazy.force cint|]) in
+ let c' = List.fold_right (fun f l -> mklApp ccons [|Lazy.force Coq_micromega.M.coq_proofTerm; Coq_micromega.dump_proof_term f; l|]) d (mklApp cnil [|Lazy.force Coq_micromega.M.coq_proofTerm|]) in
+ mklApp cLiaMicromega [|out_c c; cl'; c'|]
+ | LiaDiseq l -> mklApp cLiaDiseq [|out_c c; out_f l|]
+ | SplArith (orig,res,l) ->
+ let res' = out_f res in
+ let l' = List.fold_right (fun f l -> mklApp ccons [|Lazy.force Coq_micromega.M.coq_proofTerm; Coq_micromega.dump_proof_term f; l|]) l (mklApp cnil [|Lazy.force Coq_micromega.M.coq_proofTerm|]) in
+ mklApp cSplArith [|out_c c; out_c orig; res'; l'|]
+ | SplDistinctElim (c',f) -> mklApp cSplDistinctElim [|out_c c;out_c c'; out_f f|]
+ end
+ | _ -> assert false in
+ let step = Lazy.force cstep in
+ let def_step =
+ mklApp cRes [|mkInt 0; Term.mkArray (Lazy.force cint, [|mkInt 0|]) |] in
+ let r = ref confl in
+ let nc = ref 0 in
+ while not (isRoot !r.kind) do r := prev !r; incr nc done;
+ let last_root = !r in
+ let size = !nc in
+ let max = (Parray.trunc_size (Uint63.of_int 4194303)) - 1 in
+ let q,r1 = size / max, size mod max in
+
+ let trace =
+ let len = if r1 = 0 then q + 1 else q + 2 in
+ Array.make len (Term.mkArray (step, [|def_step|])) in
+ for j = 0 to q - 1 do
+ let tracej = Array.make (Parray.trunc_size (Uint63.of_int 4194303)) def_step in
+ for i = 0 to max - 1 do
+ r := next !r;
+ tracej.(i) <- step_to_coq !r;
+ done;
+ trace.(j) <- Term.mkArray (step, tracej)
+ done;
+ if r1 <> 0 then begin
+ let traceq = Array.make (r1 + 1) def_step in
+ for i = 0 to r1-1 do
+ r := next !r;
+ traceq.(i) <- step_to_coq !r;
+ done;
+ trace.(q) <- Term.mkArray (step, traceq)
+ end;
+
+ (Term.mkArray (mklApp carray [|step|], trace), last_root)
+
+
+
+(** Optimization of the trace *)
+
+module MakeOpt (Form:SmtForm.FORM) =
+ struct
+ (* Share the certificate building a common clause *)
+ let share_value c =
+ let tbl = Hashtbl.create 17 in
+ let to_lits v = List.map (Form.to_lit) v in
+ let process c =
+ match c.value with
+ | None -> ()
+ | Some v ->
+ let lits = to_lits v in
+ try
+ let c' = Hashtbl.find tbl lits in
+ set_same c c'
+ with Not_found -> Hashtbl.add tbl lits c in
+ let r = ref c in
+ while !r.next <> None do
+ let next = next !r in
+ process !r;
+ r := next
+ done;
+ process !r
+
+ (* Sharing of the common prefix *)
+
+ module HashedHeadRes =
+ struct
+
+ type t = Form.t resolution
+
+ let equal r1 r2 =
+ eq_clause r1.rc1 r2.rc1 && eq_clause r1.rc2 r2.rc2
+
+ let hash r = (repr r.rc1).id * 19 + (repr r.rc2).id
+
+ end
+
+ module HRtbl = Hashtbl.Make (HashedHeadRes)
+
+ let common_head tl1 tl2 =
+ let rec aux rhd tl1 tl2 =
+ match tl1, tl2 with
+ | [], _ -> List.rev rhd, tl1, tl2
+ | _, [] -> List.rev rhd, tl1, tl2
+ | c1::tl1', c2::tl2' ->
+ if eq_clause c1 c2 then aux (repr c1 :: rhd) tl1' tl2'
+ else List.rev rhd, tl1, tl2
+ in aux [] tl1 tl2
+
+ let share_prefix first_c n =
+ let tbl = HRtbl.create (min n Sys.max_array_length) in
+ let rec share c2 =
+ if isRes c2.kind then (
+ let res2 = get_res c2 "share_prefix1" in
+ try
+ let c1 = HRtbl.find tbl res2 in
+ let res1 = get_res c1 "share_prefix2" in
+ (* res1 and res2 have the same head *)
+ let head, tl1, tl2 = common_head res1.rtail res2.rtail in
+ match tl1, tl2 with
+ | [], [] ->
+ set_same c2 c1;
+ | [], c2'::tl2' ->
+ res2.rc1 <- c1;
+ res2.rc2 <- c2';
+ res2.rtail <- tl2';
+ share c2
+ | c1'::tl1', [] ->
+ skip c2;
+ HRtbl.remove tbl res1;
+ insert_before c1 c2;
+ res1.rc1 <- c2;
+ res1.rc2 <- c1';
+ res1.rtail <- tl1';
+ share c1
+ | c1'::tl1', c2'::tl2' ->
+ let c = mkRes res1.rc1 res1.rc2 head in
+ HRtbl.remove tbl res1;
+ insert_before c1 c;
+ res1.rc1 <- c;
+ res1.rc2 <- c1';
+ res1.rtail <- tl1';
+ res2.rc1 <- c;
+ res2.rc2 <- c2';
+ res2.rtail <- tl2';
+ share c;
+ share c1;
+ share c2
+ with Not_found -> HRtbl.add tbl res2 c2
+ ) in
+ let r = ref first_c in
+ while !r.next <> None do
+ let n = next !r in
+ share !r;
+ r := n
+ done
+
+ end