123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* This file implements the basic congruence-closure algorithm by *)(* Downey, Sethi and Tarjan. *)(* Plus some e-matching and constructor handling by P. Corbineau *)openCErrorsopenPpopenNamesopenSortsopenConstropenContextopenVarsopenUtilopenLazyletinit_size=5letdebug_congruence=CDebug.create~name:"congruence"()(* Signature table *)moduleST=struct(* l: sign -> term r: term -> sign *)moduleIntTable=Hashtbl.Make(Int)moduleIntPair=structtypet=int*intletequal(i1,j1)(i2,j2)=Int.equali1i2&&Int.equalj1j2lethash(i,j)=Hashset.Combine.combine(Int.hashi)(Int.hashj)endmoduleIntPairTable=Hashtbl.Make(IntPair)typet={toterm:intIntPairTable.t;tosign:(int*int)IntTable.t}letempty()={toterm=IntPairTable.createinit_size;tosign=IntTable.createinit_size}letentertsignst=ifIntPairTable.memst.totermsignthenanomaly~label:"enter"(Pp.str"signature already entered.")elseIntPairTable.replacest.totermsignt;IntTable.replacest.tosigntsignletquerysignst=IntPairTable.findst.totermsignletdeletestt=tryletsign=IntTable.findst.tosigntinIntPairTable.removest.totermsign;IntTable.removest.tosigntwithNot_found->()letdelete_setsts=Int.Set.iter(deletest)sendtypepa_constructor={cnode:int;arity:int;args:intlist}typepa_fun={fsym:int;fnargs:int}typepa_mark=Fmarkofpa_fun|Cmarkofpa_constructormodulePacOrd=structtypet=pa_constructorletcompare{cnode=cnode0;arity=arity0;args=args0}{cnode=cnode1;arity=arity1;args=args1}=letcmp=Int.comparecnode0cnode1inifcmp=0thenletcmp'=Int.comparearity0arity1inifcmp'=0thenList.compareInt.compareargs0args1elsecmp'elsecmpendmodulePafOrd=structtypet=pa_funletcompare{fsym=fsym0;fnargs=fnargs0}{fsym=fsym1;fnargs=fnargs1}=letcmp=Int.comparefsym0fsym1inifcmp=0thenInt.comparefnargs0fnargs1elsecmpendmodulePacMap=Map.Make(PacOrd)modulePafMap=Map.Make(PafOrd)typecinfo={ci_constr:pconstructor;(* inductive type *)ci_arity:int;(* # args *)ci_nhyps:int}(* # projectable args *)letfamily_eqf1f2=matchf1,f2with|Set,Set|Prop,Prop|Type_,Type_->true|_->falsetype'aterm=Symbofconstr*(* Hash: *)int|ProductofSorts.t*Sorts.t|EpsofId.t|Appliof'a*'a|Constructorofcinfo(* constructor arity + nhyps *)(* terms with eagerly cached constr and hash *)moduleATerm:sigtypetvalproj:t->ttermvalmkSymb:constr->tvalmkProduct:(Sorts.t*Sorts.t)->tvalmkEps:Id.t->tvalmkAppli:(t*t)->tvalmkConstructor:Environ.env->cinfo->tvalequal:t->t->boolvalconstr:t->constrvalhash:t->intvalnth_arg:t->int->tend=structtypet={term:tterm;constr:constrlazy_t;hash:int}letprojt=t.termletrecterm_equalt1t2=matcht1,t2with|Symb(c1,_),Symb(c2,_)->eq_constr_nounivsc1c2|Product(s1,t1),Product(s2,t2)->family_eqs1s2&&family_eqt1t2|Epsi1,Epsi2->Id.equali1i2|Appli(t1',u1'),Appli(t2',u2')->term_equalt1'.termt2'.term&&term_equalu1'.termu2'.term|Constructor{ci_constr=(c1,u1);ci_arity=i1;ci_nhyps=j1},Constructor{ci_constr=(c2,u2);ci_arity=i2;ci_nhyps=j2}->Int.equali1i2&&Int.equalj1j2&&Construct.UserOrd.equalc1c2|_->falseletequalt1t2=term_equalt1.termt2.termopenHashset.Combinelethash_termt=matchtwith|Symb(_,hash_c)->combine1hash_c|Product(s1,s2)->combine32(Sorts.hashs1)(Sorts.hashs2)|Epsi->combine3(Id.hashi)|Appli(t1',t2')->combine34(t1'.hash)(t2'.hash)|Constructor{ci_constr=(c,u);ci_arity=i;ci_nhyps=j}->combine45(Construct.UserOrd.hashc)ijlethasht=t.hash(* rebuild a constr from an applicative term *)let_A_=Name(Id.of_string"A")let_B_=Name(Id.of_string"A")let_body_=mkProd(make_annotAnonymousSorts.Relevant,mkRel2,mkRel2)letcc_products1s2=mkLambda(make_annot_A_Sorts.Relevant,mkSort(s1),mkLambda(make_annot_B_Sorts.Relevant,mkSort(s2),_body_))letrecconstr_of_term=functionSymb(s,_)->s|Product(s1,s2)->cc_products1s2|Epsid->mkVarid|Constructorcinfo->mkConstructUcinfo.ci_constr|Appli(s1',s2')->make_app[forces2'.constr]s1'andmake_applt'=matcht'.termwithAppli(s1',s2')->make_app((forces2'.constr)::l)s1'|_->Term.applist(forcet'.constr,l)letconstrt=forcet.constrletmaket={term=t;constr=lazy(constr_of_termt);hash=hash_termt}letrecdrop_univc=matchkindcwith|Const(c,_u)->mkConstU(c,UVars.Instance.empty)|Ind(c,_u)->mkIndU(c,UVars.Instance.empty)|Construct(c,_u)->mkConstructU(c,UVars.Instance.empty)|Sort(Type_u)->mkSort(type1)|_->Constr.mapdrop_univcletmkSymbs=make(Symb(s,Constr.hash(drop_univs)))letmkProduct(s1,s2)=make(Product(s1,s2))letmkEpsid=make(Epsid)letmkAppli(t1',t2')=make(Appli(t1',t2'))letmkConstructorenvinfo=letcanoni=Environ.QConstruct.canonizeenviinletinfo={infowithci_constr=on_fstcanoninfo.ci_constr}inmake(Constructorinfo)letrecnth_argtn=matcht.termwithAppli(t1',t2')->ifn>0thennth_argt1'(n-1)elset2'|_->anomaly~label:"nth_arg"(Pp.str"not enough args.")endtypeccpattern=PAppofATerm.t*ccpatternlist(* arguments are reversed *)|PVarofint*ccpatternlist(* arguments are reversed *)typeaxiom=constrletconstr_of_axiomc=ctyperule=Congruence|Axiomofaxiom*bool|Injectionofint*pa_constructor*int*pa_constructor*inttypefrom=Goal|Hypofconstr|HeqGofId.t|HeqnHofId.t*Id.ttype'aeq={lhs:int;rhs:int;rule:'a}typeequality=ruleeqtypedisequality=fromeqtypepatt_kind=Normal|Trivialoftypes|Creates_variablestypequant_eq={qe_hyp_id:Id.t;qe_pol:bool;qe_nvars:int;qe_lhs:ccpattern;qe_lhs_valid:patt_kind;qe_rhs:ccpattern;qe_rhs_valid:patt_kind}letswapeq:equality=letswap_rule=matcheq.rulewithCongruence->Congruence|Injection(i,pi,j,pj,k)->Injection(j,pj,i,pi,k)|Axiom(id,reversed)->Axiom(id,notreversed)in{lhs=eq.rhs;rhs=eq.lhs;rule=swap_rule}typeinductive_status=Unknown|Partialofpa_constructor|Partial_applied|Totalof(int*pa_constructor)typerepresentative={mutableweight:int;mutablelfathers:Int.Set.t;mutablefathers:Int.Set.t;mutableinductive_status:inductive_status;class_type:types;mutablefunctions:Int.Set.tPafMap.t}(*pac -> term = app(constr,t) *)typecl=Repofrepresentative|Eqtoofint*equalitytypevertex=Leaf|Nodeof(int*int)typenode={mutableclas:cl;mutablecpath:int;mutableconstructors:intPacMap.t;vertex:vertex;aterm:ATerm.t}moduleConstrhash=Hashtbl.Make(structtypet=constrletequal=eq_constr_nounivslethash=Constr.hashend)moduleTypehash=ConstrhashmoduleTermhash=Hashtbl.Make(structtypet=ATerm.tletequal=ATerm.equallethash=ATerm.hashend)moduleIdenthash=Hashtbl.Make(structtypet=Id.tletequal=Id.equallethash=Id.hashend)typeforest={mutablemax_size:int;mutablesize:int;mutablemap:nodearray;axioms:(ATerm.t*ATerm.t)Constrhash.t;mutableepsilons:pa_constructorlist;syms:intTermhash.t}typestate={uf:forest;sigtable:ST.t;mutableterms:Int.Set.t;combine:equalityQueue.t;marks:(int*pa_mark)Queue.t;mutablediseq:disequalitylist;mutablequant:quant_eqlist;mutablepa_classes:Int.Set.t;q_history:(intarray)Identhash.t;mutablerew_depth:int;mutablechanged:bool;by_type:Int.Set.tTypehash.t;mutableenv:Environ.env;sigma:Evd.evar_map}letdummy_node={clas=Eqto(min_int,{lhs=min_int;rhs=min_int;rule=Congruence});cpath=min_int;constructors=PacMap.empty;vertex=Leaf;aterm=ATerm.mkSymb(mkRelmin_int)}letempty_forest()={max_size=init_size;size=0;map=Array.makeinit_sizedummy_node;epsilons=[];axioms=Constrhash.createinit_size;syms=Termhash.createinit_size}letemptyenvsigmadepth:state={uf=empty_forest();terms=Int.Set.empty;combine=Queue.create();marks=Queue.create();sigtable=ST.empty();diseq=[];quant=[];pa_classes=Int.Set.empty;q_history=Identhash.createinit_size;rew_depth=depth;by_type=Constrhash.createinit_size;changed=false;env;sigma;}letforeststate=state.ufletcompress_pathufij=uf.map.(j).cpath<-iletrecfind_auxufvisitedi=letj=uf.map.(i).cpathinifj<0thenlet()=List.iter(compress_pathufi)visitedinielsefind_auxuf(i::visited)jletfindufi=find_auxuf[]iletget_representativeufi=matchuf.map.(i).claswithRepr->r|_->anomaly~label:"get_representative"(Pp.str"not a representative.")letget_constructorsufi=uf.map.(i).constructorsletrecfind_oldest_pacufipac=tryPacMap.findpac(get_constructorsufi)withNot_found->matchuf.map.(i).claswithEqto(j,_)->find_oldest_pacufjpac|Rep_->raiseNot_foundletget_constructor_infoufi=matchATerm.projuf.map.(i).atermwithConstructorcinfo->cinfo|_->anomaly~label:"get_constructor"(Pp.str"not a constructor.")letsizeufi=(get_representativeufi).weightletaxiomsufc=Constrhash.finduf.axiomscletepsilonsuf=uf.epsilonsletadd_lfatherufit=letr=get_representativeufiinr.weight<-r.weight+1;r.lfathers<-Int.Set.addtr.lfathers;r.fathers<-Int.Set.addtr.fathersletadd_rfatherufit=letr=get_representativeufiinr.weight<-r.weight+1;r.fathers<-Int.Set.addtr.fathersexceptionDiscriminableofint*pa_constructor*int*pa_constructorletappend_pactp={pwitharity=predp.arity;args=t::p.args}lettail_pacp={pwitharity=succp.arity;args=List.tlp.args}letfsuccpaf={pafwithfnargs=succpaf.fnargs}letadd_pacnodepact=ifnot(PacMap.mempacnode.constructors)thennode.constructors<-PacMap.addpactnode.constructorsletadd_pafreppaft=letalready=tryPafMap.findpafrep.functionswithNot_found->Int.Set.emptyinrep.functions<-PafMap.addpaf(Int.Set.addtalready)rep.functionsletatermufi=uf.map.(i).atermletsubtermsufi=matchuf.map.(i).vertexwithNode(j,k)->(j,k)|_->anomaly~label:"subterms"(Pp.str"not a node.")letsignatureufi=letj,k=subtermsufiin(findufj,findufk)letnextuf=letsize=uf.sizeinletnsize=succsizeinifInt.equalnsizeuf.max_sizethenletnewmax=uf.max_size*3/2+1inletnewmap=Array.makenewmaxdummy_nodeinbeginuf.max_size<-newmax;Array.blituf.map0newmap0size;uf.map<-newmapendelse();uf.size<-nsize;sizeletnew_representativetyp={weight=0;lfathers=Int.Set.empty;fathers=Int.Set.empty;inductive_status=Unknown;class_type=typ;functions=PafMap.empty}letreccanonize_namec=letc=EConstr.Unsafe.to_constrcinletfuncc=canonize_name(EConstr.of_constrc)inmatchConstr.kindcwith|Const(kn,u)->letcanon_const=Constant.make1(Constant.canonicalkn)in(mkConstU(canon_const,u))|Ind((kn,i),u)->letcanon_mind=MutInd.make1(MutInd.canonicalkn)in(mkIndU((canon_mind,i),u))|Construct(((kn,i),j),u)->letcanon_mind=MutInd.make1(MutInd.canonicalkn)inmkConstructU(((canon_mind,i),j),u)|Prod(na,t,ct)->mkProd(na,funct,funcct)|Lambda(na,t,ct)->mkLambda(na,funct,funcct)|LetIn(na,b,t,ct)->mkLetIn(na,funcb,funct,funcct)|App(ct,l)->mkApp(funcct,Array.Smart.mapfuncl)|Proj(p,r,c)->letp'=Projection.map(funkn->MutInd.make1(MutInd.canonicalkn))pin(mkProj(p',r,funcc))|_->c(* rebuild a term from a pattern and a substitution *)letbuild_substufsubst=Array.map(funi->tryatermufiwithewhenCErrors.noncriticale->anomaly(Pp.str"incomplete matching."))substletrecinst_patternsubst=functionPVar(i,args)->List.fold_right(funspatf->ATerm.mkAppli(f,inst_patternsubstspat))argssubst.(predi)|PApp(t',args)->List.fold_right(funspatf->ATerm.mkAppli(f,inst_patternsubstspat))argst'letpr_idx_termenvsigmaufi=str"["++inti++str":="++Printer.pr_econstr_envenvsigma(EConstr.of_constr(ATerm.constr(atermufi)))++str"]"letpr_termenvsigmat'=str"["++Printer.pr_econstr_envenvsigma(EConstr.of_constr(ATerm.constrt'))++str"]"letrecadd_atermstatet'=letuf=state.ufintryTermhash.finduf.symst'withNot_found->letb=nextufinlettrm=ATerm.constrt'inlettyp=Retyping.get_type_ofstate.envstate.sigma(EConstr.of_constrtrm)inlettyp=canonize_nametypinletnew_node=matchATerm.projt'withSymb_|Product(_,_)->letpaf={fsym=b;fnargs=0}inQueue.add(b,Fmarkpaf)state.marks;{clas=Rep(new_representativetyp);cpath=-1;constructors=PacMap.empty;vertex=Leaf;aterm=t'}|Epsid->{clas=Rep(new_representativetyp);cpath=-1;constructors=PacMap.empty;vertex=Leaf;aterm=t'}|Appli(t1',t2')->leti1=add_atermstatet1'andi2=add_atermstatet2'inadd_lfatheruf(findufi1)b;add_rfatheruf(findufi2)b;state.terms<-Int.Set.addbstate.terms;{clas=Rep(new_representativetyp);cpath=-1;constructors=PacMap.empty;vertex=Node(i1,i2);aterm=t'}|Constructorcinfo->letpaf={fsym=b;fnargs=0}inQueue.add(b,Fmarkpaf)state.marks;letpac={cnode=b;arity=cinfo.ci_arity;args=[]}inQueue.add(b,Cmarkpac)state.marks;{clas=Rep(new_representativetyp);cpath=-1;constructors=PacMap.empty;vertex=Leaf;aterm=t'}inuf.map.(b)<-new_node;Termhash.adduf.symst'b;Typehash.replacestate.by_typetyp(Int.Set.addb(tryTypehash.findstate.by_typetypwithNot_found->Int.Set.empty));bletadd_equality0statecs't'=leti=add_atermstates'inletj=add_atermstatet'inQueue.add{lhs=i;rhs=j;rule=Axiom(c,false)}state.combine;Constrhash.addstate.uf.axiomsc(s',t')letadd_equalitystateidst=add_equality0state(mkVarid)stletadd_disequalitystatefroms't'=leti=add_atermstates'inletj=add_atermstatet'instate.diseq<-{lhs=i;rhs=j;rule=from}::state.diseqletadd_quantstateidpol(nvars,valid1,patt1,valid2,patt2)=state.quant<-{qe_hyp_id=id;qe_pol=pol;qe_nvars=nvars;qe_lhs=patt1;qe_lhs_valid=valid1;qe_rhs=patt2;qe_rhs_valid=valid2}::state.quantletis_redundantstateidargs=tryletnorm_args=Array.map(findstate.uf)argsinletprev_args=Identhash.find_allstate.q_historyidinList.exists(funold_args->Util.Array.for_all2(funij->Int.equali(findstate.ufj))norm_argsold_args)prev_argswithNot_found->falseletadd_inststate(inst,int_subst)=Control.check_for_interrupt();ifstate.rew_depth>0thenifis_redundantstateinst.qe_hyp_idint_substthendebug_congruence(fun()->str"discarding redundant (dis)equality")elsebeginIdenthash.addstate.q_historyinst.qe_hyp_idint_subst;letsubst=build_subst(foreststate)int_substinletprfhead=mkVarinst.qe_hyp_idinletargs=Array.mapATerm.constrsubstinlet_=Array.revargsin(* highest deBruijn index first *)letprf=mkApp(prfhead,args)inlets=inst_patternsubstinst.qe_lhsandt=inst_patternsubstinst.qe_rhsinstate.changed<-true;state.rew_depth<-predstate.rew_depth;ifinst.qe_polthenbegindebug_congruence(fun()->(str"Adding new equality, depth="++intstate.rew_depth)++fnl()++(str" ["++Printer.pr_econstr_envstate.envstate.sigma(EConstr.of_constrprf)++str" : "++pr_termstate.envstate.sigmas++str" == "++pr_termstate.envstate.sigmat++str"]"));add_equality0stateprfstendelsebegindebug_congruence(fun()->(str"Adding new disequality, depth="++intstate.rew_depth)++fnl()++(str" ["++Printer.pr_econstr_envstate.envstate.sigma(EConstr.of_constrprf)++str" : "++pr_termstate.envstate.sigmas++str" <> "++pr_termstate.envstate.sigmat++str"]"));add_disequalitystate(Hypprf)stendendletlinkufijeq=(* links i -> j *)letnode=uf.map.(i)innode.clas<-Eqto(j,eq);node.cpath<-jletrecdown_pathufil=matchuf.map.(i).claswithEqto(j,eq)->down_pathufj(((i,j),eq)::l)|Rep_->lleteq_pair(i1,j1)(i2,j2)=Int.equali1i2&&Int.equalj1j2letrecmin_path=function([],l2)->([],l2)|(l1,[])->(l1,[])|(((c1,t1)::q1),((c2,t2)::q2))wheneq_pairc1c2->min_path(q1,q2)|cpl->cplletjoin_pathufij=assert(Int.equal(findufi)(findufj));min_path(down_pathufi[],down_pathufj[])letunionstatei1i2eq=debug_congruence(fun()->str"Linking "++pr_idx_termstate.envstate.sigmastate.ufi1++str" and "++pr_idx_termstate.envstate.sigmastate.ufi2++str".");letr1=get_representativestate.ufi1andr2=get_representativestate.ufi2inlinkstate.ufi1i2eq;Constrhash.replacestate.by_typer1.class_type(Int.Set.removei1(tryConstrhash.findstate.by_typer1.class_typewithNot_found->Int.Set.empty));letf=Int.Set.unionr1.fathersr2.fathersinr2.weight<-Int.Set.cardinalf;r2.fathers<-f;r2.lfathers<-Int.Set.unionr1.lfathersr2.lfathers;ST.delete_setstate.sigtabler1.fathers;state.terms<-Int.Set.unionstate.termsr1.fathers;PacMap.iter(funpacb->Queue.add(b,Cmarkpac)state.marks)state.uf.map.(i1).constructors;PafMap.iter(funpaf->Int.Set.iter(funb->Queue.add(b,Fmarkpaf)state.marks))r1.functions;matchr1.inductive_status,r2.inductive_statuswithUnknown,_->()|Partialpac,Unknown->r2.inductive_status<-Partialpac;state.pa_classes<-Int.Set.removei1state.pa_classes;state.pa_classes<-Int.Set.addi2state.pa_classes|Partial_,(Partial_|Partial_applied)->state.pa_classes<-Int.Set.removei1state.pa_classes|Partial_applied,Unknown->r2.inductive_status<-Partial_applied|Partial_applied,Partial_->state.pa_classes<-Int.Set.removei2state.pa_classes;r2.inductive_status<-Partial_applied|Totalcpl,Unknown->r2.inductive_status<-Totalcpl;|Total(i,pac),Total_->Queue.add(i,Cmarkpac)state.marks|_,_->()letmergeeqstate=(* merge and no-merge *)debug_congruence(fun()->str"Merging "++pr_idx_termstate.envstate.sigmastate.ufeq.lhs++str" and "++pr_idx_termstate.envstate.sigmastate.ufeq.rhs++str".");letuf=state.ufinleti=findufeq.lhsandj=findufeq.rhsinifnot(Int.equalij)thenif(sizeufi)<(sizeufj)thenunionstateijeqelseunionstateji(swapeq)letupdatetstate=(* update 1 and 2 *)debug_congruence(fun()->str"Updating term "++pr_idx_termstate.envstate.sigmastate.uft++str".");let(i,j)assign=signaturestate.uftinlet(u,v)=subtermsstate.uftinletrep=get_representativestate.ufiinbeginmatchrep.inductive_statuswithPartial_->rep.inductive_status<-Partial_applied;state.pa_classes<-Int.Set.removeistate.pa_classes|_->()end;PacMap.iter(funpac_->Queue.add(t,Cmark(append_pacvpac))state.marks)(get_constructorsstate.ufi);PafMap.iter(funpaf_->Queue.add(t,Fmark(fsuccpaf))state.marks)rep.functions;trylets=ST.querysignstate.sigtableinQueue.add{lhs=t;rhs=s;rule=Congruence}state.combinewithNot_found->ST.entertsignstate.sigtableletprocess_function_marktreppafstate=add_pafreppaft;state.terms<-Int.Set.unionrep.lfathersstate.termsletprocess_constructor_marktireppacstate=add_pacstate.uf.map.(i)pact;matchrep.inductive_statuswithTotal(s,opac)->ifnot(Int.equalpac.cnodeopac.cnode)then(* Conflict *)raise(Discriminable(s,opac,t,pac))else(* Match *)letcinfo=get_constructor_infostate.ufpac.cnodeinletrecfnoargsargs=ifn>0thenmatch(oargs,args)withs1::q1,s2::q2->Queue.add{lhs=s1;rhs=s2;rule=Injection(s,opac,t,pac,n)}state.combine;f(n-1)q1q2|_->anomaly~label:"add_pacs"(Pp.str"weird error in injection subterms merge.")infcinfo.ci_nhypsopac.argspac.args|Partial_applied|Partial_->(* add_pac state.uf.map.(i) pac t; *)state.terms<-Int.Set.unionrep.lfathersstate.terms|Unknown->ifInt.equalpac.arity0thenrep.inductive_status<-Total(t,pac)elsebegin(* add_pac state.uf.map.(i) pac t; *)state.terms<-Int.Set.unionrep.lfathersstate.terms;rep.inductive_status<-Partialpac;state.pa_classes<-Int.Set.addistate.pa_classesendletprocess_marktmstate=debug_congruence(fun()->str"Processing mark for term "++pr_idx_termstate.envstate.sigmastate.uft++str".");leti=findstate.uftinletrep=get_representativestate.ufiinmatchmwithFmarkpaf->process_function_marktreppafstate|Cmarkpac->process_constructor_marktireppacstatetypeexplanation=Discriminationof(int*pa_constructor*int*pa_constructor)|Contradictionofdisequality|Incompleteof(EConstr.t*int)listletcheck_disequalitiesstate=letuf=state.ufinletreccheck_aux=function|dis::q->let(info,ans)=ifInt.equal(findufdis.lhs)(findufdis.rhs)then(str"Yes",Somedis)else(str"No",check_auxq)inlet_=debug_congruence(fun()->str"Checking if "++pr_idx_termstate.envstate.sigmastate.ufdis.lhs++str" = "++pr_idx_termstate.envstate.sigmastate.ufdis.rhs++str" ... "++info)inans|[]->Noneincheck_auxstate.diseqletone_stepstate=tryleteq=Queue.takestate.combineinmergeeqstate;truewithQueue.Empty->trylet(t,m)=Queue.takestate.marksinprocess_marktmstate;truewithQueue.Empty->trylett=Int.Set.choosestate.termsinstate.terms<-Int.Set.removetstate.terms;updatetstate;truewithNot_found->falselet__eps__=Id.of_string"_eps_"letnew_state_vartypstate=letids=Environ.ids_of_named_context_val(Environ.named_context_valstate.env)inletid=Namegen.next_ident_away__eps__idsinletr=EConstr.ERelevance.relevantin(* TODO relevance *)state.env<-EConstr.push_named(Context.Named.Declaration.LocalAssum(make_annotidr,typ))state.env;idletcomplete_one_classstatei=match(get_representativestate.ufi).inductive_statuswith|Partialpac->letrecappt'typn=ifn<=0thent'elselet_,etyp,rest=destProdtypinletid=new_state_var(EConstr.of_constretyp)stateinapp(ATerm.mkAppli(t',ATerm.mkEpsid))(substl[mkVarid]rest)(n-1)inletc=Retyping.get_type_ofstate.envstate.sigma(EConstr.of_constr(ATerm.constr(atermstate.ufpac.cnode)))inletc=EConstr.Unsafe.to_constrcinletargs=List.map(funi->ATerm.constr(atermstate.ufi))pac.argsinlettyp=Term.prod_applistc(List.revargs)inletct=app(atermstate.ufi)typpac.arityinstate.uf.epsilons<-pac::state.uf.epsilons;ignore(add_atermstatect)|_->anomaly(Pp.str"wrong incomplete class.")letcompletestate=Int.Set.iter(complete_one_classstate)state.pa_classestypematching_problem={mp_subst:intarray;mp_inst:quant_eq;mp_stack:(ccpattern*int)list}letmake_fun_tablestate=letuf=state.ufinletfuntab=refPafMap.emptyinArray.iteri(funiinode->ifi<uf.sizethenmatchinode.claswithReprep->PafMap.iter(funpaf_->letelem=tryPafMap.findpaf!funtabwithNot_found->Int.Set.emptyinfuntab:=PafMap.addpaf(Int.Set.addielem)!funtab)rep.functions|_->())state.uf.map;!funtabletdo_matchstaterespb_stack=letmp=Stack.poppb_stackinmatchmp.mp_stackwith[]->res:=(mp.mp_inst,mp.mp_subst)::!res|(patt,cl)::remains->letuf=state.ufinmatchpattwithPVar(i,[])->ifmp.mp_subst.(predi)<0thenbeginmp.mp_subst.(predi)<-cl;(* no aliasing problem here *)Stack.push{mpwithmp_stack=remains}pb_stackendelseifInt.equalmp.mp_subst.(predi)clthenStack.push{mpwithmp_stack=remains}pb_stackelse(* mismatch for non-linear variable in pattern *)()|PVar_->()(* do not consider application with variable head *)|PApp(f,[])->begintryletj=Termhash.finduf.symsfinifInt.equal(findufj)clthenStack.push{mpwithmp_stack=remains}pb_stackwithNot_found->()end|PApp(f,((last_arg::rem_args)asargs))->tryletj=Termhash.finduf.symsfinletpaf={fsym=j;fnargs=List.lengthargs}inletrep=get_representativeufclinletgood_terms=PafMap.findpafrep.functionsinletauxi=let(s,t)=signaturestate.ufiinStack.push{mpwithmp_subst=Array.copymp.mp_subst;mp_stack=(PApp(f,rem_args),s)::(last_arg,t)::remains}pb_stackinInt.Set.iterauxgood_termswithNot_found->()letpaf_of_pattsyms=functionPVar_->invalid_arg"paf_of_patt: pattern with variable head"|PApp(f,args)->{fsym=Termhash.findsymsf;fnargs=List.lengthargs}letinit_pb_stackstate=letsyms=state.uf.symsinletpb_stack=Stack.create()inletfuntab=make_fun_tablestateinletauxinst=beginletgood_classes=matchinst.qe_lhs_validwithCreates_variables->Int.Set.empty|Normal->begintryletpaf=paf_of_pattsymsinst.qe_lhsinPafMap.findpaffuntabwithNot_found->Int.Set.emptyend|Trivialtyp->begintryTypehash.findstate.by_typetypwithNot_found->Int.Set.emptyendinInt.Set.iter(funi->Stack.push{mp_subst=Array.makeinst.qe_nvars(-1);mp_inst=inst;mp_stack=[inst.qe_lhs,i]}pb_stack)good_classesend;beginletgood_classes=matchinst.qe_rhs_validwithCreates_variables->Int.Set.empty|Normal->begintryletpaf=paf_of_pattsymsinst.qe_rhsinPafMap.findpaffuntabwithNot_found->Int.Set.emptyend|Trivialtyp->begintryTypehash.findstate.by_typetypwithNot_found->Int.Set.emptyendinInt.Set.iter(funi->Stack.push{mp_subst=Array.makeinst.qe_nvars(-1);mp_inst=inst;mp_stack=[inst.qe_rhs,i]}pb_stack)good_classesendinList.iterauxstate.quant;pb_stackletfind_instancesstate=letpb_stack=init_pb_stackstateinletres=ref[]inlet_=debug_congruence(fun()->str"Running E-matching algorithm ... ");trywhiletruedoControl.check_for_interrupt();do_matchstaterespb_stackdone;anomaly(Pp.str"get out of here!")withStack.Empty->()in!resletbuild_term_to_completeufpac=letopenEConstrinletcinfo=get_constructor_infoufpac.cnodeinletreal_args=List.rev_map(funi->EConstr.of_constr(ATerm.constr(atermufi)))pac.argsinlet(kn,u)=cinfo.ci_constrin(applist(mkConstructU(kn,EInstance.makeu),real_args),pac.arity)letterms_to_completestate=letuf=foreststateinList.map(build_term_to_completeuf)(epsilonsuf)letrecexecutefirst_runstate=debug_congruence(fun()->str"Executing ... ");trywhileControl.check_for_interrupt();one_stepstatedo()done;matchcheck_disequalitiesstatewithNone->ifnot(Int.Set.is_emptystate.pa_classes)thenbegindebug_congruence(fun()->str"First run was incomplete, completing ... ");completestate;executefalsestateendelseifstate.rew_depth>0thenletl=find_instancesstateinList.iter(add_inststate)l;ifstate.changedthenbeginstate.changed<-false;executetruestateendelsebegindebug_congruence(fun()->str"Out of instances ... ");Noneendelsebegindebug_congruence(fun()->str"Out of depth ... ");Noneend|Somedis->Somebeginiffirst_runthenContradictiondiselseIncomplete(terms_to_completestate)endwithDiscriminable(s,spac,t,tpac)->Somebeginiffirst_runthenDiscrimination(s,spac,t,tpac)elseIncomplete(terms_to_completestate)end