123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326(**************************************************************************)(* *)(* Alt-Ergo Zero *)(* *)(* Sylvain Conchon and Alain Mebsout *)(* Universite Paris-Sud 11 *)(* *)(* Copyright 2011. This file is distributed under the terms of the *)(* Apache Software License version 2.0 *)(* *)(**************************************************************************)moduletypeArg=Tseitin_intf.ArgmoduletypeS=Tseitin_intf.SmoduleMake(F:Tseitin_intf.Arg)=structexceptionEmpty_Ortypecombinator=And|Or|Imp|Nottypeatom=F.ttypet=|True|Litofatom|Combofcombinator*tlistletrecppfmtphi=matchphiwith|True->Format.fprintffmt"true"|Lita->F.ppfmta|Comb(Not,[f])->Format.fprintffmt"not (%a)"ppf|Comb(And,l)->Format.fprintffmt"(%a)"(pp_list"and")l|Comb(Or,l)->Format.fprintffmt"(%a)"(pp_list"or")l|Comb(Imp,[f1;f2])->Format.fprintffmt"(%a => %a)"ppf1ppf2|_->assertfalseandpp_listsepfmt=function|[]->()|[f]->ppfmtf|f::l->Format.fprintffmt"%a %s %a"ppfsep(pp_listsep)lletmakecombl=Comb(comb,l)letmake_atomp=Litpletf_true=Trueletf_false=Comb(Not,[True])letrecflattencombacc=function|[]->acc|(Comb(c,l))::rwhenc=comb->flattencomb(List.rev_appendlacc)r|a::r->flattencomb(a::acc)rletrecopt_rev_mapfacc=function|[]->acc|a::r->beginmatchfawith|None->opt_rev_mapfaccr|Someb->opt_rev_mapf(b::acc)rendletremove_truel=letaux=function|True->None|f->Somefinopt_rev_mapaux[]lletremove_falsel=letaux=function|Comb(Not,[True])->None|f->Somefinopt_rev_mapaux[]lletmake_notf=makeNot[f]letmake_andl=letl'=remove_true(flattenAnd[]l)inifList.exists((=)f_false)l'thenf_falseelsemakeAndl'letmake_orl=letl'=remove_false(flattenOr[]l)inifList.exists((=)f_true)l'thenf_trueelsematchl'with|[]->raiseEmpty_Or|[a]->a|_->Comb(Or,l')letmake_implyf1f2=makeImp[f1;f2]letmake_equivf1f2=make_and[make_implyf1f2;make_implyf2f1]letmake_xorf1f2=make_or[make_and[make_notf1;f2];make_and[f1;make_notf2]](* simplify formula *)let(%%)fgx=f(gx)letrecsformfk=matchfwith|True|Comb(Not,[True])->kf|Comb(Not,[Lita])->k(Lit(F.nega))|Comb(Not,[Comb(Not,[f])])->sformfk|Comb(Not,[Comb(Or,l)])->sform_list_not[]l(k%%make_and)|Comb(Not,[Comb(And,l)])->sform_list_not[]l(k%%make_or)|Comb(And,l)->sform_list[]l(k%%make_and)|Comb(Or,l)->sform_list[]l(k%%make_or)|Comb(Imp,[f1;f2])->sform(make_notf1)(funf1'->sformf2(funf2'->k(make_or[f1';f2'])))|Comb(Not,[Comb(Imp,[f1;f2])])->sformf1(funf1'->sform(make_notf2)(funf2'->k(make_and[f1';f2'])))|Comb((Imp|Not),_)->assertfalse|Lit_->kfandsform_listacclk=matchlwith|[]->kacc|f::tail->sformf(funf'->sform_list(f'::acc)tailk)andsform_list_notacclk=matchlwith|[]->kacc|f::tail->sform(make_notf)(funf'->sform_list_not(f'::acc)tailk)let(@@)l1l2=List.rev_appendl1l2(* let ( @ ) = `Use_rev_append_instead (* prevent use of non-tailrec append *) *)(*
let distrib l_and l_or =
let l =
if l_or = [] then l_and
else
List.rev_map
(fun x ->
match x with
| Lit _ -> Comb (Or, x::l_or)
| Comb (Or, l) -> Comb (Or, l @@ l_or)
| _ -> assert false
) l_and
in
Comb (And, l)
let rec flatten_or = function
| [] -> []
| Comb (Or, l)::r -> l @@ (flatten_or r)
| Lit a :: r -> (Lit a)::(flatten_or r)
| _ -> assert false
let rec flatten_and = function
| [] -> []
| Comb (And, l)::r -> l @@ (flatten_and r)
| a :: r -> a::(flatten_and r)
let rec cnf f =
match f with
| Comb (Or, l) ->
begin
let l = List.rev_map cnf l in
let l_and, l_or =
List.partition (function Comb(And,_) -> true | _ -> false) l in
match l_and with
| [ Comb(And, l_conj) ] ->
let u = flatten_or l_or in
distrib l_conj u
| Comb(And, l_conj) :: r ->
let u = flatten_or l_or in
cnf (Comb(Or, (distrib l_conj u)::r))
| _ ->
begin
match flatten_or l_or with
| [] -> assert false
| [r] -> r
| v -> Comb (Or, v)
end
end
| Comb (And, l) ->
Comb (And, List.rev_map cnf l)
| f -> f
let rec mk_cnf = function
| Comb (And, l) ->
List.fold_left (fun acc f -> (mk_cnf f) @@ acc) [] l
| Comb (Or, [f1;f2]) ->
let ll1 = mk_cnf f1 in
let ll2 = mk_cnf f2 in
List.fold_left
(fun acc l1 -> (List.rev_map (fun l2 -> l1 @@ l2)ll2) @@ acc) [] ll1
| Comb (Or, f1 :: l) ->
let ll1 = mk_cnf f1 in
let ll2 = mk_cnf (Comb (Or, l)) in
List.fold_left
(fun acc l1 -> (List.rev_map (fun l2 -> l1 @@ l2)ll2) @@ acc) [] ll1
| Lit a -> [[a]]
| Comb (Not, [Lit a]) -> [[F.neg a]]
| _ -> assert false
let rec unfold mono f =
match f with
| Lit a -> a::mono
| Comb (Not, [Lit a]) ->
(F.neg a)::mono
| Comb (Or, l) ->
List.fold_left unfold mono l
| _ -> assert false
let rec init monos f =
match f with
| Comb (And, l) ->
List.fold_left init monos l
| f -> (unfold [] f)::monos
let make_cnf f =
let sfnc = cnf (sform f) in
init [] sfnc
*)letmk_proxy=F.freshletacc_or=ref[]letacc_and=ref[](* build a clause by flattening (if sub-formulas have the
same combinator) and proxy-ing sub-formulas that have the
opposite operator. *)letreccnff=matchfwith|Lita->None,[a]|Comb(Not,[Lita])->None,[F.nega]|Comb(And,l)->List.fold_left(fun(_,acc)f->matchcnffwith|_,[]->assertfalse|_cmb,[a]->SomeAnd,a::acc|SomeAnd,l->SomeAnd,l@@acc(* let proxy = mk_proxy () in *)(* acc_and := (proxy, l) :: !acc_and; *)(* proxy :: acc *)|SomeOr,l->letproxy=mk_proxy()inacc_or:=(proxy,l)::!acc_or;SomeAnd,proxy::acc|None,l->SomeAnd,l@@acc|_->assertfalse)(None,[])l|Comb(Or,l)->List.fold_left(fun(_,acc)f->matchcnffwith|_,[]->assertfalse|_cmb,[a]->SomeOr,a::acc|SomeOr,l->SomeOr,l@@acc(* let proxy = mk_proxy () in *)(* acc_or := (proxy, l) :: !acc_or; *)(* proxy :: acc *)|SomeAnd,l->letproxy=mk_proxy()inacc_and:=(proxy,l)::!acc_and;SomeOr,proxy::acc|None,l->SomeOr,l@@acc|_->assertfalse)(None,[])l|_->assertfalseletcnff=letacc=matchfwith|True->[]|Comb(Not,[True])->[[]]|Comb(And,l)->List.rev_map(funf->snd(cnff))l|_->[snd(cnff)]inletproxies=ref[]in(* encore clauses that make proxies in !acc_and equivalent to
their clause *)letacc=List.fold_left(funacc(p,l)->proxies:=p::!proxies;letnp=F.negpin(* build clause [cl = l1 & l2 & ... & ln => p] where [l = [l1;l2;..]]
also add clauses [p => l1], [p => l2], etc. *)letcl,acc=List.fold_left(fun(cl,acc)a->(F.nega::cl),[np;a]::acc)([p],acc)lincl::acc)acc!acc_andin(* encore clauses that make proxies in !acc_or equivalent to
their clause *)letacc=List.fold_left(funacc(p,l)->proxies:=p::!proxies;(* add clause [p => l1 | l2 | ... | ln], and add clauses
[l1 => p], [l2 => p], etc. *)letacc=List.fold_left(funacca->[p;F.nega]::acc)acclin(F.negp::l)::acc)acc!acc_orinaccletmake_cnff=acc_or:=[];acc_and:=[];cnf(sformf(funf'->f'))(* Naive CNF XXX remove???
let make_cnf f = mk_cnf (sform f)
*)end