123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 boolean subterms} *)openLogtkopenLibzipperpositionmoduleT=Termtypeselection_setting=Any|Minimal|Largetypereasoning_kind=BoolReasoningDisabled|BoolCasesInference|BoolCasesSimplification|BoolCasesKeepParent|BoolCasesEagerFar|BoolCasesEagerNearletsection=Util.Section.make~parent:Const.section"booleans"letk_bool_reasoning=Flex_state.create_key()letk_cased_term_selection=Flex_state.create_key()letk_quant_rename=Flex_state.create_key()letk_interpret_bool_funs=Flex_state.create_key()letk_cnf_non_simpl=Flex_state.create_key()letk_norm_bools=Flex_state.create_key()letk_solve_formulas=Flex_state.create_key()moduletypeS=sigmoduleEnv:Env.SmoduleC:moduletypeofEnv.C(** {6 Registration} *)valsetup:unit->unit(** Register rules in the environment *)endmoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleC=Env.CmoduleCtx=Env.CtxmoduleFool=Fool.Make(Env)let(=~),(/~)=Literal.mk_eq,Literal.mk_neqlet(@:)=T.app_builtin~ty:Type.propletnoa=a=~T.false_letyesa=a=~T.true_letimplyab=Builtin.Imply@:[a;b]letconst_truep=T.fun_(List.hd@@fst@@Type.open_fun(T.typ))T.true_lettrue_not_false=[T.true_/~T.false_]lettrue_or_falsea=[yesa;a=~T.false_]letimp_true1ab=[yesa;yes(implyab)]letimp_true2ab=[nob;yes(implyab)]letimp_falseab=[no(implyab);noa;yesb]letall_truep=[p/~const_truep;yes(Builtin.ForallConst@:[p])]letall_falsep=[no(Builtin.ForallConst@:[p]);p=~const_truep]leteq_truexy=[x/~y;yes(Builtin.Eq@:[x;y])]leteq_falsexy=[no(Builtin.Eq@:[x;y]);x=~y]letand_ab=[Builtin.And@:[a;b]=~imply(implya(implybT.false_))T.false_]letor_ab=[Builtin.Or@:[a;b]=~imply(implyaT.false_)b]letand_truea=[Builtin.And@:[T.true_;a]=~a]letand_falsea=[Builtin.And@:[T.false_;a]=~T.false_]letexistst=lett2bool=Type.arrow[t]Type.propin[T.app_builtin~ty:(Type.arrow[t2bool]Type.prop)Builtin.ExistsConst[]=~T.fun_t2bool(Builtin.Not@:[Builtin.ForallConst@:[T.fun_t(Builtin.Not@:[T.app(T.bvart2bool1)[T.bvart0]])]])]letas_clausec=Env.C.create~penalty:1~trail:Trail.emptycProof.Step.trivialletcreate_clauses()=leta=T.var(HVar.make~ty:Type.prop0)in[[Builtin.And@:[T.true_;a]=~a];[Builtin.And@:[T.false_;a]=~T.false_];[Builtin.Or@:[T.true_;a]=~T.true_];[Builtin.Or@:[T.false_;a]=~a];[Builtin.Imply@:[T.true_;a]=~a];[Builtin.Imply@:[T.false_;a]=~T.true_];[Builtin.Not@:[T.true_]=~T.false_];[Builtin.Not@:[T.false_]=~T.true_];]|>List.mapas_clause|>Iter.of_listletbool_cases(c:C.t):C.tlist=letterm_as_true=Term.Tbl.create8inletterm_as_false=Term.Tbl.create4inletcased_term_selection=Env.flex_getk_cased_term_selectioninletrecfind_boolstopt=letcan_be_cased=Type.is_prop(T.tyt)&&T.DB.is_closedt&&(nottop||(* It is useful to case top level equality like 𝘵𝘦𝘳𝘮𝘴
because these are simplified into 𝘭𝘪𝘵𝘦𝘳𝘢𝘭𝘴. *)matchT.viewtwithAppBuiltin((Eq|Neq|Equiv|Xor),_)->true|_->false)inletis_quant=matchT.viewtwith|AppBuiltin(b,_)->Builtin.equalbBuiltin.ForallConst||Builtin.equalbBuiltin.ExistsConst|_->falsein(* Add only propositions. *)letadd=ifcan_be_casedthenTerm.Tbl.addterm_as_trueelsefun__->()inletyes=ifcan_be_casedthenyeselsefun_->yesT.true_in(* Stop recursion in combination of certain settings. *)letinnerfx=ifis_quant||can_be_cased&&cased_term_selection=Largethen()elseList.iter(ffalse)xinmatchT.viewtwith|DB_|Var_->()|Const_->addt(yest)|Fun(_,b)->find_boolsfalseb|App(f,ps)->addt(yest);innerfind_bools(f::ps)|AppBuiltin(f,ps)->innerfind_boolsps;matchfwith|Builtin.True|Builtin.False->()|Builtin.Eq|Builtin.Neq|Builtin.Equiv|Builtin.Xor->beginmatchpswith|[x;y]when(cased_term_selection!=Minimal||Type.is_prop(T.tyx))->iff=Builtin.Neq||f=Builtin.Xorthen(ifcan_be_casedthenTerm.Tbl.addterm_as_falset(x=~y);addt(x/~y))elseaddt(x=~y)|_->()end|Builtin.And|Builtin.Or|Builtin.Imply|Builtin.Not->ifcased_term_selection!=Minimalthenaddt(yest)else()|_->addt(yest)inLiterals.Seq.terms(C.litsc)|>Iter.iter(find_boolstrue);letcasepolaritybb_litclauses=letproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"bool_cases")~tags:[Proof.Tag.T_ho]inC.create~trail:(C.trailc)~penalty:(C.penaltyc)(b_lit::Array.to_list(C.litsc|>Literals.map(T.replace~old:b~by:polarity)))proof::clausesinTerm.Tbl.fold(caseT.false_)term_as_true[]@Term.Tbl.fold(caseT.true_)term_as_false[]letbool_case_simp(c:C.t):C.tlistoption=letterm_to_equations=Term.Tbl.create8inletcased_term_selection=Env.flex_getk_cased_term_selectioninletrecfind_boolstopt=letcan_be_cased=Type.is_prop(T.tyt)&&T.DB.is_closedt&&(nottop||(* It is useful to case top level equality like 𝘵𝘦𝘳𝘮𝘴 because these are simplified into 𝘭𝘪𝘵𝘦𝘳𝘢𝘭𝘴. *)matchT.viewtwithAppBuiltin((Eq|Neq|Equiv|Xor),_)->true|_->false)inletis_quant=matchT.viewtwith|AppBuiltin(b,_)->Builtin.equalbBuiltin.ForallConst||Builtin.equalbBuiltin.ExistsConst|_->falsein(* Add only propositions. *)letaddtxy=ifcan_be_casedthenTerm.Tbl.addterm_to_equationst(x=~y,x/~y)in(* Stop recursion in combination of certain settings. *)letinnerfx=ifis_quant||(can_be_cased&&cased_term_selection=Large)then()elseList.iter(ffalse)xinmatchT.viewtwith|DB_|Var_->()|Const_->addttT.true_|Fun(_,b)->find_boolsfalseb|App(f,ps)->addttT.true_;innerfind_bools(f::ps)|AppBuiltin(f,ps)->innerfind_boolsps;matchfwith|Builtin.True|Builtin.False->()|Builtin.Eq|Builtin.Neq|Builtin.Equiv|Builtin.Xor->(matchpswith|[_;x;y]|[x;y]when(cased_term_selection!=Minimal||Type.is_prop(T.tyx))->addtxy;if(f=Builtin.Neq||f=Builtin.Xor)&&can_be_casedthenTerm.Tbl.replaceterm_to_equationst(Term.Tbl.findterm_to_equationst|>CCPair.swap)|_->())|Builtin.And|Builtin.Or|Builtin.Imply|Builtin.Not->ifcased_term_selection!=MinimalthenaddttT.true_else()|_->addttT.true_inifnot@@Iter.existsT.is_formula(C.Seq.termsc)then((* first clausify, then get bool subterms *)Literals.Seq.terms(C.litsc)|>Iter.iter(find_boolstrue));letres=Term.Tbl.fold(funb(b_true,b_false)clauses->ifcased_term_selection!=Minimal||Term.Seq.subtermsb|>Iter.for_all(funst->T.equalbst||not(Type.is_prop(T.tyst)))then(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"bool_case_simp")~tags:[Proof.Tag.T_ho]inC.create~trail:(C.trailc)~penalty:(C.penaltyc)(b_true::Array.to_list(C.litsc|>Literals.map(T.replace~old:b~by:T.false_)))proof::C.create~trail:(C.trailc)~penalty:(C.penaltyc)(b_false::Array.to_list(C.litsc|>Literals.map(T.replace~old:b~by:T.true_)))proof::clauses)elseclauses)term_to_equations[]inifCCList.is_emptyresthenNoneelse((* CCFormat.printf "bool case simp: %a.\n" C.pp c; *)(* CCList.iteri (fun i nc -> CCFormat.printf "@[%d: @[%a@]@].\n" i C.pp nc) res; *)Someres)letsimpl_bool_subtermsc=letnew_lits=Literals.mapT.simplify_bools(C.litsc)inifLiterals.equal(C.litsc)new_litsthen(SimplM.return_samec)else(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"simplify boolean subterms")inletnew_=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(Array.to_listnew_lits)proofinSimplM.return_newnew_)letnormalize_bool_termsc=letnew_lits=Literals.mapT.normalize_bools(C.litsc)inifLiterals.equal(C.litsc)new_litsthen(SimplM.return_samec)else(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"normalize subterms")inletnew_=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(Array.to_listnew_lits)proofinSimplM.return_newnew_)letnormalize_equalitiesc=letlits=Array.to_list(C.litsc)inletnormalized=List.mapLiteral.normalize_eqlitsinifList.existsCCOpt.is_somenormalizedthen(letnew_lits=List.mapi(funil_opt->CCOpt.get_or~default:(Array.get(C.litsc)i)l_opt)normalizedinletproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"simplify nested equalities")inletnew_c=C.create~trail:(C.trailc)~penalty:(C.penaltyc)new_litsproofinSimplM.return_newnew_c)else(SimplM.return_samec)letcnf_otfc:C.tlistoption=letidx=CCArray.find_idx(funl->leteq=Literal.View.as_eqnlinmatcheqwith|Some(l,r,sign)->Type.is_prop(T.tyl)&&((not(T.equalrT.true_)&¬(T.equalrT.false_))||T.is_formulal||T.is_formular)|None->false)(C.litsc)inletrenaming_weight=40inletmax_formula_weight=C.Seq.termsc|>Iter.filterT.is_formula|>Iter.mapT.size|>Iter.maxinletopts=matchmax_formula_weightwith|None->[Cnf.DisableRenaming]|Somem->ifm<renaming_weightthen[Cnf.DisableRenaming]else[]inmatchidxwith|Some_->letf=Literals.Conv.to_tst(C.litsc)inletproof=Proof.Step.simp~rule:(Proof.Rule.mk"cnf_otf")~tags:[Proof.Tag.T_ho][C.proof_parentc]inlettrail=C.trailcandpenalty=C.penaltycinletstmt=Statement.assert_~prooffinletcnf_vec=Cnf.convert@@CCVector.to_seq@@Cnf.cnf_of~opts~ctx:(Ctx.sk_ctx())stmtinCCVector.iter(funcl->Statement.Seq.ty_declscl|>Iter.iter(fun(id,ty)->Ctx.declareidty))cnf_vec;letclauses=CCVector.map(C.of_statement~convert_defs:true)cnf_vec|>CCVector.to_list|>CCList.flatten|>List.map(func->C.create~penalty~trail(CCArray.to_list(C.litsc))proof)inList.iteri(funinew_c->assert((C.proof_depthc)<=C.proof_depthnew_c);)clauses;Someclauses|None->Noneletcnf_infercl=CCOpt.get_or~default:[](cnf_otfcl)letinterpret_boolean_functionsc=(* Collects boolean functions only at top level,
and not the ones that are already a part of the quantifier *)letcollect_tl_bool_funcstk=letrecauxt=matchT.viewtwith|Var_|Const_|DB_->()|Fun_->ifType.is_prop(Term.ty(snd@@Term.open_funt))thenkt|App(f,l)->auxf;List.iterauxl|AppBuiltin(b,l)->ifnot@@Builtin.is_quantifierbthenList.iterauxlinauxtinletinterpretti=letty_args,body=T.open_funtinassert(Type.is_prop(Term.tybody));T.fun_lty_argsiinletnegate_bool_funbool_fun=letty_args,body=T.open_funbool_funinassert(Type.is_prop(Term.tybody));T.fun_lty_args(T.Form.not_body)inIter.flat_mapcollect_tl_bool_funcs(C.Seq.termsc|>Iter.filter(funt->not@@T.is_funt))|>Iter.sort_uniq~cmp:Term.compare|>Iter.filter(funt->letcached_t=Subst.FO.canonize_all_varstinnot(Term.Set.memcached_t!Higher_order.prim_enum_terms))|>Iter.fold(funrest->assert(T.DB.is_closedt);letproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"interpret boolean function")~tags:[Proof.Tag.T_ho]inletas_forall=Literal.mk_prop(T.Form.forallt)falseinletas_neg_forall=Literal.mk_prop(T.Form.forall(negate_bool_funt))falseinletforall_cl=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(as_forall::Array.to_list(C.litsc|>Literals.map(T.replace~old:t~by:(interprettT.true_))))proofinletforall_neg_cl=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(as_neg_forall::Array.to_list(C.litsc|>Literals.map(T.replace~old:t~by:(interprettT.false_))))proofinUtil.debugf~section1"interpret bool: %a !!> %a.\n"(funk->kC.ppcC.ppforall_cl);Util.debugf~section1"interpret bool: %a !!~> %a.\n"(funk->kC.ppcC.ppforall_neg_cl);forall_cl::forall_neg_cl::res)[]letsolve_bool_formulascl=letmodulePUnif=PUnif.Make(structletst=Env.flex_state()end)inletunifiers=CCList.flat_map(funliteral->matchliteralwith|Literal.Equation(lhs,rhs,false)whenType.is_prop(Term.tylhs)->PUnif.unify_scoped(lhs,0)(rhs,0)|>OSeq.filter_mapCCFun.id|>OSeq.to_list|_->[])(CCArray.to_list(C.litscl))inifCCList.is_emptyunifiersthenNoneelseSome(List.map(funsubst->letsubst=Unif_subst.substsubstinC.apply_subst(cl,0)subst)unifiers)letsetup()=matchEnv.flex_getk_bool_reasoningwith|BoolReasoningDisabled->()|_->(* Env.ProofState.PassiveSet.add (create_clauses ()); *)Env.add_basic_simplifysimpl_bool_subterms;Env.add_basic_simplifynormalize_equalities;ifEnv.flex_getk_norm_boolsthen(Env.add_basic_simplifynormalize_bool_terms);Env.add_multi_simpl_ruleFool.rw_bool_lits;ifEnv.flex_getk_cnf_non_simplthen(Env.add_unary_inf"cnf otf inf"cnf_infer;)elseEnv.add_multi_simpl_rulecnf_otf;ifEnv.flex_getk_solve_formulasthen(Env.add_multi_simpl_rulesolve_bool_formulas);if(Env.flex_getk_interpret_bool_funs)then(Env.add_unary_inf"interpret boolean functions"interpret_boolean_functions;);ifEnv.flex_getk_bool_reasoning=BoolCasesInferencethen(Env.add_unary_inf"bool_cases"bool_cases;)elseifEnv.flex_getk_bool_reasoning=BoolCasesSimplificationthen(Env.set_single_step_multi_simpl_rulebool_case_simp;)elseifEnv.flex_getk_bool_reasoning=BoolCasesKeepParentthen(letkeep_parentc=CCOpt.get_or~default:[](bool_case_simpc)inEnv.add_unary_inf"bool_cases_keep_parent"keep_parent;)endopenCCFunopenBuiltinopenStatementopenTypedSTermopenCCListletif_changedproof(mk:?attrs:Logtk.Statement.attrs->'r)sfp=letfp=fspiniffp=[p]then[s]elsemap(funx->mk~proof:(proofs)x)fpletmap_propositions~prooff=CCVector.flat_map_list(funs->matchStatement.viewswith|Assertp->if_changedproofassert_sfp|Lemmaps->if_changedprooflemmas(map%f)ps|Goalp->if_changedproofgoalsfp|NegatedGoal(ts,ps)->if_changedproof(neg_goal~skolems:ts)s(map%f)ps|_->[s])letis_boolt=CCOpt.equalTy.equal(Someprop)(tyt)letis_T_Ft=matchviewtwithAppBuiltin((True|False),[])->true|_->false(* Modify every subterm of t by f except those at the "top". Here top is true if subterm occures under a quantifier Æ in a context where it could participate to the clausification if the surrounding context of Æ was ignored. *)letrecreplaceTSTftopt=letre=replaceTSTfinletty=ty_exntinlettransformer=iftopthenidelsefintransformer(matchviewtwith|App(t,ts)->app_whnf~ty(refalset)(map(refalse)ts)|Ite(c,x,y)->ite(refalsec)(refalsex)(refalsey)|Match(t,cases)->match_(refalset)(map(fun(c,vs,e)->(c,vs,refalsee))cases)|Let(binds,expr)->let_(map(CCPair.map2(refalse))binds)(refalseexpr)|Bind(b,x,t)->lettop=Binder.equalbBinder.Forall||Binder.equalbBinder.Existsinbind~tybx(retopt)|AppBuiltin(b,ts)->letlogical=for_allis_booltsinapp_builtin~tyb(map(re(top&&logical))ts)|Multisetts->multiset~ty(map(refalse)ts)|_->t)letname_quantifiersstmts=letproofs=Proof.Step.esa[Proof.Parent.from(Statement.as_proof_is)]~rule:(Proof.Rule.mk"Quantifier naming")inletnew_stmts=CCVector.create()inletchanged=reffalseinletif_changed(mk:?attrs:Logtk.Statement.attrs->'r)sr=if!changedthen(changed:=false;mk~proof:(proofs)r)elsesinletif_changed_list(mk:?attrs:Logtk.Statement.attrs->'l)sr=if!changedthen(changed:=false;mk~proof:(proofs)r)elsesinletname_prop_Qss=replaceTST(funt->matchTypedSTerm.viewtwith|Bind(Binder.Forall,_,_)|Bind(Binder.Exists,_,_)->changed:=true;letvars=Var.Set.of_seq(TypedSTerm.Seq.free_varst)|>Var.Set.to_listinletqid=ID.gensym()inletty=app_builtin~ty:tTypeArrow(prop::mapVar.tyvars)inletq=const~tyqidinletq_vars=app~ty:propq(mapvarvars)inletproof=Proof.Step.define_internalqid[Proof.Parent.from(Statement.as_proof_is)]inletq_typedecl=ty_decl~proofqidtyinletdefinition=(* ∀ vars: q[vars] ⇔ t, where t is a quantifier formula and q is a new name for it. *)bind_list~ty:propBinder.Forallvars(app_builtin~ty:propBuiltin.Equiv[q_vars;t])inCCVector.pushnew_stmtsq_typedecl;CCVector.pushnew_stmts(assert_~proofdefinition);q_vars|_->t)trueinstmts|>CCVector.map(funs->matchStatement.viewswith|TyDecl(id,t)->s|Datats->s|Defdefs->s|Rewrite_->s|Assertp->if_changedassert_s(name_prop_Qssp)|Lemmaps->if_changed_listlemmas(map(name_prop_Qss)ps)|Goalp->if_changedgoals(name_prop_Qssp)|NegatedGoal(ts,ps)->if_changed_list(neg_goal~skolems:ts)s(map(name_prop_Qss)ps))|>CCVector.appendnew_stmts;CCVector.freezenew_stmtsletrecreplaceoldbyt=letr=replaceoldbyinletty=ty_exntinifTypedSTerm.equaltoldthenbyelsematchviewtwith|App(f,ps)->app_whnf~ty(rf)(maprps)|AppBuiltin(f,ps)->app_builtin~tyf(maprps)|Ite(c,x,y)->ite(rc)(rx)(ry)|Let(bs,e)->let_(map(CCPair.map2r)bs)(re)|Bind(b,v,e)->bind~tybv(re)|_->texceptionReturnofTypedSTerm.t(* If f _ s = Some r for a subterm s of t, then r else t. *)letwith_subterm_or_idtf=try(Seq.subterms_with_boundt(fun(s,var_ctx)->matchfvar_ctxswith|None->()|Somer->raise(Returnr)));twithReturnr->r(* If p is non-constant subproposition closed wrt variables vs, then (p ⇒ c[p:=⊤]) ∧ (p ∨ c[p:=⊥]) or else c unmodified. *)letcase_boolvscp=ifis_boolp&¬(is_T_Fp)&&p!=c&&Var.Set.is_empty(Var.Set.diff(free_vars_setp)vs)thenletty=propinapp_builtin~tyAnd[app_builtin~tyImply[p;replacepForm.true_c];app_builtin~tyOr[p;replacepForm.false_c];]elsec(* Apply repeatedly the transformation t[p] ↦ (p ⇒ t[⊤]) ∧ (¬p ⇒ t[⊥]) for each boolean parameter p≠⊤,⊥ that is closed in context where variables vs are bound. *)letreccase_bools_wrtvst=with_subterm_or_idt(fun_s->matchviewswith|App(f,ps)->lett'=fold_left(case_boolvs)tpsinift==t'thenNoneelseSome(case_bools_wrtvst')|_->None)leteager_cases_far=letproofs=Proof.Step.esa[Proof.Parent.from(Statement.as_proof_is)]~rule:(Proof.Rule.mk"eager_cases_far")inmap_propositions~proof(fun_t->[with_subterm_or_idt(funvss->matchviewswith|Bind((Forall|Exists)asq,v,b)->letb'=case_bools_wrt(Var.Set.addvsv)binifb==b'thenNoneelseSome(replaces(bind~ty:propqvb')t)|_->None)|>case_bools_wrtVar.Set.empty])leteager_cases_near=letproofs=Proof.Step.esa[Proof.Parent.from(Statement.as_proof_is)]~rule:(Proof.Rule.mk"eager_cases_near")inletreccase_neart=with_subterm_or_idt(funvss->matchviewswith|AppBuiltin((And|Or|Imply|Not|Equiv|Xor|ForallConst|ExistsConst),_)|Bind((Forall|Exists),_,_)->None|AppBuiltin((Eq|Neq),[x;y])whenis_boolx->None|_whenis_bools->lets'=case_boolvss(with_subterm_or_ids(fun_->CCOpt.if_(funx->x!=s&&is_boolx&¬(is_T_Fx))))inifs==s'thenNoneelseSome(case_near(replacess't))|_->None)inmap_propositions~proof(fun_p->[case_nearp])openTermletpost_eager_cases=letproofs=Proof.Step.esa[Proof.Parent.from(Statement.as_proof_cs)]~rule:(Proof.Rule.mk"post_eager_cases")inmap_propositions~proof(fun_c->letcased=refSet.emptyinfold_left(SLiteral.fold(funres->(* Loop over subterms of terms of literals of a clause. *)Seq.subterms_depth%>Iter.fold(funres(s,d)->ifd=0||not(Type.is_prop(tys))||is_true_or_falses||is_vars||Set.mems!casedthenreselse(cased:=Set.adds!cased;letreplace_s_byby=map(SLiteral.map~f:(replace~old:s~by))inflatten(map(func->[SLiteral.atom_trues::replace_s_byfalse_c;SLiteral.atom_falses::replace_s_bytrue_c])res)))res))[c]c)let_bool_reasoning=refBoolReasoningDisabledlet_quant_rename=reffalse(* These two options run before CNF,
so (for now it is impossible to move them to Env
since it is not even made at the moment) *)letpreprocess_booleansstmts=(match!_bool_reasoningwith|BoolCasesEagerFar->eager_cases_far|BoolCasesEagerNear->eager_cases_near|_->id)(if!_quant_renamethenname_quantifiersstmtselsestmts)letpreprocess_cnf_booleansstmts=match!_bool_reasoningwith|BoolCasesEagerFar|BoolCasesEagerNear->post_eager_casesstmts|_->stmtslet_cased_term_selection=refLargelet_interpret_bool_funs=reffalselet_cnf_non_simpl=reffalselet_norm_bools=reffalselet_solve_formulas=reffalseletextension=letregisterenv=letmoduleE=(valenv:Env.S)inletmoduleET=Make(E)inE.flex_addk_bool_reasoning!_bool_reasoning;E.flex_addk_cased_term_selection!_cased_term_selection;E.flex_addk_quant_rename!_quant_rename;E.flex_addk_interpret_bool_funs!_interpret_bool_funs;E.flex_addk_cnf_non_simpl!_cnf_non_simpl;E.flex_addk_norm_bools!_norm_bools;E.flex_addk_solve_formulas!_solve_formulas;ET.setup()in{Extensions.defaultwithExtensions.name="bool";env_actions=[register];}let()=Options.add_opts["--boolean-reasoning",Arg.Symbol(["off";"cases-inf";"cases-simpl";"cases-simpl-kp";"cases-eager";"cases-eager-near"],funs->_bool_reasoning:=matchswith|"off"->BoolReasoningDisabled|"cases-inf"->BoolCasesInference|"cases-simpl"->BoolCasesSimplification|"cases-simpl-kp"->BoolCasesKeepParent|"cases-eager"->BoolCasesEagerFar|"cases-eager-near"->BoolCasesEagerNear|_->assertfalse)," enable/disable boolean axioms";"--bool-subterm-selection",Arg.Symbol(["A";"M";"L"],(funopt->_cased_term_selection:=matchoptwith"A"->Any|"M"->Minimal|"L"->Large|_->assertfalse))," select boolean subterm selection criterion: A for any, M for minimal and L for large";"--quantifier-renaming",Arg.Bool(funv->_quant_rename:=v)," turn the quantifier renaming on or off";"--disable-simplifying-cnf",Arg.Set_cnf_non_simpl,"implement cnf on-the-fly as an inference rule";"--interpret-bool-funs",Arg.Bool(funv->_interpret_bool_funs:=v)," turn interpretation of boolean functions as forall or negation of forall on or off";"--normalize-bool-terms",Arg.Bool((funv->_norm_bools:=v))," normalize boolean subterms using their weight.";"--solve-formulas",Arg.Bool(funv->_solve_formulas:=v)," solve phi != psi eagerly using unification, where phi and psi are formulas"];Params.add_to_mode"ho-complete-basic"(fun()->_bool_reasoning:=BoolReasoningDisabled);Params.add_to_mode"fo-complete-basic"(fun()->_bool_reasoning:=BoolReasoningDisabled);Extensions.registerextension