diff options
Diffstat (limited to 'src/trace/smtCnf.ml')
-rw-r--r-- | src/trace/smtCnf.ml | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/src/trace/smtCnf.ml b/src/trace/smtCnf.ml new file mode 100644 index 0000000..d159db0 --- /dev/null +++ b/src/trace/smtCnf.ml @@ -0,0 +1,264 @@ +(**************************************************************************) +(* *) +(* 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 SmtForm +open SmtCertif +open SmtTrace + +module MakeCnf (Form:FORM) = + struct + + type form_info = + | Immediate of bool (* true if the positive literal is set *) + | Done (* means that the equivalence clauses have been generated *) + | Todo (* nothing has been done, process the cnf transformation *) + + let info = Hashtbl.create 17 + + let init_last = + let last = SmtTrace.mk_scertif Root None in + SmtTrace.clear (); + last + + let last = ref init_last + + let cnf_todo = ref [] + + let clear () = + Hashtbl.clear info; + last := init_last; + cnf_todo := [] + + let push_cnf args = cnf_todo := args :: !cnf_todo + + let get_info l = + try Hashtbl.find info (Form.index l) + with Not_found -> Todo + + let set_done l = + Hashtbl.add info (Form.index l) Done + + let set_immediate l = + Hashtbl.add info (Form.index l) (Immediate (Form.is_pos l)) + + let test_immediate l = + match get_info l with + | Immediate b -> b = Form.is_pos l + | _ -> false + + let check_trivial cl = + List.exists test_immediate cl + + let link_Other other cl = + if not (check_trivial cl) then + let c = mkOther other (Some cl) in + link !last c; + last := c + + let both_lit l = if Form.is_pos l then Form.neg l,l else l, Form.neg l + + let or_of_imp args = + Array.mapi (fun i l -> + if i = Array.length args - 1 then l else Form.neg l) args + + let rec cnf l = + match get_info l with + | Immediate _ | Done -> () + | Todo -> + match Form.pform l with + | Fatom _ -> () + + | Fapp (op,args) -> + match op with + | Ftrue | Ffalse -> () + + | Fand -> + let nl,pl = both_lit l in + let nargs = Array.map Form.neg args in + link_Other (BuildDef pl) (pl::Array.to_list nargs); + Array.iteri (fun i l' -> + link_Other (BuildProj (nl,i)) [nl;l']) args; + set_done l; + Array.iter cnf args + + | For -> + let nl,pl = both_lit l in + link_Other (BuildDef nl) (nl::Array.to_list args); + Array.iteri (fun i l' -> + link_Other (BuildProj(pl,i)) [pl;Form.neg l']) args; + set_done l; + Array.iter cnf args + + | Fimp -> + let args = or_of_imp args in + let nl,pl = both_lit l in + link_Other (BuildDef nl) (nl::Array.to_list args); + Array.iteri (fun i l' -> + link_Other (BuildProj(pl,i)) [pl;Form.neg l']) args; + set_done l; + Array.iter cnf args + + | Fxor -> + let nl,pl = both_lit l in + let a, b = args.(0), args.(1) in + let na, nb = Form.neg a, Form.neg b in + link_Other (BuildDef nl) [nl;a;b]; + link_Other (BuildDef pl) [pl;a;nb]; + link_Other (BuildDef2 nl) [nl;na;nb]; + link_Other (BuildDef2 pl) [pl;na;b]; + set_done l; + cnf a; + cnf b + + | Fiff -> + let nl,pl = both_lit l in + let a, b = args.(0), args.(1) in + let na, nb = Form.neg a, Form.neg b in + link_Other (BuildDef nl) [nl;a;nb]; + link_Other (BuildDef pl) [pl;na;nb]; + link_Other (BuildDef2 nl) [pl;na;b]; + link_Other (BuildDef2 pl) [pl;a;b]; + set_done l; + cnf a; + cnf b + + | Fite -> + let nl,pl = both_lit l in + let a, b, c = args.(0), args.(1), args.(2) in + let na, nb, nc = Form.neg a, Form.neg b, Form.neg c in + link_Other (BuildDef nl) [nl;a;c]; + link_Other (BuildDef pl) [pl;a;nc]; + link_Other (BuildDef2 nl) [nl;na;b]; + link_Other (BuildDef2 pl) [pl;na;nb]; + set_done l; + cnf a; + cnf b; + cnf c + + | Fnot2 _ -> cnf args.(0) + + exception Cnf_done + + let rec imm_link_Other other l = + if not (test_immediate l) then + let c = mkOther other (Some [l]) in + link !last c; + last := c; + imm_cnf c + + and imm_cnf c = + let l = + match c.value with + | Some [l] -> + begin match Form.pform l with + | Fapp (Fnot2 _, args) -> + let l' = args.(0) in + if Form.is_pos l then l' + else Form.neg l' + | _ -> l + end + | _ -> assert false in + match get_info l with + | Immediate b -> if b = Form.is_neg l then raise Cnf_done + | Done -> assert false + | Todo -> + set_immediate l; + + match Form.pform l with + | Fatom _ -> () + + | Fapp (op,args) -> + match op with + | Ftrue | Ffalse -> () + + | Fand -> + if Form.is_pos l then + Array.iteri (fun i l' -> + imm_link_Other (ImmBuildProj(c,i)) l') args + else begin + let nargs = Array.map Form.neg args in + link_Other (ImmBuildDef c) (Array.to_list nargs); + push_cnf args + end + + | For -> + if Form.is_pos l then begin + link_Other (ImmBuildDef c) (Array.to_list args); + push_cnf args + end else + Array.iteri (fun i l' -> + imm_link_Other (ImmBuildProj(c,i)) (Form.neg l')) args + + | Fimp -> + let args = or_of_imp args in + if Form.is_pos l then begin + link_Other (ImmBuildDef c) (Array.to_list args); + push_cnf args + end else + Array.iteri (fun i l' -> + imm_link_Other (ImmBuildProj(c,i)) (Form.neg l')) args + + | Fxor -> + let args1 = + if Form.is_pos l then [args.(0);args.(1)] + else [args.(0);Form.neg args.(1)] in + let args2 = + if Form.is_pos l then [Form.neg args.(0);Form.neg args.(1)] + else [Form.neg args.(0); args.(1)] in + link_Other (ImmBuildDef c) args1; + link_Other (ImmBuildDef2 c) args2; + push_cnf args + + | Fiff -> + let args1 = + if Form.is_pos l then [args.(0);Form.neg args.(1)] + else [Form.neg args.(0);Form.neg args.(1)] in + let args2 = + if Form.is_pos l then [Form.neg args.(0);args.(1)] + else [args.(0); args.(1)] in + link_Other (ImmBuildDef c) args1; + link_Other (ImmBuildDef2 c) args2; + push_cnf args + + | Fite -> + let args1 = + if Form.is_pos l then [args.(0);Form.neg args.(2)] + else [args.(0);Form.neg args.(2)] in + let args2 = + if Form.is_pos l then [Form.neg args.(0);args.(1)] + else [Form.neg args.(0); Form.neg args.(1)] in + link_Other (ImmBuildDef c) args1; + link_Other (ImmBuildDef2 c) args2; + push_cnf args + + | Fnot2 _ -> assert false + + let make_cnf reify c = + let ftrue = Form.get reify (Fapp(Ftrue, [||])) in + let ffalse = Form.get reify (Fapp(Ffalse, [||])) in + last := c; + link_Other True [ftrue]; + link_Other False [Form.neg ffalse]; + (try + imm_cnf c; + List.iter (Array.iter cnf) !cnf_todo + with Cnf_done -> ()); + let res = !last in + clear (); + res + + end + |