1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159(* 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()letk_only_original_gates=Flex_state.create_key()letk_only_non_conjecture_gates=Flex_state.create_key()letk_check_gates_semantically=Flex_state.create_key()letk_non_singular_pe=Flex_state.create_key()letk_measure_fun=Flex_state.create_key()letk_relax_val=Flex_state.create_key()letk_prefer_spe=Flex_state.create_key()letk_fp_mode=Flex_state.create_key()let_enabled=reffalselet_check_gates=reftruelet_inprocessing=reffalselet_check_at=ref10let_max_resolvents=ref(-1)let_non_singular_pe=reffalselet_relax_val=ref0let_prefer_spe=reffalselet_measure_name=ref"relaxed"let_original_gates_only=reffalselet_only_non_conj_gates=reffalselet_check_semantically=reffalseletsection=Util.Section.make~parent:Const.section"pred-elim"moduleA=Libzipperposition_avatarmoduleOrigEnv=EnvmoduletypeS=sigmoduleEnv:Env.S(** {6 Registration} *)valsetup:?in_fp_mode:bool->unit->unitvalbegin_fixpoint:unit->unitvalfixpoint_step:unit->boolvalend_fixpoint:unit->unitendletregister_parametersenv=letmoduleE=(valenv:Env.S)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;E.flex_addk_only_original_gates!_original_gates_only;E.flex_addk_only_non_conjecture_gates!_only_non_conj_gates;E.flex_addk_check_gates_semantically!_check_semantically;E.flex_addk_non_singular_pe!_non_singular_pe;E.flex_addk_relax_val!_relax_val;E.flex_addk_prefer_spe!_prefer_spemoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleC=Env.CmoduleCS=C.ClauseSetmoduleL=LiteralmoduleT=TermmoduleSAT=Sat_solver.Make()typelogic=|NEqFO(* nonequational FO *)|EqFO(* equational FO *)|NonAppVarHo(* higher-order logic, but at the top level
each literal has only (fully applied)
function symbols *)|Unsupported(* HO or FO with theories *)letlog_to_int=[(NEqFO,0);(EqFO,1);(NonAppVarHo,2);(Unsupported,3)]letlog_compare(l1:logic)(l2:logic)=compare(List.assocl1log_to_int)(List.assocl2log_to_int)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;mutabledeleted:bool;}letcardt=CS.cardinalt.pos_cls+CS.cardinalt.neg_cls+(matcht.is_gatewith|None->0|Some(p,n)->List.lengthp+List.lengthn)+CS.cardinalt.offending_clsletpp_taskouttask=letoriginal=ID.payload_pred~f:(functionID.Attr_cnf_def->true|_->false)task.syminCCFormat.fprintfout"%a(%b) {@. +: @[%a@];@. -:@[%a@];@. ?:@[%a@]@. g:@[%a@]@. v^2:@[%g@]; |l|:@[%d@]; |%a|:@[%d@]; h_idx: @[%d@] @.}@."ID.pptask.symoriginal(CS.ppC.pp)task.pos_cls(CS.ppC.pp)task.neg_cls(CS.ppC.pp)task.offending_cls(CCOpt.pp(CCPair.pp(CCList.ppC.pp)(CCList.ppC.pp)))task.is_gatetask.sq_var_weighttask.num_litsID.pptask.sym(cardtask)task.heap_idxletcopy_taskt=letc={sym=t.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;num_lits=0;last_check=None;heap_idx=-1;deleted=false;}inc.pos_cls<-t.pos_cls;c.neg_cls<-t.neg_cls;c.offending_cls<-t.offending_cls;c.possible_gates<-t.possible_gates;c.sq_var_weight<-t.sq_var_weight;c.num_lits<-t.num_lits;c.last_check<-t.last_check;c.heap_idx<-t.heap_idx;cmoduleTaskWrapper=structtypet=pred_elim_infoletidxtask=task.heap_idxletset_idxtaskidx=task.heap_idx<-idxletltab=assert((nota.deleted)||(notb.deleted));ifnota.deleted&¬b.deletedthen(letopenCCOrdin(compare(carda)(cardb)<?>(compare,(not(CCOpt.is_somea.is_gate)),(not(CCOpt.is_someb.is_gate)))<?>(compare,a.num_lits,b.num_lits)<?>(compare,a.sq_var_weight,b.sq_var_weight)<?>(ID.compare,a.sym,b.sym))<0)else(a.deleted)endmoduleTaskSet=structincludeMyHeap.Make(TaskWrapper)(* a trick to remove an element in O(log (n)):
make it the smallest, remove the smallest -- ugly hack*)letremove_elhel=assert(in_heapel);el.deleted<-true;(* implicitly makes it the smallest *)decreasehel;letmin_el=remove_minhinassert(ID.equalmin_el.symel.sym);el.deleted<-false(* clear it for the next insertion *)letupdateh~old~new_=assert(ID.equalold.symnew_.sym);assert(old.heap_idx==new_.heap_idx);assert(in_heapnew_&&in_heapold);ifTaskWrapper.ltnew_oldthen(decreasehnew_)elseifTaskWrapper.ltoldnew_then(increasehnew_)else()endletk_measure_fun=Flex_state.create_key()let_task_queue=TaskSet.create()(* 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)letlogic_to_str=function|EqFO->"eq"|NEqFO->"neq"|NonAppVarHo->"non_appvar"|Unsupported->"unsupported"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;deleted=false;}let_pred_sym_idx=refID.Map.emptyletget_sym_signlit=matchlitwith|L.Equation(lhs,rhs,_)->letsign=L.is_positivoidlitinletis_poly=not(Type.VarSet.is_empty(T.ty_varslhs))||not(Type.VarSet.is_empty(T.ty_varsrhs))inifnotis_poly&¬(Type.is_fun(T.tylhs))then(ifType.is_prop(T.tylhs)then(ifnot(CCOpt.is_some(T.headlhs))then(raiseUnsupportedLogic;);ifnot(Term.is_fo_termlhs)then(refine_logicNonAppVarHo;);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(ifT.is_fo_termlhs&&T.is_fo_termrhsthenrefine_logicEqFOelserefine_logicNonAppVarHo;None))else(_logic:=Unsupported;Util.debugf~section1"unsupported because of @[%a@]@."(funk->kL.pplit);raiseUnsupportedLogic)|_->Noneletremove_symbolentry=_pred_sym_idx:=ID.Map.removeentry.sym!_pred_sym_idx;_ignored_symbols:=ID.Set.addentry.sym!_ignored_symbols;ifTaskSet.in_heapentrythen(TaskSet.remove_el_task_queueentry)letcalc_sq_varcl=letn=List.length(Literals.vars(C.litscl))infloat_of_int(n*n)letcalc_new_statsresolvents=List.fold_left(fun(acc_sq,acc_lit_num)cl->acc_sq+.calc_sq_varcl,acc_lit_num+C.lengthcl)(0.0,0)resolventsletcalc_num_clstask=CS.cardinaltask.pos_cls+CS.cardinaltask.neg_cls+(matchtask.is_gatewith|None->0|Some(ps,ns)->List.lengthps+List.lengthns)+CS.cardinaltask.offending_clsletkk_measurerelaxtaskresolvents=letnew_mu,new_lit_num=calc_new_statsresolventsintask.num_lits>=new_lit_num&&task.sq_var_weight>=new_muletrelaxed_measurerelaxtaskresolvents=let(new_mu,new_lit_num),new_cl_num=calc_new_statsresolvents,List.lengthresolventsintask.num_lits>new_lit_num-relax||calc_num_clstask>new_cl_num-relax||task.sq_var_weight>new_muletconservative_measurerelaxtaskresolvents=let(_,new_lit_num)=calc_new_statsresolventsinCS.cardinal(CS.filterC.is_unit_clausetask.pos_cls)>=2||CS.cardinal(CS.filterC.is_unit_clausetask.neg_cls)>=2||task.num_lits>new_lit_num-relaxlet_measure=refrelaxed_measureletshould_scheduletask=leteligible_for_non_singular_petask=Env.flex_getk_non_singular_pe&&(matchtask.is_gatewith|Some(pos,neg)->letlimit=ifEnv.flex_getk_max_resolvents<0thenmax_intelseEnv.flex_getk_max_resolventsinletpos_num,neg_num=List.lengthpos,List.lengthneginletmax_resolvents=(CS.fold(funclnum_res->ifnum_res==limitthenlimit(*shortcut *)else(letnew_res=CCArray.fold(funacclit->matchget_sym_signlitwith|Some(sym,sign)whenID.equaltask.symsym->acc*(ifsignthenneg_numelsepos_num)|_->acc)1(C.litscl)inifnew_res+num_res<limitthennew_res+num_reselselimit))task.offending_cls0)inifmax_resolvents<limitthentrueelse(remove_symboltask;false)|None->false)inCS.is_emptytask.offending_cls||eligible_for_non_singular_petaskletpossibly_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_resolventsthenremove_symbolentry)letscan_cl_lits?(handle_gates=true)cl=if!_logic==UnsupportedthenraiseUnsupportedLogic;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)oldinletold_=copy_taskentryinbeginmatchactionwith|`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.in_heapentry&&(not(should_scheduleentry))then(TaskSet.remove_el_task_queueentry;)|`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;ifTaskSet.in_heapold_&&TaskSet.in_heapentrythen(TaskSet.update_task_queue~old:old_~new_:entry);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;intryletpos,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_varsclwithUnsupportedLogic->refine_logicUnsupported;TaskSet.clear_task_queueletreact_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=should_scheduletask&¬(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;ifEnv.flex_getk_non_singular_pe&&TaskSet.in_heaptask&¬(CS.is_emptytask.offending_cls)then(TaskSet.remove_el_task_queuetask);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->letold=copy_tasktaskintask.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.in_heaptask)&&should_retrytaskthen(Util.debugf~section10"retrying @[%a@]@."(funk->kpp_tasktask);TaskSet.insert_task_queuetask;);ifTaskSet.in_heapold&&TaskSet.in_heaptaskthen(TaskSet.update_task_queue~new_:task~old;);CCOpt.return_if(not(ID.Set.memtask.sym!_ignored_symbols))task|None->None(*probably the symbol became ignored*))!_pred_sym_idx;|_->())(C.litscl));Signal.ContinueListening)elseSignal.StopListeningletreplace_clausestaskclauses=Util.debugf~section2"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~section2"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||Env.flex_getk_non_singular_pe);remove(CS.to_itertask.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_idxletis_tautoc=Literals.is_trivial(C.litsc)||Trail.is_trivial(C.trailc)letfind_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))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=lethandle_distinct_varsxssc_xyssc_y=letis_uniquexs=List.for_all(Term.is_var)xs&&CCList.length(CCList.sort_uniq~cmp:T.comparexs)==CCList.lengthxsinletmk_substvarssc_varstermssc_terms=List.fold_left(funsubst(v,t)->Subst.FO.bind'subst(T.as_var_exnv,sc_vars)(t,sc_terms))Subst.empty(CCList.combinevarsterms)inifis_uniquexsthenSome(mk_substxssc_xyssc_y)elseifis_uniqueysthenSome(mk_substyssc_yxssc_x)elseNoneinletpos_sc,neg_sc=0,1inletrenaming=Subst.Renaming.create()inletpos_idx,pos_term=find_lit_by_symsymtruepos_clinletneg_idx,neg_term=find_lit_by_symsymfalseneg_clinletpos_args,neg_args=CCPair.map_sameT.args(pos_term,neg_term)inletproofsubstrenaming=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=matchhandle_distinct_varspos_argspos_scneg_argsneg_scwith|Somesubst->letpos_lits=Literals.apply_substrenamingsubst(C.litspos_cl,pos_sc)inletneg_lits=Literals.apply_substrenamingsubst(C.litsneg_cl,neg_sc)inletlits=(CCArray.except_idxpos_litspos_idx)@(CCArray.except_idxneg_litsneg_idx)inC.create~penalty:(max(C.penaltypos_cl)(C.penaltyneg_cl))~trail:(C.trail_l[pos_cl;neg_cl])lits(proofsubstrenaming)|None->letsubst=Subst.emptyinletpos_cl'=C.apply_subst~renaming(pos_cl,pos_sc)substinletneg_cl'=C.apply_subst~renaming(neg_cl,neg_sc)substinletapplyt=Subst.FO.applyrenamingsubsttinletlits=(List.map(fun(p,n)->L.mk_neq(apply(p,pos_sc))(apply(n,neg_sc)))(List.combinepos_argsneg_args))@(CCArray.except_idx(C.litspos_cl')pos_idx)@(CCArray.except_idx(C.litsneg_cl')neg_idx)inC.create~penalty:(max(C.penaltypos_cl')(C.penaltyneg_cl'))~trail:(C.trail_l[pos_cl';neg_cl'])lits(proofsubstrenaming)inCCOpt.return_if(not(is_tautoc))cletcheck_if_gatetask=letsym=task.syminletgates_l=CS.to_listtask.possible_gatesinletfilter_gates?(sign=None)~lit_num_filtergates_l=List.filter(funcl->not(is_tautocl)&&lit_num_filter(Array.length(C.litscl))&&(match(CCArray.find_idx(funlit->matchget_sym_signlitwith|Some(sym',sign')->ID.equalsymsym'&&((CCOpt.is_nonesign)||CCOpt.get_exnsign==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))(CCList.fast_sort(funclcl'->compare(C.lengthcl)(C.lengthcl'))gates_l)inletfind_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_clausesinletdiff_vars_cntcl=List.length@@Literals.vars(C.litscl)inletcheck_and()=letpos_gates=filter_gates~sign:(Sometrue)~lit_num_filter:(funn->n>2)gates_linletneg_gates=filter_gates~sign:(Somefalse)~lit_num_filter:((=)2)gates_linmatchfind_and_orneg_gatespos_gateswith|Some(pos_cl,neg_cls)when(diff_vars_cntpos_cl<=3)->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|_->falseinletcheck_or()=letpos_gates=filter_gates~sign:(Sometrue)~lit_num_filter:((=)2)gates_linletneg_gates=filter_gates~sign:(Somefalse)~lit_num_filter:(funn->n>2)gates_lin(* checking for or will also check for equivalences p(x) <-> q(x) *)matchfind_and_orpos_gatesneg_gateswith|Some(neg_cl,pos_cls)when(diff_vars_cntneg_cl<=3)->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|_->falsein(* not yet implemented *)letcheck_ite()=falseinletcheck_sat()=SAT.clear();letorig_sc,new_sc=0,1inletrename_clause~name_litc=letlits=C.litscinCCArray.find_map_i(funilit->matchlitwith|L.Equation(lhs,_,_)whenL.is_predicate_litlit->begintryletsubst=Unif.FO.variant(lhs,new_sc)(name_lit,orig_sc)inletlits=Literals.apply_substSubst.Renaming.nonesubst((CCArray.of_list(CCArray.except_idxlitsi)),new_sc)inSome(i,lits,c)withUnif.Fail->Noneend|_->None)litsinletsplit_clausesused_cls=letpos_cls,neg_cls=CCList.partition(funcl->CCArray.exists(funlit->matchget_sym_signlitwith|Some(id,sign)->ID.equalidtask.sym&&sign|_->false)(C.litscl))used_clsinifList.exists(funpos_cl->List.exists(funneg_cl->CCOpt.is_some@@neq_resolver~sym:task.sym~pos_cl~neg_cl)neg_cls)pos_clsthenNoneelseSome(pos_cls,neg_cls)inletfind_definition_setcls=List.iter(fun(i,lits,c)->ifnot(is_tautoc)then(CCList.filter_mapBBox.inject_lit(CCArray.to_listlits)|>SAT.add_clause~proof:(C.proof_stepc)))cls;(matchSAT.check~full:true()with|Sat_solver.Unsat_->letproof=Proof.S.step(SAT.get_proof())inletparents=List.map(funp->Proof.S.step@@Proof.Parent.proofp)(Proof.Step.parentsproof)inUtil.debugf~section5"SAT prover found unsat set: %d@."(funk->k(CCList.lengthparents));letused_cls=CCList.filter_map(fun(_,_,cl)->CCOpt.return_if(CCList.mem~eq:Proof.Step.equal(C.proof_stepcl)parents)cl)clsinUtil.debugf~section5"used clauses: @[%a@]@."(funk->k(CCList.ppC.pp)used_cls);split_clausesused_cls|_->None)inletis_def=function|(Literal.Equation(lhs,_,_)aslit)whenLiteral.is_predicate_litlit->CCOpt.is_some(Term.headlhs)&&List.for_allT.is_var(T.argslhs)|_->falseinmatchgates_lwith|x::xs->(* we will standardize all clauses by the first name literal in x *)leti,name_lit=CCOpt.get_exn(CCArray.find_map_i(funilit->matchlitwith|L.Equation(lhs,rhs,_)whenL.is_predicate_litlit->ifID.equaltask.sym(T.head_exnlhs)thenSome(i,lhs)elseNone|_->None)(C.litsx))inletcls=(i,CCArray.of_list@@CCArray.except_idx(C.litsx)i,x)::(CCList.filter_map(rename_clause~name_lit)xs)in(matchfind_definition_setclswith|Some(core_pos,core_neg)->letto_remove=CS.of_list(core_pos@core_neg)inifCS.cardinalto_remove!=2||(* if there are two clauses then they must be of the form p(X,Y) <-> q(X,Y) *)CS.for_all(func->C.lengthc==2&&CCArray.for_allis_def(C.litsc))to_removethen(Util.debugf~section3"semantic pos def: @[%a@]@."(funk->k(CCList.ppC.pp)core_pos);Util.debugf~section3"semantic neg def: @[%a@]@."(funk->k(CCList.ppC.pp)core_neg);task.neg_cls<-CS.difftask.neg_clsto_remove;task.pos_cls<-CS.difftask.pos_clsto_remove;task.is_gate<-Some(core_pos,core_neg);true)elsefalse|_->false)|_->falseinifEnv.flex_getk_check_gates&&((not(Env.flex_getk_only_original_gates))||not@@ID.payload_pred~f:(functionID.Attr_cnf_def->true|_->false)task.sym)&&((not(Env.flex_getk_only_non_conjecture_gates))||not@@Signature.sym_in_conjtask.sym(Env.signature()))then(ifEnv.flex_getk_check_gates_semanticallythenignore(check_sat())elseignore(check_and()||check_or()||check_ite()))letschedule_tasks()=ID.Map.iter(fun_task->check_if_gatetask;ifshould_scheduletaskthen(Util.debugf~section5"inserting: @[%a@]"(funk->kpp_tasktask);TaskSet.insert_task_queuetask))!_pred_sym_idxletget_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)posletcalc_non_singular_resolvents~sym~pos~neg~offending=letfind_lit_by_sym_optsymsigncl=tryCCOpt.return(find_lit_by_symsymsigncl)with_->Noneinletrecauxhas_predno_pred=(matchhas_predwith|[]->no_pred|cl::cls->(* for the first occurrence of the symbol p in cl,
we compute all possible replacements w.r.t. gate clauses.
If there are more symbols left, we continue with all the replacements *)letnew_cls=(matchfind_lit_by_sym_optsymtrueclwith|Some_->CCList.filter_map(funneg_cl->get_resolver()~sym~pos_cl:cl~neg_cl)neg|None->(matchfind_lit_by_sym_optsymfalseclwith|Some_->CCList.filter_map(funpos_cl->get_resolver()~sym~pos_cl~neg_cl:cl)pos|None->invalid_arg""))inlethas_litcl=let(<+>)=CCOpt.(<+>)inCCOpt.is_some(find_lit_by_sym_optsymtruecl<+>find_lit_by_sym_optsymfalsecl)inlethas_pred',no_pred'=List.partitionhas_litnew_clsinaux(has_pred'@cls)(no_pred'@no_pred))inaux(CS.to_listoffending)[]letmeasure_decreases()=Env.flex_getk_measure_funletdo_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||Env.flex_getk_non_singular_pe);letpos_cls,neg_cls=CCPair.map_sameCS.to_list(task.pos_cls,task.neg_cls)inletsym=task.syminletresolvents=matchtask.is_gatewith|Some(pos_gates,neg_gates)->ifEnv.flex_getk_prefer_spe&&CS.is_emptytask.offending_clsthen(letresults=(calc_resolvents~sym~pos:pos_gates~neg:neg_cls)@(calc_resolvents~sym~pos:pos_cls~neg:neg_gates)@(calc_resolvents~sym~pos:pos_cls~neg:neg_cls)inifmeasure_decreases()(Env.flex_getk_relax_val)taskresultsthen(results)else((calc_resolvents~sym~pos:pos_gates~neg:neg_cls)@(calc_resolvents~sym~pos:pos_cls~neg:neg_gates)))else((calc_non_singular_resolvents~sym~pos:pos_gates~neg:neg_gates~offending:task.offending_cls)@(calc_resolvents~sym~pos:pos_gates~neg:neg_cls)@(calc_resolvents~sym~pos:pos_cls~neg:neg_gates))|None->assert(CS.is_emptytask.offending_cls);calc_resolvents~sym~pos:pos_cls~neg:neg_clsinifmeasure_decreases()(Env.flex_getk_relax_val)taskresolventsthen(Util.debugf~section1"task info: @[%a@]"(funk->kpp_tasktask);updated_removed(calc_num_clstask-List.lengthresolvents);replace_clausestaskresolvents;)else(task.last_check<-Some(task.sq_var_weight,task.num_lits))inletmoduleS=TaskSetinwhilenot(S.is_empty_task_queue)dolettask=S.remove_min_task_queueinifnot(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;CCFormat.printf"logic: %s@."(logic_to_str!_logic);if!_logic==Unsupportedthen(raiseUnsupportedLogic);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.Ctx.lost_completeness (); *)Env.add_clause_elimination_rule~priority:2"pred_elim"do_predicate_elimination)elseifnot@@Env.flex_getk_fp_modethenraiseUnsupportedLogicwithUnsupportedLogic->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;letenv=(moduleE:OrigEnv.S)inregister_parametersenv;(* has to be called after register parameters as
measure functions are not visible outside the module *)Env.flex_addk_measure_fun(match!_measure_namewith|"kk"->kk_measure|"relaxed"->relaxed_measure|"conservative"->conservative_measure|_->invalid_arg"measure function not found");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())inCCFormat.printf"%% PE start fixpoint: @[%a@]@."(CCOpt.ppCCInt.pp)ans;Util.debugf~section2"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()=CCFormat.printf"relax val: %d@."(Env.flex_getk_relax_val);letans=do_pred_elim()inUtil.debugf~section1"Clause number changed for %a"(funk->k(CCOpt.ppCCInt.pp)ans);ifCCOpt.is_someansthen(CCFormat.printf"%% PE fixpoint: %d@."(CCOpt.get_exnans));CCOpt.is_someansletend_fixpoint()=_logic:=Unsupported;_pred_sym_idx:=ID.Map.empty;fixpoint_active:=falseletsetup?(in_fp_mode=false)()=Env.flex_addk_fp_modein_fp_mode;Env.flex_addk_measure_fun(match!_measure_namewith|"kk"->kk_measure|"relaxed"->relaxed_measure|"conservative"->conservative_measure|_->invalid_arg"measure function not found");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)inregister_parametersenv;letmodulePredElim=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;E.flex_addk_non_singular_pe!_non_singular_pe;E.flex_addk_relax_val!_relax_val;PredElim.setup()in{Extensions.defaultwithExtensions.name="pred_elim";prio=50;env_actions=[action];}let()=Options.add_opts["--pred-elim",Arg.Bool((:=)_enabled)," enable predicate elimination";"--pred-elim-relax-value",Arg.Int((:=)_relax_val)," value of relax constant for our new measure";"--pred-elim-measure-fun",Arg.Symbol(["kk";"relaxed";"conservative"],((:=)_measure_name))," use either standard Korovin-Khasidashvili measure or our relaxed measure for measuring the proof state size";"--pred-elim-check-gates",Arg.Bool((:=)_check_gates)," enable recognition of gate clauses";"--pred-elim-only-original-gates",Arg.Bool((:=)_original_gates_only)," recognize only gates that are not introduced by Zipperposition";"--pred-elim-check-gates-semantically",Arg.Bool((:=)_check_semantically)," recognize gates semantically, as described in our SAT techniques paper";"--pred-elin-only-non-conjecture-gates",Arg.Bool((:=)_only_non_conj_gates)," recognize only non-conjecture symbols as possible gates";"--pred-elim-prefer-spe",Arg.Bool((:=)_prefer_spe)," try DPE only when SPE fails";"--pred-elim-relax-value",Arg.Int((:=)_relax_val)," value of relax constant for our new measure";"--pred-elim-measure-fun",Arg.Symbol(["kk";"relaxed";"conservative"],((:=)_measure_name))," use either standard Korovin-Khasidashvili measure or our relaxed measure for measuring the proof state size";"--pred-elim-non-singular",Arg.Bool((:=)_non_singular_pe)," enable PE when gate is recognized and there are multiple occurrences of a symbol";"--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";]