123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 boolean subterms} *)openLogtkopenLibzipperpositionmoduleBV=CCBVmoduleT=Termletsection=Util.Section.make~parent:Const.section"ho"letstat_eq_res=Util.mk_stat"ho.eq_res.steps"letstat_eq_res_syntactic=Util.mk_stat"ho.eq_res_syntactic.steps"letstat_ext_neg=Util.mk_stat"ho.extensionality-.steps"letstat_ext_pos=Util.mk_stat"ho.extensionality+.steps"letstat_complete_eq=Util.mk_stat"ho.complete_eq.steps"letstat_beta=Util.mk_stat"ho.beta_reduce.steps"letstat_eta_expand=Util.mk_stat"ho.eta_expand.steps"letstat_eta_reduce=Util.mk_stat"ho.eta_reduce.steps"letstat_prim_enum=Util.mk_stat"ho.prim_enum.steps"letstat_elim_pred=Util.mk_stat"ho.elim_pred.steps"letstat_ho_unif=Util.mk_stat"ho.unif.calls"letstat_ho_unif_steps=Util.mk_stat"ho.unif.steps"letprof_eq_res=Util.mk_profiler"ho.eq_res"letprof_eq_res_syn=Util.mk_profiler"ho.eq_res_syntactic"letprof_ho_unif=Util.mk_profiler"ho.unif"let_purify_applied_vars=ref`Nonelet_general_ext_pos=reffalselet_ext_pos=reftruelet_ext_axiom=reffalselet_elim_pred_var=reftruelet_ext_neg=reftruemoduletypeS=sigmoduleEnv:Env.SmoduleC:moduletypeofEnv.C(** {6 Registration} *)valsetup:unit->unit(** Register rules in the environment *)endletk_some_ho:boolFlex_state.key=Flex_state.create_key()letk_enabled:boolFlex_state.key=Flex_state.create_key()letk_enable_ho_unif:boolFlex_state.key=Flex_state.create_key()letk_ho_prim_mode:_Flex_state.key=Flex_state.create_key()letk_ho_prim_max_penalty:intFlex_state.key=Flex_state.create_key()letk_eta:[`Reduce|`Expand|`None]Flex_state.key=Flex_state.create_key()moduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleC=Env.CmoduleCtx=Env.Ctx(* @param vars the free variables the parameter must depend upon
@param ty_ret the return type *)letmk_parameter=letn=ref0infunvarsty_ret->leti=CCRef.incr_then_getninletid=ID.makef"#k%d"iinID.set_payloadid(ID.Attr_parameteri);letty_vars,vars=List.partition(funv->Type.is_tType(HVar.tyv))varsinletty=Type.forall_fvarsty_vars(Type.arrow(List.mapHVar.tyvars)ty_ret)inT.app_full(T.constid~ty)(List.mapType.varty_vars)(List.mapT.varvars)(* index for ext-neg, to ensure α-equivalent negative equations have the same skolems *)moduleFV_ext_neg=FV_tree.Make(structtypet=Literal.t*T.tlist(* lit -> skolems *)letcompare=CCOrd.(pairLiteral.compare(listT.compare))letto_lits(l,_)=Iter.return(Literal.Conv.to_forml)letlabels_=Util.Int_set.emptyend)letidx_ext_neg_:FV_ext_neg.tref=ref(FV_ext_neg.empty())(* retrieve skolems for this literal, if any *)letfind_skolems_(lit:Literal.t):T.tlistoption=FV_ext_neg.retrieve_alpha_equiv_c!idx_ext_neg_(lit,[])|>Iter.find_map(fun(lit',skolems)->letsubst=Literal.variant(lit',0)(lit,1)|>Iter.headinbeginmatchsubstwith|Some(subst,_)->letskolems=List.map(funt->Subst.FO.applySubst.Renaming.nonesubst(t,0))skolemsinSomeskolems|None->Noneend)(* negative extensionality rule:
[f != g] where [f : a -> b] becomes [f k != g k] for a fresh parameter [k] *)letext_neg(lit:Literal.t):_option=matchlitwith|Literal.Equation(f,g,false)whenType.is_fun(T.tyf)&¬(T.is_varf)&¬(T.is_varg)&¬(T.equalfg)->letn_ty_params,ty_args,_=Type.open_poly_fun(T.tyf)inassert(n_ty_params=0);letparams=matchfind_skolems_litwith|Somel->l|None->(* create new skolems, parametrized by free variables *)letvars=Literal.varslitinletl=List.map(mk_parametervars)ty_argsin(* save list *)idx_ext_neg_:=FV_ext_neg.add!idx_ext_neg_(lit,l);linletnew_lit=Literal.mk_neq(T.appfparams)(T.appgparams)inUtil.incr_statstat_ext_neg;Util.debugf~section4"(@[ho_ext_neg@ :old `%a`@ :new `%a`@])"(funk->kLiteral.pplitLiteral.ppnew_lit);Some(new_lit,[],[Proof.Tag.T_ho;Proof.Tag.T_ext])|_->None(* positive extensionality `m x = n x --> m = n` *)letext_pos(c:C.t):C.tlist=beginmatchC.litscwith|[|Literal.Equation(t1,t2,true)|]->letf1,l1=T.as_appt1inletf2,l2=T.as_appt2inbeginmatchList.revl1,List.revl2with|last1::l1,last2::l2->beginmatchT.viewlast1,T.viewlast2with|T.Varx,T.VarywhenHVar.equalType.equalxy&¬(Type.is_tType(HVar.tyx))&&beginIter.of_list[Iter.doubletonf1f2;Iter.of_listl1;Iter.of_listl2]|>Iter.flatten|>Iter.flat_mapT.Seq.vars|>Iter.for_all(funv'->not(HVar.equalType.equalv'x))end->(* it works! *)letnew_lit=Literal.mk_eq(T.appf1(List.revl1))(T.appf2(List.revl2))inletproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"ho_ext_pos")~tags:[Proof.Tag.T_ho;Proof.Tag.T_ext]inletnew_c=C.create[new_lit]proof~penalty:(C.penaltyc)~trail:(C.trailc)inUtil.incr_statstat_ext_pos;Util.debugf~section4"(@[ext_pos@ :clause %a@ :yields %a@])"(funk->kC.ppcC.ppnew_c);[new_c]|_->[]end|_->[]end|_->[]end(* More general version of ext_pos:
e.g. C \/ f X Y = g X Y becomes C \/ f X = g X and C \/ f = g,
if the variables X and Y occur nowhere else in the clause.
Removes variables only in literals eligible for paramodulation,
and only in one literal at a time.
*)letext_pos_general(c:C.t):C.tlist=leteligible=C.Eligible.paramcin(* Remove recursively variables at the end of the literal t = s if possible.
e.g. ext_pos_lit (f X Y) (g X Y) other_lits = [f X = g X, f = g]
if X and Y do not appear in other_lits *)letrecext_pos_littsother_lits=letf,tt=T.as_apptinletg,ss=T.as_appsinbeginmatchList.revtt,List.revsswith|last_t::tl_rev_t,last_s::tl_rev_s->iflast_t=last_s&¬(T.is_typelast_t)thenmatchT.as_varlast_twith|Somev->ifnot(T.var_occurs~var:vf)&¬(T.var_occurs~var:vg)&¬(List.exists(T.var_occurs~var:v)tl_rev_t)&¬(List.exists(T.var_occurs~var:v)tl_rev_s)&¬(List.exists(Literal.var_occursv)other_lits)then(letbutlast=(funl->CCList.take(List.lengthl-1)l)inlett'=T.appf(butlasttt)inlets'=T.appg(butlastss)inLiteral.mk_eqt's'::ext_pos_litt's'other_lits)else[]|None->[]else[]|_->[]endinletnew_clauses=(* iterate over all literals eligible for paramodulation *)C.litsc|>Iter.of_array|>Util.seq_zipi|>Iter.filter(fun(idx,lit)->eligibleidxlit)|>Iter.flat_map_l(fun(lit_idx,lit)->matchlitwith|Literal.Equation(t,s,true)->ext_pos_litts(CCArray.except_idx(C.litsc)lit_idx)|>Iter.of_list|>Iter.flat_map_l(funnew_lit->(* create a clause with new_lit instead of lit *)letnew_lits=new_lit::CCArray.except_idx(C.litsc)lit_idxinletproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"ho_ext_pos_general")inletnew_c=C.createnew_litsproof~penalty:(C.penaltyc)~trail:(C.trailc)in[new_c])|>Iter.to_list|_->[])|>Iter.to_rev_listinifnew_clauses<>[]then(Util.debugf~section4"(@[ext-pos-general-eq@ :clause %a@ :yields (@[<hv>%a@])@])"(funk->kC.ppc(Util.pp_list~sep:" "C.pp)new_clauses););new_clauses(* complete [f = g] into [f x1…xn = g x1…xn] for each [n ≥ 1] *)letcomplete_eq_args(c:C.t):C.tlist=letvar_offset=C.Seq.varsc|>Type.Seq.max_var|>succinleteligible=C.Eligible.paramcinletnew_c=C.litsc|>Iter.of_array|>Util.seq_zipi|>Iter.filter(fun(idx,lit)->eligibleidxlit)|>Iter.flat_map_l(fun(lit_idx,lit)->matchlitwith|Literal.Equation(t,u,true)whenType.is_fun(T.tyt)->letn_ty_args,ty_args,_=Type.open_poly_fun(T.tyt)inassert(n_ty_args=0);assert(ty_args<>[]);letvars=List.mapi(funity->HVar.make~ty(i+var_offset)|>T.var)ty_argsinCCList.(1--List.lengthvars)|>List.map(funprefix_len->letvars_prefix=CCList.takeprefix_lenvarsinletnew_lit=Literal.mk_eq(T.apptvars_prefix)(T.appuvars_prefix)inletnew_lits=new_lit::CCArray.except_idx(C.litsc)lit_idxinletproof=Proof.Step.inference[C.proof_parentc]~rule:(Proof.Rule.mk"ho_complete_eq")inletnew_c=C.createnew_litsproof~penalty:(C.penaltyc)~trail:(C.trailc)innew_c)|_->[])|>Iter.to_rev_listinifnew_c<>[]then(Util.add_statstat_complete_eq(List.lengthnew_c);Util.debugf~section4"(@[complete-eq@ :clause %a@ :yields (@[<hv>%a@])@])"(funk->kC.ppc(Util.pp_list~sep:" "C.pp)new_c););new_c(* try to eliminate a predicate variable in one fell swoop *)letelim_pred_variable(c:C.t):C.tlist=(* find unshielded predicate vars *)letfind_vars():_HVar.tIter.t=C.Seq.varsc|>T.VarSet.of_seq|>T.VarSet.to_seq|>Iter.filter(funv->(Type.is_prop@@Type.returns@@HVar.tyv)&¬(Literals.is_shieldedv(C.litsc)))(* find all constraints on [v], also returns the remaining literals.
returns None if some constraints contains [v] itself. *)andgather_litsv:(Literal.tlist*(T.tlist*bool)list)option=tryArray.fold_left(fun(others,set)lit->beginmatchlitwith|Literal.Prop(t,sign)->letf,args=T.as_apptinbeginmatchT.viewfwith|T.VarqwhenHVar.equalType.equalvq->(* found an occurrence *)ifList.exists(T.var_occurs~var:v)argsthen(raiseExit;(* [P … t[v] …] is out of scope *));others,(args,sign)::set|_->lit::others,setend|_->lit::others,setend)([],[])(C.litsc)|>CCOpt.returnwithExit->Nonein(* try to eliminate [v], if it doesn't occur in its own arguments *)lettry_elim_varv:_option=(* gather constraints on [v] *)beginmatchgather_litsvwith|None|Some(_,[])->None|Some(other_lits,constr_l)->(* gather positive/negative args *)letpos_args,neg_args=CCList.partition_map(fun(args,sign)->ifsignthen`Leftargselse`Rightargs)constr_lin(* build substitution used for this inference *)letsubst=letsome_tup=matchpos_args,neg_argswith|tup::_,_|_,tup::_->tup|[],[]->assertfalseinletoffset=C.Seq.varsc|>T.Seq.max_var|>succinletvars=List.mapi(funit->HVar.make~ty:(T.tyt)(i+offset))some_tupinletvars_t=List.mapT.varvarsinletbody=neg_args|>List.map(funtup->assert(List.lengthtup=List.lengthvars);List.map2T.Form.eqvars_ttup|>T.Form.and_l)|>T.Form.or_linUtil.debugf~section5"(@[elim-pred-with@ (@[@<1>λ @[%a@].@ %a@])@])"(funk->k(Util.pp_list~sep:" "Type.pp_typed_var)varsT.ppbody);Util.incr_statstat_elim_pred;lett=T.fun_of_fvarsvarsbodyinSubst.FO.of_list[((v:>InnerTerm.tHVar.t),0),(t,0)]in(* build new clause *)letrenaming=Subst.Renaming.create()inletnew_lits=letl1=Literal.apply_subst_listrenamingsubst(other_lits,0)inletl2=CCList.product(funargs_posargs_neg->letargs_pos=Subst.FO.apply_lrenamingsubst(args_pos,0)inletargs_neg=Subst.FO.apply_lrenamingsubst(args_neg,0)inList.map2Literal.mk_eqargs_posargs_neg)pos_argsneg_args|>List.flatteninl1@l2inletproof=Proof.Step.inference~rule:(Proof.Rule.mk"ho_elim_pred")~tags:[Proof.Tag.T_ho][C.proof_parent_substrenaming(c,0)subst]inletnew_c=C.createnew_litsproof~penalty:(C.penaltyc)~trail:(C.trailc)inUtil.debugf~section3"(@[<2>elim_pred_var %a@ :clause %a@ :yields %a@])"(funk->kT.pp_varvC.ppcC.ppnew_c);Somenew_cendinbeginfind_vars()|>Iter.filter_maptry_elim_var|>Iter.to_rev_listend(* maximum penalty on clauses to perform Primitive Enum on *)letmax_penalty_prim_=E.flex_getk_ho_prim_max_penalty(* rule for primitive enumeration of predicates [P t1…tn]
(using ¬ and ∧ and =) *)letprim_enum_~mode(c:C.t):C.tlist=(* set of variables to refine (only those occurring in "interesting" lits) *)letvars=Literals.fold_lits~eligible:C.Eligible.always(C.litsc)|>Iter.mapfst|>Iter.flat_mapLiteral.Seq.terms|>Iter.flat_mapT.Seq.subterms|>Iter.filter(funt->Type.is_prop(T.tyt))|>Iter.filter_map(funt->lethd=T.head_termtinbeginmatchT.as_varhd,Type.arity(T.tyhd)with|Somev,Type.Arity(0,n)whenn>0&&Type.returns_prop(T.tyhd)->Somev|_->Noneend)|>T.VarSet.of_seq(* unique *)inifnot(T.VarSet.is_emptyvars)then(Util.debugf~section5"(@[<hv2>ho.refine@ :clause %a@ :terms {@[%a@]}@])"(funk->kC.ppc(Util.pp_seqT.pp_var)(T.VarSet.to_seqvars)););letsc_c=0inletoffset=C.Seq.varsc|>T.Seq.max_var|>succinbeginvars|>T.VarSet.to_seq|>Iter.flat_map_l(funv->HO_unif.enum_prop~mode(v,sc_c)~offset)|>Iter.map(fun(subst,penalty)->letrenaming=Subst.Renaming.create()inletlits=Literals.apply_substrenamingsubst(C.litsc,sc_c)inletproof=Proof.Step.inference~rule:(Proof.Rule.mk"ho.refine")~tags:[Proof.Tag.T_ho][C.proof_parent_substrenaming(c,sc_c)subst]inletnew_c=C.create_alitsproof~penalty:(C.penaltyc+penalty)~trail:(C.trailc)inUtil.debugf~section3"(@[<hv2>ho.refine@ :from %a@ :subst %a@ :yields %a@])"(funk->kC.ppcSubst.ppsubstC.ppnew_c);Util.incr_statstat_prim_enum;new_c)|>Iter.to_rev_listendletprim_enum~modec=ifC.penaltyc<max_penalty_prim_thenprim_enum_~modecelse[]letpp_pairs_out=letopenCCFormatinFormat.fprintfout"(@[<hv>%a@])"(Util.pp_list~sep:" "@@hvbox@@HO_unif.pp_pair)(* perform HO unif on [pairs].
invariant: [C.lits c = pairs @ other_lits] *)letho_unif_real_cpairsother_lits:C.tlist=Util.debugf~section5"(@[ho_unif.try@ :pairs (@[<hv>%a@])@ :other_lits %a@])"(funk->kpp_pairs_pairs(Util.pp_list~sep:" "Literal.pp)other_lits);Util.incr_statstat_ho_unif;letoffset=C.Seq.varsc|>T.Seq.max_var|>succinbeginHO_unif.unif_pairs?fuel:None(pairs,0)~offset|>List.map(fun(new_pairs,us,penalty,renaming)->letsubst=Unif_subst.substusinletc_guard=Literal.of_unif_substrenamingusinletnew_pairs=List.map(fun(env,t,u)->assert(env==[]);Literal.mk_constrainttu)new_pairsandother_lits=Literal.apply_subst_listrenamingsubst(other_lits,0)inletall_lits=c_guard@new_pairs@other_litsinletproof=Proof.Step.inference~rule:(Proof.Rule.mk"ho_unif")~tags:[Proof.Tag.T_ho][C.proof_parent_substrenaming(c,0)subst]inletnew_c=C.createall_litsproof~trail:(C.trailc)~penalty:(C.penaltyc+penalty)inUtil.debugf~section5"(@[ho_unif.step@ :pairs (@[%a@])@ :subst %a@ :yields %a@])"(funk->kpp_pairs_pairsSubst.ppsubstC.ppnew_c);Util.incr_statstat_ho_unif_steps;new_c)end(* HO unification of constraints *)letho_unif(c:C.t):C.tlist=ifC.litsc|>CCArray.existsLiteral.is_ho_constraintthen((* separate constraints from the rest *)letpairs,others=C.litsc|>Array.to_list|>CCList.partition_map(function|Literal.Equation(t,u,false)aslitwhenLiteral.is_ho_constraintlit->`Left([],t,u)|lit->`Rightlit)inassert(pairs<>[]);Util.enter_profprof_ho_unif;letr=ho_unif_real_cpairsothersinUtil.exit_profprof_ho_unif;r)else[](* rule for β-reduction *)letbeta_reducet=assert(T.DB.is_closedt);lett'=Lambda.snftinif(T.equaltt')thenNoneelse(Util.debugf~section4"(@[beta_reduce `%a`@ :into `%a`@])"(funk->kT.pptT.ppt');Util.incr_statstat_beta;assert(T.DB.is_closedt');Some(t',[]))(* rule for eta-expansion *)leteta_expandt=assert(T.DB.is_closedt);lett'=Lambda.eta_expandtinif(T.equaltt')thenNoneelse(Util.debugf~section4"(@[eta_expand `%a`@ :into `%a`@])"(funk->kT.pptT.ppt');Util.incr_statstat_eta_expand;assert(T.DB.is_closedt');Some(t',[]))(* rule for eta-expansion *)leteta_reducet=assert(T.DB.is_closedt);lett'=Lambda.eta_reducetinif(T.equaltt')thenNoneelse(Util.debugf~section4"(@[eta_reduce `%a`@ :into `%a`@])"(funk->kT.pptT.ppt');Util.incr_statstat_eta_reduce;assert(T.DB.is_closedt');Some(t',[]))moduleTVar=structtypet=Type.tHVar.tletequal=HVar.equalType.equallethash=HVar.hashletcompare=HVar.compareType.compareendmoduleVarTermMultiMap=CCMultiMap.Make(TVar)(Term)moduleVTbl=CCHashtbl.Make(TVar)(* Purify variables
- if they occur applied and unapplied ("int" mode).
- if they occur with different arguments ("ext" mode).
Example: g X = X a \/ X a = b becomes g X = Y a \/ Y a = b \/ X != Y.
Literals with only a variable on both sides are not affected. *)letpurify_applied_variablec=(* set of new literals *)letnew_lits=ref[]inletadd_lit_lit=new_lits:=lit::!new_litsin(* cache for term headed by variable -> replacement variable *)letcache_replacement_=T.Tbl.create8in(* cache for variable -> untouched term (the first term we encounter with a certain variable as head) *)letcache_untouched_=VTbl.create8in(* index of the next fresh variable *)letvaridx=Literals.Seq.terms(C.litsc)|>Iter.flat_mapT.Seq.vars|>T.Seq.max_var|>succ|>CCRef.createin(* variable used to purify a term *)letreplacement_vart=tryT.Tbl.findcache_replacement_twithNot_found->lethead,_=T.as_apptinletty=T.tyheadinletv=T.var_of_int~ty(CCRef.get_then_incrvaridx)inletlit=Literal.mk_neqvheadinadd_lit_lit;T.Tbl.addcache_replacement_tv;vin(* We make the variables of two (variable-headed) terms different if they are
in different classes.
For extensional variable purification, two terms are only in the same class
if they are identical.
For intensional variable purification, two terms are in the same class if
they are both unapplied variables or both applied variables. *)letsame_classt1t2=assert(T.is_var(fst(T.as_appt1)));assert(T.is_var(fst(T.as_appt2)));if!_purify_applied_vars==`Extthent1=t2else(assert(!_purify_applied_vars==`Int);matchT.viewt1,T.viewt2with|T.Varx,T.Varywhenx=y->true|T.App(f,_),T.App(g,_)whenf=g->true|_->false)in(* Term should not be purified if
- this is the first term we encounter with this variable as head or
- it is equal to the first term encountered with this variable as head *)letshould_purifytv=tryifsame_classt(VTbl.findcache_untouched_v)then(Util.debugf~section5"Leaving untouched: %a"(funk->kT.ppt);false)else(Util.debugf~section5"To purify: %a"(funk->kT.ppt);true)withNot_found->VTbl.addcache_untouched_vt;Util.debugf~section5"Add untouched term: %a"(funk->kT.ppt);falsein(* purify a term *)letrecpurify_termt=lethead,args=T.as_apptinletres=matchT.as_varheadwith|Somev->ifshould_purifytvthen((* purify *)Util.debugf~section5"@[Purifying: %a.@ Untouched is: %a@]"(funk->kT.pptT.pp(VTbl.findcache_untouched_v));letv'=replacement_vartinassert(Type.equal(HVar.tyv)(T.tyv'));T.appv'(List.mappurify_termargs))else((* don't purify *)T.apphead(List.mappurify_termargs))|None->(* don't purify *)T.apphead(List.mappurify_termargs)inassert(Type.equal(T.tyres)(T.tyt));resin(* purify a literal *)letpurify_litlit=(* don't purify literals with only a variable on both sides *)ifLiteral.for_allT.is_varlitthenlitelseLiteral.mappurify_termlitin(* try to purify *)letlits'=Array.mappurify_lit(C.litsc)inbeginmatch!new_litswith|[]->SimplM.return_samec|_::_->(* replace! *)letall_lits=!new_lits@(Array.to_listlits')inletparent=C.proof_parentcinletproof=Proof.Step.simp~rule:(Proof.Rule.mk"ho.purify_applied_variable")~tags:[Proof.Tag.T_ho][parent]inletnew_clause=(C.create~trail:(C.trailc)~penalty:(C.penaltyc)all_litsproof)inUtil.debugf~section5"@[<hv2>Purified:@ Old: %a@ New: %a@]"(funk->kC.ppcC.ppnew_clause);SimplM.return_newnew_clauseendletextensionality_clause=letdiff_id=ID.make("zf_ext_diff")inID.set_payloaddiff_id(ID.Attr_skolem(ID.K_normal,2));(* make the arguments of diff mandatory *)letalpha=Type.var(HVar.make~ty:Type.tType0)inletbeta=Type.var(HVar.make~ty:Type.tType1)inletalpha_to_beta=Type.arrow[alpha]betainletdiff_type=Type.arrow[alpha_to_beta;alpha_to_beta]alphainletdiff=Term.const~ty:diff_typediff_idinletx=Term.var(HVar.make~ty:alpha_to_beta2)inlety=Term.var(HVar.make~ty:alpha_to_beta3)inletx_diff=Term.appx[Term.appdiff[x;y]]inlety_diff=Term.appy[Term.appdiff[x;y]]inletlits=[Literal.mk_eqxy;Literal.mk_neqx_diffy_diff]inEnv.C.create~penalty:5~trail:Trail.emptylitsProof.Step.trivialletsetup()=ifnot(Env.flex_getk_enabled)then(Util.debug~section1"HO rules disabled";)else(Util.debug~section1"setup HO rules";Env.Ctx.lost_completeness();Env.add_unary_inf"ho_complete_eq"complete_eq_args;if!_elim_pred_varthenEnv.add_unary_inf"ho_elim_pred_var"elim_pred_variable;if!_ext_negthenEnv.add_lit_rule"ho_ext_neg"ext_neg;if!_ext_pos&&!_general_ext_posthen(Env.add_unary_inf"ho_ext_pos_general"ext_pos_general)elseif!_ext_posthen(Env.add_unary_inf"ho_ext_pos"ext_pos);Env.add_rewrite_rule"beta_reduce"beta_reduce;beginmatchEnv.flex_getk_etawith|`Expand->Env.add_rewrite_rule"eta_expand"eta_expand|`Reduce->Env.add_rewrite_rule"eta_reduce"eta_reduce|`None->()end;ifEnv.flex_getk_enable_ho_unifthen(Env.add_unary_inf"ho_unif"ho_unif;);beginmatchEnv.flex_getk_ho_prim_modewith|`None->()|mode->Env.add_unary_inf"ho_prim_enum"(prim_enum~mode);end;if!_purify_applied_vars!=`NonethenEnv.add_unary_simplifypurify_applied_variable;if!_ext_axiomthenEnv.ProofState.PassiveSet.add(Iter.singletonextensionality_clause););()endletenabled_=reftrueletforce_enabled_=reffalseletenable_unif_=reftrueletprim_mode_=ref`Negletprim_max_penalty=ref15(* FUDGE *)leteta_=ref`Reduceletset_prim_mode_=letl=["neg",`Neg;"full",`Full;"none",`None;]inletset_s=prim_mode_:=List.assocslinArg.Symbol(List.mapfstl,set_)letst_contains_ho(st:(_,_,_)Statement.t):bool=letis_non_atomic_tyty=letn_ty_vars,args,_=Type.open_poly_funtyinn_ty_vars>0||args<>[]in(* is there a HO variable? *)lethas_ho_var()=Statement.Seq.termsst|>Iter.flat_mapT.Seq.vars|>Iter.exists(funv->is_non_atomic_ty(HVar.tyv))(* is there a HO symbol? *)andhas_ho_sym()=Statement.Seq.ty_declsst|>Iter.exists(fun(_,ty)->Type.orderty>1)andhas_ho_eq()=Statement.Seq.formsst|>Iter.exists(func->c|>List.exists(function|SLiteral.Eq(t,u)|SLiteral.Neq(t,u)->T.is_ho_at_roott||T.is_ho_at_rootu||is_non_atomic_ty(T.tyt)|_->false))inhas_ho_sym()||has_ho_var()||has_ho_eq()letextension=letregisterenv=letmoduleE=(valenv:Env.S)inifE.flex_getk_some_ho||!force_enabled_then(letmoduleET=Make(E)inET.setup())(* check if there are HO variables *)andcheck_hovecstate=letis_ho=CCVector.to_seqvec|>Iter.existsst_contains_hoinifis_hothen(Util.debug~section2"problem is HO");state|>Flex_state.addk_some_hois_ho|>Flex_state.addk_enabled!enabled_|>Flex_state.addk_enable_ho_unif(!enabled_&&!enable_unif_)|>Flex_state.addk_ho_prim_mode(if!enabled_then!prim_mode_else`None)|>Flex_state.addk_ho_prim_max_penalty!prim_max_penalty|>Flex_state.addk_eta!eta_in{Extensions.defaultwithExtensions.name="ho";post_cnf_actions=[check_ho];env_actions=[register];}leteta_opt=letset_n=eta_:=ninletl=["reduce",`Reduce;"expand",`Expand;"none",`None]inArg.Symbol(List.mapfstl,funs->set_(List.assocsl))letpurify_opt=letset_n=_purify_applied_vars:=ninletl=["ext",`Ext;"int",`Int;"none",`None]inArg.Symbol(List.mapfstl,funs->set_(List.assocsl))let()=Options.add_opts["--ho",Arg.Setenabled_," enable HO reasoning";"--force-ho",Arg.Setforce_enabled_," enable HO reasoning even if the problem is first-order";"--no-ho",Arg.Clearenabled_," disable HO reasoning";"--ho-unif",Arg.Setenable_unif_," enable full HO unification";"--no-ho-unif",Arg.Clearenable_unif_," disable full HO unification";"--no-ho-elim-pred-var",Arg.Clear_elim_pred_var," disable predicate variable elimination";"--ho-prim-enum",set_prim_mode_," set HO primitive enum mode";"--ho-prim-max",Arg.Set_intprim_max_penalty," max penalty for HO primitive enum";"--ho-eta",eta_opt," eta-expansion/reduction";"--ho-purify",purify_opt," enable purification of applied variables: 'ext' purifies"^" whenever a variable is applied to different arguments."^" 'int' purifies whenever a variable appears applied and unapplied.";"--ho-general-ext-pos",Arg.Set_general_ext_pos," enable general positive extensionality rule";"--ho-ext-axiom",Arg.Set_ext_axiom," enable extensionality axiom";"--ho-no-ext-pos",Arg.Clear_ext_pos," disable positive extensionality rule";"--ho-no-ext-neg",Arg.Clear_ext_neg," disable negative extensionality rule"];Extensions.registerextension;