123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 boolean subterms} *)openLogtkopenLibzipperpositionmoduleT=TermmodulePos=PositionmoduleUS=Unif_substmoduleL=LiteralmoduleLs=Literalstypereasoning_kind=BoolReasoningDisabled|BoolSimplificationsOnly|BoolHoist|BoolCasesPreprocessletsection=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_filter_literals=Flex_state.create_key()letk_nnf=Flex_state.create_key()letk_simplify_bools=Flex_state.create_key()letk_trigger_bool_inst=Flex_state.create_key()letk_trigger_bool_ind=Flex_state.create_key()letk_include_quants=Flex_state.create_key()letk_bool_hoist_simpl=Flex_state.create_key()letk_rename_nested_bools=Flex_state.create_key()letk_bool_app_var_repl=Flex_state.create_key()letk_fluid_hoist=Flex_state.create_key()letk_fluid_log_hoist=Flex_state.create_key()letk_solve_formulas=Flex_state.create_key()letk_replace_unsupported_quants=Flex_state.create_key()letk_disable_ho_bool_unif=Flex_state.create_key()letk_generalize_trigger=Flex_state.create_key()letk_bool_triggers_only=Flex_state.create_key()moduletypeS=sigmoduleEnv:Env.SmoduleC:moduletypeofEnv.C(** {5 Registration} *)valsetup:unit->unit(** Register rules in the environment *)endmoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmodulePS=E.ProofStatemoduleC=Env.CmoduleCtx=Env.CtxmoduleFool=Fool.Make(Env)moduleCombs=Combinators.Make(Env)moduleHO=Higher_order.Make(Env)moduleLazyCNF=Lazy_cnf.Make(Env)moduleFR=Env.FormRenamemoduleStm=Env.StmmoduleStmQ=Env.StmQlet(=~),(/~)=Literal.mk_eq,Literal.mk_neqlet(@:)=T.app_builtin~ty:Type.propletnoa=a=~T.false_letyesa=a=~T.true_let_trigger_bools=ref(Type.Map.empty)(* type --> boolean trigger *)let_cls_w_pred_vars=ref(Type.Map.empty)(* type --> (clause,var) *)letget_unif_alg()=ifEnv.flex_getk_disable_ho_bool_unifthen(fun__->OSeq.empty)elseEnv.flex_getSuperposition.k_unif_algletget_unif_alg_l()=ifEnv.flex_getk_disable_ho_bool_unifthen(fun__->OSeq.empty)else(let(moduleU)=Superposition.get_unif_module(moduleE)inU.unify_scoped_l)letget_triggersc=letord=Ctx.ord()inlettrivial_triggert=letbody=snd@@T.open_funtinT.is_varbody||T.is_true_or_falsebodyinletrecget_termstk=ifT.DB.is_closedtthenkt;matchT.viewtwith|T.App(hd,args)->List.iter(funt->get_termstk)(args)|T.AppBuiltin((And|Or|Not|Imply|Eq|Neq|Equiv|Xor),args)->List.iter(funt->get_termstk)(args)|T.AppBuiltin((ForallConst|ExistsConst),[_;body])->ifEnv.flex_getk_include_quantsthenkbody|_->()inLiterals.fold_terms~ord~subterms:false~eligible:C.Eligible.always~which:`All(C.litsc)~fun_bodies:false|>Iter.flat_map(fun(t,p)->get_termst)|>Iter.filter_map(funt->letty=Term.tytandhd=Term.head_termtinletcached_t=Subst.FO.canonize_all_varstinifnot(Term.Set.memcached_t!Higher_order.prim_enum_terms)&&Type.is_funty&&Type.returns_propty&¬(Term.is_varhd)&¬(trivial_triggert)then(Somet)elseNone)letinstantiate_w_bool~clause~var~trigger=assert(Type.equal(T.tyvar)(T.tytrigger));letcl_sc,trig_sc=0,1inletsubst=Subst.FO.bind'Subst.empty(T.as_var_exnvar,cl_sc)(trigger,trig_sc)inletrenaming=Subst.Renaming.create()inletexpand_quant=not@@Env.flex_getCombinators.k_enable_combinatorsinletlits=Literals.apply_substrenamingsubst(C.litsclause,cl_sc)inletlits=Literals.map(funt->Lambda.eta_reduce~expand_quant@@Lambda.snft)litsinletproof=Proof.Step.inference~rule:(Proof.Rule.mk"triggered_bool_instantiation")~tags:[Proof.Tag.T_ho;Proof.Tag.T_cannot_orphan][C.proof_parent_substrenaming(clause,cl_sc)subst]inletres=C.create_alitsproof~penalty:(C.penaltyclause)~trail:(C.trailclause)in(* CCFormat.printf "instatiate:@.c:@[%a@]@.subst:@[%a@]@.res:@[%a@]@." C.pp clause Subst.pp subst C.pp res; *)resletinst_clauses_w_triggert=lettriggers=Type.Map.get_or~default:[](T.tyt)!_trigger_boolsinifnot(CCList.mem~eq:T.equalttriggers)&&(not(Env.flex_getk_bool_triggers_only)||Type.returns_prop(T.tyt))then(_trigger_bools:=Type.Map.update(T.tyt)(function|None->Some[t]|Someres->Some(t::res))!_trigger_bools;Type.Map.get_or~default:[](T.tyt)!_cls_w_pred_vars|>CCList.map(fun(clause,var)->instantiate_w_bool~clause~var~trigger:t))else[]letinsert_new_triggert=letdo_insertt=inst_clauses_w_triggert|>CCList.to_iter|>Env.add_passiveindo_insertt;if(Type.returns_prop(T.tyt))then(lett=Lambda.eta_expandtinmatchEnv.flex_getk_generalize_triggerwith|`Neg->letvars,body=T.open_funtinifnot(Type.is_prop(T.tybody))then(CCFormat.printf"%a:%a@."T.ppbodyType.pp(T.tybody);assert(false););do_insert(T.fun_lvars(T.Form.not_body))|`Var->letvars,body=T.open_funtinassert(Type.is_prop(T.tybody));letn=List.lengthvarsinletdbs=List.mapi(funity->T.bvar~ty(n-i-1))varsinletvar_ty=Type.(==>)(vars@[Type.prop])Type.propinletvar=T.var(HVar.fresh~ty:var_ty())indo_insert(T.fun_lvars(T.appvar(dbs@[body])))|_->())letupdate_triggerscl=(* if triggered boolean instantiation is off
k_trigger_bool_inst is -1 *)ifC.proof_depthcl<Env.flex_getk_trigger_bool_instthen(letnew_triggers=(get_triggerscl)inifnot(Iter.is_emptynew_triggers)then(Iter.iterinsert_new_triggernew_triggers));Signal.ContinueListeninglethandle_new_pred_var_clause(clause,var)=assert(T.is_varvar);assert(Type.returns_prop(T.tyvar));letty=T.tyvarinType.Map.get_or~default:[]ty!_trigger_bools|>CCList.map(funtrigger->instantiate_w_bool~clause~var~trigger)|>CCList.to_iter|>Env.add_passive;_cls_w_pred_vars:=Type.Map.updatety(function|None->Some[(clause,var)]|Someres->Some((clause,var)::res))!_cls_w_pred_vars;Signal.ContinueListeninglethandle_new_skolem_sym(c,trigger)=lettrig_hd=T.head_termtriggerinassert(T.is_consttrig_hd);assert(ID.is_postcnf_skolem(T.as_const_exntrig_hd));ifC.proof_depthc<Env.flex_getk_trigger_bool_insttheninsert_new_triggertrigger;Signal.ContinueListeninglettrigger_inductioncl=(* abstracts away closed subterm from the term t
by replacing it with (accordingly shifted) DB variable 0 *)letabstract~subtermt=assert(T.DB.is_closedsubterm);letrecaux~deptht=ifT.equalsubtermtthen(T.bvar~ty:(T.tysubterm)depth)else(matchT.viewtwith|T.App(hd,args)->lethd'=aux~depthhdinletargs'=List.map(aux~depth)argsinifT.equalhdhd'&&T.same_largsargs'thentelseT.apphd'args'|T.AppBuiltin(hd,args)->letargs'=List.map(aux~depth)argsinifT.same_largsargs'thentelseT.app_builtin~ty:(T.tyt)hdargs'|T.Fun_->letpref,body=T.open_funtinletbody'=aux~depth:(depth+(List.lengthpref))bodyinifT.equalbodybody'thentelseT.fun_lprefbody'|_->t)inletres=aux~depth:0tinassert(Type.equal(T.tyres)(T.tyt));ifT.equalrestthenNoneelse(Someres)inletmake_triggerslhsrhssign=letlhs_body,rhs_body=snd(Term.open_funlhs),snd(Term.open_funrhs)inletimmediate_args=if(T.is_const(T.head_termlhs_body))&&(T.is_const(T.head_termrhs_body))then(List.sort_uniqT.compare(T.argslhs_body@T.argsrhs_body))else[]inCCList.filter_map(funarg->ifT.DB.is_closedarg&¬(Type.is_tType(T.tyarg))then(matchabstract~subterm:arglhs,abstract~subterm:argrhswith|Some(lhs'),Some(rhs')->assert(Type.equal(T.tylhs')(T.tyrhs'));(* Flipping the sign that is present in conjecture,
to prove the negated conjecture using induction *)letbuild_bodysign=ifsignthenT.Form.neqelseT.Form.eqinletres=T.fun_(T.tyarg)(build_bodysignlhs'rhs')inassert(T.DB.is_closedres);Someres|_->None)elseNone)immediate_argsinifC.proof_depthcl<Env.flex_getk_trigger_bool_ind&&CCOpt.is_some(C.distance_to_goalcl)then(matchC.litsclwith|[|Literal.Equation(lhs,rhs,_)aslit|]->letres=CCList.flat_mapinst_clauses_w_trigger(make_triggerslhsrhs(Literal.is_positivoidlit))inres|_->[])else[]let()=Signal.onPS.ActiveSet.on_add_clause(func->update_triggersc)letmk_res~proof~old~replnew_litc=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(new_lit::Array.to_list(C.litsc|>Literals.map(T.replace~old~by:repl)))proofletget_green_eligiblec=letord=C.Ctx.ord()inLs.fold_terms~vars:false~var_args:false~fun_bodies:false~ty_args:false~ord~which:`Max~subterms:true~eligible:(C.Eligible.resc)(C.litsc)letget_bool_eligiblec=Iter.append(SClause.TPSet.to_iter(C.eligible_subterms_of_boolc))(get_green_eligiblec)letget_bool_hoist_eligiblec=get_bool_eligiblec|>Iter.filter(fun(t,p)->letmoduleP=Positioninmatchpwith|P.Arg(idx,P.LeftP.Stop)|P.Arg(idx,P.RightP.Stop)->(match(C.litsc).(idx)with|L.Equation(_,_,false)->true|_->false)|_->true)|>Iter.filter(fun(t,_)->letty=T.tytin(Type.is_propty||Type.is_varty)&¬(T.is_true_or_falset)&¬(T.is_vart)&&matchT.viewtwith|T.AppBuiltin(hd,_)->(* check that the term has no interpreted sym on top *)not(List.memhdBuiltin.([Eq;Neq;ForallConst;ExistsConst;Not])||Builtin.is_logical_binophd)|T.App(hd,_)->not@@T.is_varhd|_->true)|>Iter.to_list(* since we are doing simultaneous version -- we take only unique terms *)|>CCList.sort_uniq~cmp:(fun(t1,_)(t2,_)->T.comparet1t2)lethandle_poly_bool_hoisttc=letty=T.tytinassert(Type.is_propty||Type.is_varty);ifType.is_proptythen((t,c))else(letsub=Subst.Ty.bindSubst.empty(* absolutely horrible castings of OCaml *)((Type.as_var_exnty,0):>InnerTerm.tHVar.tScoped.t)(Type.prop,0)inletrenaming=Subst.Renaming.create()inlett'=Subst.FO.applyrenamingsub(t,0)inletc'=C.apply_subst~renaming(c,0)subin(t',c'))letbool_hoist(c:C.t):C.tlist=letproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"bool_hoist")~tags:[Proof.Tag.T_ho]inList.map(fun(t,_)->lett,c=handle_poly_bool_hoisttcinmk_res~proof~old:t~repl:T.false_(yest)c)(get_bool_hoist_eligiblec)|>CCFun.tap(funres->Util.debugf~section3"hoist(@[%a@])"(funk->kC.ppc);ifCCList.is_emptyresthen(Util.debugf~section3" = ∅ (%d)(%a)(%d)"(funk->k(Iter.length(get_green_eligiblec))(Iter.pp_seqTerm.pp)(Iter.mapfst(get_bool_eligiblec))(List.length(get_bool_hoist_eligiblec)));)else(Util.debugf~section3" = @[%a@]"(funk->k(CCList.ppC.pp)res)))letbool_hoist_simpl(c:C.t):C.tlistoption=letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"bool_hoist")~tags:[Proof.Tag.T_ho]inletbool_subterms=get_bool_hoist_eligiblecinCCOpt.return_if(not@@CCList.is_emptybool_subterms)(CCList.fold_left(funacc(t,_)->lett,c=handle_poly_bool_hoisttcinletneg_lit,repl_neg=not,T.true_inletpos_lit,repl_pos=yest,T.false_in(mk_res~proof~old:t~repl:repl_negneg_litc)::(mk_res~proof~old:t~repl:repl_pospos_litc)::acc)[]bool_subterms)|>CCFun.tap(function|Someres->Util.debugf~section2"bool_hoist_simpl(@[%a@])=@. @[%a@]@."(funk->kC.ppc(CCList.ppC.pp)res);|None->Util.debugf~section2"bool_hoist_simpl(@[%a@])= None@."(funk->kC.ppc))leteq_hoist(c:C.t):C.tlist=letproof~prefix=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk(prefix^"_hoist"))~tags:[Proof.Tag.T_ho]inget_bool_eligiblec|>Iter.filter(fun(t,_)->matchT.viewtwith|T.AppBuiltin(hd,_)->List.memhd[Builtin.Eq;Neq;Xor;Equiv;ForallConst;ExistsConst]&&Type.is_prop(T.tyt)|_->false)|>Iter.to_list(* since we are doing simultaneous version -- we take only unique terms *)|>CCList.sort_uniq~cmp:(fun(t1,_)(t2,_)->T.comparet1t2)|>List.map(fun(t,_)->matchT.viewtwith|T.AppBuiltin(Builtin.(Eq|Equiv),([a;b]|[_;a;b]))->letnew_lit=Literal.mk_eqabinmk_res~proof:(proof~prefix:"eq")~old:t~repl:T.false_new_litc|T.AppBuiltin(Builtin.(Neq|Xor),([a;b]|[_;a;b]))->letnew_lit=Literal.mk_eqabinmk_res~proof:(proof~prefix:"neq")~old:t~repl:T.true_new_litc|_->assertfalse)|>CCFun.tap(funres->Util.debugf~section3"eq-hoist(@[%a@])"(funk->kC.ppc);ifCCList.is_emptyresthen(Util.debugf~section3" = ∅ (%d)(%d)(%a)"(funk->k(Iter.length(get_green_eligiblec))(Iter.length(get_bool_eligiblec))(Iter.pp_seqTerm.pp)(Iter.mapfst(get_bool_eligiblec)));)else(Util.debugf~section3" = @[%a@]"(funk->k(CCList.ppC.pp)res)))letfluid_hoist(c:C.t)=lettyvar=Type.var(HVar.fresh~ty:Type.tType())inletz=T.var(HVar.fresh~ty:(Type.arrow[Type.prop]tyvar)())inletx=T.var(HVar.fresh~ty:Type.prop())inletzx=T.appz[x]inletz_false,z_true=T.appz[T.false_],T.appz[T.true_]inletsc_zx,sc_cl=0,1inletmk_ressignrenamingsubat=letc'=C.apply_subst~renaming(c,sc_cl)subinletstill_at_eligible=get_bool_eligiblec'|>Iter.exists(fun(_,p)->Position.equalpat)inifstill_at_eligiblethen(letnew_lit=letx_sub=Subst.FO.applyrenamingsub(x,sc_zx)inLiteral.mk_eqx_sub(ifsignthenT.true_elseT.false_)inletby=Subst.FO.applyrenamingsub((ifsignthenz_falseelsez_true),sc_zx)inLiterals.Pos.replace(C.litsc')~at~by;letrule=Proof.Rule.mk("fluid_"^(ifsignthen"bool_"else"loob_")^"hoist")inletproof=Proof.Step.inference~rule[C.proof_parent_substrenaming(c,sc_cl)sub]inletres=C.create~penalty:(C.penaltyc+(C.proof_depthc)+(ifProof.Step.has_ho_step(C.proof_stepc)then3else1))~trail:(C.trailc)(new_lit::CCArray.to_list(C.litsc'))proofinSomeres)elseNoneinget_bool_eligiblec|>(funiter->Iter.fold(funacc(u,p)->ifT.is_app_varu||T.is_funu&&(not(T.is_groundu))then(letunif_seq=get_unif_alg()(zx,sc_zx)(u,sc_cl)|>OSeq.flat_map(funus_opt->CCOpt.map_or~default:OSeq.empty(funus->assert(not@@US.has_construs);letsub=US.substusinletrenaming=Subst.Renaming.create()inletz_false_sub=Lambda.snf@@Subst.FO.applyrenamingsub(z_false,sc_zx)inletz_true_sub=Lambda.snf@@Subst.FO.applyrenamingsub(z_true,sc_zx)inletx_sub=Lambda.snf@@Subst.FO.applyrenamingsub(x,sc_zx)inletzx_sub=Lambda.snf@@Subst.FO.applyrenamingsub(zx,sc_zx)inifT.is_true_or_falsex_subthenOSeq.emptyelse(letbool_res=ifT.equalz_false_subzx_subthen[]else[(mk_restruerenamingsubp)]inletloob_res=ifT.equalz_true_subzx_subthen[]else[(mk_resfalserenamingsubp)]inOSeq.of_list(bool_res@loob_res)))us_opt)inifEnv.should_force_stream_eval()then((Env.get_finite_infs[unif_seq])@acc)else(letstm_res=Env.Stm.make~penalty:(C.penaltyc+2)~parents:[c](unif_seq)inEnv.StmQ.add(Env.get_stm_queue())stm_res;acc))elseacc)[]iter)(* Record holding info for constructing Eq/Neq/Forall/ExistsHoist inference*)typefluid_log_partner_info={unif_partner:Term.t;(* what is u unified with *)repl:Term.t;(* what is u replaced with *)new_lit:Literal.toption(* possibly a new literal *)}(* Fluid hoisting of logical symbols --
rules EqHoist, NeqHoist, ForallHoist, ExistsHoist
and BoolRw where head is a variable*)letfluid_log_hoist(c:C.t)=(* It is assumed Boolean selection will
not select any top-level terms *)leta=Type.var(HVar.fresh~ty:(Type.tType)())inletx_a=T.var(HVar.fresh~ty:a())inlety_a=T.var(HVar.fresh~ty:a())inlety_quant=Lambda.eta_expand@@T.var(HVar.fresh~ty:(Type.arrow[a]Type.prop)())inletyx=Lambda.whnf@@T.appy_quant[y_a]inletmoduleF=T.ForminletmodulePB=Position.Buildinletpartners=[{unif_partner=F.eqx_ay_a;repl=T.false_;new_lit=Some(L.mk_eqx_ay_a)};{unif_partner=F.neqx_ay_a;repl=T.true_;new_lit=Some(L.mk_eqx_ay_a)};{unif_partner=F.forally_quant;repl=T.false_;new_lit=Some(L.mk_eqyxT.true_)};{unif_partner=F.existsy_quant;repl=T.true_;new_lit=Some(L.mk_eqyxT.false_)};{unif_partner=(F.not_T.false_);repl=T.true_;new_lit=None};{unif_partner=(F.not_T.true_);repl=T.false_;new_lit=None};{unif_partner=(F.eqx_ax_a);repl=T.true_;new_lit=None};{unif_partner=(F.neqx_ax_a);repl=T.false_;new_lit=None};{unif_partner=(F.and_T.false_T.false_);repl=T.false_;new_lit=None};{unif_partner=(F.and_T.true_T.false_);repl=T.false_;new_lit=None};{unif_partner=(F.and_T.false_T.true_);repl=T.false_;new_lit=None};{unif_partner=(F.and_T.true_T.true_);repl=T.true_;new_lit=None};{unif_partner=(F.or_T.false_T.false_);repl=T.false_;new_lit=None};{unif_partner=(F.or_T.true_T.false_);repl=T.true_;new_lit=None};{unif_partner=(F.or_T.false_T.true_);repl=T.true_;new_lit=None};{unif_partner=(F.or_T.true_T.true_);repl=T.true_;new_lit=None};{unif_partner=(F.implyT.false_T.false_);repl=T.true_;new_lit=None};{unif_partner=(F.implyT.true_T.false_);repl=T.false_;new_lit=None};{unif_partner=(F.implyT.false_T.true_);repl=T.true_;new_lit=None};{unif_partner=(F.implyT.true_T.true_);repl=T.true_;new_lit=None};]inletsc_partner,sc_cl=0,1inletmk_ressubatpartner=letrenaming=Subst.Renaming.create()inletlits=Literals.apply_substrenamingsub((C.litsc),sc_cl)inLiterals.Pos.replacelits~at~by:partner.repl;letnew_lits=(CCOpt.map_or~default:[](funx->[L.apply_substrenamingsub(x,sc_partner)])partner.new_lit)@(Array.to_list(lits))inletrule=Proof.Rule.mk"fluid_log_symbol_hoist"inletstep=Proof.Step.inference~rule[C.proof_parent_substrenaming(c,sc_cl)sub]inC.create~penalty:(C.penaltyc+(C.proof_depthc)+(ifProof.Step.has_ho_step(C.proof_stepc)then2else0))~trail:(C.trailc)new_litsstepinleteligible=C.Eligible.rescinLiterals.fold_lits~eligible(C.litsc)|>Iter.fold(funacc(lit,idx)->letlit_pos=PB.argidxPB.emptyinmatchlitwith|Literal.Equation(u,v,true)when(Type.is_prop(T.tyu)||Type.is_var(T.tyu))&&T.is_app_varu->letapp_vars=ifLiteral.is_predicate_litlitthen[(u,PB.to_pos(PB.leftlit_pos))]elseifTerm.is_app_varvthen[(u,PB.to_pos(PB.leftlit_pos));(v,PB.to_pos(PB.rightlit_pos))]else[]inList.fold_left(funacc(var,pos)->List.fold_left(funaccp->letseq=get_unif_alg()(p.unif_partner,sc_partner)(var,sc_cl)|>OSeq.filter_map(CCOpt.map(funus->assert(not(Unif_subst.has_construs));letsub=Unif_subst.substusinleteligible'=C.eligible_res(c,sc_cl)subin(* not eligible under substitution *)ifnot(CCBV.geteligible'idx)thenNoneelse(Some(mk_ressubposp))))inifEnv.should_force_stream_eval()then(Env.get_finite_infs[seq]@acc)else(letstm_res=Env.Stm.make~penalty:(C.penaltyc+2)~parents:[c](seq)inEnv.StmQ.add(Env.get_stm_queue())stm_res;acc))accpartners;)accapp_vars|_->acc)[](* Fluid version of (Forall|Exists)RW *)letfluid_quant_rw(c:C.t)=letmodulePB=Position.BuildinletmoduleF=T.Forminletsc_partner,sc_cl=0,1inleta=Type.var(HVar.fresh~ty:(Type.tType)())inlety_quant=Lambda.eta_expand@@T.var(HVar.fresh~ty:(Type.arrow[a]Type.prop)())inletpartners=[{unif_partner=F.forally_quant;repl=T.fun_a(F.not_(Lambda.whnf@@T.appy_quant[T.bvar~ty:a0]));new_lit=None};{unif_partner=F.existsy_quant;repl=y_quant(*already eta-expanded *);new_lit=None};]inletmk_ressubatpartner=letlits=Array.copy@@C.litscin(* Literals.Pos.replace lits ~at ~by:partner.repl; *)letrenaming=Subst.Renaming.create()inletexpand_quant=not@@Env.flex_getCombinators.k_enable_combinatorsinletrepl_sub=Lambda.eta_reduce~expand_quant@@Lambda.snf@@Subst.FO.applyrenamingsub(partner.repl,sc_partner)inletsk=FR.get_skolem~parent:c~mode:`SkolemRecyclerepl_subinlety_sk=T.app(Subst.FO.applyrenamingsub(y_quant,sc_partner))[sk]inletlits=Literals.apply_substrenamingsub(lits,sc_cl)inLiterals.Pos.replacelits~at~by:y_sk;letrule=Proof.Rule.mk"fluid_quant_rw"inletstep=Proof.Step.inference~rule[C.proof_parent_substrenaming(c,sc_cl)sub]inletres=C.create_a~penalty:(C.penaltyc+2)~trail:(C.trailc)litsstepinUtil.debugf~section5"fluid_quant_rw:@.@[%a@] -> @.@[%a@]@."(funk->kC.ppcC.ppres);resinleteligible=C.Eligible.rescinLiterals.fold_lits~eligible(C.litsc)|>Iter.fold(funacc(lit,idx)->letlit_pos=PB.argidxPB.emptyinmatchlitwith|Literal.Equation(u,v,true)when(Type.is_var(T.tyu)||Type.is_prop(T.tyu))&&T.is_app_varu->letapp_vars=ifLiteral.is_predicate_litlitthen[(u,PB.to_pos(PB.leftlit_pos))]elseifTerm.is_app_varvthen[(u,PB.to_pos(PB.leftlit_pos));(v,PB.to_pos(PB.rightlit_pos))]else[]inList.fold_left(funacc(var,pos)->List.fold_left(funaccp->letseq=get_unif_alg()(p.unif_partner,sc_partner)(var,sc_cl)|>OSeq.filter_map(CCOpt.map(funus->assert(not(Unif_subst.has_construs));letsub=Unif_subst.substusinleteligible'=C.eligible_res(c,sc_cl)subin(* not eligible under substitution *)ifnot(CCBV.geteligible'idx)thenNoneelse(Some(mk_ressubposp))))inifEnv.should_force_stream_eval()then(Env.get_finite_infs[seq]@acc)else(letstm_res=Env.Stm.make~penalty:(C.penaltyc+2)~parents:[c](seq)inEnv.StmQ.add(Env.get_stm_queue())stm_res;acc))accpartners;)accapp_vars|_->acc)[]letfalse_elimc=letmoduleS=Subst.FOinletpsubrenaming=Proof.Step.inference[C.proof_parent_substrenaming(c,0)sub]~rule:(Proof.Rule.mk("false_elim"))~tags:[Proof.Tag.T_ho]inletadd_immediateaccsubidx=letrenaming=Subst.Renaming.create()inletres=C.apply_subst~renaming~proof:(Some(psubrenaming))(c,0)subinres::accinletscheduleapp_vartargetidx=assert(T.is_groundtarget);letseq=get_unif_alg()(app_var,0)(target,0)|>OSeq.filter_map(CCOpt.map(funus->assert(not(Unif_subst.has_construs));letsub=Unif_subst.substusinletrenaming=Subst.Renaming.create()inletres=C.apply_subst~penalty_inc:(Some1)~renaming~proof:(Some(psubrenaming))(c,0)subin(* not eligible under substitution *)ifnot@@CCBV.get(C.eligible_res_no_substres)idxthenNoneelse(Some(res))))inifEnv.should_force_stream_eval()then(Env.get_finite_infs[seq])else(letstm_res=Env.Stm.make~penalty:(C.penaltyc)~parents:[c](seq)inEnv.StmQ.add(Env.get_stm_queue())stm_res;[])inleteligible=C.eligible_res(c,0)Subst.emptyinletget_var=T.as_var_exninLs.fold_eqn_simple(C.litsc)|>Iter.filter(fun(_,_,_,p)->letidx=Ls.Pos.idxpinCCBV.geteligibleidx)|>Iter.fold(funacc(lhs,rhs,sign,p)->letidx=Ls.Pos.idxpinifT.equalT.true_rhsthen(ifT.is_varlhsthen(letsub=S.bind'Subst.empty(get_varlhs,0)(T.false_,0)inadd_immediateaccsubidx)elseifT.is_app_varlhsthen(schedulelhsT.false_idx@acc)elseacc)elseifT.equalT.false_rhsthen(ifT.is_varlhsthen(letsub=S.bind'Subst.empty(get_varlhs,0)(T.true_,0)inadd_immediateaccsubidx)elseifT.is_app_varlhsthen(schedulelhsT.true_idx@acc)elseacc)elseifT.is_var(T.head_termlhs)&&T.is_var(T.head_termrhs)&&signthen(ifT.is_varlhs&&T.is_varrhs&&Type.is_prop(T.tylhs)then(letsub_t_f=S.bind'(S.bind'Subst.empty(get_varlhs,0)(T.true_,0))(get_varrhs,0)(T.false_,0)inletsub_f_t=S.bind'(S.bind'Subst.empty(get_varlhs,0)(T.false_,0))(get_varrhs,0)(T.true_,0)inadd_immediate(add_immediateaccsub_t_fidx)sub_f_tidx)else(letl_eq_r=T.Form.eqlhsrhsinlett_eq_f=T.Form.eqT.true_T.false_inletf_eq_t=T.Form.eqT.false_T.true_inschedulel_eq_rt_eq_fidx@schedulel_eq_rf_eq_tidx@acc))elseacc)[]letreplace_bool_vars(c:C.t)=letp=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk("replace_bool_vars"))~tags:[Proof.Tag.T_ho]inletall_bool_substsvars=letsc=0inassert(not(CCList.is_emptyvars));letrecaux=function|[]->assertfalse|[v]->[Subst.FO.bind'Subst.empty(v,sc)(T.true_,sc);Subst.FO.bind'Subst.empty(v,sc)(T.false_,sc)]|v::vs->CCList.flat_map(funsubst->[Subst.FO.bind'subst(v,sc)(T.true_,sc);Subst.FO.bind'subst(v,sc)(T.false_,sc)])(auxvs)inauxvarsinget_bool_eligiblec|>Iter.find_pred(fun(t,_)->Type.is_prop(T.tyt)&&(matchT.viewtwith|T.AppBuiltin(Builtin.(Eq|Neq),[_;a;b])whenType.is_prop(T.tya)->(* tyarg does not have to be a variable *)T.is_vara&&T.is_varb|T.AppBuiltin(hd,args)->(Builtin.is_logical_binophd||hd=Builtin.Not)&&List.for_allT.is_varargs|_->false))|>CCOpt.map(fun(t,_)->letvars=T.VarSet.to_list(T.varst)inassert(List.for_all(funt->Type.is_prop(HVar.tyt))vars);all_bool_substsvars|>List.map(C.apply_subst~proof:(Somep)(c,0)))letreplace_bool_app_vars(c:C.t)=letpsubrenaming=Proof.Step.simp[C.proof_parent_substrenaming(c,0)sub]~rule:(Proof.Rule.mk("replace_bool_app_vars"))~tags:[Proof.Tag.T_ho]inletis_var_headedt=T.is_var(T.head_termt)inletis_eligiblexs=CCOpt.return_if((List.for_allis_var_headedxs)&&(List.existsT.is_app_varxs))xsinletcreate_targetsn=letrecaux=function|0->[]|1->[[T.true_];[T.false_]]|n->letrest=aux(n-1)inList.rev_append(List.rev_map(List.consT.true_)rest)(List.rev_map(List.consT.false_)rest)inauxninletstms=get_bool_eligiblec|>Iter.filter_map(fun(t,_)->(matchT.viewtwith|T.AppBuiltin((Eq|Neq),[_;a;b])whenType.is_prop(T.tya)->(* tyarg does not have to be a variable *)is_eligible[a;b]|T.AppBuiltin(hd,args)when(Builtin.is_logical_binophd||hd=Builtin.Not)&&Type.is_prop(T.tyt)->is_eligibleargs|_->None))|>Iter.flat_map_l(fun(args)->List.map(funtarget->get_unif_alg_l()(args,0)(target,0)|>OSeq.filter_map(CCOpt.map(funus->assert(not(Unif_subst.has_construs));letsub=Unif_subst.substusinletrenaming=Subst.Renaming.create()inletres=C.apply_subst~penalty_inc:(Some1)~renaming~proof:(Some(psubrenaming))(c,0)subin(* not eligible under substitution *)Some(res))))(create_targets(List.lengthargs)))|>Iter.to_listinifEnv.should_force_stream_eval()then(Env.get_finite_infsstms)else(Env.StmQ.add_lst(Env.get_stm_queue())(List.map(funseq->Env.Stm.make~penalty:(C.penaltyc)~parents:[c](seq))stms);[])letquantifier_rw_and_hoist(c:C.t)=letquant_rw~atbbody=letquant_rw_unapplicable=letmoduleP=Posinmatchatwith|P.Arg(i,P.LeftP.Stop)|P.Arg(i,P.RightP.Stop)whenL.is_predicate_lit(C.litsc).(i)->(* CAUTION: Using is_pos to really mean is the RHS of the
term true or false? *)letsign=L.is_positivoid((C.litsc).(i))in(Builtin.equalbBuiltin.ForallConst&&sign)||(Builtin.equalbBuiltin.ExistsConst&¬sign)|_->falseinifquant_rw_unapplicablethenNoneelse(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk("quantifier_rw"))~tags:[Proof.Tag.T_ho]inletbody=Combs.expandbodyinletform_for_skolem=(ifb=Builtin.ForallConstthenT.Form.not_elseCCFun.id)(snd@@T.open_funbody)inletsk=FR.get_skolem~parent:c~mode:`SkolemRecycle(T.fun_l(fst@@T.open_funbody)form_for_skolem)inletrepl=T.appbody[sk]inletnew_lits=CCArray.copy(C.litsc)inLiterals.Pos.replace~at~by:replnew_lits;Some(C.create~trail:(C.trailc)~penalty:(C.penaltyc)(Array.to_listnew_lits)proof))inletquant_hoist~oldbbody=letproof~prefix=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk(prefix^"_hoist"))~tags:[Proof.Tag.T_ho]inletfresh_var~body=assert(Type.is_fun(T.tybody));letpref,_=Type.open_fun(T.tybody)inassert(List.lengthpref==1);letvar_ty=List.hdprefinletfresh_var=HVar.fresh~ty:var_ty()inT.varfresh_varinletsubst_t=fresh_var~bodyinmatchbwith|Builtin.ForallConst->letnew_lit=yes(T.appbody[subst_t])inletres=mk_res~proof:(proof~prefix:"forall")~old~repl:T.false_new_litcinifType.returns_prop(T.tysubst_t)then(Signal.sendEnv.on_pred_var_elimination(res,subst_t));res|Builtin.ExistsConst->letnew_lit=no(T.appbody[subst_t])inletres=mk_res~proof:(proof~prefix:"exists")~old~repl:T.true_new_litcinifType.returns_prop(T.tysubst_t)then(Signal.sendEnv.on_pred_var_elimination(res,subst_t));res|_->assertfalseinget_bool_eligiblec|>Iter.fold(funacc(t,p)->matchT.viewtwith|T.AppBuiltin(Builtin.(ForallConst|ExistsConst)asb,[_;body])->lethoisted=quant_hoist~old:tbbodyinletrest=ifCCArray.existsLiteral.is_trivial(C.litshoisted)thenaccelsehoisted::accinCCList.cons_maybe(quant_rw~at:pbbody)(rest)|_->acc)[]|>(funres->CCOpt.return_if(not@@CCList.is_emptyres)res)letnested_eq_rwc=(* TODO(BOOL): currently incompatible with combiantors *)letsc=0inletmk_sct=(t,sc)inletparentsrs=[C.proof_parent_substr(mk_scc)s]inget_bool_eligiblec|>Iter.filter_map(fun(t,p)->matchT.viewtwith|T.AppBuiltin((Builtin.(Eq|Neq|Equiv|Xor)ashd),([a;b]|[_;a;b]))->Some(get_unif_alg()(mk_sca)(mk_scb)|>OSeq.map(fununif_subst_opt->CCOpt.map(fununif_subst->assert(not@@US.has_construnif_subst);letsubst=US.substunif_substinletrepl=ifhd=Builtin.Eq||hd=Builtin.EquivthenT.true_elseT.false_inletnew_lits=Array.copy(C.litsc)inLiterals.Pos.replace~at:p~by:replnew_lits;letrenaming=Subst.Renaming.create()inletnew_lits=Literals.apply_substrenamingsubst(mk_scnew_lits)|>CCArray.to_listinletrule=Proof.Rule.mk((ifT.equalreplT.true_then"eq"else"neq")^"_rw")inletproof=Proof.Step.inference~tags:[Proof.Tag.T_ho]~rule(parentsrenamingsubst)inC.create~penalty:(C.penaltyc)~trail:(C.trailc)new_litsproof)unif_subst_opt))|_->None)|>Iter.flat_map_l(funclause_seq->ifEnv.should_force_stream_eval()then(Env.get_finite_infs[clause_seq])else(letstm_res=Env.Stm.make~penalty:(C.penaltyc)~parents:[c](clause_seq)inEnv.StmQ.add(Env.get_stm_queue())stm_res;[]))|>Iter.to_rev_listletrename_nested_booleansc=letmoduleL=Literalin(* Introduce a new simple name of the form P(vars) for the
given literal -- renaming clauses will stop combinatorial explosion
when hoisting boolean subterms *)letrename_litlit=letsign=L.is_positivoidlitinifL.is_predicate_litlitthen(matchlitwith|L.Equation(lhs,_,_)->CCOpt.get_exn(FR.rename_form~polarity_aware:false~clhssign)|_->assertfalse)else(letmk_form=(ifsignthenT.Form.eqelseT.Form.neq)inmatchlitwith|L.Equation(lhs,rhs,_)->CCOpt.get_exn(FR.rename_form~polarity_aware:false~c(mk_formlhsrhs)sign)|_->assertfalse)in(* literal needs to have at least 2 nested booleans *)letthreshold=2inC.bool_selectedc|>List.map(fun(_,lit_pos)->Literals.Pos.idxlit_pos)|>CCList.group_by~hash:CCInt.hash~eq:CCInt.equal|>List.map(funidx_list->(List.hdidx_list,List.lengthidx_list))|>List.filter(fun(_,cnt)->cnt>=threshold)|>(function|x::xswhennot(CCList.is_emptyxs)->(* there need to be at least two literals with deep booleans.
we will rename all but one (for example the first one) *)letnew_lits=CCArray.copy(C.litsc)inlet(new_defs,new_parents)=CCList.fold_left(fun(defs,parents)(idx,_)->letlit=(C.litsc).(idx)inletrenamer,new_defs,new_parents=rename_litlitinletnew_lit=Literal.mk_proprenamer(Literal.is_positivoidlit)innew_lits.(idx)<-new_lit;(new_defs@defs,new_parents@parents))([],[])xsinletrule=Proof.Rule.mk"rename_nested_bools"inletparents=List.mapC.proof_parent(c::new_parents)inletproof=Proof.Step.simp~ruleparentsinletrenamed=C.create_a~penalty:(C.penaltyc)~trail:(C.trailc)new_litsproofinUtil.debugf~section1"renamed @[%a@] into@. @[%a@]"(funk->kC.ppcC.pprenamed);Util.debugf~section1"new_defs @[%a@]"(funk->k(CCList.ppC.pp)new_defs);Some(renamed::new_defs)|_->None)letsimplify_boolst=letnegatet=matchT.viewtwith|T.AppBuiltin(((Builtin.Eq|Builtin.Neq)asb),l)->lethd=ifb=Builtin.EqthenBuiltin.NeqelseBuiltin.EqinT.app_builtin~ty:(T.tyt)hdl|T.AppBuiltin(Builtin.Not,[s])->s|_->T.Form.not_tinletsimplify_and_ortbl=letopenTerminletcompl_in_ll=letpos,neg=CCList.partition_map(funt->matchviewtwith|AppBuiltin(Builtin.Not,[s])->`Rights|_->`Leftt)l|>CCPair.map_sameSet.of_listinnot(Set.is_empty(Set.interposneg))inletres=assert(b=Builtin.And||b=Builtin.Or);letnetural_el,absorbing_el=ifb=Builtin.Andthentrue_,false_else(false_,true_)inletl'=CCList.sort_uniq~cmp:comparelinifcompl_in_ll||List.exists(equalabsorbing_el)lthenabsorbing_elelse(letl'=List.filter(funs->not(equalsnetural_el))l'inifList.lengthl=List.lengthl'thentelse(ifCCList.is_emptyl'thennetural_elelse(ifList.lengthl'=1thenList.hdl'elseapp_builtin~ty:(Type.prop)bl')))inresinletrecauxt=letty_is_propt=Type.is_prop(T.tyt)inmatchT.viewtwith|DB_|Const_|Var_->t|Fun(ty,body)->letbody'=auxbodyinassert(Type.equal(T.tybody)(T.tybody'));ifT.equalbodybody'thentelseT.fun_tybody'|App(hd,args)->lethd'=auxhdandargs'=List.mapauxargsinifT.equalhdhd'&&T.same_largsargs'thentelseT.apphd'args'|AppBuiltin(Builtin.And,[x])whenT.is_true_or_falsex&&ty_is_propt&&List.length(Type.expected_args(T.tyt))=1->ifT.equalxT.true_then(T.fun_Type.prop(T.bvar~ty:Type.prop0))else(assert(T.equalxT.false_);T.fun_Type.propT.false_)|AppBuiltin(Builtin.Or,[x])whenT.is_true_or_falsex&&ty_is_propt&&List.length(Type.expected_args(T.tyt))=1->letprop=Type.propinifT.equalxT.true_then(T.fun_propT.true_)else(assert(T.equalxT.false_);T.fun_prop(T.bvar~ty:prop0))|AppBuiltin(Builtin.And,l)whenty_is_propt&&List.lengthl>1->letl'=List.mapauxlinlett=ifT.same_lll'thentelseT.app_builtin~ty:(Type.prop)Builtin.Andl'insimplify_and_ortBuiltin.Andl'|AppBuiltin(Builtin.Or,l)whenty_is_propt&&List.lengthl>1->letl'=List.mapauxlinlett=ifT.same_lll'thentelseT.app_builtin~ty:(Type.prop)Builtin.Orl'insimplify_and_ortBuiltin.Orl'|AppBuiltin(Builtin.Not,[s])->lets'=auxsinbeginmatchT.views'with|AppBuiltin(Builtin.Not,[s''])->s''|_->ifT.equals'T.true_thenT.false_elseifT.equals'T.false_thenT.true_elseifT.equalss'thentelseT.app_builtin~ty:(Type.prop)Builtin.Not[s']end|AppBuiltin(Builtin.Imply,[p;c])->letunroll_andp=matchT.viewpwith|AppBuiltin(And,l)->T.Set.of_listl|_->T.Set.singletonpinletunroll_orp=matchT.viewpwith|AppBuiltin(Or,l)->T.Set.of_listl|_->T.Set.singletonpinletis_implp=matchT.viewpwith|AppBuiltin(Imply,[l;r])->true|_->falsein(* Take a term of the form p11 /\ ... /\ p1n1 -> p21 /\ ... /\ p2n2 -> ... -> q1 \/ ... \/ qn
and return the set of premises {p11,...} and conclusions {q1, ... }
*)letunroll_implp=assert(is_implp);letrecauxaccp=matchT.viewpwith|AppBuiltin(Imply,[l;r])->letunrolled_l=unroll_andlinletacc'=Term.Set.unionunrolled_laccinifis_implrthenauxacc'relse(acc',unroll_orr)|_->assertfalseinauxTerm.Set.emptypinletp'=auxpandc'=auxcinlet(premises,conclusions)=unroll_impl(T.Form.implyp'c')inifnot(T.Set.is_empty(T.Set.interpremisesconclusions))then(T.true_)elseifT.equalp'c'thenT.true_elseifT.equalc'(negatep')thenc'elseifT.equalp'(negatec')thenc'elseifT.equalp'T.true_thenc'elseifT.equalp'T.false_thenT.true_elseifT.equalc'T.false_thenaux(T.Form.not_p')elseifT.equalc'T.true_thenT.true_else(ifT.equalpp'&&T.equalcc'thentelseT.app_builtin~ty:(T.tyt)Builtin.Imply[p';c'])|AppBuiltin((Builtin.Eq|Builtin.Equiv)ashd,([a;b]|[_;a;b]))whenType.is_prop(T.tyt)->letcons=ifhd=Builtin.EqthenT.Form.eqelseT.Form.equivinleta',b'=auxa,auxbinifT.equala'b'thenT.true_elseifT.equala'T.true_thenb'elseifT.equalb'T.true_thena'elseifT.equala'T.false_thenaux(T.Form.not_b')elseifT.equalb'T.false_thenaux(T.Form.not_a')else(ifT.equalaa'&&T.equalbb'thentelseconsa'b')|AppBuiltin((Builtin.Neq|Builtin.Xor)ashd,([a;b]|[_;a;b]))whenType.is_prop(T.tyt)->letcons=ifhd=Builtin.NeqthenT.Form.neqelseT.Form.xorinleta',b'=auxa,auxbinifT.equala'b'thenT.false_elseifT.equala'T.true_thenaux(T.Form.not_b')elseifT.equalb'T.true_thenaux(T.Form.not_a')elseifT.equala'T.false_thenb'elseifT.equalb'T.false_thena'else(ifT.equalaa'&&T.equalbb'thentelseconsa'b')|AppBuiltin((ExistsConst|ForallConst)asb,[tyarg;g])->letg'=auxginletexp_g=Combs.expandg'inlet_,body=T.open_funexp_ginassert(Type.is_prop(T.tybody));if(T.Seq.subterms~include_builtin:truebody|>Iter.existsT.is_bvar)then(ifT.equalgg'thentelseT.app_builtin~ty:(T.tyt)b[tyarg;g'])elsebody|AppBuiltin(hd,args)->letargs'=List.mapauxargsinifT.same_largsargs'thentelseT.app_builtin~ty:(T.tyt)hdargs'inletres=auxtinassert(T.DB.is_closedres);res(* Look at the HOSup paper for the definition of unsupported quant *)letfix_unsupported_quantt=(* for the time being var_ty is not used.. if the definition
changes it is useful to have it around *)letquant_normal_q_body=lethas_loosely_bound_0t=List.mem0(T.DB.unboundt)inletrecauxt=matchT.viewtwith|Fun(_,body)->not(has_loosely_bound_0t)|App(hd,args)->ifT.is_consthdthenList.for_allauxargselse(not(List.existshas_loosely_bound_0(hd::args)))|AppBuiltin(hd,args)->List.for_allauxargs|_->trueinletres=auxq_bodyinresinletrecauxt=matchT.viewtwith|Fun(ty,body)->letbody'=auxbodyinassert(Type.equal(T.tybody)(T.tybody'));ifT.equalbodybody'thentelseT.fun_tybody'|App(hd,args)->lethd'=auxhdinletargs'=List.mapauxargsinifT.equalhdhd'&&T.same_largsargs'thentelseT.apphd'args'|AppBuiltin((ExistsConst|ForallConst)ashd,[alpha])->letalpha=Type.of_term_unsafe(alpha:>InnerTerm.t)inletalpha2prop=Type.arrow[alpha]Type.propinletinner_quant=letbody=ifBuiltin.equalhdExistsConstthenT.false_elseT.true_inT.fun_alphabodyinletvar=T.bvar~ty:alpha2prop0inletbody=ifBuiltin.equalhdExistsConstthenT.Form.neqvarinner_quantelseT.Form.eqvarinner_quantinT.fun_alpha2propbody|AppBuiltin((ExistsConst|ForallConst),([]))->invalid_arg"type argument must be present"|AppBuiltin(hd,args)->letargs'=List.mapauxargsin(* fully applied quantifier *)ifBuiltin.is_quantifierhd&&List.lengthargs'==2then(letq_pref,q_body=T.open_fun@@List.nthargs'1inletvar_ty=List.hdq_prefinifnot(quant_normalvar_tyq_body)then(ifBuiltin.equalhdBuiltin.ExistsConstthen(T.Form.neq(List.nthargs'1)(T.fun_var_tyT.false_))else(T.Form.eq(List.nthargs'1)(T.fun_var_tyT.true_)))elseT.app_builtin~ty:(T.tyt)hdargs')else(ifT.same_largsargs'thentelseT.app_builtin~ty:(T.tyt)hdargs')|DB_|Const_|Var_->tinifEnv.flex_getCombinators.k_enable_combinatorsthentelseaux(Lambda.eta_reduce@@Lambda.snft)letreplace_unsupported_quantsc=letnew_lits=Literals.mapfix_unsupported_quant(C.litsc)inifLiterals.equal(C.litsc)new_litsthen(None)else(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"replace unsupported quants")inletnew_=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(Array.to_listnew_lits)proofinSomenew_)letsimpl_bool_subtermsc=tryletnew_lits=Literals.mapsimplify_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_)withType.ApplyErrorerr->CCFormat.printf"error(%s):@[%a@]@."errC.ppc;CCFormat.printf"@[%a@]@."Proof.S.pp_tstp(C.proofc);assertfalseletnnf_boolst=letmoduleF=T.Forminletexpand_quant=not@@Env.flex_getCombinators.k_enable_combinatorsinletrecauxt=matchT.viewtwith|Const_|DB_|Var_->t|Fun_->lettyargs,body=T.open_funtinletbody'=auxbodyinifT.equalbodybody'thentelseT.fun_ltyargsbody'|App(hd,l)->lethd'=auxhdandl'=List.mapauxlinifT.equalhdhd'&&T.same_lll'thentelseT.apphd'l'|AppBuiltin(Builtin.Not,[f])->beginmatchT.viewfwith|AppBuiltin(Not,[g])->auxg|AppBuiltin(((And|Or)asb),l)whenList.lengthl>=2->letflipped=ifb=Builtin.AndthenF.or_lelseF.and_linflipped(List.map(funt->aux(F.not_t))l)|AppBuiltin(((ForallConst|ExistsConst)asb),([g]|[_;g]))->letflipped=ifb=Builtin.ForallConstthenBuiltin.ExistsConstelseBuiltin.ForallConstinletg_ty_args,g_body=T.open_fun(Combs.expandg)inletg_body'=aux@@F.not_g_bodyinletg'=Lambda.eta_reduce~expand_quant(T.fun_lg_ty_argsg_body')inT.app_builtin~ty:(T.tyt)flipped[g']|AppBuiltin(Imply,[g;h])->F.and_(auxg)(aux@@F.not_h)|AppBuiltin(((Equiv|Xor)asb),[g;h])->letflipped=ifb=EquivthenBuiltin.XorelseBuiltin.Equivinaux(T.app_builtin~ty:(T.tyt)flipped[g;h])|AppBuiltin(((Eq|Neq)asb),([_;s;t]|[s;t]))->letflipped=ifb=EqthenF.neqelseF.eqinflipped(auxs)(auxt)|_->F.not_(auxf)end|AppBuiltin(Imply,[f;g])->aux(F.or_(F.not_f)g)|AppBuiltin(Equiv,[f;g])->aux(F.and_(F.implyfg)(F.implygf))|AppBuiltin(Xor,[f;g])->aux(F.and_(F.or_fg)(F.or_(F.not_f)(F.not_g)))|AppBuiltin(b,l)->letl'=List.mapauxlinifT.same_lll'thentelseT.app_builtin~ty:(T.tyt)bl'inauxtletnnf_bool_subtersc=letnew_lits=Literals.mapnnf_bools(C.litsc)inifLiterals.equal(C.litsc)new_litsthen(SimplM.return_samec)else(letproof=Proof.Step.simp[C.proof_parentc]~rule:(Proof.Rule.mk"nnf 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_)(* Find resolvable boolean literals and resolve them.
If which is `OnlyPositive then _only_ literals of the form s = t
are rewritten into s != ~t and then unified. Else, both negative
and positive literals are unified *)letsolve_bool_formulas~whichc=letnormalize_nott=letrecauxt=matchT.viewtwith|T.AppBuiltin(Not,[f])->beginmatchT.viewfwith|T.AppBuiltin(Not,[g])->auxg|T.AppBuiltin(((Eq|Equiv)asb),l)->letflipped=ifb=Builtin.EqthenBuiltin.NeqelseBuiltin.XorinT.app_builtinflippedl~ty:(T.tyf)|T.AppBuiltin(((Neq|Xor)asb),l)->letflipped=ifb=Builtin.NeqthenBuiltin.EqelseBuiltin.EquivinT.app_builtinflippedl~ty:(T.tyf)|_->tend|_->tinauxtinletfind_resolvable_formlit=letis_var_headedt=T.is_var(T.head_termt)in(* Rewrite positive equations of the form F s = t, where t is not
var-headed into F s != (not t). *)letfind_pos_var_headed_eqlr=ifis_var_headedl&¬(is_var_headedr)then(Some(l,T.Form.not_r))elseifis_var_headedr&¬(is_var_headedl)then(Some(r,T.Form.not_l))elseNoneinmatch(Literal.View.as_eqnlit)with|Some(l,r,sign)->ifnot(T.is_true_or_falser)&&Type.is_prop(T.tyl)then(ifnotsign&&which=`AllthenSome(l,r)elseifsignthenfind_pos_var_headed_eqlrelseNone)elseifT.is_true_or_falserthen(letapply_sign=ifsignthenCCFun.idelseT.Form.not_inmatchT.view(normalize_not(apply_signl))with|T.AppBuiltin((Neq|Xor),([f;g]|[_;f;g]))whenType.is_prop(T.tyf)&&which==`All->assert(Type.equal(T.tyf)(T.tyg));Some(f,g)|T.AppBuiltin((Eq|Equiv),([f;g]|[_;f;g]))whenType.is_prop(T.tyf)->assert(Type.equal(T.tyf)(T.tyg));find_pos_var_headed_eqfg|_->None)elseNone|None->Noneinletunif_alglr=ifnot(Env.flex_getCombinators.k_enable_combinators)then(Env.flex_getSuperposition.k_unif_alg(l,0)(r,0))elseOSeq.return(Some(Unif.FO.unify_full(l,0)(r,0)))inUtil.debugf~section5"bool solving @[%a@]@."(funk->kC.ppc);C.litsc|>CCArray.mapi(funilit->matchfind_resolvable_formlitwith|None->Util.debugf~section5"for lit %d(@[%a@]) of @[%a@] no resolvable lits found@."(funk->kiLiteral.pplitC.ppc);None|Some(l,r)->letmoduleUS=Unif_substintryUtil.debugf~section5"trying lit @[%d:%a@]@."(funk->kiLiteral.pplit);Util.debugf~section5"unif problem: @[%a=?=%a@]@."(funk->kT.pplT.ppr);letstm=unif_alglr|>OSeq.map(CCOpt.map(funsubst->letrenaming=Subst.Renaming.create()inletnew_lits=CCArray.except_idx(C.litsc)i|>CCArray.of_list|>(funl->Literals.apply_substrenaming(US.substsubst)(l,0))|>CCArray.to_listinletproof=Proof.Step.simp~tags:[Proof.Tag.T_ho]~rule:(Proof.Rule.mk"solve_formulas")[C.proof_parent_substrenaming(c,0)(US.substsubst)]inletres=C.create~penalty:(C.penaltyc)~trail:(C.trailc)new_litsproofinUtil.debugf~section5"solved by @[%a@]@."(funk->kC.ppres);res))inmatchstm()with|OSeq.Cons(hd,rest)->letstm=Stm.make~penalty:(C.penaltyc)~parents:[c]restinStmQ.add(Env.get_stm_queue())stm;hd|OSeq.Nil->Nonewith_->Util.debugf~section5"failed @."(funk->k);None)|>CCArray.filter_mapCCFun.id|>CCArray.to_list|>(funl->ifCCList.is_emptylthenNoneelseSomel)letcnf_otfc:C.tlistoption=letidx=CCArray.find_idx(funl->leteq=Literal.View.as_eqnlinmatcheqwith|Some(l,r,_)->Type.is_prop(T.tyl)&¬(T.equallr)&&((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_iter@@Cnf.cnf_of~opts~ctx:(Ctx.sk_ctx())stmtinCCVector.iter(funcl->Statement.Seq.ty_declscl|>Iter.iter(fun(id,ty)->Ctx.declareidty;ID.set_payloadid(ID.Attr_skolemID.K_after_cnf)))cnf_vec;letsolved=ifEnv.flex_getk_solve_formulasthen(CCOpt.get_or~default:[](solve_bool_formulas~which:`Allc))else[]inletclauses=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)inUtil.debugf~section5"cl:@[%a@]@."(funk->kC.ppc);Util.debugf~section5" @[%a@]@."(funk->k(CCList.ppC.pp)clauses);List.iteri(funinew_c->assert((C.proof_depthc)<=C.proof_depthnew_c);)clauses;Some(solved@clauses)|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_funstk=letrecauxt=letty_args,ret_ty=Type.open_fun(T.tyt)inifnot(CCList.is_emptyty_args)&&Type.is_propret_ty&¬(T.is_vart)&¬(T.is_app_vart)thenktelse(matchT.viewtwith|App(f,l)->(* head positions are not taken into account *)List.iterauxl|AppBuiltin(b,l)whennot(Builtin.is_quantifierb)->List.iterauxl|_->())inauxtinletinterpretti=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)inletforall_closet=letty_args,body=T.open_funtinassert(Type.is_prop(T.tybody));List.fold_right(funtyacc->T.Form.forall(T.fun_tyacc))ty_argsbodyinIter.flat_mapcollect_tl_bool_funs(C.Seq.termsc(* If the term is a top-level function, then apply extensionality,
not this rule on it. *)|>Iter.filter(funt->not@@Type.is_fun(T.tyt)))(* avoiding terms introduced by primitive enumeration *)|>Iter.filter(funt->letcached_t=Subst.FO.canonize_all_varstinnot(Term.Set.memcached_t!Higher_order.prim_enum_terms))|>Iter.sort_uniq~cmp:Term.compare|>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]inlett'=Combs.expandtinlet_,t'_body=T.open_funt'inifnot(T.is_true_or_falset'_body)then(letas_forall=Literal.mk_prop(forall_closet')falseinletas_neg_forall=Literal.mk_prop(forall_close(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:(interprett'T.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:(interprett'T.false_))))proofinUtil.debugf~section5"interpret bool(@[%a@]):@.@[%a@] !!> @. @[%a@]@."(funk->kT.pptLiterals.pp(C.litsc)Literals.pp(C.litsforall_cl));Util.debugf~section5"interpret bool(@[%a@]):@.@[%a@] !!> @. @[%a@]@."(funk->kT.pptLiterals.pp(C.litsc)Literals.pp(C.litsforall_neg_cl));forall_cl::forall_neg_cl::res)elseres)[]letsetup()=(* Env.add_basic_simplify normalize_equalities; put into superposition right now *)ifEnv.flex_getk_replace_unsupported_quantsthen(Signal.onceEnv.on_start(fun()->Env.ProofState.PassiveSet.clauses()|>C.ClauseSet.iter(funcl->matchreplace_unsupported_quantsclwith|None->()|Somenew_->Env.remove_passive(Iter.singletoncl);Env.add_passive(Iter.singletonnew_);)););matchEnv.flex_getk_bool_reasoningwith|BoolReasoningDisabled->()|BoolCasesPreprocess->Env.add_unary_inf"false_elim"false_elim;|_->ifEnv.flex_getk_solve_formulasthen(Env.add_unary_inf"solve formulas"(func->CCOpt.get_or~default:[]@@solve_bool_formulas~which:`OnlyPositivec));ifEnv.flex_getk_trigger_bool_inst>0||Env.flex_getk_trigger_bool_ind>0then(Signal.onEnv.on_pred_var_eliminationhandle_new_pred_var_clause;Signal.onEnv.FormRename.on_pred_skolem_introductionhandle_new_skolem_sym;);ifEnv.flex_getk_trigger_bool_ind>0then(Env.add_unary_inf"trigger bool ind"trigger_induction);ifEnv.flex_getk_simplify_boolsthen(Env.add_basic_simplifysimpl_bool_subterms);ifEnv.flex_getk_nnfthen(E.add_basic_simplifynnf_bool_subters;);ifEnv.flex_getk_norm_boolsthen(Env.add_basic_simplifynormalize_bool_terms);ifnot!Lazy_cnf.enabledthen(Env.add_multi_simpl_rule~priority:2Fool.rw_bool_lits;ifEnv.flex_getk_cnf_non_simplthen(Env.add_unary_inf"cnf otf inf"cnf_infer;)elseEnv.add_multi_simpl_rule~priority:2cnf_otf);if(Env.flex_getk_interpret_bool_funs)then(Env.add_unary_inf"interpret boolean functions"interpret_boolean_functions;);Env.add_unary_inf"false_elim"false_elim;ifEnv.flex_getk_bool_reasoning=BoolHoistthen(ifEnv.flex_getk_bool_hoist_simplthenEnv.add_multi_simpl_rule~priority:1000bool_hoist_simpl;Env.add_unary_inf"bool_hoist"bool_hoist;ifEnv.flex_getk_rename_nested_boolsthen(Env.add_multi_simpl_rule~priority:500rename_nested_booleans);Env.add_unary_inf"formula_hoist"eq_hoist;Env.add_multi_simpl_rule~priority:100replace_bool_vars;Env.add_multi_simpl_rule~priority:90quantifier_rw_and_hoist;Env.add_unary_inf"eq_rw"nested_eq_rw;ifEnv.flex_getSuperposition.k_ho_basic_rulesthen(ifEnv.flex_getk_bool_app_var_replthen(Env.add_unary_inf"replace_bool_app_vars"replace_bool_app_vars);ifEnv.flex_getk_fluid_hoistthen(Env.add_unary_inf"fluid_hoist"fluid_hoist);ifEnv.flex_getk_fluid_log_hoistthen(Env.add_unary_inf"fluid_log_hoist"fluid_log_hoist;Env.add_unary_inf"fluid_quant_rw"fluid_quant_rw;););)endopenCCFunopenBuiltinopenStatementopenTypedSTermopenCCListletif_changedproof(mk:?attrs:Logtk.Statement.attrs->'r)sfp=letfp=fspiniffp==[p]then[s]elsemap(funx->mk~proof:(proofs)x)fp(* match fp with
| [ x ] when TypedSTerm.equal x p -> [s]
| _ -> map(fun x -> mk ~proof:(proof s) x) fp *)letmap_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 occurs 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.map_snd(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_iter(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.map_sndr)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)&¬(TypedSTerm.equalpc)&&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)tpsinifTypedSTerm.equaltt'thenNoneelseSome(case_bools_wrtvst')|_->None)leteager_cases_farstms=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)binifTypedSTerm.equalbb'thenNoneelseSome(replaces(bind~ty:propqvb')t)|_->None)|>case_bools_wrtVar.Set.empty])stmsleteager_cases_nearstms=letproofs=Proof.Step.esa[Proof.Parent.from(Statement.as_proof_is)]~rule:(Proof.Rule.mk"eager_cases_near")inletmoduleT=TypedSTerminletfind_fool_subterm?(free_vars=Var.Set.empty)p=letrecaux~topp=letp_ty=T.ty_exnpinletno_leaky_variablest=Var.Set.intersection_empty(T.free_vars_sett)free_varsinletreturnp=assert(T.Ty.is_prop(T.ty_exnp));assert(no_leaky_variablesp);Some(T.Form.true_,T.Form.false_,p)inmatchT.viewpwith|AppBuiltin(hd,args)whennottop&&no_leaky_variablesp&&T.Ty.is_prop(T.ty_exnp)&&(* making sure it is not T or F *)(Builtin.is_logical_ophd||Builtin.equalhdBuiltin.Eq||Builtin.equalhdBuiltin.Neq)->CCFormat.printf"found OK eq@.";returnp|Bind((Binder.Exists|Binder.Forall),var,body)whennottop&&no_leaky_variablesp->returnp|Bind(Binder.Lambda,var,body)->CCOpt.map(fun(body_t,body_f,s)->assert(no_leaky_variabless);(T.fun_l[var]body_t,T.fun_l[var]body_f,s))(aux~top:falsebody)|App(hd,args)whennottop&&T.Ty.is_propp_ty&&no_leaky_variablesp->returnp|Const_whennottop&&T.Ty.is_propp_ty->returnp|AppBuiltin(b,args)->CCOpt.map(fun(args_t,args_f,s)->(T.app_builtin~ty:p_tybargs_t,T.app_builtin~ty:p_tybargs_f,s))(aux_largs)|App(hd,args)->CCOpt.map(fun(args_t,args_f,s)->(T.app~ty:p_tyhdargs_t,T.app~ty:p_tyhdargs_f,s))(aux_largs)|_->Noneandaux_l=function|[]->None|x::xs->beginmatchaux~top:falsexwith|Some(x_t,x_f,s)->Some(x_t::xs,x_f::xs,s)|None->beginmatchaux_lxswith|Some(xs_t,xs_f,s)->Some(x::xs_t,x::xs_f,s)|None->Noneendendinletres=aux~top:truepinresinletunroll_foolp=letrecaux~varsp=letp_ty=T.ty_exnpinmatchT.viewpwith|AppBuiltin(((Builtin.Neq|Builtin.Eq)ashd),([_;a;b]|[a;b]))whennot(T.Ty.is_prop(T.ty_exna))->letcons=ifhd=NeqthenT.Form.neqelseT.Form.eqinbeginmatchfind_fool_subtermawith|None->beginmatchfind_fool_subtermbwith|None->p|Some(b_t,b_f,subterm)->letsubterm'=aux~varssubterminletif_true=T.Form.or_[T.Form.not_(subterm');aux~vars@@consab_t]inletif_false=T.Form.or_[subterm';aux~vars@@consab_f]inT.Form.and_[if_true;if_false]end|Some(a_t,a_f,subterm)->letsubterm'=aux~varssubterminletif_true=T.Form.or_[T.Form.not_(subterm');aux~vars@@consa_tb]inletif_false=T.Form.or_[subterm';aux~vars@@consa_fb]inT.Form.and_[if_true;if_false]end|AppBuiltin(hd,args)->T.app_builtin~ty:p_tyhd(List.map(aux~vars)args)|App(hd,args)->beginmatchfind_fool_subtermpwith|Some(p_t,p_f,subterm)->letsubterm'=aux~varssubterminletif_true=T.Form.or_[T.Form.not_(subterm');aux~varsp_t]inletif_false=T.Form.or_[subterm';aux~varsp_f]inT.Form.and_[if_true;if_false]|None->pend|Bind((Binder.Exists|Binder.Forall)asb,var,body)->letbody'=aux~vars:(Var.Set.addvarsvar)bodyinT.bind~ty:p_tybvarbody'|_->pinletres=aux~vars:Var.Set.emptypinresinmap_propositions~proof(fun_p->[unroll_foolp])stmsopenTermletpost_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!cased||not(T.DB.is_closeds)thenreselse(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|BoolCasesPreprocess->eager_cases_near|_->id)(if!_quant_renamethenname_quantifiersstmtselsestmts)letpreprocess_cnf_booleansstmts=match!_bool_reasoningwith|BoolCasesPreprocess->letres=post_eager_casesstmtsinres|_->stmtslet_interpret_bool_funs=reffalselet_cnf_non_simpl=reffalselet_norm_bools=reffalselet_filter_literals=ref`Maxlet_nnf=reffalselet_simplify_bools=reftruelet_trigger_bool_inst=ref(-1)let_trigger_bool_ind=ref(-1)let_generalize_trigger=ref(`Off)let_include_quants=reftruelet_bool_hoist_simpl=reffalselet_rename_nested_bools=reffalselet_fluid_hoist=reffalselet_bool_app_var_repl=reffalselet_fluid_log_hoist=reffalselet_solve_formulas=reffalselet_replace_quants=reffalselet_disable_ho_unif=reffalselet_bool_triggers_only=ref(false)letextension=letregisterenv=letmoduleE=(valenv:Env.S)inletmoduleET=Make(E)inE.flex_addk_bool_reasoning!_bool_reasoning;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_filter_literals!_filter_literals;E.flex_addk_nnf!_nnf;E.flex_addk_simplify_bools!_simplify_bools;E.flex_addk_trigger_bool_inst!_trigger_bool_inst;E.flex_addk_trigger_bool_ind!_trigger_bool_ind;E.flex_addk_include_quants!_include_quants;E.flex_addk_bool_hoist_simpl!_bool_hoist_simpl;E.flex_addk_rename_nested_bools!_rename_nested_bools;E.flex_addk_fluid_hoist!_fluid_hoist;E.flex_addk_bool_app_var_repl!_bool_app_var_repl;E.flex_addk_fluid_log_hoist!_fluid_log_hoist;E.flex_addk_solve_formulas!_solve_formulas;E.flex_addk_replace_unsupported_quants!_replace_quants;E.flex_addk_disable_ho_bool_unif!_disable_ho_unif;E.flex_addk_generalize_trigger!_generalize_trigger;E.flex_addk_bool_triggers_only!_bool_triggers_only;ET.setup()in{Extensions.defaultwithExtensions.name="bool";env_actions=[register];}let()=Options.add_opts["--boolean-reasoning",Arg.Symbol(["off";"simpl-only";"bool-hoist";"cases-preprocess"],(funs->_bool_reasoning:=(matchswith|"off"->BoolReasoningDisabled|"simpl-only"->BoolSimplificationsOnly|"bool-hoist"->BoolHoist|"cases-preprocess"->BoolCasesPreprocess|_->assertfalse);if!_bool_reasoning==BoolHoistthen((* setting default Boolean selection if BoolHoist is on *)Params.bool_select:="smallest";);))," enable/disable boolean axioms";"--quantifier-renaming",Arg.Bool(funv->_quant_rename:=v)," turn the quantifier renaming on or off";"--replace-quants",Arg.Bool(funv->_replace_quants:=v)," replace unsupported quantifiers";"--replace-bool-app-vars",Arg.Bool(funv->_bool_app_var_repl:=v)," unify applied variables with combinations of T and F";"--rename-nested-bools",Arg.Bool(funv->_rename_nested_bools:=v)," rename deeply nested bool subterms";"--trigger-bool-ind",Arg.Set_int_trigger_bool_ind," abstract away constants from the goal and use them to trigger axioms of induction";"--trigger-bool-inst",Arg.Set_int_trigger_bool_inst," instantiate predicate variables with boolean terms already in the proof state. Argument is the maximal proof depth of predicate variable";"--trigger-bool-inst-prop-only",Arg.Bool((:=)_bool_triggers_only)," make sure that lambdas are REALLY only of Boolean type";"--trigger-bool-include-quants",Arg.Bool((:=)_include_quants)," include lambdas directly under a quant in consdieration";"--trigger-bool-generalize",Arg.Symbol(["off";"neg";"var"],(funs->_generalize_trigger:=(matchswith|"off"->`Off|"neg"->`Neg|"var"->`Var|_->invalid_arg"off, neg or var are the only options")))," generalize the trigger: neg adds the negation before the trigger body, "^" and var applies the body to a fresh variable";"--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";"--bool-hoist-simpl",Arg.Bool(funv->_bool_hoist_simpl:=v;_rename_nested_bools:=true)," use BoolHoistSimpl instead of BoolHoist; NOTE: Setting this option triggers nested booleans renaming";"--normalize-bool-terms",Arg.Bool((funv->_norm_bools:=v))," normalize boolean subterms using their weight.";"--nnf-nested-formulas",Arg.Bool(funv->_nnf:=v)," convert nested formulas into negation normal form";"--simplify-bools",Arg.Bool(funv->_simplify_bools:=v)," simplify boolean subterms";"--fluid-hoist",Arg.Bool(funv->_fluid_hoist:=v)," enable/disable Fluid(Bool|Loob)Hoist rules";"--fluid-log-hoist",Arg.Bool(funv->_fluid_log_hoist:=v)," enable/disable fluid version of BoolRW, (Forall|Exists)RW, (Eq|Neq|Forall|Exists)Hoist rules";"--solve-formulas",Arg.Bool(funv->_solve_formulas:=v)," solve phi = psi eagerly by unifying phi != ~psi, where phi and psi are formulas";"--boolean-reasoning-filter-literals",Arg.Symbol(["all";"max"],(funv->matchvwith|"all"->_filter_literals:=`All|"max"->_filter_literals:=`Max|_->assertfalse;))," select on which literals to apply bool reasoning rules"];Params.add_to_modes["ho-pragmatic";"lambda-free-intensional";"lambda-free-purify-intensional";"lambda-free-extensional";"ho-comb-complete";"lambda-free-purify-extensional";"fo-complete-basic"](fun()->_bool_reasoning:=BoolReasoningDisabled);Params.add_to_mode"ho-complete-basic"(fun()->_bool_reasoning:=BoolHoist;_fluid_hoist:=true;_bool_app_var_repl:=true;_fluid_log_hoist:=true;_replace_quants:=true);Params.add_to_modes["ho-pragmatic";"lambda-free-intensional";"lambda-free-purify-intensional";"lambda-free-extensional";"ho-comb-complete";"ho-competititve";"lambda-free-purify-extensional";"fo-complete-basic"](fun()->_replace_quants:=false;);Params.add_to_modes["lambda-free-intensional";"lambda-free-purify-intensional";"lambda-free-extensional";"ho-comb-complete";"lambda-free-purify-extensional"](fun()->_disable_ho_unif:=true);Extensions.registerextension