123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Equational literals} *)moduleT=TermmoduleS=SubstmodulePB=Position.BuildmoduleP=PositionmoduleUS=Unif_substmoduleVS=T.VarSettypeterm=Term.ttypet=|True|False|Equationofterm*term*booltypelit=tletequall1l2=matchl1,l2with|Equation(l1,r1,sign1),Equation(l2,r2,sign2)->sign1=sign2&&l1==l2&&r1==r2|True,True|False,False->true|Equation_,_|True,_|False,_->falseletequal_coml1l2=matchl1,l2with|Equation(l1,r1,sign1),Equation(l2,r2,sign2)->sign1=sign2&&((T.equall1l2&&T.equalr1r2)||(T.equall1r2&&T.equalr1l2))|True,True|False,False->true|_->equall1l2(* regular comparison *)letno_prop_invariant=function|Equation(lhs,rhs,sign)->ifT.is_true_or_falserhs&¬signthen(CCFormat.printf"literal wrongly encoded: @[%a@] @[%a@] @[%b@]@."T.pplhsT.pprhssign;false)elsetrue|_->trueletcomparel1l2=(* assert(List.for_all no_prop_invariant [l1;l2]); *)let__to_int=function|False->0|True->1|Equation_->2inmatchl1,l2with|Equation(l1,r1,sign1),Equation(l2,r2,sign2)->letc=T.comparel1l2inifc<>0thencelseletc=T.comparer1r2inifc<>0thencelsePervasives.comparesign1sign2|True,True|False,False->0|_,_->__to_intl1-__to_intl2letfoldfacclit=matchlitwith|Equation(l,r,_)->f(faccl)r|True|False->accletfor_allflit=fold(funbt->b&&ft)truelitlethashlit=matchlitwith|Equation(l,r,sign)->Hash.combine430(Hash.boolsign)(T.hashl)(T.hashr)|True->40|False->50let[@inline]is_predicate_lit=function|Equation(_,rhs,true)->T.is_true_or_falserhs|_->falseletweightlit=fold(funacct->acc+T.sizet)0litletho_weight=fold(funacct->acc+T.ho_weightt)0letheuristic_weightweight=function|Equation(l,_,_)aslitwhenis_predicate_litlit->weightl|Equation(l,r,_)->weightl+weightr|True|False->0letdepthlit=fold(funacct->maxacc(T.deptht))0litmoduleSet=CCSet.Make(structtypet=litletcompare=compareend)letis_positivoid=function|Equation(l,r,sign)->sign&&(not@@T.equalrT.false_)|False->false|_->trueleteqn_sign=function|Equation(_,_,sign)->sign|False->false|_->true(* specific: for the term comparison *)letpolarity=function|Equation(_,_,s)->s|l->is_positivoidlletis_negativoidlit=not(is_positivoidlit)letis_eqn=function|Equation_->true|_->falseletis_eqlit=is_eqnlit&&is_positivoidlitletis_neqlit=is_eqnlit&&is_negativoidlitletis_app_var_eq=function|Equation(l,r,_)->T.is_app_varl&&T.is_app_varr|_->falseletis_prop=function|True|False->true|_->falseletis_type_pred=function|Equation(lhs,_,_)aslwhenis_predicate_litl->beginmatchTerm.viewlhswith|App(f,[x])->T.is_varx&&T.is_constf|_->falseend|_->falseletis_typex_pred=function|Equation(lhs,rhs,_)aslwhenis_predicate_litl->beginmatchTerm.viewlhswith|App(f,xs)whennot(CCList.is_emptyxs)->T.is_constf&&List.for_allT.is_varxs|_->falseend|_->falseletty_error_ab=letmsg=CCFormat.sprintf"@[<2>Literal: incompatible types in equational lit@ for `@[%a : %a@]`@ and `@[%a : %a@]`@]"T.TPTP.ppaType.pp(T.tya)T.TPTP.ppbType.pp(T.tyb)inraise(Type.ApplyErrormsg)(* primary constructor for equations and predicates *)letrecmk_litabsign=ifnot(Type.equal(T.tya)(T.tyb))thenty_error_ab;(* Maybe the sign will flip, so we have to beta reduce. *)matchT.viewa,T.viewbwith|T.AppBuiltin(Builtin.True,[]),T.AppBuiltin(Builtin.False,[])->ifsignthenFalseelseTrue|T.AppBuiltin(Builtin.False,[]),T.AppBuiltin(Builtin.True,[])->ifsignthenFalseelseTrue|T.AppBuiltin(Builtin.True,[]),T.AppBuiltin(Builtin.True,[])->ifsignthenTrueelseFalse|T.AppBuiltin(Builtin.False,[]),T.AppBuiltin(Builtin.False,[])->ifsignthenTrueelseFalse|T.AppBuiltin(Builtin.True,[]),_->letlhs,rhs=b,ifsignthenT.true_elseT.false_inEquation(lhs,rhs,true)|_,T.AppBuiltin(Builtin.True,[])->letlhs,rhs=a,ifsignthenT.true_elseT.false_inEquation(lhs,rhs,true)|T.AppBuiltin(Builtin.False,[]),_->letlhs,rhs=b,ifsignthenT.false_elseT.true_inEquation(lhs,rhs,true)|_,T.AppBuiltin(Builtin.False,[])->letlhs,rhs=a,ifsignthenT.false_elseT.true_inEquation(lhs,rhs,true)|_->Equation(a,b,sign)andmk_proppsign=matchT.viewpwith|T.AppBuiltin(Builtin.True,[])->ifsignthenTrueelseFalse|T.AppBuiltin(Builtin.False,[])->ifsignthenFalseelseTrue|T.AppBuiltin(Builtin.Not,[p'])->mk_propp'(notsign)|T.AppBuiltin(Builtin.Eq,[a;b])->mk_litabsign|T.AppBuiltin(Builtin.Neq,[a;b])->mk_litab(notsign)|_->ifnot(Type.equal(T.typ)Type.prop)thenty_error_pT.true_;mk_litpT.true_signletmk_eqab=mk_litabtrueletmk_neqab=mk_litabfalseletmk_truep=mk_propptrueletmk_falsep=mk_proppfalseletmk_tauto=Trueletmk_absurd=Falseletmk_constraintlr=mk_neqlrmoduleSeq=structlettermslitk=matchlitwith|Equation(l,r,_)->kl;kr|True|False->()letvarslit=Iter.flat_mapT.Seq.vars(termslit)letsymbols?(include_types=false)lit=Iter.flat_map(T.Seq.symbols~include_types)(termslit)endletsymbols?(include_types=false)lit=Seq.symbols~include_typeslit|>ID.Set.of_iter(** Unification-like operation on components of a literal. *)moduleUnifOp=structtype'substop={term:subst:'subst->termScoped.t->termScoped.t->'substIter.t;}end(* match {x1,y1} in scope 1, with {x2,y2} with scope2 *)letunif4op~substx1y1sc1x2y2sc2k=op~subst(Scoped.makex1sc1)(Scoped.makex2sc2)(funsubst->op~subst(Scoped.makey1sc1)(Scoped.makey2sc2)k);op~subst(Scoped.makey1sc1)(Scoped.makex2sc2)(funsubst->op~subst(Scoped.makex1sc1)(Scoped.makey2sc2)k);()(* generic unification structure *)letunif_litsop~subst(lit1,sc1)(lit2,sc2)k=letopenUnifOpinmatchlit1,lit2with|True,True|False,False->k(subst,[])|Equation(l1,r1,sign1),Equation(l2,r2,sign2)whensign1=sign2->unif4op.term~substl1r1sc1l2r2sc2(funs->k(s,[]))|_,_->()letvariant?(subst=S.empty)lit1lit2k=letop=UnifOp.({term=(fun~substt1t2k->tryk(Unif.FO.variant~substt1t2)withUnif.Fail->());})inunif_litsop~substlit1lit2(fun(subst,tags)->ifSubst.is_renamingsubstthenk(subst,tags))letare_variantlit1lit2=not(Iter.is_empty(variant(Scoped.makelit10)(Scoped.makelit21)))letmatching?(subst=Subst.empty)~pattern:lit1lit2k=letop=UnifOp.({term=(fun~substt1t2k->tryk(Unif.FO.matching_adapt_scope~subst~pattern:t1t2)withUnif.Fail->());})inunif_litsop~substlit1lit2k(* find substitutions such that subst(l1=r1) implies l2=r2 *)let_eq_subsumes~substl1r1sc1l2r2sc2k=(* make l2 and r2 equal using l1 = r2 (possibly several times) *)letrecequate_terms~substl2r2k=(* try to make the terms themselves equal *)equate_root~substl2r2k;(* decompose *)matchT.viewl2,T.viewr2with|_whenT.equall2r2->ksubst|T.App(f,ss),T.App(g,ts)whenList.lengthss=List.lengthts->(* Don't rewrite heads because it can cause incompletness, e.g. by
subsuming ho_complete_eq inferences. *)ifT.equalfgthenequate_lists~substsstskelse()|_->()andequate_lists~substl2sr2sk=matchl2s,r2swith|[],[]->ksubst|[],_|_,[]->()|l2::l2s',r2::r2s'->equate_terms~substl2r2(funsubst->equate_lists~substl2s'r2s'k)(* make l2=r2 by a direct application of l1=r1, if possible. This can
enrich [subst] *)andequate_root~substl2r2k=begintryletsubst=Unif.FO.matching_adapt_scope~subst~pattern:(Scoped.makel1sc1)(Scoped.makel2sc2)inletsubst=Unif.FO.matching_adapt_scope~subst~pattern:(Scoped.maker1sc1)(Scoped.maker2sc2)in(* CCFormat.printf "%a = %a;\n%a = %a;\n%a.\n" T.pp l1 T.pp l2 T.pp r1 T.pp r2 Subst.pp subst; *)ksubstwithUnif.Fail->(* CCFormat.printf "FAILED: %a = %a;\n%a = %a;\n%a.\n" T.pp l1 T.pp l2 T.pp r1 T.pp r2 Subst.pp subst; *)()end;begintryletsubst=Unif.FO.matching_adapt_scope~subst~pattern:(Scoped.makel1sc1)(Scoped.maker2sc2)inletsubst=Unif.FO.matching_adapt_scope~subst~pattern:(Scoped.maker1sc1)(Scoped.makel2sc2)inksubstwithUnif.Fail->(* CCFormat.printf "FAILED: %a = %a;\n%a = %a;\n%a.\n" T.pp l1 T.pp l2 T.pp r1 T.pp r2 Subst.pp subst; *)()end;()inequate_terms~substl2r2kletsubsumes?(subst=Subst.empty)(lit1,sc1)(lit2,sc2)k=matchlit1,lit2with|Equation(l1,r1,true),Equation(l2,r2,true)->_eq_subsumes~substl1r1sc1l2r2sc2(funs->k(s,[]))|_->matching~subst~pattern:(lit1,sc1)(lit2,sc2)kletunify?(subst=US.empty)lit1lit2k=letop=UnifOp.({term=(fun~substt1t2k->tryk(Unif.FO.unify_full~substt1t2)withUnif.Fail->());})inunif_litsop~substlit1lit2kletmap_f=function|Equation(left,right,sign)->letnew_left=fleftandnew_right=frightinmk_litnew_leftnew_rightsign|True->True|False->Falseletmapflit=map_flitletapply_subst_~f_termsubst(lit,sc)=matchlitwith|Equation(l,r,sign)->letnew_l=f_termsubst(l,sc)andnew_r=f_termsubst(r,sc)inmk_litnew_lnew_rsign|True|False->litletapply_substrenamingsubst(lit,sc)=apply_subst_subst(lit,sc)~f_term:(S.FO.applyrenaming)letapply_subst_no_simprenamingsubst(lit,sc)=matchlitwith|Equation(l,r,sign)->Equation((S.FO.applyrenamingsubst(l,sc)),(S.FO.applyrenamingsubst(r,sc)),sign)|True|False->litletapply_subst_listrenamingsubst(lits,sc)=List.map(funlit->apply_substrenamingsubst(lit,sc))litsexceptionLit_is_constraintletis_ho_constraint=function|Equation(l,r,_)aslitwhenis_negativoidlit->T.is_ho_at_rootl||T.is_ho_at_rootr|_->falseletis_constraint=function|Equation(t,u,_)aslitwhenis_negativoidlit->T.is_vart||T.is_varu|_->falseletnegatelit=assert(no_prop_invariantlit);matchlitwith|Equation(l,r,sign)->mk_litlr(notsign)|True->False|False->Trueletvarslit=Seq.varslit|>T.VarSet.of_iter|>T.VarSet.to_listletvar_occursvlit=matchlitwith|Equation(l,r,_)->T.var_occurs~var:vl||T.var_occurs~var:vr|True|False->falseletis_groundlit=matchlitwith|Equation(l,r,_)->T.is_groundl&&T.is_groundr|True|False->trueletroot_termsl=Seq.termsl|>Iter.to_rev_listletto_multisetlit=matchlitwith|Equation(l,r,_)whenis_predicate_litlit->Multisets.MT.singletonl|Equation(l,r,_)->Multisets.MT.doubletonlr|True|False->Multisets.MT.singletonT.true_letis_triviallit=assert(no_prop_invariantlit);matchlitwith|True->true|False->false|Equation(l,r,true)->T.equallr|Equation(_,_,false)->false(* is it impossible for these terms to be equal? check if a cstor-only
path leads to distinct constructors/constants *)letreccannot_be_eq(t1:term)(t2:term):Builtin.Tag.tlistoption=letmoduleTC=T.ClassicinbeginmatchTC.viewt1,TC.viewt2with|TC.AppBuiltin(Builtin.Intz1,[]),TC.AppBuiltin(Builtin.Intz2,[])->ifZ.equalz1z2thenNoneelseSome[Builtin.Tag.T_lia;Builtin.Tag.T_cannot_orphan]|TC.AppBuiltin(Builtin.Ratn1,[]),TC.AppBuiltin(Builtin.Ratn2,[])->ifQ.equaln1n2thenNoneelseSome[Builtin.Tag.T_lra;Builtin.Tag.T_cannot_orphan]|TC.App(c1,l1),TC.App(c2,l2)whenInd_ty.is_constructorc1&&Ind_ty.is_constructorc2->(* two constructor applications cannot be equal if they
don't have the same constructor *)ifID.equalc1c2&&List.lengthl1=List.lengthl2then(List.combinel1l2|>Iter.of_list|>Iter.find_map(fun(a,b)->cannot_be_eqab))elseSome[Builtin.Tag.T_data]|_->Noneendletis_absurdlit=assert(no_prop_invariantlit);matchlitwith|Equation(l,r,false)whenT.equallr->true|Equation(l,r,true)->CCOpt.is_some(cannot_be_eqlr)|False->true|Equation_|True->falseletis_absurd_tagslit=assert(no_prop_invariantlit);matchlitwith|Equation(l,r,true)->cannot_be_eqlr|>CCOpt.get_or~default:[]|Equation_|False->[]|True->assertfalseletfold_terms?(position=Position.stop)?(vars=false)?(var_args=true)?(fun_bodies=true)?ty_args~which?(ord=Ordering.none)~subtermslitk=assert(no_prop_invariantlit);(* function to call at terms *)letfilter_formula_subtermshdargs=letopenBuiltininmatchwhichwith|`Max->(matchhd,argswith|(Eq|Neq|Xor|Equiv),([_;a;b]|[a;b])->(matchOrdering.compareordabwith|Comparison.Lt->Some[List.lengthargs-1]|Comparison.Gt->Some[List.lengthargs-2]|_->None)|(ForallConst|ExistsConst),[_;_]->Some[]|_->None)|`All->Noneinletat_term~post=ifsubtermsthenT.all_positions~filter_formula_subterms?ty_args~vars~var_args~fun_bodies~postkelseifT.is_vart&¬varsthen()(* ignore *)elsek(t,pos)inbeginmatchlitwith|Equation(l,r,_)->beginmatchwhichwith|`All->at_term~pos:P.(appendposition(leftstop))l;at_term~pos:P.(appendposition(rightstop))r|`Max->beginmatchOrdering.compareordlrwith|Comparison.Gt->at_term~pos:P.(appendposition(leftstop))l|Comparison.Lt->at_term~pos:P.(appendposition(rightstop))r|Comparison.Eq|Comparison.Incomparable->(* visit both sides, they are both (potentially) maximal *)at_term~pos:P.(appendposition(leftstop))l;at_term~pos:P.(appendposition(rightstop))rendend|True|False->()end(* try to convert a literal into a term *)letto_ho_term(lit:t):T.toption=matchlitwith|True->SomeT.true_|False->SomeT.false_|Equation(t,u,_)whenis_predicate_litlit->Some((ifis_negativoidlitthenT.Form.not_elseCCFun.id)t)|Equation(t,u,sign)->Some(ifsignthenT.Form.eqtuelseT.Form.neqtu)letas_ho_predicate(lit:t):_option=assert(no_prop_invariantlit);matchlitwith|Equation(lhs,rhs,_)whenis_predicate_litlit->lethd_t,args_t=T.as_applhsinbeginmatchT.viewhd_t,args_twith|T.Varv,_::_->Some(v,hd_t,args_t,is_positivoidlit)|_->Noneend|_->Noneletis_ho_predicatelit=CCOpt.is_some(as_ho_predicatelit)letis_ho_uniflit=matchlitwith|Equation(t,u,_)whenis_negativoidlit->Term.is_ho_appt||Term.is_ho_appu|_->falseletof_unif_substrenaming(s:Unif_subst.t):tlist=Unif_subst.constr_l_substrenamings|>List.map(fun(t,u)->(* upcast *)lett=T.of_term_unsafetinletu=T.of_term_unsafeuinmk_constrainttu)letnormalize_eqlit=letas_negt=matchT.viewtwith|T.AppBuiltin(Not,[f])->Somef|_->Noneinletis_negativoidt=CCOpt.is_some@@as_negtinleteq_builder~pos~neglr=matchas_negl,as_negrwith|Somef1,Somef2->posf1f2|Somef1,None->negf1r|None,Somef2->neglf2|None,None->poslrinletmk_eq_lr=eq_builder~pos:mk_eq~neg:mk_neqlrinletmk_neq_lr=eq_builder~pos:mk_neq~neg:mk_eqlrinletrecauxlit=matchlitwith|Equation(lhs,rhs,_)whenis_predicate_litlit->letsign=is_positivoidlitinbeginmatchT.viewlhswith|T.AppBuiltin(Builtin.(Eq|Equiv),([_;l;r]|[l;r]))->(* first arg can be type variable *)leteq_cons=ifsignthenmk_eq_elsemk_neq_inSome(eq_conslr)|T.AppBuiltin(Builtin.(Neq|Xor),([_;l;r]|[l;r]))->leteq_cons=ifsignthenmk_neq_elsemk_eq_inSome(eq_conslr)|T.AppBuiltin(Builtin.Not,[f])->letelim_not=mk_litfT.true_(notsign)inSome(CCOpt.get_or~default:elim_not(auxelim_not))|_->Noneend|Equation(lhs,rhs,sign)whenis_negativoidlhs||is_negativoidrhs->assert(not(T.is_true_or_falserhs));Some((ifsignthenmk_eq_elsemk_neq_)lhsrhs)|_->Noneinauxlit(** {2 IO} *)letpp_debug?(hooks=[])outlit=(* assert(no_prop_invariant lit); *)ifList.for_all(funh->not(houtlit))hooksthen(beginmatchlitwith|Equation(p,t,_)whenis_predicate_litlit->Format.fprintfout"@[%s%a@]"(if(is_positivoidlit)then""else"¬")T.ppp|True->CCFormat.stringout"Τ"|False->CCFormat.stringout"⊥"|Equation(l,r,true)->Format.fprintfout"@[<1>%a@ = %a@]"T.pplT.ppr|Equation(l,r,false)->Format.fprintfout"@[<1>%a@ ≠ %a@]"T.pplT.pprend)letpp_tstpoutlit=matchlitwith|Equation(p,t,_)whenis_predicate_litlit->Format.fprintfout"%s %a"(if(is_positivoidlit)then""else"~")T.TPTP.ppp|True->CCFormat.stringout"$true"|False->CCFormat.stringout"$false"|Equation(l,r,true)->Format.fprintfout"(@[<1>%a@ = %a@])"T.TPTP.pplT.TPTP.ppr|Equation(l,r,false)->Format.fprintfout"(@[<1>%a@ != %a@])"T.TPTP.pplT.TPTP.pprletpp_zfoutlit=matchlitwith|Equation(p,t,_)whenis_predicate_litlit->Format.fprintfout"%s %a"(if(is_positivoidlit)then""else"~")T.ZF.ppp|True->CCFormat.stringout"true"|False->CCFormat.stringout"false"|Equation(l,r,true)->Format.fprintfout"@[<1>%a@ = %a@]"T.ZF.pplT.ZF.ppr|Equation(l,r,false)->Format.fprintfout"@[<1>%a@ != %a@]"T.ZF.pplT.ZF.pprtypeprint_hook=CCFormat.t->t->boollet__hooks=ref[]letadd_default_hookh=__hooks:=h::!__hooksletppbuflit=pp_debug~hooks:!__hooksbuflitletto_stringt=CCFormat.to_stringppt(* comparison should live in its scope *)moduleComp=structmoduleO=OrderingmoduleC=Comparisonlet_maxterms2~ordlr=matchO.compareordlrwith|C.Gt->[l]|C.Lt->[r]|C.Eq->[l]|C.Incomparable->[l;r](* maximal terms of the literal *)letmax_terms~ordlit=(* assert(no_prop_invariant lit); *)matchlitwith|Equation(l,r,_)->_maxterms2~ordlr|True|False->[](* general comparison is a bit complicated.
- First we compare literals l1 and l2
by their (set of potential) maximal terms.
- then by their polarity (neg > pos)
- then by their kind (regular equation/prop on bottom)
- then, l1 and l2 must be of the same kind, so we use a
kind-specific comparison.
*)(* is there an element of [l1] that dominates all elements of [l2]? *)let_some_term_dominatesfl1l2=List.exists(funx->List.for_all(funy->fxy=Comparison.Gt)l2)l1let_cmp_by_maxterms~ordl1l2=lett1=max_terms~ordl1andt2=max_terms~ordl2inletf=Ordering.compareordinmatch_some_term_dominatesft1t2,_some_term_dominatesft2t1with|false,false->lett1'=CCList.fold_rightT.Set.addt1T.Set.emptyandt2'=CCList.fold_rightT.Set.addt2T.Set.emptyinifT.Set.equalt1't2'thenC.Eq(* next criterion *)elseC.Incomparable|true,true->assertfalse|true,false->C.Gt|false,true->C.Lt(* negative literals dominate *)let_cmp_by_polarityl1l2=letp1=polarityl1inletp2=polarityl2inmatchp1,p2with|true,true|false,false->Comparison.Eq|true,false->Comparison.Lt|false,true->Comparison.Gtlet_cmp_by_kindl1l2=let_to_int=function|False|True->0|Equation_->30inC.of_total(Pervasives.compare(_to_intl1)(_to_intl2))(* by multiset of terms *)let_cmp_by_term_multiset~ordl1l2=letm1=to_multisetl1andm2=to_multisetl2inMultisets.MT.compare_partial(Ordering.compareord)m1m2let_cmp_specific~ordl1l2=matchl1,l2with|True,True|True,False|True,Equation_|False,False|False,True|False,Equation_|Equation_,Equation_|Equation_,True|Equation_,False->_cmp_by_term_multiset~ordl1l2letcompare~ordl1l2=letf=Comparison.(_cmp_by_maxterms~ord@>>_cmp_by_polarity@>>_cmp_by_kind@>>_cmp_specific~ord)inletres=fl1l2inresendmodulePos=structtypesplit={lit_pos:Position.t;term_pos:Position.t;term:term;}let_fail_litlitpos=letmsg=CCFormat.sprintf"@[<2>invalid position @[%a@]@ in lit @[%a@]@]"Position.pppospplitininvalid_argmsgletsplitlitpos=matchlit,poswith|True,P.Stop->{lit_pos=P.stop;term_pos=P.stop;term=T.true_;}|False,P.Stop->{lit_pos=P.stop;term_pos=P.stop;term=T.false_;}|Equation(l,_,_),P.Leftpos'->{lit_pos=P.(leftstop);term_pos=pos';term=l;}|Equation(_,r,_),P.Rightpos'->{lit_pos=P.(rightstop);term_pos=pos';term=r;}|_->_fail_litlitposletcutlitpos=lets=splitlitposins.lit_pos,s.term_posletatlitpos=lets=splitlitposinT.Pos.ats.terms.term_posletreplacelit~at~by=matchlit,atwith|Equation(l,r,sign),P.Leftpos'->letcons=ifsignthenmk_eqelsemk_neqincons(T.Pos.replacelpos'~by)r|Equation(l,r,sign),P.Rightpos'->letcons=ifsignthenmk_eqelsemk_neqinconsl(T.Pos.replacerpos'~by)|True,_|False,_->lit(* flexible, lit can be the result of a simplification *)|_->_fail_litlitatletroot_termlitpos=atlit(fst(cutlitpos))letterm_poslitpos=snd(cutlitpos)letis_max_term~ordlitpos=matchlit,poswith|Equation(l,r,_),P.Left_->Ordering.compareordlr<>Comparison.Lt|Equation(l,r,_),P.Right_->Ordering.compareordrl<>Comparison.Lt|True,_|False,_->true(* why not. *)|Equation_,_->_fail_litlitposendletreplacelit~old~by=map(T.replace~old~by)litmoduleConv=structtypehook_from=termSLiteral.t->toptiontypehook_to=t->termSLiteral.toptionletrectry_hooksxhooks=matchhookswith|[]->None|h::hooks'->matchhxwith|None->try_hooksxhooks'|(Some_)asres->resletof_form?(hooks=[])f=matchtry_hooksfhookswith|Somelit->lit|None->beginmatchfwith|SLiteral.True->True|SLiteral.False->False|SLiteral.Atom(t,b)->mk_proptb|SLiteral.Eq(l,r)->mk_eqlr|SLiteral.Neq(l,r)->mk_neqlrendletto_form?(hooks=[])lit=assert(no_prop_invariantlit);beginmatchtry_hookslithookswith|Somef->f|None->beginmatchlitwith|Equation(l,r,_)->assert(Type.equal(Term.tyl)(Term.tyr));letsign=is_positivoidlitinifType.is_prop(Term.tyl)then(ifT.is_true_or_falserthenSLiteral.atomlsignelse(lethd=ifsignthenBuiltin.EquivelseBuiltin.XorinSLiteral.atom(T.app_builtin~ty:Type.prophd[l;r])true))else(ifsignthenSLiteral.eqlrelseSLiteral.neqlr)|True->SLiteral.true_|False->SLiteral.false_endendletlit_to_tst?(ctx=T.Conv.create())lit=beginmatchlitwith|SLiteral.Atom(p,s)->letp=ifsthenpelseT.Form.not_pinT.Conv.to_simple_termctxp|SLiteral.Eq(l,r)whenT.equalT.true_r->T.Conv.to_simple_termctxl|SLiteral.Eq(l,r)whenT.equalT.false_r->T.Conv.to_simple_termctx(T.Form.not_l)|SLiteral.Neq(l,r)whenT.equalT.true_r->T.Conv.to_simple_termctx(T.Form.not_l)|SLiteral.Neq(l,r)whenT.equalT.false_r->T.Conv.to_simple_termctxl|SLiteral.Eq(l,r)->letl,r=CCPair.map_same(T.Conv.to_simple_termctx)(l,r)inTypedSTerm.Form.eqlr|SLiteral.Neq(l,r)->letl,r=CCPair.map_same(T.Conv.to_simple_termctx)(l,r)inTypedSTerm.Form.neqlr|SLiteral.True->TypedSTerm.Form.true_|SLiteral.False->TypedSTerm.Form.false_endletto_s_form?allow_free_db?(ctx=T.Conv.create())?hookslit=to_form?hookslit|>SLiteral.map~f:(T.Conv.to_simple_term?allow_free_dbctx)|>SLiteral.to_formendmoduleView=structletas_eqnlit=assert(no_prop_invariantlit);matchlitwith|Equation(l,r,sign)->Some(l,r,sign)|True|False->Noneletget_eqnlitposition=matchlit,positionwith|Equation(l,r,sign),P.Left_->Some(l,r,sign)|Equation(l,r,sign),P.Right_->Some(r,l,sign)|True,_|False,_->None|_->invalid_arg"get_eqn: wrong literal or position"letget_lhs=function|Equation(lhs,_,_)->Somelhs|_->Noneletget_rhs=function|Equation(_,rhs,_)->Somerhs|_->Noneendlet_as_var=funt->T.as_var_exn(Lambda.eta_reducet)letas_inj_deflit=matchView.as_eqnlitwith|Some(l,r,false)->(trylethd_l,hd_r=T.head_exnl,T.head_exnrinletvars_l,vars_r=List.map_as_var(T.argsl),List.map_as_var(T.argsr)inletargs_l,args_r=VS.of_listvars_l,VS.of_listvars_rin(* We are looking for literal f X1 ... Xn ~= f Y1 ... Yn
where all X_i, Y_i are different pairwise, but form each
other also. *)ifhd_l=hd_r&&VS.cardinalargs_l=List.length(T.argsl)&&VS.cardinalargs_r=List.length(T.argsr)&&VS.cardinalargs_l=VS.cardinalargs_r&&VS.interargs_largs_r=VS.emptythenSome(hd_l,List.combinevars_lvars_r)elseNonewithInvalid_argument_->None)|_->Noneletis_pure_varlit=matchlitwith|Equation(l,r,_)->begintryignore(_as_varl,_as_varr);truewithInvalid_argument_->falseend|_->falseletmax_term_positions~ord=function|Equation(lhs,rhs,_)->beginmatchOrdering.compareordlhsrhswith|Comparison.Gt->Term.ho_weightlhs|Comparison.Lt->Term.ho_weightrhs|_->Term.ho_weightlhs+Term.ho_weightrhsend|_->1letas_pos_pure_varlit=matchView.as_eqnlitwith|Some(l,r,true)whenis_pure_varlit&&is_positivoidlit->Some(_as_varl,_as_varr)|_->Noneletare_opposite_subst~subst(l1,sc1)(l2,sc2)=letmoduleUF=Unif.FOinis_positivoidl1!=is_positivoidl2&&is_predicate_litl1=is_predicate_litl2&&matchl1,l2with|Equation(lhs,rhs,_),Equation(lhs',rhs',_)whenis_predicate_litl1->(UF.equal~subst(lhs,sc1)(lhs',sc2)&&UF.equal~subst(rhs,sc1)(rhs',sc2))||(UF.equal~subst(lhs,sc1)(rhs',sc2)&&UF.equal~subst(rhs,sc1)(lhs',sc2))|Equation(lhs,_,_),Equation(lhs',_,_)->UF.equal~subst(lhs,sc1)(lhs',sc2)|True,True->true|False,False->true|_->falseletare_opposite_same_scl1l2=are_opposite_subst~subst:Subst.empty(l1,0)(l2,0)