123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Blocked Clause Elimination} *)openLogtkopenLibzipperpositionletk_enabled=Flex_state.create_key()letk_check_at=Flex_state.create_key()letk_inprocessing=Flex_state.create_key()letk_max_resolvents=Flex_state.create_key()letk_check_gates=Flex_state.create_key()let_enabled=reffalselet_check_gates=reftruelet_inprocessing=reffalselet_check_at=ref10let_max_resolvents=ref(-1)letsection=Util.Section.make~parent:Const.section"pred-elim"moduleA=Libzipperposition_avatarmoduletypeS=sigmoduleEnv:Env.S(** {5 Registration} *)valsetup:unit->unitvalbegin_fixpoint:unit->unitvalfixpoint_step:unit->boolvalend_fixpoint:unit->unitendmoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleC=Env.CmoduleCS=C.ClauseSetmoduleL=LiteralmoduleT=Termtypelogic=|NEqFO(* nonequational FO *)|EqFO(* equational FO *)|Unsupported(* HO or FO with theories *)exceptionUnsupportedLogictypepred_elim_info={sym:ID.t;(* clauses with single pos/neg occurrence of a symbol *)mutablepos_cls:CS.t;mutableneg_cls:CS.t;(* clauses with multiple occurrences of a symbol *)mutableoffending_cls:CS.t;(* clauses that have the gate shape (occurs in pos/neg cls) *)mutablepossible_gates:CS.t;(* do the clauses in the possible_gates form a gate, and if so which one? *)mutableis_gate:(C.tlist*C.tlist)option;(* square of number of different variables stored in this clause set *)mutablesq_var_weight:float;(* number of literals stored in this clause set *)mutablenum_lits:int;(* what was this number during the last check *)mutablelast_check:(float*int)option;mutableheap_idx:int;}letpp_taskouttask=CCFormat.fprintfout"%a {@. +: @[%a@];@. -:@[%a@];@. ?:@[%a@]@. g:@[%b@]@. v^2:@[%g@]; |l|:@[%d@]; @.}@."ID.pptask.sym(CS.ppC.pp)task.pos_cls(CS.ppC.pp)task.neg_cls(CS.ppC.pp)task.offending_cls(CCOpt.is_sometask.is_gate)task.sq_var_weighttask.num_litsmoduleTaskWrapper=structtypet=pred_elim_infoletidxtask=task.heap_idxletset_idxtaskidx=task.heap_idx<-idxletltab=letcardt=CS.cardinalt.pos_cls+CS.cardinalt.neg_clsinletcard_a=cardaandcard_b=cardbincard_a<card_b||(card_a=card_b&&ID.comparea.symb.sym<0)endmoduleTaskSet=CCSet.Make(structtypet=pred_elim_infoletcomparet1t2=ID.comparet1.symt2.symend)let_task_queue=refTaskSet.empty(* an optimization -- profiler showed that much time is spent in
doing evaluation queue functions for added clauses -- instead
we temporarily store the clauses in this set and then
when we are sure that the clause is retained we
add it to the passive set *)let_newly_added=refCS.empty(* clause set containing all the registered clauses. Makes sure that
no clause is tracked or deleted multiple times from the system *)let_tracked=refCS.emptylet_logic=refNEqFOletrefine_logicnew_val=if!_logic!=Unsupportedthen(_logic:=new_val)let_ignored_symbols=refID.Set.emptyletmk_pred_elim_infosym={sym;pos_cls=CS.empty;neg_cls=CS.empty;offending_cls=CS.empty;possible_gates=CS.empty;is_gate=None;sq_var_weight=0.0;last_check=None;heap_idx=(-1);num_lits=0;}let_pred_sym_idx=refID.Map.emptyletcalc_sq_varcl=letn=List.length(Literals.vars(C.litscl))infloat_of_int(n*n)letget_sym_signlit=matchlitwith|L.Equation(lhs,rhs,_)->letsign=L.is_poslitinletis_poly=not(Type.VarSet.is_empty(T.ty_varslhs))||not(Type.VarSet.is_empty(T.ty_varsrhs))inifnotis_poly&&T.is_fo_termlhs&&T.is_fo_termrhsthen(ifType.is_prop(T.tylhs)then(ifL.is_predicate_litlitthen(lethd_sym=T.head_exnlhsinSome(hd_sym,sign))else((* reasoning with formulas is currently unsupported *)Util.debugf~section1"unsupported because of @[%a@]@."(funk->kL.pplit);_logic:=Unsupported;raiseUnsupportedLogic;))else(refine_logicEqFO;None))else(_logic:=Unsupported;Util.debugf~section1"unsupported because of @[%a@]@."(funk->kL.pplit);raiseUnsupportedLogic)|_->Noneletpossibly_ignore_symentry=letcards=CS.cardinalsinletpossible_resolvents=matchentry.is_gatewith|Some(pos_gates,neg_gates)->List.lengthpos_gates*cardentry.neg_cls+List.lengthneg_gates*cardentry.pos_cls|None->cardentry.neg_cls*cardentry.pos_clsinifEnv.flex_getk_max_resolvents<0then()else(ifpossible_resolvents>Env.flex_getk_max_resolventsthen(_pred_sym_idx:=ID.Map.removeentry.sym!_pred_sym_idx;_ignored_symbols:=ID.Set.addentry.sym!_ignored_symbols;ifTaskSet.mementry!_task_queuethen(_task_queue:=TaskSet.removeentry!_task_queue)))letscan_cl_lits?(handle_gates=true)cl=letnum_vars=List.length@@Literals.vars(C.litscl)inletis_flat=function|L.Equation(lhs,_,_)aslit->assert(L.is_predicate_litlit);letargs=T.argslhsinList.for_allT.is_varargs&&T.Set.cardinal(T.Set.of_listargs)==List.lengthargs|_->assertfalseinletupdate_idxposnegoffendinggatesnum_varscl=letupdate~actionsym=_pred_sym_idx:=ID.Map.updatesym(funold->letentry=CCOpt.get_or~default:(mk_pred_elim_infosym)oldinbeginmatchactionwith|`Pos->entry.pos_cls<-CS.addclentry.pos_cls;|`Neg->entry.neg_cls<-CS.addclentry.neg_cls;possibly_ignore_symentry;|`Offending->entry.offending_cls<-CS.addclentry.offending_cls;ifTaskSet.mementry!_task_queuethen(_task_queue:=TaskSet.removeentry!_task_queue;)|`Gates->ifhandle_gatesthen(entry.possible_gates<-CS.addclentry.possible_gates)end;ifaction!=`Gatesthen(entry.sq_var_weight<-entry.sq_var_weight+.calc_sq_varcl;entry.num_lits<-entry.num_lits+C.lengthcl);possibly_ignore_symentry;ifID.Set.mementry.sym!_ignored_symbolsthenNoneelseSomeentry)!_pred_sym_idxinID.Set.iter(update~action:`Pos)pos;ID.Set.iter(update~action:`Neg)neg;ID.Set.iter(update~action:`Offending)offending;ID.Set.iter(update~action:`Gates)gates;inletpos,neg,offending,gates=CCArray.foldi(fun((pos,neg,offending,gates)asacc)idxlit->letsymbol_is_freshsym=not(ID.Set.memsympos)&¬(ID.Set.memsymneg)&¬(ID.Set.memsymoffending)&¬(ID.Set.memsym!_ignored_symbols)in(matchget_sym_signlitwith|Some(sym,sign)whensymbol_is_freshsym->letis_offending=reffalseinfori=idx+1to(C.lengthcl)-1do(matchget_sym_sign(C.litscl).(i)with|Some(sym',_)->is_offending:=!is_offending||ID.equalsymsym'|None->())done;if!is_offendingthen(pos,neg,ID.Set.addsymoffending,gates)else(letgates=ifis_flatlitthenID.Set.addsymgateselsegatesinifsignthen(ID.Set.addsympos,neg,offending,gates)else(pos,ID.Set.addsymneg,offending,gates))|_->acc))(ID.Set.empty,ID.Set.empty,ID.Set.empty,ID.Set.empty)(C.litscl)inupdate_idxposnegoffendinggatesnum_varsclletreact_clause_adddedcl=if!_logic!=Unsupportedthen(ifnot(CS.memcl!_tracked)then(Util.debugf~section5"added:@[%a@]"(funk->kC.ppcl);_tracked:=CS.addcl!_tracked;scan_cl_lits~handle_gates:falsecl);Signal.ContinueListening)elseSignal.StopListeningletreact_clause_removedcl=if!_logic!=Unsupportedthen(letshould_retrytask=CS.is_emptytask.offending_cls&¬(ID.Set.memtask.sym!_ignored_symbols)&&(matchtask.last_checkwith|Some(old_sq_var_sum,old_num_lit)->task.sq_var_weight<old_sq_var_sum||task.num_lits<old_num_lit|None->true)inlethandle_gatesigntaskcl=matchtask.is_gatewith|Some(pos_cls,neg_cls)->ifsign&&CCList.mem~eq:C.equalclpos_cls||(notsign)&&CCList.mem~eq:C.equalclneg_clsthen((* reintroduce gate clauses *)task.pos_cls<-CS.add_listtask.pos_clspos_cls;task.neg_cls<-CS.add_listtask.neg_clsneg_cls;task.is_gate<-None)|None->()inlethandled=refID.Set.emptyinifnot(CS.memcl!_newly_added)&&CS.memcl!_trackedthen(_tracked:=CS.removecl!_tracked;Array.iteri(funidxlit->matchget_sym_signlitwith|Some(sym,sign)whennot(ID.Set.memsym!handled)->letis_offending=reffalseinfori=idx+1to(C.lengthcl)-1domatchget_sym_sign(C.litscl).(i)with|Some(sym',sign)->is_offending:=!is_offending||ID.equalsymsym'|None->()done;_pred_sym_idx:=ID.Map.updatesym(function|Sometask->task.sq_var_weight<-task.sq_var_weight-.calc_sq_varcl;task.num_lits<-task.num_lits-C.lengthcl;if!is_offendingthen(task.offending_cls<-CS.removecltask.offending_cls)elseifsignthen(handle_gatesigntaskcl;task.pos_cls<-CS.removecltask.pos_cls;)else(handle_gatesigntaskcl;task.neg_cls<-CS.removecltask.neg_cls;);ifnot(TaskSet.memtask!_task_queue)&&should_retrytaskthen(Util.debugf~section10"retrying @[%a@]@."(funk->kpp_tasktask);_task_queue:=TaskSet.addtask!_task_queue);Sometask|None->None(*probably the symbol became ignored*))!_pred_sym_idx;|_->())(C.litscl));Signal.ContinueListening)elseSignal.StopListeningletreplace_clausestaskclauses=Util.debugf~section1"replaced clauses(%a):@. regular:@[%a@]@. gates:@[%a@]@."(funk->kID.pptask.sym(CS.ppC.pp)(CS.uniontask.pos_clstask.neg_cls)(CCOpt.pp(CCPair.pp(CCList.ppC.pp)(CCList.ppC.pp)))task.is_gate);Util.debugf~section1"resolvents: @[%a@]@."(funk->k(CCList.ppC.pp)clauses);_ignored_symbols:=ID.Set.addtask.sym!_ignored_symbols;letremoveiter=Env.remove_activeiter;Env.remove_passiveiter;Env.remove_simpliter;Iter.iter(func->(C.mark_redundantc);ifCS.memc!_newly_addedthen(_newly_added:=CS.removec!_newly_added;ignore(react_clause_removedc);))iter;inassert(CS.is_emptytask.offending_cls);remove(CS.to_itertask.pos_cls);remove(CS.to_itertask.neg_cls);(matchtask.is_gatewith|Some(pos_cls,neg_cls)->remove(CCList.to_iterpos_cls);remove(CCList.to_iterneg_cls)|None->());_newly_added:=CS.add_list!_newly_addedclauses;List.iter(funcl->ignore(react_clause_adddedcl))clauses;_pred_sym_idx:=ID.Map.removetask.sym!_pred_sym_idxletcheck_if_gatetask=letsym=task.syminletgates_l=CS.to_listtask.possible_gatesinletfilter_gates~sign~lit_num_filter=List.filter(funcl->lit_num_filter(Array.length(C.litscl))&&(match(CCArray.find_idx(funlit->matchget_sym_signlitwith|Some(sym',sign')->ID.equalsymsym'&&sign=sign'|None->false)(C.litscl))with|Some(i,lit)->letfree_vars=T.VarSet.of_list(L.varslit)inCCOpt.is_none(CCArray.find_map_i(funjlit'->if(i=j||T.VarSet.subset(T.VarSet.of_list(L.varslit'))free_vars)thenNoneelseSomej)(C.litscl))|_->false))gates_linletfind_and_orbin_clauseslong_clauses=(* both AND and OR definitions are of the form (~)name \/ literals
and a bunch of binary clauses (~)name \/ lit *)CCList.find_map(funlong_cl->letsym_lits,other_lits=List.partition(funlit->matchget_sym_signlitwith|Some(sym',_)->ID.equalsymsym'|_->false)(CCArray.to_list@@C.litslong_cl)inassert(List.lengthsym_lits=1);letsym_name_lit=List.hdsym_litsinletbin_gates=CCArray.of_listbin_clausesinifList.lengthother_lits>CCArray.lengthbin_gatesthenNoneelse((* bit vector remembering which binary clauses we have already used *)letmatched=CCBV.create~size:(CCArray.lengthbin_gates)falseinletis_gate=List.for_all(funlit->letfound=reffalseinleti=ref0inwhilenot!found&&!i<CCArray.lengthbin_gatesdoletcl=bin_gates.(!i)inifnot(CCBV.getmatched!i)then(letidx_name_opt=CCArray.find_idx(funlit->matchget_sym_signlitwith|Some(sym',_)->ID.equalsymsym'|None->false)(C.litscl)inletidx_name,_=CCOpt.get_exnidx_name_optinletname_lit=L.negate(C.litscl).(idx_name)inletother_lit=L.negate(C.litscl).(1-idx_name)inletis_matched=not@@Iter.is_empty(L.variant(lit,0)(other_lit,1)|>Iter.filter(fun(subst,_)->not@@Iter.is_empty@@L.variant~subst(sym_name_lit,0)(name_lit,1)))inifis_matchedthen(CCBV.setmatched!i;found:=true));incri;done;!found)other_litsinletbin_cls=CCBV.selectmatchedbin_gatesinifis_gatethenSome(long_cl,bin_cls)elseNone))long_clausesinletcheck_and()=letpos_gates=filter_gates~sign:true~lit_num_filter:(funn->n>=3)inletneg_gates=filter_gates~sign:false~lit_num_filter:((=)2)inmatchfind_and_orneg_gatespos_gateswith|Some(pos_cl,neg_cls)->letto_remove=CS.of_list(pos_cl::neg_cls)intask.neg_cls<-CS.difftask.neg_clsto_remove;task.pos_cls<-CS.difftask.pos_clsto_remove;task.is_gate<-Some([pos_cl],neg_cls);true|None->falseinletcheck_or()=letpos_gates=filter_gates~sign:true~lit_num_filter:((=)2)inletneg_gates=filter_gates~sign:false~lit_num_filter:(funn->n>=3)inmatchfind_and_orpos_gatesneg_gateswith|Some(neg_cl,pos_cls)->letto_remove=CS.of_list(neg_cl::pos_cls)intask.neg_cls<-CS.difftask.neg_clsto_remove;task.pos_cls<-CS.difftask.pos_clsto_remove;task.is_gate<-Some(pos_cls,[neg_cl]);true|None->falsein(* not yet implemented *)letcheck_ite()=falseinifEnv.flex_getk_check_gatesthen(ignore(check_and()||check_or()||check_ite()))letschedule_tasks()=ID.Map.iter(fun_task->check_if_gatetask;Util.debugf~section5"initially: @[%a@]"(funk->kpp_tasktask);ifCS.is_emptytask.offending_clsthen(_task_queue:=TaskSet.addtask!_task_queue))!_pred_sym_idxletfind_lit_by_symsymsigncl=CCOpt.get_exn(CCArray.find_map_i(funidxlit->matchget_sym_signlitwith|Some(sym',sign')whenID.equalsymsym'&&sign=sign'->Some(idx,CCOpt.get_exn(L.View.get_lhslit))|_->None)(C.litscl))letis_tautoc=Literals.is_trivial(C.litsc)||Trail.is_trivial(C.trailc)letneq_resolver~sym~pos_cl~neg_cl=letpos_sc,neg_sc=0,1inletpos_idx,pos_term=find_lit_by_symsymtruepos_clinletneg_idx,neg_term=find_lit_by_symsymfalseneg_clintryletsubst=Unif.FO.unify_syn(pos_term,pos_sc)(neg_term,neg_sc)inletrenaming=Subst.Renaming.create()inletlits=(List.map(funlit->L.apply_substrenamingsubst(lit,pos_sc))(CCArray.except_idx(C.litspos_cl)pos_idx))@(List.map(funlit->L.apply_substrenamingsubst(lit,neg_sc))(CCArray.except_idx(C.litsneg_cl)neg_idx))inletproof=Proof.Step.simp~tags:[Proof.Tag.T_cannot_orphan]~rule:(Proof.Rule.mk"dp-resolution")[C.proof_parent_substrenaming(pos_cl,pos_sc)subst;C.proof_parent_substrenaming(neg_cl,neg_sc)subst]inletc=C.create~penalty:(max(C.penaltypos_cl)(C.penaltyneg_cl))~trail:(C.trail_l[pos_cl;neg_cl])litsproofinCCOpt.return_if(not(is_tautoc))cwithUnif.Fail->Noneleteq_resolver~sym~pos_cl~neg_cl=letpos_sc,neg_sc=0,1inletrenaming=Subst.Renaming.create()inletsubst=Subst.emptyinletpos_cl'=C.apply_subst~renaming(pos_cl,pos_sc)substinletneg_cl'=C.apply_subst~renaming(neg_cl,neg_sc)substinletpos_idx,pos_term=find_lit_by_symsymtruepos_cl'inletneg_idx,neg_term=find_lit_by_symsymfalseneg_cl'inletpos_args,neg_args=CCPair.map_sameT.args(pos_term,neg_term)inletlits=(List.map(fun(p,n)->L.mk_neqpn)(List.combinepos_argsneg_args))@(CCArray.except_idx(C.litspos_cl')pos_idx)@(CCArray.except_idx(C.litsneg_cl')neg_idx)inletproof=Proof.Step.simp~tags:[Proof.Tag.T_cannot_orphan]~rule:(Proof.Rule.mk"dp-resolution")[C.proof_parent_substrenaming(pos_cl,pos_sc)subst;C.proof_parent_substrenaming(neg_cl,neg_sc)subst]inletc=C.create~penalty:(max(C.penaltypos_cl')(C.penaltyneg_cl'))~trail:(C.trail_l[pos_cl';neg_cl'])litsproofinCCOpt.return_if(not(is_tautoc))cletget_resolver()=if!_logic=NEqFOthenneq_resolverelseeq_resolverletcalc_resolvents~sym~pos~neg=CCList.flat_map(funpos_cl->CCList.filter_map(funneg_cl->get_resolver()~sym~pos_cl~neg_cl)neg)posletdo_pred_elim()=letremoved_cls=refNoneinletupdated_removedinc=match!removed_clswith|None->removed_cls:=Someinc|Someinc'->removed_cls:=Some(inc'+inc)inletprocess_tasktask=assert(CS.is_emptytask.offending_cls);letpos_cls,neg_cls=CCPair.map_sameCS.to_list(task.pos_cls,task.neg_cls)inletsym=task.syminletresolvents,pos_gates,neg_gates=matchtask.is_gatewith|Some(pos_gates,neg_gates)->((calc_resolvents~sym~pos:pos_gates~neg:neg_cls)@(calc_resolvents~sym~pos:pos_cls~neg:neg_gates)),pos_gates,neg_gates|None->calc_resolvents~sym~pos:pos_cls~neg:neg_cls,[],[]inletnew_sq_var_weight,new_lit_num=List.fold_left(fun(acc_sq,acc_lit_num)cl->acc_sq+.calc_sq_varcl,acc_lit_num+C.lengthcl)(0.0,0)resolventsinletold_clauses=CS.cardinaltask.pos_cls+CS.cardinaltask.neg_cls+List.lengthpos_gates+List.lengthneg_gatesinletnum_new_cls=List.lengthresolventsinifnew_sq_var_weight<=task.sq_var_weight||new_lit_num<=task.num_lits||num_new_cls<old_clausesthen(Util.debugf~section5"replacing: @[%a@] (%d/%d) "(funk->kID.pptask.symold_clauses(num_new_cls));updated_removed(old_clauses-num_new_cls);replace_clausestaskresolvents;)else(task.last_check<-Some(task.sq_var_weight,task.num_lits))inletmoduleS=TaskSetinwhilenot(S.is_empty!_task_queue)dolettask=S.min_elt!_task_queuein_task_queue:=S.removetask!_task_queue;ifnot(ID.Set.memtask.sym!_ignored_symbols)then(Util.debugf~section5"checking: @[%a@]"(funk->kpp_tasktask);process_task(task))done;(* storing all newly computed clauses *)Env.add_passive(CS.to_iter!_newly_added);_newly_added:=CS.empty;!removed_clsletsteps=ref0(* driver that does that every k-th step of given-clause loop *)letdo_predicate_elimination()=steps:=(!steps+1)mod(Env.flex_getk_check_at);if!steps=0then(ignore(do_pred_elim());)letinitialize()=letinit_clauses=CS.to_list(Env.ProofState.ActiveSet.clauses())@CS.to_list(Env.ProofState.PassiveSet.clauses())inbegintryUtil.debugf~section5"init_cl: @[%a@]@."(funk->k(CCList.ppC.pp)init_clauses);letinit_clause_num=List.lengthinit_clausesinCCFormat.printf"%% PE start: %d@."init_clause_num;List.iter(funcl->scan_cl_litscl;_tracked:=CS.addcl!_tracked;)init_clauses;schedule_tasks();Util.debugf~section5"state:@[%a@]@."(funk->k(Iter.pp_seqpp_task)(ID.Map.values!_pred_sym_idx));Util.debugf~section1"logic has%sequalities"(funk->k(if!_logic==EqFOthen" "else" no "));Signal.onEnv.ProofState.PassiveSet.on_add_clausereact_clause_addded;Signal.onEnv.ProofState.PassiveSet.on_remove_clausereact_clause_removed;Signal.onEnv.ProofState.ActiveSet.on_add_clausereact_clause_addded;Signal.onEnv.ProofState.ActiveSet.on_remove_clausereact_clause_removed;Signal.on_everyEnv.on_forward_simplified(fun(c,new_state)->if!_logic!=Unsupportedthen(matchnew_statewith|Somec'->ignore(react_clause_removedc);ignore(react_clause_adddedc')|_->ignore(react_clause_removedc)(* c is redundant *)));ignore(do_pred_elim());Util.debugf~section5"after elim: @[%a@]@."(funk->k(CS.ppC.pp)(Env.ProofState.PassiveSet.clauses()));Util.debugf~section5"state:@[%a@]@."(funk->k(Iter.pp_seqpp_task)(ID.Map.values!_pred_sym_idx));letclause_diff=init_clause_num-(Iter.length(Env.get_active())+Iter.length(Env.get_passive()))inCCFormat.printf"%% PE eliminated: %d@."clause_diff;ifEnv.flex_getk_inprocessingthen(Env.add_clause_elimination_rule~priority:2"pred_elim"do_predicate_elimination)elseraiseUnsupportedLogicwithUnsupportedLogic->Util.debugf~section1"logic is unsupported"CCFun.id;(* releasing possibly used memory *)_logic:=Unsupported;_pred_sym_idx:=ID.Map.emptyend;Signal.StopListeningletregister()=Signal.onEnv.on_startinitializeletfixpoint_active=reffalseletbegin_fixpoint()=fixpoint_active:=true;E.flex_addk_enabled!_enabled;E.flex_addk_max_resolvents!_max_resolvents;E.flex_addk_check_gates!_check_gates;letinit_clauses=CS.to_list(Env.ProofState.ActiveSet.clauses())@CS.to_list(Env.ProofState.PassiveSet.clauses())inbegintryList.iter(funcl->scan_cl_litscl;_tracked:=CS.addcl!_tracked;)init_clauses;schedule_tasks();Signal.onEnv.ProofState.PassiveSet.on_add_clause(func->if!fixpoint_activethenreact_clause_adddedcelseSignal.StopListening);Signal.onEnv.ProofState.PassiveSet.on_remove_clause(func->if!fixpoint_activethenreact_clause_removedcelseSignal.StopListening);letans=(do_pred_elim())inUtil.debugf~section1"Clause number changed for %a"(funk->k(CCOpt.ppCCInt.pp)ans)withUnsupportedLogic->Util.debugf~section1"logic is unsupported"CCFun.id;(* releasing possibly used memory *)_logic:=Unsupported;_pred_sym_idx:=ID.Map.emptyendletfixpoint_step()=letans=do_pred_elim()inUtil.debugf~section1"Clause number changed for %a"(funk->k(CCOpt.ppCCInt.pp)ans);CCOpt.is_someansletend_fixpoint()=_logic:=Unsupported;_pred_sym_idx:=ID.Map.empty;fixpoint_active:=falseletsetup()=ifEnv.flex_getk_enabledthen(ifnot(Env.flex_getA.k_avatar_enabled)then(register())else(CCFormat.printf"AVATAR is not yet compatible with PredElim@."))endletextension=letactionenv=letmoduleE=(valenv:Env.S)inletmodulePredElim=Make(E)inE.flex_addk_enabled!_enabled;E.flex_addk_check_at!_check_at;E.flex_addk_inprocessing!_inprocessing;E.flex_addk_max_resolvents!_max_resolvents;E.flex_addk_check_gates!_check_gates;PredElim.setup()in{Extensions.defaultwithExtensions.name="pred_elim";prio=90;env_actions=[action];}let()=Options.add_opts["--pred-elim",Arg.Bool((:=)_enabled)," enable predicate elimination";"--pred-elim-check-gates",Arg.Bool((:=)_check_gates)," enable recognition of gate clauses";"--pred-elim-inprocessing",Arg.Bool((:=)_inprocessing)," predicate elimination as inprocessing rule";"--pred-elim-check-at",Arg.Int((:=)_check_at)," when to perform predicate elimination inprocessing";"--pred-elim-max-resolvents",Arg.Int((:=)_max_resolvents)," after how many resolvents to stop tracking a symbol";]