123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803(* 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_max_symbol_occ=Flex_state.create_key()letk_processing_kind=Flex_state.create_key()letsection=Util.Section.make~parent:Const.section"bce"let_enabled=reffalselet_processing_kind=ref`PreprocessingOnlylet_check_at=ref10let_max_symbol_occ=ref(-1)(* -1 stands for infinity *)moduleAvatar=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.CmoduleL=LiteralmoduleT=TermmoduleCC=Congruence.FOmoduleDEQ=CCDequemoduleSymSignIdx=Map.Make(structtypet=(ID.t*bool)letcompare=CCPair.compareID.compareCCBool.compareend)typelogic=|NEqFO(* nonequational FO *)|EqFO(* equational FO *)|Unsupported(* HO or FO with theories *)exceptionUnsupportedLogic(* an object representing the information necessary for
performing a task of checking whether a clause is blocked on
a given literals *)typebce_check_task={(* clause and index for which we are checking blockedness *)lit_idx:int;clause:C.t;(* list of candidates to check *)cands:C.tCCDeque.t;(* is the list actively stored in the heap of tasks, or in the waiting
state, because check against some candidate failed *)mutableheap_idx:int;}moduleTaskStore=Map.Make(structtypet=int*C.tletcompare(idx_a,cl_a)(idx_b,cl_b)=CCOrd.(<?>)(CCInt.compare(C.idcl_a)(C.idcl_b))(compare,idx_a,idx_b)end)moduleTaskWrapper=structtypet=bce_check_taskletidxtask=task.heap_idxletset_idxtaskidx=task.heap_idx<-idxletltab=(DEQ.lengtha.cands<DEQ.lengthb.cands)||(DEQ.lengtha.cands=DEQ.lengthb.cands&&CCInt.compare(C.ida.clause)(C.idb.clause)<0)||(DEQ.lengtha.cands=DEQ.lengthb.cands&&CCInt.compare(C.ida.clause)(C.idb.clause)=0&&a.lit_idx<b.lit_idx)endmoduleTaskPriorityQueue=CCMutHeap.Make(TaskWrapper)letinit_heap_idx=-1(* (symbol, sign) -> clauses with the corresponding occurence *)letss_idx=refSymSignIdx.empty(* clause (or its id) -> all clauses that it locks *)letclause_lock=refUtil.Int_map.empty(* a store that implements perfect sharing of tasks *)lettask_store=refTaskStore.empty(* priority queue of the tasks to be performed *)lettask_queue=TaskPriorityQueue.create()(* a set containing symbols for which BCE will not be tried *)letignored_symbols=refID.Set.empty(* assuming the weakest logic *)letlogic=refNEqFOletrefine_logicnew_val=if!logic!=Unsupportedthen(logic:=new_val)letlit_to_termsign=ifsignthenCCFun.idelseT.Form.not_(* ignoring other fields of tasks *)lettask_eqab=a.lit_idx=b.lit_idx&&C.equala.clauseb.clauseletsymbol_occurrs_too_oftensym_count=Env.flex_getk_max_symbol_occ>0&&(sym_count>Env.flex_getk_max_symbol_occ)letadd_lit_to_idxlit_lhssigncl=letsym=T.head_exnlit_lhsinletsym_occssymsign=CCOpt.map_or~default:0C.ClauseSet.cardinal(SymSignIdx.find_opt(sym,sign)!ss_idx)inlettotal_sym_occs=sym_occssymtrue+sym_occssymfalse+1inifsymbol_occurrs_too_oftentotal_sym_occsthen(ss_idx:=SymSignIdx.remove(sym,false)(SymSignIdx.remove(sym,true)!ss_idx);ignored_symbols:=ID.Set.addsym!ignored_symbols;Util.debugf~section5"ignoring symbol @[%a@]@."(funk->kID.ppsym);)else(ss_idx:=SymSignIdx.update(sym,sign)(funold->Some(C.ClauseSet.addcl(CCOpt.get_or~default:C.ClauseSet.emptyold)))!ss_idx;)(* find all clauses for which L-resolution should be tried against literal
with given lhs and sign *)letfind_candindateslhssign=lethd=T.head_exnlhsinC.ClauseSet.to_list(CCOpt.get_or~default:C.ClauseSet.empty(SymSignIdx.find_opt(hd,notsign)!ss_idx))(* Scan the clause and if it is in supported logic fragment,
store its literals in the symbol index *)letscan_cl_litscl=CCArray.iter(function|L.Equation(lhs,rhs,_)aslit->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_exnlhsinifnot(ID.Set.memhd_sym!ignored_symbols)thenadd_lit_to_idxlhssigncl)else((* reasoning with formulas is currently unsupported *)Util.debugf~section1"unsupported because of @[%a@]@."(funk->kL.pplit);logic:=Unsupported;raiseUnsupportedLogic;))elserefine_logicEqFO)else(logic:=Unsupported;Util.debugf~section1"unsupported because of @[%a@]@."(funk->kL.pplit);raiseUnsupportedLogic)|_->())(C.litscl)(* Add candidates to already registered task *)letadd_candidateslit_idxclcand_cls=lett=TaskStore.find(lit_idx,cl)!task_storeinDEQ.add_iter_backt.cands(CCList.to_itercand_cls);ifTaskPriorityQueue.in_heaptthen(TaskPriorityQueue.increasetask_queuet;)(* Register a new task, calculate its candidates and make it active. Only
clauses within the supported logic fragment can be registered.
If update_others is false, index state of other clauses will not be
updated. We want to turn this option to false in the initialization phase,
as index state will be update when the time for registering new clause
comes and updating of states is an expensive operation since it traverses
the heap in O(n) *)letregister_task?(update_others=true)lit_idxclause=(* insert new clause into the candidate list of previously inserted clauses *)letupdate_cand_listshdsignclausecands=List.iter(funcand->ifnot(C.equalcandclause)then(CCArray.iteri(funlit_idxlit->matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit&&ID.equal(T.head_exnlhs)hd&&sign!=L.is_poslit->add_candidateslit_idxcand[clause]|_->())(C.litscand)))cands;inmatch(C.litsclause).(lit_idx)with|L.Equation(lhs,rhs,_)aslitwhenL.is_predicate_litlit&¬(ID.Set.mem(T.head_exnlhs)!ignored_symbols)->assert(T.is_fo_termlhs);lethd=T.head_exnlhsinletsign=L.is_poslitinletcands=find_candindateslhssigninifupdate_othersthen(update_cand_listshdsignclausecands);lettask={lit_idx;clause;cands=DEQ.of_listcands;heap_idx=init_heap_idx}intask_store:=TaskStore.add(lit_idx,clause)task!task_store;TaskPriorityQueue.inserttask_queuetask|_->((* equation literals do not represent tasks *))(* Update all the bookeeping information when a new clause is introduced *)letadd_clausecl=tryscan_cl_litscl;CCArray.iteri(funlit_idx_->register_tasklit_idxcl)(C.litscl)withUnsupportedLogic->(* if the initial problem had only supported features (FO logic),
it cannot jump out of the fragment *)invalid_arg"jumped out of the supported logic fragment"(* remove the clause from symbol index *)letderegister_symbolscl=CCArray.iteri(fun_lit->matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->ss_idx:=SymSignIdx.update(T.head_exnlhs,L.is_poslit)(function|Someold->letnew_=C.ClauseSet.removecloldinCCOpt.return_if(not(C.ClauseSet.is_emptynew_))new_|None->None(*already removed*))!ss_idx;|_->())(C.litscl)letlock_clauselockerlocked_task=assert(C.idlocker==C.id(DEQ.peek_frontlocked_task.cands));clause_lock:=Util.Int_map.update(C.idlocker)(funold_val->letlocked_tasks=CCOpt.get_or~default:[]old_valinSome(locked_task::locked_tasks))!clause_lock(* If clause is removed from the active/passive set, then release
the locks that it holds, and make all the locked clauses active *)letrelease_locksclause=Util.debugf~section3"clearing locks: @[%a@]@."(funk->kC.ppclause);tryList.iter(funtask->assert(not(TaskPriorityQueue.in_heaptask));assert(not(DEQ.is_emptytask.cands));letlocking_cl=DEQ.take_fronttask.candsinassert(C.idlocking_cl=C.idclause);Util.debugf~section3" |@[%a@]|%d@."(funk->kC.pptask.clausetask.lit_idx);TaskPriorityQueue.inserttask_queuetask)(Util.Int_map.find(C.idclause)!clause_lock);clause_lock:=Util.Int_map.remove(C.idclause)!clause_lockwithNot_found->(* clause was already removed *)()(* remove the clause from the whole BCE tracking system *)letderegister_clauseclause=deregister_symbolsclause;release_locksclauseletremove_from_proof_stateclause=C.mark_redundantclause;Env.remove_active(Iter.singletonclause);Env.remove_passive(Iter.singletonclause);Env.remove_simpl(Iter.singletonclause)(* checks whether all L-resolvents between orig_cl on literal with index
lit_idx and partner are valid *)letresolvent_is_valid_neqlit_idxorig_clpartner=assert(lit_idx<C.lengthorig_cl);letsc_orig,sc_partner=0,1in(* splits the partner clause into unifiable and nonunifiable literals
with respect to the literal of the original clause chosen for checking *)letsplit_partnerlhssignpartner=CCArray.foldi(fun(unifiable,others)idxlit->matchlitwith|L.Equation(lhs',_,_)whenL.is_predicate_litlit&&L.is_poslit!=sign->begintryletsubst=Unif.FO.unify_syn(lhs,sc_orig)(lhs',sc_partner)in(lhs',subst)::unifiable,otherswithUnif.Fail->unifiable,lit::othersend|_->unifiable,lit::others)([],[])(C.litspartner)inletcheck_resolventsl_idxorig_cl(unifiable,nonunifiable)=letorig_sign=L.is_pos((C.litsorig_cl).(l_idx))in(* literals against which unifiable part of the clause needs to be checked *)letfor_tautology_checking=List.filter(fun(lit,_)->L.is_poslit=orig_sign&&L.is_predicate_litlit)((List.map(funx->x,sc_orig)(CCArray.except_idx(C.litsorig_cl)l_idx))@List.map(funx->x,sc_partner)nonunifiable)inifCCList.is_emptyunifiablethentrueelse((* lhs is the lhs of the literal we are currently checking
subst is substitution built so far
rest are other literals that should be checked *)letreccheck_litlhssubstrest=(* if clause is valid because there are opposite literals in nonunifiable
part -- we have won as those literals will not be removed with L-resolution *)letis_valid=List.exists(funlit'->CCOpt.is_some(CCArray.find_map_i(funidxlit->ifidx!=l_idx&&L.are_opposite_subst~subst(lit,sc_orig)(lit',sc_partner)then(Somelit)elseNone)(C.litsorig_cl)))nonunifiableinUtil.debugf~section30"check: @. lit: @[%a@]@. unif:@[%a@]@. non_unif @[%a@]@. partner_cl: @[%a@]@."(funk->kL.pp((C.litsorig_cl).(l_idx))(CCList.ppT.pp)(List.mapfstunifiable)(CCList.ppL.pp)nonunifiableC.pppartner);is_valid||(not(CCList.is_emptyrest)&&((* else, we do L-resolution with the unifiable part extended *)letcontrasting,rest'=CCList.partition(fun(lhs,_)->CCOpt.is_some(List.find_opt(fun(lit,sc)->letlhs'=CCOpt.get_exn(L.View.get_lhslit)inUnif.FO.equal~subst(lhs',sc)(lhs,sc_partner))(for_tautology_checking)))restin(* clause is not valid *)ifCCList.is_emptycontrastingthenfalseelse(tryletsubst=List.fold_left(funsubst(lhs',_)->(* extending the substitution *)Unif.FO.unify_syn~subst(lhs,sc_partner)(lhs',sc_partner))(subst)contrastingin(* clause is valid, but using only literals in the unifiable part,
try extended L-resolution *)check_litlhssubstrest'withUnif.Fail->(* substitution cannot be extended, on the ground level L-resolution
is not possible, thus clause is valid *)true)))in(* check if all L-resolvents are valid in polynomial time *)letreccheck_l_resolventsrest=function|(lhs,subst)asx::xs->check_litlhssubst(rest@xs)&&check_l_resolvents(x::rest)xs|[]->trueincheck_l_resolvents[]unifiable)inletlit=(C.litsorig_cl).(lit_idx)inletlhs,sign=matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->(lhs,L.is_poslit)|_->assertfalse(* literal must be eligible for BCE *)incheck_resolventslit_idxorig_cl(split_partnerlhssignpartner)(* checks whether all *flat* L-resolvents between orig_cl on literal with
index lit_idx and partner are valid *using congruence closure algorithm* *)letresolvent_is_valid_eqlit_idxorig_clpartner=assert(lit_idx<C.lengthorig_cl);letsc_orig,sc_partner=0,1inletrenaming=Subst.Renaming.create()in(* renaming clauses apart -- cannot be done automatically since no unifiers
are being computed and the API will not take care of that for us *)letorig_cl=C.apply_subst~renaming(orig_cl,sc_orig)Subst.emptyinletpartner=C.apply_subst~renaming(partner,sc_partner)Subst.emptyin(* splitting into parts that have the same head and the sign as the literal
in the original clause and the other ones *)letsplit_partnerlhssignpartner=CCArray.foldi(fun(same_hds,others)idxlit->matchlitwith|L.Equation(lhs',_,_)whenL.is_predicate_litlit&&L.is_poslit!=sign&&ID.equal(T.head_exnlhs)(T.head_exnlhs')->lhs'::same_hds,others|_->same_hds,lit::others)([],[])(C.litspartner)inletlit=(C.litsorig_cl).(lit_idx)inletorig_lhs,orig_sign=matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->(lhs,L.is_poslit)|_->assertfalse(* literal must be eligible for BCE *)inletcheck_resolventsl_idxorig_cl(same_hd_lits,diff_hd_lits)=letorig_args=T.args@@CCOpt.get_exn@@(L.View.get_lhs(C.litsorig_cl).(l_idx))in(* add equations that correspond to computing a flat resolvent between
original lit and the one that has new_args arguments to the head *)letadd_flat_resolvent~ccnew_args=Util.debugf~section10" adding resolvent <%a>, <%a>@."(funk->k(CCList.ppT.pp)orig_args(CCList.ppT.pp)new_args);List.fold_left(funacc(lhs,rhs)->CC.mk_eqacclhsrhs)cc(List.combineorig_argsnew_args)in(* calculating positive, that is negative literals in both clauses *)letorig_pos,orig_neg=CCList.partitionL.is_pos(CCArray.except_idx(C.litsorig_cl)l_idx)inletpartner_pos,partner_neg=CCList.partitionL.is_pos(diff_hd_lits)inletall_pos=orig_pos@partner_posinletall_neg=orig_neg@partner_negin(* Literals from same_hd_lits part might need to be tested for congruence
with literals of the same head, but opposite side from either clause *)letfor_congruence_testing=CCList.filter_map(funlit->ifL.is_predicate_litlit&&L.is_poslit=orig_signthen(CCOpt.flat_map(funt->CCOpt.return_if(ID.equal(T.head_exnt)(T.head_exnorig_lhs))t)(L.View.get_lhslit))elseNone)(iforig_signthenall_poselseall_neg)in(* equational theory induced by all the negative literals *)letorig_cc=List.fold_left(funacclit->assert(L.is_neglit);letlhs,rhs,_=CCOpt.get_exn@@L.View.as_eqnlitinCC.mk_eqacclhsrhs)(CC.create~size:16())all_neginifCCList.is_emptysame_hd_litsthentrue(* no L-resolvent possible *)else(letreccheck_lit~ccrest=(* validity is achieved without using same_hd_lits literals *)letis_valid=List.exists(funlit->assert(L.is_poslit);matchlitwith|L.Equation(lhs,rhs,_)->CC.is_eqcclhsrhs|L.True->true|_->false)all_posinis_valid||(not(CCList.is_emptyrest)&&(letcongruent,rest=List.partition(funlhs->List.exists(funlhs'->CC.is_eqcclhslhs')for_congruence_testing)restin(* clause is not valid *)ifCCList.is_emptycongruentthenfalseelse((* validity is achieved using literals from same_hd_lits, let's
see what happens when they are removed as part of flat
L-resolvent computation*)letcc=List.fold_left(funacclhs->add_flat_resolvent~cc(T.argslhs))cccongruentincheck_lit~ccrest)))in(* check if all l-resolvents are valid in polynomial time *)letreccheck_l_resolventsothers=function|x::xs->letcc_with_lhs=add_flat_resolvent~cc:orig_cc(T.argsx)incheck_lit~cc:cc_with_lhs(others@xs)&&check_l_resolvents(x::others)xs|[]->trueincheck_l_resolvents[]same_hd_lits)incheck_resolventslit_idxorig_cl(split_partnerorig_lhsorig_signpartner)letget_validity_checker()=assert(!logic!=Unsupported);if!logic==EqFOthenresolvent_is_valid_eqelseresolvent_is_valid_neqletis_blockedcl=letvalidity_checker=get_validity_checker()inletblocked_lit_idx=CCArray.find_map_i(funidxlit->matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->letsym=T.head_exnlhsin(matchSymSignIdx.find_opt(sym,not(L.is_poslit))!ss_idxwith|Somepartners->if(C.ClauseSet.for_all(funpartner->C.equalclpartner||validity_checkeridxclpartner)partners)then(Someidx)elseNone|None->ifnot(ID.Set.memsym!ignored_symbols)thenSomeidxelseNone)|_->None)(C.litscl)inletans=CCOpt.is_someblocked_lit_idxinifansthen(Util.debugf~section3"@[%a@] is blocked on @[%a@] @."(funk->kC.ppclL.pp(C.litscl).(CCOpt.get_exnblocked_lit_idx));Util.debugf~section3"proof:@[%a@]@."(funk->kProof.S.pp_tstp(C.proofcl)););ans(* function that actually performs the blocked clause elimination *)letdo_eliminate_blocked_clauses()=letremoved_cnt=ref0in(* checks if each candidate stored in the task has valid L-resolvent.
if that is not the case, it returns the rest of candidates to be checked. *)letprocess_tasktask=letcl=task.clauseinletlit_idx=task.lit_idxinlethd_sym=T.head_exn@@CCOpt.get_exn@@L.View.get_lhs(C.litstask.clause).(lit_idx)inletvalidity_checker=get_validity_checker()inletrectask_is_blockeddeq=DEQ.is_emptydeq||(letpartner=DEQ.take_frontdeqinifC.equalclpartner||C.is_redundantpartner||validity_checkerlit_idxclpartnerthen(Util.debugf~section5"valid-res(@[%a@], @[%a@](%b))@."(funk->kC.ppclC.pppartner(C.is_redundantpartner));task_is_blockeddeq)else(Util.debugf~section5"blocks(@[%a@], @[%a@])@."(funk->kC.pppartnerC.ppcl);DEQ.push_frontdeqpartner;lock_clausepartnertask;false))inUtil.debugf~section3"working on @[%a@]|%d@."(funk->kC.pptask.clausetask.lit_idx);ifnot(C.is_emptytask.clause||C.is_redundanttask.clause||ID.Set.memhd_sym!ignored_symbols)then(Util.debugf~section3"checking blockedness"CCFun.id;(* let original_partners = CCDeque.to_list task.cands in *)matchtask_is_blockedtask.candswith|true->Util.debugf~section1"removed(%d): @[%a@]"(funk->ktask.lit_idxC.ppcl);(* Util.debugf ~section 1 "partners: @[%a@]" (fun k -> k (CCList.pp C.pp) original_partners); *)deregister_clausecl;remove_from_proof_statecl;incrremoved_cnt;|false->assert(not(TaskPriorityQueue.in_heaptask)))else(Util.debugf~section3"ignoring %b %b %b"(funk->k(C.is_emptytask.clause)(C.is_redundanttask.clause)(ID.Set.memhd_sym!ignored_symbols)););inletmoduleQ=TaskPriorityQueueinwhilenot(Q.is_emptytask_queue)doprocess_task(Q.remove_mintask_queue)done;Util.debugf~section2"bce removed %d clauses@."(funk->k!removed_cnt);!removed_cntletsteps=ref0(* driver that does that every k-th step of given-clause loop *)leteliminate_blocked_clauses()=steps:=(!steps+1)mod(Env.flex_getk_check_at);if!steps=0then(letoriginal_cls=Iter.to_list(Iter.append(Env.get_active())(Env.get_passive()))inleteliminated=do_eliminate_blocked_clauses()inifeliminated!=0then(Util.debugf~section2"original clause set:@.@[%a@]"(funk->k(CCList.ppC.pp)original_cls););)letreact_clause_adddedcl=add_clauseclletreact_clause_removedcl=deregister_clauseclletinitialize_regular()=letinit_clauses=C.ClauseSet.to_list(Env.ProofState.ActiveSet.clauses())@C.ClauseSet.to_list(Env.ProofState.PassiveSet.clauses())inbegintryUtil.debugf~section3"init_cl: @[%a@]@."(funk->k(CCList.ppC.pp)init_clauses);letinit_clause_num=List.lengthinit_clausesinCCFormat.printf"%% BCE start: %d@."init_clause_num;(* build the symbol index *)List.iterscan_cl_litsinit_clauses;Util.debugf~section1"logic has%sequalities"(funk->k(if!logic==EqFOthen" "else" no "));(* create tasks for each clause *)List.iter(funcl->CCArray.iteri(funlit_idx_->register_task~update_others:falselit_idxcl)(C.litscl))init_clauses;(* eliminate clauses *)ignore(do_eliminate_blocked_clauses());letclause_diff=init_clause_num-(Iter.length(Env.get_active())+Iter.length(Env.get_passive()))inCCFormat.printf"%% BCE eliminated: %d@."clause_diff;ifEnv.flex_getk_processing_kind=`InprocessingFullthen((* clauses begin their life when they are added to the passive set *)Signal.on_everyEnv.ProofState.PassiveSet.on_add_clausereact_clause_addded;(* clauses can be calculus-removed from the active set only in DISCOUNT loop *)Signal.on_everyEnv.ProofState.ActiveSet.on_remove_clausereact_clause_removed;(* Clauses are removed from the passive set when they are moved to active.
In this case clause can me modified or deemed redundant by forward
modification procedures. we react accordingly.*)Signal.on_everyEnv.on_forward_simplified(fun(c,new_state)->matchnew_statewith|Somec'->ifnot(C.equalcc')then(react_clause_removedc;react_clause_adddedc')|_->react_clause_removedc;(* c is redundant *));Env.add_clause_elimination_rule~priority:1"BCE"eliminate_blocked_clauses)elseifEnv.flex_getk_processing_kind=`InprocessingInitialthen(Env.add_is_trivialis_blocked;)else(raiseUnsupportedLogic)(* clear all data structures *)withUnsupportedLogic->Util.debugf~section2"logic is unsupported"CCFun.id;(* releasing possibly used memory *)ss_idx:=SymSignIdx.empty;clause_lock:=Util.Int_map.empty;task_store:=TaskStore.empty;TaskPriorityQueue.cleartask_queue;end;Signal.StopListeningletfixpoint_active=reffalseletbegin_fixpoint()=E.flex_addk_max_symbol_occ!_max_symbol_occ;letinit_clauses=C.ClauseSet.to_list(Env.ProofState.ActiveSet.clauses())@C.ClauseSet.to_list(Env.ProofState.PassiveSet.clauses())inbegintryfixpoint_active:=true;List.iterscan_cl_litsinit_clauses;List.iter(funcl->CCArray.iteri(funlit_idx_->register_task~update_others:falselit_idxcl)(C.litscl))init_clauses;(* eliminate clauses *)letnum_eliminated=do_eliminate_blocked_clauses()inUtil.debugf~section1"Step eliminates %d clauses"(funk->knum_eliminated);Signal.onEnv.ProofState.PassiveSet.on_add_clause(func->if!fixpoint_activethen(react_clause_adddedc;Signal.ContinueListening)elseSignal.StopListening);Signal.onEnv.ProofState.PassiveSet.on_remove_clause(func->if!fixpoint_activethen(react_clause_removedc;Signal.ContinueListening)elseSignal.StopListening);withUnsupportedLogic->Util.debugf~section2"logic is unsupported"CCFun.id;(* releasing possibly used memory *)ss_idx:=SymSignIdx.empty;clause_lock:=Util.Int_map.empty;task_store:=TaskStore.empty;TaskPriorityQueue.cleartask_queue;fixpoint_active:=falseendletfixpoint_step()=letnum_eliminated=do_eliminate_blocked_clauses()inUtil.debugf~section1"Step eliminates %d clauses"(funk->knum_eliminated);num_eliminated!=0letend_fixpoint()=ss_idx:=SymSignIdx.empty;clause_lock:=Util.Int_map.empty;task_store:=TaskStore.empty;TaskPriorityQueue.cleartask_queue;fixpoint_active:=falseletregister()=Signal.onEnv.on_startinitialize_regularletsetup()=ifEnv.flex_getk_enabledthen(ifnot(Env.flex_getAvatar.k_avatar_enabled)then(register())else(CCFormat.printf"AVATAR is not yet compatible with BCE@."))endletextension=letactionenv=letmoduleE=(valenv:Env.S)inletmoduleBCE=Make(E)inE.flex_addk_enabled!_enabled;E.flex_addk_max_symbol_occ!_max_symbol_occ;E.flex_addk_check_at!_check_at;E.flex_addk_processing_kind!_processing_kind;BCE.setup()in{Extensions.defaultwithExtensions.name="bce";prio=80;env_actions=[action];}let()=Options.add_opts["--bce",Arg.Bool((:=)_enabled)," scan clauses for AC definitions";"--bce-processing-kind",Arg.Symbol(["preprocessing";"inprocessing-full";"inprocessing-initial"],(function|"preprocessing"->_processing_kind:=`PreprocessingOnly|"inprocessing-full"->_processing_kind:=`InprocessingFull|"inprocessing-initial"->_processing_kind:=`InprocessingInitial|_->assertfalse))," scan clauses for AC definitions";"--bce-check-every",Arg.Int((:=)_check_at)," check BCE every n steps of saturation algorithm";"--bce-max-symbol-occurences",Arg.Int((:=)_max_symbol_occ)," limit a given symbol to n occurences only";]