Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sat_solver.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Bridge to [MSat] prover} *)openLogtkmoduleSI=Msat.Solver_intfletsection=Util.Section.make~parent:Const.section"msat"letprof_call_msat=ZProf.make"msat.call"letstat_num_clauses=Util.mk_stat"msat.num_clauses"letstat_num_calls=Util.mk_stat"msat.num_calls"typeproof_step=Sat_solver_intf.proof_steptypeproof=Sat_solver_intf.prooftyperesult=Sat_solver_intf.result=|Sat|UnsatofproofexceptionWrongStateofstringletwrong_state_msg=raise(WrongStatemsg)leterrorfmsg=Util.errorf~where:"sat_solver"msgletsat_dump_file_=ref""letsat_log_file=ref""letsat_compact_=reftrueletsat_pp_model_=reffalsemoduletypeS=Sat_solver_intf.S(* Instantiate solver *)moduleSolver=Msat.Make_pure_sat(structmoduleFormula=structincludeBBox.Litletnorm(l:t):t*_=letl',b=normlinl',ifbthenSI.NegatedelseSI.Same_signendtypeproof=Sat_solver_intf.proof_stepend)moduleMake()(* : Sat_solver_intf.S *)=structmoduleLit=BBox.Litletsolver=ref(Solver.create~size:`Big())typeclause=Lit.tlist(* queue of clauses waiting for being pushed into the solver *)letqueue_=Queue.create()(* flag to indicate whether it's time to re-check the model *)letmust_check=reffalse(* channel on which to print boolean clauses *)letdump_to:out_channeloptionref=refNone(* print list of clauses on [dump_to], if it's defined *)letdump_ll=match!dump_towith|None->()|Someout->letpp_litoutl=output_stringout(string_of_int(Lit.to_intl))inletpp_coutc=List.iter(funl->output_charout' ';pp_litoutl)c;output_stringout" 0\n";inList.iter(pp_cout)l;flushoutmoduleClauseTbl=CCHashtbl.Make(structtypet=Lit.tlistletequal=CCList.equalLit.equallethash=(Hash.listLit.hash)end)letclause_tbl_:unitClauseTbl.t=ClauseTbl.create32letlit_tbl_:unitLit.Tbl.t=Lit.Tbl.create32(* add clause, if not added already *)letadd_clause_~proofc=letopenMsatinifnot(ClauseTbl.memclause_tbl_c)then(Util.incr_statstat_num_clauses;(* add new clause -> check again *)must_check:=true;ClauseTbl.addclause_tbl_c();List.iter(funlit->Lit.Tbl.replacelit_tbl_(Lit.abslit)())c;Queue.push([c],proof)queue_)letadd_clause~proof(c:clause)=letc=CCList.sort_uniq~cmp:Lit.comparecin(* no duplicates *)dump_l[c];add_clause_~proofcletadd_clauses~proofl=dump_ll;List.iter(add_clause_~proof)lletadd_clause_seq~proof(seq:clauseIter.t)=add_clauses~proof(Iter.to_rev_listseq)letresult_=refSatletres_is_unsat_()=match!result_withSat->false|Unsat_->true(* invariant:
when result_ = Sat, only eval/eval_level are defined
when result_ = Unsat, only unsat_core_ is defined
*)leteval_fail__=assert(res_is_unsat_());wrong_state_"eval"leteval_=refeval_fail_leteval_level_=refeval_fail_letproof_:proofoptionref=refNoneletproved_lits_:Lit.Set.tlazy_tref=ref(lazyLit.Set.empty)letpp_=refLit.ppletpp_clauseoutc=Format.fprintfout"[@[<hv>%a@]]"(Util.pp_list~sep:" ⊔ "!pp_)cletpp_form_simploutl=Util.pp_list~sep:""pp_clauseoutlletpp_formfmtf:unit=Format.fprintffmt"[@[<hv>%a@]]"pp_form_simplfletlast_result()=!result_letvaluationl=!eval_lletvaluation_levell=!eval_level_lletall_proved()=Lazy.force!proved_lits_letget_proof()=match!proof_with|None->assertfalse|Somep->pletget_proof_opt()=!proof_let()=if!sat_log_file<>""then(letoc=open_out!sat_log_fileinletfmt=Format.formatter_of_out_channelocinMsat.Log.set_debug_outfmt;Msat.Log.set_debug9999;at_exit(fun()->Format.pp_print_flushfmt();close_out_noerroc);)exceptionUndecidedLit=Solver.UndecidedLittypesat_clause=Lit.tlistletbool_clause_of_sat(c:Solver.Clause.t):sat_clause=Solver.Clause.atoms_lc|>List.mapSolver.Atom.formula(* (clause * proof * proof) -> 'a *)moduleResTbl=CCHashtbl.Make(structtypet=sat_clause*Proof.tlistletequal(c,l1)(c',l2)=CCList.equalLit.equalcc'&&CCList.equalProof.S.equall1l2lethash(c,l)=CCHash.combine2(CCHash.int@@List.lengthc)(CCHash.listProof.S.hashl)end)lettbl_res=ResTbl.create16letproof_of_leafcstep:proof=letc=bool_clause_of_satcinProof.S.mkstep(Bool_clause.mk_proof_resc)(* convert a SAT proof into a tree of ProofStep *)letconv_proof_atomic_p:proof=letrecauxp=letmoduleP=Solver.ProofinmatchP.expandpwith|{P.step=P.Lemma_;_}->errorf"SAT proof involves a lemma"|{P.step=P.Assumption;_}->errorf"SAT proof involves an assumption"|{P.step=P.Duplicate(c',_);_}->auxc'|{P.conclusion=c;step=P.Hyper_res{P.hr_init;hr_steps}}->letc=bool_clause_of_satcin(* atomic resolution step *)letq1=auxhr_initinletq2=List.map(fun(_,p)->auxp)hr_stepsinbeginmatchResTbl.gettbl_res(c,q1::q2)with|Somes->s|None->letparents=Proof.Parent.fromq1::List.mapProof.Parent.fromq2inletstep=Proof.Step.inferenceparents~rule:(Proof.Rule.mk"sat_resolution")inlets=Proof.S.mkstep(Bool_clause.mk_proof_resc)inResTbl.addtbl_res(c,q1::q2)s;send|{P.conclusion=c;step=P.Hypothesisstep;_}->proof_of_leafcstepinSolver.Proof.checkp;auxpletconv_proof_compact_p:proof=letmoduleP=Solver.Proofinletleaves=P.fold(funaccpnode->matchpnodewith|{P.step=P.Lemma_;_}->errorf"SAT proof involves a lemma"|{P.step=P.Assumption;_}->errorf"SAT proof involves an assumption"|{P.step=(P.Hyper_res_|P.Duplicate_);_}->acc(* ignore, intermediate node *)|{P.conclusion=c;step=P.Hypothesisstep;_}->Proof.Parent.from(proof_of_leafcstep)::acc)[]pinlet{P.conclusion=c;_}=P.expandpinletc=bool_clause_of_satcinletstep=Proof.Step.inferenceleaves~rule:(Proof.Rule.mk"sat_resolution*")inProof.S.mkstep(Bool_clause.mk_proof_resc)letconv_proof_p=if!sat_compact_thenconv_proof_compact_pelseconv_proof_atomic_pletget_proof_of_litlit=letmoduleP=Solver.Proofinletb,l=valuation_levellitinifnotb||l<>0theninvalid_arg"get_proof_of_lit";leta=Solver.make_atom!solverlitinmatchP.prove_atomawith|Somep->conv_proof_p|None->assertfalseletproved_at_0lit=leta=Solver.make_atom!solverlitinifSolver.true_at_level0!solverathenSometrueelseifSolver.true_at_level0!solver(Solver.Atom.nega)thenSomefalseelseNoneletget_proved_lits():Lit.Set.t=Lit.Tbl.to_iterlit_tbl_|>Iter.filter_map(fun(lit,_)->matchproved_at_0litwith|Sometrue->Somelit|Somefalse->Some(Lit.neglit)|None->None)|>Lit.Set.of_iterletpp_model_():unit=matchlast_result()with|Sat->letm=Lit.Tbl.keyslit_tbl_|>Iter.map(funl->l,valuationl)|>Iter.to_rev_listinletpp_pairout(l,b)=Format.fprintfout"(@[%B %a@])"bBBox.pplinFormat.printf"(@[<hv2>bool_model@ %a@])@."(Util.pp_list~sep:" "pp_pair)m|Unsat_->()(* call [S.solve()] in any case, and enforce invariant about eval/unsat_core *)letcheck_unconditional_()=(* reset functions, so they will fail if called in the wrong state *)proof_:=None;eval_:=eval_fail_;eval_level_:=eval_fail_;Util.incr_statstat_num_calls;(* add pending clauses *)whilenot(Queue.is_emptyqueue_)doletc,proof=Queue.popqueue_inUtil.debugf~section4"@[<hv2>assume@ @[%a@]@ proof: %a@]"(funk->kpp_formcProof.Step.ppproof);Solver.assume!solvercproofdone;(* solve *)Util.debug~section4"solve...";letres=Solver.solve!solverinUtil.debug~section4"solve done.";beginmatchreswith|Solver.Sats->eval_:=s.SI.eval;eval_level_:=s.SI.eval_level;proved_lits_:=lazy(get_proved_lits());result_:=Sat;|Solver.Unsatus->letp=us.SI.get_proof()|>conv_proof_inresult_:=Unsatp;proof_:=Somep;end;!result_letcheck_full=iffull||!must_checkthen(assert(full||not(Queue.is_emptyqueue_));Util.debug~section5"check_real";must_check:=false;check_unconditional_())else!result_(* initialize eval/eval_level to enforce invariant *)let()=letres=check_unconditional_()inassert(res=Sat)letcheck~full()=ZProf.with_profprof_call_msatcheck_fullletset_printerpp=pp_:=ppletsetup()=if!sat_dump_file_<>""then(Util.debugf~section1"dump SAT clauses to `%s`"(funk->k!sat_dump_file_);tryletoc=open_out!sat_dump_file_indump_to:=Someoc;at_exit(fun()->close_out_noerroc);withe->Util.warnf"@[<2>could not open `%s`:@ %s@]"!sat_dump_file_(Printexc.to_stringe););if!sat_pp_model_thenat_exitpp_model_;()letclear?(size=`Big)()=Queue.clearqueue_;must_check:=true;ClauseTbl.clearclause_tbl_;Lit.Tbl.clearlit_tbl_;solver:=Solver.create~size()endletset_compactb=sat_compact_:=blet()=Params.add_opts["--sat-dump",Arg.Set_stringsat_dump_file_," output SAT problem(s) into <file>";"--sat-log",Arg.Set_stringsat_log_file," output SAT logs into <file>";"--compact-sat",Arg.Setsat_compact_," compact SAT proofs";"--no-compact-sat",Arg.Clearsat_compact_," do not compact SAT proofs";"--pp-sat-model",Arg.Setsat_pp_model_," print SAT model on exit"]