123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931openLogtkopenLibzipperpositionmoduleT=TermmoduleTy=TypemoduleLits=LiteralsmoduleLit=LiteralmoduleA=Libzipperposition_avatarletsection=Util.Section.make~parent:Const.section"hlt-elim"letk_enabled=Flex_state.create_key()letk_max_depth=Flex_state.create_key()letk_simpl_new=Flex_state.create_key()letk_clauses_to_track=Flex_state.create_key()letk_max_self_impls=Flex_state.create_key()letk_unit_propagated_hle=Flex_state.create_key()letk_reduce_tautologies=Flex_state.create_key()letk_delete_lits=Flex_state.create_key()letk_max_tracked_clauses=Flex_state.create_key()letk_track_eq=Flex_state.create_key()letk_insert_only_ordered=Flex_state.create_key()letk_heartbeat_steps=Flex_state.create_key()letk_heartbeat_disabled_hlbe=Flex_state.create_key()letk_max_imp_entries=Flex_state.create_key()letk_basic_rules=Flex_state.create_key()letk_penalize_tautologies=Flex_state.create_key()moduletypeS=sigmoduleEnv:Env.SmoduleC:moduletypeofEnv.C(** {5 Registration} *)valsetup:unit->unitendmoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleC=Env.CmoduleCS=C.ClauseSetmoduleL=Literal(* index from literals to the map implied literal
-> clauses necessary for the proof
with an additional field storing whether there are literals
l, \neg l in the set of implied literals*)modulePremiseIdx=NPDtree.MakeTerm(structtypet=(CS.tT.Tbl.t)*bool(* as we will maintain the invariant that each term is mapped to a single
table, comparing the lengths suffices *)letcompare(a1,_)(a2,_)=compare(T.Tbl.lengtha1)(T.Tbl.lengtha2)end)(* index from literals that appear as conclusions to all the premises
in which they appear *)moduleConclusionIdx=NPDtree.MakeTerm(structtypet=T.tletcompare=Term.compareend)moduleUnitIdx=NPDtree.MakeTerm(structtypet=C.tletcompare=C.compareend)typepropagation_kind=Failed|UnitPropagatedmodulePropagatedLitsIdx=NPDtree.MakeTerm(structtypet=CS.t*propagation_kindletcompare(a,_)(b,_)=CS.compareabend)exceptionRuleNotApplicableletprems_=ref(PremiseIdx.empty())letconcls_=ref(ConclusionIdx.empty())letunits_=ref(UnitIdx.empty())letpropagated_=ref(PropagatedLitsIdx.empty())letpropagated_size_=ref0(* occurrences of the clause in the premise_idx *)letcl_occs=refUtil.Int_map.empty(* binary clauses tracked so far *)lettracked_binary=ref0(* binary clauses tracked so far *)lettracked_unary=ref0(* HLBE heartbeat will be set as soons as one rule modifies a clause *)letheartbeat_=reffalseletis_tautoc=Literals.is_trivial(C.litsc)||Trail.is_trivial(C.trailc)let[@inline]tracking_eq()=Env.flex_getk_track_eq(* constants denoting the scope of index and the query, respectively *)letidx_sc,q_sc=0,1letshould_update_propagated()=Env.flex_getk_unit_propagated_hle&&!propagated_size_<=(Env.flex_getk_max_tracked_clauses)letapp_subst?(sc=idx_sc)~substt=Subst.FO.applySubst.Renaming.nonesubst(t,sc)letregister_conclusion~tbl~premiseconclproofset=ifnot@@T.Tbl.memtblconcl&&T.depthconcl<=4then(T.Tbl.replacetblconclproofset;concls_:=ConclusionIdx.add!concls_conclpremise)(* iterate over the parts of the common context of the term --
EXCLUDING THE EMPTY CONTEXT *)letiter_ctxabk=letcommon_argxsys=letrecauxaccxsys=matchxswith|x::xs'->beginmatchyswith|y::ys'->if(not(T.equalxy))&&CCOpt.is_noneaccthen(aux(Some(x,y))xs'ys')elseifT.equalxythenauxaccxs'ys'elseNone|_->assertfalseend|_->(assert(CCList.is_emptyys));accinauxNonexsysinletrecauxab=matchT.viewa,T.viewbwith|T.App(hda,argsa),T.App(hdb,argsb)whenType.equal(T.tya)(T.tyb)->ifT.is_consthda&&T.equalhdahdbthen(matchcommon_argargsaargsbwith|Some(a,b)->k(a,b);auxab|None->())|_->()inauxabletretrieve_idx~getter(premise,q_sc)=matchT.viewpremisewith|T.AppBuiltin(Builtin.Eq,([_;a;b]|[a;b]))whentracking_eq()->Iter.append(getter(premise,q_sc))(getter((T.Form.eqba),q_sc))|T.AppBuiltin(Builtin.Neq,([_;a;b]|[a;b]))whentracking_eq()->Iter.append(getter(premise,q_sc))(getter((T.Form.neqba),q_sc))|_->getter(premise,q_sc)letretrieve_gen_prem_idx()=retrieve_idx~getter:(PremiseIdx.retrieve_generalizations(!prems_,idx_sc))letretrieve_spec_prem_idx()=retrieve_idx~getter:(PremiseIdx.retrieve_specializations(!prems_,idx_sc))letretrieve_gen_concl_idx()=retrieve_idx~getter:(ConclusionIdx.retrieve_generalizations(!concls_,idx_sc))letretrieve_spec_concl_idx()=retrieve_idx~getter:(ConclusionIdx.retrieve_specializations(!concls_,idx_sc))letretrieve_gen_unit_idxunit_sc=retrieve_idx~getter:(UnitIdx.retrieve_generalizations(!units_,unit_sc))let[@inline]get_predicatelit=matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->Some(lhs,Lit.is_positivoidlit)|L.Equation(lhs,rhs,sign)whentracking_eq()->Some(T.Form.eqlhsrhs,sign)|_->Nonelet[@inline]matching_eq?(decompose=false)~subst~pattern(t,sc)=lettry_decompositions?(cons=T.Form.eq)ab=iter_ctxab|>Iter.find(fun(a,b)->trySome(Unif.FO.matching~subst~pattern(consab,sc))withUnif.Fail->begintrySome(Unif.FO.matching~subst~pattern(consba,sc))withUnif.Fail->Noneend)|>(function|Someunif->unif|_->raiseUnif.Fail)intryUnif.FO.matching~subst~pattern(t,sc)withUnif.Fail->matchT.viewtwith|T.AppBuiltin(Builtin.Eq,([_;a;b]|[a;b]))whentracking_eq()->begintryUnif.FO.matching~subst~pattern(T.Form.eqba,sc)withUnif.Failwhendecompose->try_decompositionsabend|T.AppBuiltin(Builtin.Neq,([_;a;b]|[a;b]))whentracking_eq()->Unif.FO.matching~subst~pattern(T.Form.neqba,sc)|_->raiseUnif.Faillet[@inline]flip_eqt=matchT.viewtwith|T.AppBuiltin(Builtin.Eq,([a;b]|[_;a;b]))whentracking_eq()->T.Form.eqba|T.AppBuiltin(Builtin.Neq,([a;b]|[_;a;b]))whentracking_eq()->T.Form.neqba|_->tlet[@inline]cl_is_ht_trackablecl=Trail.is_empty(C.trailcl)&&(matchC.litsclwith|[|l1;l2|]->CCOpt.is_some(get_predicatel1)&&CCOpt.is_some(get_predicatel2)|_->false)let[@inline]recnormalize_negationslhs=matchT.viewlhswith|T.AppBuiltin(Builtin.Not,[t])->(matchT.viewtwith|T.AppBuiltin(Builtin.Not,[s])->normalize_negationss|T.AppBuiltin(Builtin.Eq,([_;a;b]|[a;b]))->T.Form.neqab|T.AppBuiltin(Builtin.Neq,([_;a;b]|[a;b]))->T.Form.eqab|_->lhs)|_->lhslet[@inline]lit_to_term?(negate=false)a_lhssign=letsign=ifnegatethennotsignelsesigninnormalize_negations(ifsignthena_lhselseT.Form.not_a_lhs)letregister_cl_termclpremise=letpremises,propagated=Util.Int_map.get_or~default:(Term.Set.empty,Term.Set.empty)(C.idcl)!cl_occsincl_occs:=Util.Int_map.add(C.idcl)((Term.Set.addpremisepremises),propagated)!cl_occsletregister_cl_propagatedclpremise=letpremises,propagated=Util.Int_map.get_or~default:(Term.Set.empty,Term.Set.empty)(C.idcl)!cl_occsincl_occs:=Util.Int_map.add(C.idcl)(premises,Term.Set.addpremisepropagated)!cl_occsletregister_propagated_lit~prop_kindlit_tclcs=lethas_renaming=reffalseinletto_remove=refTerm.Set.emptyinretrieve_idx~getter:(PropagatedLitsIdx.retrieve_specializations(!propagated_,idx_sc))(lit_t,q_sc)|>Iter.iter(fun(t,_,subst)->ifSubst.is_renamingsubstthenhas_renaming:=trueelse(to_remove:=Term.Set.addt!to_remove;));ifnot@@Term.Set.is_empty!to_removethen(Util.debugf~section2"removing: @[%a@]"(funk->k(Term.Set.ppT.pp)!to_remove));Term.Set.iter(funt->decrpropagated_size_;propagated_:=PropagatedLitsIdx.update_leaf!propagated_t(fun_->false))!to_remove;ifnot(!propagated_size_>=0)then(CCFormat.printf"prop size: %d@."!propagated_size_;assertfalse);ifnot!has_renamingthen(letproofset=CS.addclcsinCS.iter(func->register_cl_propagatedclit_t)proofset;propagated_:=PropagatedLitsIdx.add!propagated_lit_t(proofset,prop_kind);incrpropagated_size_)letreact_unit_addedunit_clunit_term=ifshould_update_propagated()then(retrieve_idx~getter:(PremiseIdx.retrieve_unifiables(!prems_,idx_sc))(unit_term,q_sc)|>Iter.iter(fun(_,(concls,_),subst)->letsubst=Unif_subst.substsubstinT.Tbl.to_iterconcls|>Iter.iter(fun(concl,cs)->letconcl=Subst.FO.applySubst.Renaming.nonesubst(concl,idx_sc)inregister_propagated_lit~prop_kind:UnitPropagatedconclunit_clcs)))letgeneralization_presentpremiseconcl=retrieve_gen_prem_idx()(premise,q_sc)|>Iter.exists(fun(_,(tbl,_),subst)->T.Tbl.keystbl|>Iter.exists(funt->tryignore(matching_eq~subst~pattern:(t,idx_sc)(concl,q_sc));truewithUnif.Fail->false))letremove_instancespremiseconcl=retrieve_spec_prem_idx()(premise,q_sc)|>(funi->Iter.fold(funtasks(t,(tbl,_),subst)->letsets_to_remove=Iter.fold(funacc(s,cls)->tryletsubst=matching_eq~subst~pattern:(concl,q_sc)(s,idx_sc)inifSubst.is_renamingsubstthenaccelsecls::accwithUnif.Fail->acc)[](T.Tbl.to_itertbl)inifCCList.is_emptysets_to_removethentaskselse(t,sets_to_remove)::tasks)[]i)|>CCList.iter(fun(t,sets)->prems_:=PremiseIdx.update_leaf!prems_t(fun(tbl,_)->T.Tbl.filter_map_inplace(funconclproofset->ifList.exists(funset->CS.subsetsetproofset)setsthen(concls_:=ConclusionIdx.remove!concls_conclt;None)elseSomeproofset)tbl;T.Tbl.lengthtbl!=0);)letcompute_is_unittblconclcl=letneg_concl=normalize_negations(T.Form.not_concl)inletneg_concl_flip=normalize_negations(T.Form.not_(flip_eqconcl))inT.Tbl.find_opttblneg_concl|>CCOpt.(<+>)(T.Tbl.find_opttblneg_concl_flip)|>CCOpt.(<$>)(CS.addcl)(* find already stored implications a -> b such that premise\sigma = b.
Then, store the implication a -> concl\sigma *)letextend_conclpremiseconclcl=Util.debugf~section3"transitive conclusion: @[%a@] --> @[%a@]"(funk->kT.pppremiseT.ppconcl);letto_add_concl=ref[]inletmax_imps=Env.flex_getk_max_imp_entriesinretrieve_spec_concl_idx()(premise,q_sc)|>Iter.iter(fun(concl',premise',subst)->(* add implication premise' -> subst (concl) *)prems_:=PremiseIdx.update_leaf!prems_premise'(fun(tbl,is_unit)->(matchT.Tbl.gettblconcl'with|Someold_proofset->ifCS.cardinalold_proofset<Env.flex_getk_max_depththen(letconcl=(Subst.FO.applySubst.Renaming.nonesubst(concl,q_sc))inifnot@@T.Tbl.memtblconcl&&T.depthconcl<=4&&T.Tbl.lengthtbl<=max_impsthen(letproofset=CS.addclold_proofsetinregister_cl_termclpremise';to_add_concl:=(concl,premise',proofset,tbl)::!to_add_concl))|None->assertfalse;);(* if by adding concl something became unit we remove
the leaf as the new one with updated unit status will be added *)true));CCList.iter(fun(c,premise,ps,tbl)->register_conclusion~tbl~premisecps)!to_add_concl;(* checking if the literal became unit *)CCList.iter(fun(c,premise,ps,tbl)->matchcompute_is_unittblcclwith|Someps->prems_:=PremiseIdx.add!prems_premise(tbl,true);letneg_prem=normalize_negations(T.Form.not_premise)inregister_propagated_lit~prop_kind:Failedneg_premclps|_->())!to_add_conclletextend_premisetblpremise'conclcl=letauxconcl=register_conclusion~tbl~premise:premise'concl(CS.singletoncl);(matchT.viewconclwith|T.AppBuiltin(Builtin.Neq,([_;a;b]|[a;b]))->iter_ctxab|>Iter.iter(fun(a,b)->letnew_neq=T.Form.neqabinregister_conclusion~tbl~premise:premise'new_neq(CS.singletoncl));|_->());register_cl_termclpremise';letmax_proof_size=Env.flex_getk_max_depthinretrieve_gen_prem_idx()(concl,q_sc)|>Iter.iter(fun(_,(tbl',_),subst)->letto_add=ref[]inT.Tbl.to_itertbl'|>Iter.iter(fun(t,proof_set)->ifC.ClauseSet.cardinalproof_set<max_proof_sizethen(letconcl=(Subst.FO.applySubst.Renaming.nonesubst(t,idx_sc))inifT.depthconcl<=4then(letnew_cls=CS.addclproof_setinCS.iter(funcl->register_cl_termclpremise')new_cls;to_add:=(concl,new_cls)::!to_add);));CCList.iter(fun(c,n)->register_conclusion~tbl~premise:premise'cn)!to_add)intryletsubst=Unif.FO.matching~pattern:(premise',0)(concl,1)inleti=ref0inletconcl'=Subst.FO.applySubst.Renaming.nonesubst(concl,0)in(* if the terms are the same -- variable does not get bound to a term containing
that variable we cannot pump the term -- give up *)ifT.equalconclconcl'thenraiseUnif.Fail;letconcl=refconclinwhile!i<=Env.flex_getk_max_self_implsdoaux!concl;(* PUTTING concl IN THE SCOPE OF premise' -- intentional!!! *)concl:=Subst.FO.applySubst.Renaming.nonesubst(!concl,0);ifT.depth!concl>3then((* breaking out of the loop for the very deep terms *)i:=Env.flex_getk_max_self_impls+1);i:=!i+1;done;withUnif.Fail->auxconclletget_unit_predicatecl=ifTrail.is_empty(C.trailcl)then(matchC.litsclwith|[|(L.Equation(lhs,_,_)asl)|]whenL.is_predicate_litl->Some(lit_to_termlhs(L.is_positivoidl))|[|L.Equation(lhs,rhs,sign)|]whentracking_eq()->Some(lit_to_term(T.Form.eqlhsrhs)(sign))|_->None)elseNoneletadd_new_premisepremiseconclcl=letalpha_renaming=retrieve_spec_prem_idx()(premise,q_sc)|>Iter.find(fun(premise',tbl,subst)->ifSubst.is_renamingsubstthenSome(premise',subst)elseNone)inmatchalpha_renamingwith|Some(premise',subst)->letconcl=Subst.FO.applySubst.Renaming.nonesubst(concl,q_sc)inletbecame_unit=refNoneinprems_:=PremiseIdx.update_leaf!prems_premise'(fun(tbl,is_unit)->ifnot(T.Tbl.memtblconcl)&¬(T.Tbl.memtbl(flip_eqconcl))&&T.Tbl.lengthtbl<=Env.flex_getk_max_imp_entriesthen(extend_premisetblpremise'conclcl;ifnotis_unitthen((matchcompute_is_unittblconclclwith|Someps->became_unit:=Some(ps,tbl)|None->());));(* if by adding concl something became unit we remove
the leaf as the new one with updated unit status will be added *)CCOpt.is_none!became_unit);(match!became_unitwith|Some(ps,tbl)->ignore(PremiseIdx.update_leaf!prems_premise'(fun(tbl,is_unit)->assertfalse));prems_:=PremiseIdx.add!prems_premise'(tbl,true);letneg_prem=normalize_negations(T.Form.not_premise')inregister_propagated_lit~prop_kind:Failedneg_premclps|None->())|_->lettbl=T.Tbl.create64inextend_premisetblpremiseconclcl;matchcompute_is_unittblconclclwith|Someps->prems_:=PremiseIdx.add!prems_premise(tbl,true);letneg_prem=normalize_negations(T.Form.not_premise)inregister_propagated_lit~prop_kind:Failedneg_premclps|None->prems_:=PremiseIdx.add!prems_premise(tbl,false)letnormalize_variablespremiseconcl=letto_rename=T.VarSet.diff(T.varsconcl)(T.varspremise)inifT.VarSet.is_emptyto_renamethenpremise,conclelse(letrenamer=T.VarSet.fold(funvarsubst->letty=HVar.tyvarinSubst.FO.bind'subst(var,0)(T.var(HVar.fresh~ty()),0))to_renameSubst.emptyinpremise,Subst.FO.applySubst.Renaming.nonerenamer(concl,0))letmax_t_depth=3letinsert_implicationpremiseconclcl=ifT.depthpremise<=max_t_depth&&T.depthconcl<=max_t_depth&¬(T.equalpremiseconcl)&¬(T.equalpremise(flip_eqconcl)&¬(generalization_presentpremiseconcl))then(Util.debugf~section3"inserting @[%a@] -> @[%a@]"(funk->kT.pppremiseT.ppconcl);letpremise,concl=normalize_variablespremiseconclinremove_instancespremiseconcl;extend_conclpremiseconclcl;add_new_premisepremiseconclcl;)letinsert_into_indicescl=matchCCArray.mapget_predicate(C.litscl)with|[|Some(a_lhs,a_sign);Some(b_lhs,b_sign)|]->letelig=ifEnv.flex_getk_insert_only_orderedthenC.eligible_param(cl,0)Subst.emptyelseCCBV.create~size:2trueinif(CCBV.getelig0)then(insert_implication(lit_to_term~negate:truea_lhsa_sign)(lit_to_termb_lhsb_sign)cl);if(CCBV.getelig1)then(insert_implication(lit_to_term~negate:trueb_lhsb_sign)(lit_to_terma_lhsa_sign)cl)|_->()letcan_track_bin_clcl=cl_is_ht_trackablecl&&(Env.flex_getk_max_tracked_clauses==-1||!tracked_binary<=Env.flex_getk_max_tracked_clauses)letcan_track_unary_clcl=Env.flex_getk_unit_propagated_hle&&(Env.flex_getk_max_tracked_clauses==-1||!tracked_unary<=4*Env.flex_getk_max_tracked_clauses)letsteps=ref0lettrack_clausecl=tryifEnv.flex_getk_heartbeat_disabled_hlbethenraiseRuleNotApplicable;(matchEnv.flex_getk_heartbeat_stepswith|Someh_stepswhen!steps!=0&&!stepsmodh_steps=0->if!heartbeat_thenheartbeat_:=falseelse(CCFormat.printf"disabling heartbeat %d@."!steps;Env.flex_addk_heartbeat_disabled_hlbetrue;raiseRuleNotApplicable;)|_->());ifcan_track_bin_clclthen(Util.debugf~section2"tracking @[%a@]"(funk->kC.ppcl);insert_into_indicescl;incrtracked_binary;)elseifcan_track_unary_clclthen(matchget_unit_predicateclwith|Someunit->react_unit_addedclunit;incrtracked_unary|None->());withRuleNotApplicable->()letmake_tauto~proof=C.create~penalty:1~trail:Trail.empty[Literal.mk_tauto]proofletpenalize_hidden_tautologycl=ifEnv.flex_getk_penalize_tautologies&¬@@ID.Set.exists(funid->Signature.sym_in_conjid(Env.signature()))(C.symbols(Iter.singletoncl))then(C.inc_penaltycl(C.lengthcl-1))letfind_implicationclpremiseconcl=retrieve_gen_prem_idx()(premise,q_sc)|>Iter.find(fun(premise',(tbl,_),subst)->T.Tbl.to_itertbl|>Iter.find(fun(concl',proofset)->tryifCS.memclproofsetthenNoneelse(letsubst=matching_eq~decompose:true~subst~pattern:(concl',idx_sc)(concl,q_sc)inSome(premise',concl',proofset,subst))withUnif.Fail->None))letdo_unit_hle_htrcl=letn=C.lengthclinletbv=CCBV.create~size:ntrueinletexceptionUnitHTRofint*(CS.t*propagation_kind)inletproofset=refCS.emptyintryifEnv.flex_getk_heartbeat_disabled_hlbethenraiseRuleNotApplicable;ifn>7thenraiseRuleNotApplicable;CCArray.iteri(funilit->matchget_predicatelitwith|Some(i_lhs,i_sign)->leti_t=lit_to_term(i_lhs)(i_sign)inleti_neg_t=lit_to_term~negate:true(i_lhs)(i_sign)inifn!=1&&Env.flex_getk_reduce_tautologiesthen(retrieve_idx~getter:(PropagatedLitsIdx.retrieve_generalizations(!propagated_,idx_sc))(i_t,q_sc)|>Iter.head|>CCOpt.iter(fun(_,ps,_)->raise(UnitHTR(i,ps))));ifEnv.flex_getk_delete_litsthen(retrieve_idx~getter:(PropagatedLitsIdx.retrieve_generalizations(!propagated_,idx_sc))(i_neg_t,q_sc)|>Iter.head|>CCOpt.iter(fun(_,(ps,_),_)->proofset:=CS.unionps!proofset;CCBV.resetbvi))|None->())(C.litscl);ifCCBV.is_empty(CCBV.negatebv)thenNoneelse(letlit_l=List.rev@@CCBV.selectbv(C.litscl)inletproof=Proof.Step.simp~rule:(Proof.Rule.mk"unit_hle/fle")(List.mapC.proof_parent(cl::CS.to_list!proofset))inletres=C.create~penalty:(C.penaltycl)~trail:(C.trailcl)lit_lproofinUtil.debugf~section2"simplified[fle]: @[%a@] --> @[%a@]"(funk->kC.ppclC.ppres);Util.debugf~section2"used: @[%a@]"(funk->k(CS.ppC.pp)!proofset);Some(res))withUnitHTR(idx,(ps,prop_kind))->letlit_l=[CCArray.get(C.litscl)idx]inletproof=Proof.Step.simp~rule:(Proof.Rule.mk(ifprop_kind=Failedthen"ftr"else"unit_htr"))(List.mapC.proof_parent(cl::CS.to_listps))inletrepl=C.create~penalty:(C.penaltycl)~trail:(C.trailcl)lit_lproofinpenalize_hidden_tautologyrepl;Util.debugf~section2"simplified[unit_htr]: @[@[%a@] --> @[%a@]@]"(funk->kC.ppclC.pprepl);Some(repl)|RuleNotApplicable->Noneletdo_hte_hlecl=letexceptionHiddenTautoofint*int*CS.tinletn=C.lengthclintryifEnv.flex_getk_heartbeat_disabled_hlbethenraiseRuleNotApplicable;ifn>7thenraiseRuleNotApplicable;letbv=CCBV.create~size:ntrueinlet(<+>)=CCOpt.(<+>)inletproofset=refCS.emptyinCCArray.iteri(funii_lit->matchget_predicatei_litwith|Some(i_lhs,i_sign)whenCCBV.getbvi->leti_t=lit_to_term(i_lhs)(i_sign)inleti_neg_t=lit_to_term~negate:true(i_lhs)(i_sign)inCCArray.iteri(funjj_lit->beginmatchget_predicatej_litwith|Some(j_lhs,j_sign)whenCCBV.getbvj&&i!=j->letj_t=lit_to_term(j_lhs)(j_sign)inletj_neg_t=lit_to_term~negate:true(j_lhs)(j_sign)inifEnv.flex_getk_reduce_tautologies&&C.lengthcl!=2then((matchfind_implicationcli_neg_tj_t<+>find_implicationclj_neg_ti_twith|Some(lit_a,lit_b,proofset,subst)when(not(CS.memclproofset))&&(C.lengthcl!=2||not(Subst.is_renamingsubst))->(* stopping further search *)raise(HiddenTauto(i,j,proofset))|_->()));ifEnv.flex_getk_delete_litsthen((matchfind_implicationcli_neg_tj_neg_t<+>find_implicationclj_ti_twith|Some(_,_,proofset',subst)->CCBV.resetbvj;Util.debugf~section3"@[%a@] --> @[%a@]"(funk->kT.ppi_neg_tT.ppj_neg_t);Util.debugf~section3"used(%d): @[%a@]"(funk->kj(CS.ppC.pp)proofset');proofset:=CS.unionproofset'!proofset|_->()))|_->()end)(C.litscl)|_->())(C.litscl);ifCCBV.is_empty(CCBV.negatebv)thenNoneelse(letlit_l=List.rev@@CCBV.selectbv(C.litscl)inletproof=Proof.Step.simp~rule:(Proof.Rule.mk"hidden_literal_elimination")(List.mapC.proof_parent(cl::CS.to_list!proofset))inletres=C.create~penalty:(C.penaltycl)~trail:(C.trailcl)lit_lproofinUtil.debugf~section2"simplified[hle]: @[%a@] --> @[%a@]"(funk->kC.ppclC.ppres);Util.debugf~section2"used: @[%a@]"(funk->k(CS.ppC.pp)!proofset);Some(res))withHiddenTauto(i,j,proofset)->letlit_l=[CCArray.get(C.litscl)i;CCArray.get(C.litscl)j]inletproof=Proof.Step.simp~rule:(Proof.Rule.mk"hidden_tautology_elimination")(List.mapC.proof_parent(cl::CS.to_listproofset))inletrepl=C.create~penalty:(C.penaltycl)~trail:(C.trailcl)lit_lproofinpenalize_hidden_tautologyrepl;Somerepl|>CCFun.tap(function|Someres->Util.debugf~section2"HTR(@[%a@])=@[%a@]@. > @[%a@]"(funk->kC.ppclC.ppres(CS.ppC.pp)proofset);|_->())|RuleNotApplicable->Noneletdo_context_simplificationcl=letlits_to_keep=CCBV.create~size:(C.lengthcl)trueinletexceptionStopIterationinCCArray.iteri(funilit->ifCCBV.getlits_to_keepi&¬(Lit.is_predicate_litlit)then(tryCCArray.iteri(funjlit'->ifi!=j&&CCBV.getlits_to_keepj&¬(Lit.is_predicate_litlit')&&Lit.is_positivoidlit=Lit.is_positivoidlit'then(matchLit.View.as_eqnlit,Lit.View.as_eqnlit'with|Some(s,t,sign),Some(ctx_s,ctx_t,_)->iter_ctxctx_sctx_t(fun(s',t')->if(T.equalss'&&T.equaltt')||(T.equalst'&&T.equalts')then(ifsignthen((* if we found a pair of literals i:s=t and j:u[s]=u[t]
then we remove the first one *)CCBV.resetlits_to_keepi;raiseStopIteration;)else(CCBV.resetlits_to_keepj)(* else the pair is i:s!=t and j:u[s]!=u[t] and the literal j
can be removed *)))|_->()))(C.litscl);withStopIteration->()))(C.litscl);ifCCBV.is_empty(CCBV.negatelits_to_keep)thenNoneelse(letlit_l=List.rev@@CCBV.selectlits_to_keep(C.litscl)inletproof=Proof.Step.simp~rule:(Proof.Rule.mk"eq_context_simplification")([C.proof_parentcl])inletres=C.create~penalty:(C.penaltycl)~trail:(C.trailcl)lit_lproofinSome(res))letsimplify_opt~fcl=(* other rules will take care of this *)ifis_tautoclthen(SimplM.return_samecl)else(matchfclwith|Somecl'->SimplM.return_newcl'|None->SimplM.return_samecl)let[@inline]check_heartbeatarg=ifCCOpt.is_someargthenheartbeat_:=true;arglethle_htr=simplify_opt~f:(funa->check_heartbeat@@do_hte_hlea)letunit_hle_htr=simplify_opt~f:(funa->check_heartbeat@@do_unit_hle_htra)letctx_simpl=simplify_opt~f:do_context_simplificationletuntrack_clausecl=(matchUtil.Int_map.get(C.idcl)!cl_occswith|Some(premises,propagated)->Term.Set.iter(funpremise->prems_:=PremiseIdx.update_leaf!prems_premise(fun(tbl,_)->T.Tbl.filter_map_inplace(funconclproofset->ifCS.memclproofsetthen(concls_:=ConclusionIdx.remove!concls_conclpremise;None)elseSomeproofset)tbl;T.Tbl.lengthtbl!=0))premises;Term.Set.iter(funprop_lit->propagated_:=PropagatedLitsIdx.update_leaf!propagated_prop_lit(fun(cs,_)->if(not@@CS.memclcs)then(decrpropagated_size_;false)elsetrue))propagated|_->());ifUtil.Int_map.mem(C.idcl)!cl_occsthen(Util.debugf~section3"removed: @[%a@]."(funk->kC.ppcl);decrtracked_binary;);cl_occs:=Util.Int_map.remove(C.idcl)!cl_occs;matchget_unit_predicateclwith|Someunit->units_:=UnitIdx.remove!units_unitcl;decrtracked_unary;|None->()letinitialize()=lettrack_active()=Signal.on_everyEnv.ProofState.ActiveSet.on_add_clausetrack_clause;Signal.on_everyEnv.ProofState.ActiveSet.on_remove_clauseuntrack_clause;Signal.on_everyEnv.on_forward_simplified(fun(_,_)->incrsteps);inlettrack_passive()=Signal.on_everyEnv.ProofState.PassiveSet.on_add_clausetrack_clause;Signal.on_everyEnv.ProofState.PassiveSet.on_remove_clauseuntrack_clause;Signal.on_everyEnv.on_forward_simplified(fun(_,_)->incrsteps)inlettrack_all()=Signal.on_everyEnv.ProofState.PassiveSet.on_add_clausetrack_clause;Signal.on_everyEnv.ProofState.ActiveSet.on_remove_clauseuntrack_clause;Signal.on_everyEnv.on_forward_simplified(fun(c,new_state)->incrsteps;matchnew_statewith|Somec'->ifnot(C.equalcc')then(untrack_clausec;track_clausec')|_->untrack_clausec(* c is redundant *))inletinitialize_with_passive()=Iter.itertrack_clause(E.get_passive());Util.debugf~section3"discovered implications:"CCFun.id;PremiseIdx.iter!prems_(funpremise(tbl,_)->Util.debugf~section3"@[%a@] --> @[%a@]"(funk->kT.pppremise(Iter.pp_seqT.pp)(T.Tbl.keystbl)))inbeginmatchEnv.flex_getk_clauses_to_trackwith|`Passive->initialize_with_passive();track_passive()|`Active->track_active()|`All->initialize_with_passive();track_all()end;Signal.StopListeningletsetup()=ifE.flex_getk_enabledthen(Signal.onEnv.on_startinitialize;letadd_simpl=ifEnv.flex_getk_simpl_newthenEnv.add_basic_simplifyelseEnv.add_active_simplifyinifEnv.flex_getk_basic_rulesthenadd_simplhle_htr;add_simplctx_simpl;ifEnv.flex_getk_unit_propagated_hlethen(add_simplunit_hle_htr);)endletmax_depth_=ref3letenabled_=reffalseletsimpl_new_=reffalseletclauses_to_track_=ref`Activeletmax_self_impls_=ref1letmax_tracked_clauses=ref(-1)letpropagated_hle=reftruelethte_=reftruelethle_=reftruelettrack_eq_=reffalseletinsert_ordered_=reffalseletheartbeat_steps=refNoneletmax_imp_=ref48letbasic_rules_=reftrueletpenalize_tautologies_=reftrueletextension=letregisterenv=letmoduleE=(valenv:Env.S)inletmoduleHLT=Make(E)inE.flex_addk_enabled!enabled_;E.flex_addk_max_depth!max_depth_;E.flex_addk_simpl_new!simpl_new_;E.flex_addk_clauses_to_track!clauses_to_track_;E.flex_addk_max_self_impls!max_self_impls_;E.flex_addk_unit_propagated_hle!propagated_hle;E.flex_addk_max_tracked_clauses!max_tracked_clauses;E.flex_addk_track_eq!track_eq_;E.flex_addk_delete_lits!hle_;E.flex_addk_reduce_tautologies!hte_;E.flex_addk_insert_only_ordered!insert_ordered_;E.flex_addk_heartbeat_steps!heartbeat_steps;E.flex_addk_heartbeat_disabled_hlbefalse;E.flex_addk_max_imp_entries!max_imp_;E.flex_addk_basic_rules!basic_rules_;E.flex_addk_penalize_tautologies!penalize_tautologies_;HLT.setup()in{Extensions.defaultwithExtensions.name="hidden literal elimination";prio=45;env_actions=[register]}let()=Options.add_opts["--hlbe-elim",Arg.Bool((:=)enabled_)," enable/disable hidden literal and tautology elimination";"--hlbe-elim-max-tracked",Arg.Int((:=)max_tracked_clauses)," negative value for disabling the limit";"--hlbe-elim-lits",Arg.Bool((:=)hle_)," remove literals using HLBE (hidden-lt-elim must be on)";"--hlbe-reduce-tautologies",Arg.Bool((:=)hte_)," reduce tautologies using HLBE (hidden-lt-elim must be on)";"--hlbe-max-depth",Arg.Set_intmax_depth_," max depth of binary implication graph precomputation";"--hlbe-simplify-new",Arg.Bool((:=)simpl_new_)," apply HLTe also when moving a clause from fresh to passive";"--hlbe-track-eq",Arg.Bool((:=)track_eq_)," enable/disable tracking and simplifying equality literals";"--hlbe-heartbeat",Arg.Int(funv->heartbeat_steps:=Somev)," when set to n, every n steps it will be checked if any HLBE simplification is performed."^" If not, any HLBE will be disabled.";"--hlbe-clauses-to-track",Arg.Symbol(["all";"passive";"active"],(function|"all"->clauses_to_track_:=`All;|"passive"->clauses_to_track_:=`Passive;|"active"->clauses_to_track_:=`Active;|_->()))," what clauses to use for simplification";"--hlbe-max-self-implications",Arg.Int((:=)max_self_impls_)," how many times do we loop implications of the kind p(X) -> p(f(X)) ";"--hlbe-unit-rules",Arg.Bool((:=)propagated_hle)," do unit-triggered removal of literals ";"--hlbe-insert-ordered",Arg.Bool((:=)insert_ordered_)," for clauses of the form l|r where l > r then insert only ~l -> r ";"--hlbe-max-entries",Arg.Int((:=)max_imp_)," maximal number of entries stored for each element mapped by implication map ";"--hlbe-basic-rules",Arg.Bool((:=)basic_rules_)," enable/disable basic (non unit) rules HLE and HTR";"--hlbe-penalize-tautologies",Arg.Bool((:=)penalize_tautologies_)," penalize hidden tautologies"];Extensions.registerextension