123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303(************************************************************************)(* * 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) *)(************************************************************************)(* Generic dnet implementation over non-recursive types *)moduletypeDatatype=sigtype'atvalmap:('a->'b)->'at->'btvalmap2:('a->'b->'c)->'at->'bt->'ctvalfold:('a->'b->'a)->'a->'bt->'avalfold2:('a->'b->'c->'a)->'a->'bt->'ct->'avalcompare:unitt->unitt->intvalterminal:'at->boolvalchoose:('a->'b)->'at->'bendmoduletypeS=sigtypettypeidenttypemetatype'astructuremoduleIdset:Set.Swithtypeelt=identtypeterm_pattern=|Termofterm_patternstructure|Metaofmetavalempty:tvaladd:t->term_pattern->ident->tvalfind_all:t->Idset.tvalfold_pattern:('a->(Idset.t*meta*t)->'a)->'a->term_pattern->t->Idset.toption*'avalfind_match:term_pattern->t->Idset.tvalinter:t->t->tvalunion:t->t->tvalmap:(ident->ident)->(unitstructure->unitstructure)->t->tvalmap_metas:(meta->meta)->t->tendmoduleMake=functor(T:Datatype)->functor(Ident:Set.OrderedType)->functor(Meta:Set.OrderedType)->structtypeident=Ident.ttypemeta=Meta.ttype'astructure='aT.ttypeterm_pattern=|Termofterm_patternstructure|MetaofmetamoduleIdset=Set.Make(Ident)moduleMmap=Map.Make(Meta)moduleTmap=Map.Make(structtypet=unitstructureletcompare=T.compareend)typeidset=Idset.t(* we store identifiers at the leaf of the dnet *)typenode=|Nodeoftstructure|Terminaloftstructure*idset(* at each node, we have a bunch of nodes (actually a map between
the bare node and a subnet) and a bunch of metavariables *)andt=NodesofnodeTmap.t*idsetMmap.tletempty:t=Nodes(Tmap.empty,Mmap.empty)(* the head of a data is of type unit structure *)letheadw=T.map(func->())w(* given a node of the net and a word, returns the subnet with the
same head as the word (with the rest of the nodes) *)letsplitl(w:'astructure):node*nodeTmap.t=letelt:node=Tmap.find(headw)lin(elt,Tmap.remove(headw)l)letselectlw=Tmap.find(headw)lletrecadd(Nodes(t,m):t)(w:term_pattern)(id:ident):t=matchwwithTermw->(trylet(n,tl)=splittwinletnew_node=matchnwith|Terminal(e,is)->Terminal(e,Idset.addidis)|Nodee->Node(T.map2(funtp->addtpid)ew)inNodes((Tmap.add(headw)new_nodetl),m)withNot_found->letnew_content=T.map(funp->addemptypid)winletnew_node=ifT.terminalwthenTerminal(new_content,Idset.singletonid)elseNodenew_contentinNodes((Tmap.add(headw)new_nodet),m))|Metai->letm=tryMmap.addi(Idset.addid(Mmap.findim))mwithNot_found->Mmap.addi(Idset.singletonid)minNodes(t,m)letaddtwid=addtwidletrecfind_all(Nodes(t,m)):idset=Idset.union(Mmap.fold(fun_->Idset.union)mIdset.empty)(Tmap.fold(fun_nacc->lets2=matchnwith|Terminal(_,is)->is|Nodee->T.choosefind_alleinIdset.unionaccs2)tIdset.empty)(* (\* optimization hack: Not_found is caught in fold_pattern *\) *)(* let fast_inter s1 s2 = *)(* if Idset.is_empty s1 || Idset.is_empty s2 then raise Not_found *)(* else Idset.inter s1 s2 *)(* let option_any2 f s1 s2 = match s1,s2 with *)(* | Some s1, Some s2 -> f s1 s2 *)(* | (Some s, _ | _, Some s) -> s *)(* | _ -> raise Not_found *)(* let fold_pattern ?(complete=true) f acc pat dn = *)(* let deferred = ref [] in *)(* let leafs,metas = ref None, ref None in *)(* let leaf s = leafs := match !leafs with *)(* | None -> Some s *)(* | Some s' -> Some (fast_inter s s') in *)(* let meta s = metas := match !metas with *)(* | None -> Some s *)(* | Some s' -> Some (Idset.union s s') in *)(* let defer c = deferred := c::!deferred in *)(* let rec fp_rec (p:term_pattern) (Nodes(t,m) as dn:t) = *)(* Mmap.iter (fun _ -> meta) m; (\* TODO: gérer patterns nonlin ici *\) *)(* match p with *)(* | Meta m -> defer (m,dn) *)(* | Term w -> *)(* try match select t w with *)(* | Terminal (_,is) -> leaf is *)(* | Node e -> *)(* if complete then T.fold2 (fun _ -> fp_rec) () w e else *)(* if T.fold2 *)(* (fun b p dn -> match p with *)(* | Term _ -> fp_rec p dn; false *)(* | Meta _ -> b *)(* ) true w e *)(* then T.choose (T.choose fp_rec w) e *)(* with Not_found -> *)(* if Mmap.is_empty m then raise Not_found else () *)(* in try *)(* fp_rec pat dn; *)(* (try Some (option_any2 Idset.union !leafs !metas) with Not_found -> None), *)(* List.fold_left (fun acc (m,dn) -> f m dn acc) acc !deferred *)(* with Not_found -> None,acc *)(* Sets with a neutral element for inter *)moduleOSet(S:Set.S)=structtypet=S.toptionletunions1s2:t=matchs1,s2with|(None,_|_,None)->None|Somea,Someb->Some(S.unionab)letinters1s2:t=matchs1,s2with|(None,a|a,None)->a|Somea,Someb->Some(S.interab)letis_empty:t->bool=function|None->false|Somes->S.is_emptys(* optimization hack: Not_found is caught in fold_pattern *)letfast_inters1s2=ifis_emptys1||is_emptys2thenraiseNot_foundelseletr=inters1s2inifis_emptyrthenraiseNot_foundelserletfull=Noneletempty=SomeS.emptyendmoduleOIdset=OSet(Idset)letfold_pattern?(complete=true)faccpatdn=letdeferred=ref[]inletdeferc=deferred:=c::!deferredinletrecfp_recmetasp(Nodes(t,m)asdn:t)=(* TODO gérer les dnets non-linéaires *)letmetas=Mmap.fold(fun_->Idset.union)mmetasinmatchpwith|Metam->defer(metas,m,dn);OIdset.full|Termw->letcurm=Mmap.fold(fun_->Idset.union)mIdset.emptyintrymatchselecttwwith|Terminal(_,is)->Some(Idset.unioncurmis)|Nodee->letids=ifcompletethenT.fold2(funaccwe->OIdset.fast_interacc(fp_recmetaswe))OIdset.fullweelselet(all_metas,res)=T.fold2(fun(b,acc)we->matchwwith|Term_->false,OIdset.fast_interacc(fp_recmetaswe)|Meta_->b,acc)(true,OIdset.full)weinifall_metasthenT.choose(T.choose(fp_recmetas)w)eelseresinOIdset.unionids(Somecurm)withNot_found->ifIdset.is_emptymetasthenraiseNot_foundelseSomecurminletcand=tryfp_recIdset.emptypatdnwithNot_found->OIdset.emptyinletres=List.fold_leftfacc!deferredincand,res(* intersection of two dnets. keep only the common pairs *)letrecinter(t1:t)(t2:t):t=letinter_mapf(Nodes(t1,m1):t)(Nodes(t2,m2):t):t=Nodes(Tmap.fold(funkeacc->tryTmap.addk(fe(Tmap.findkt2))accwithNot_found->acc)t1Tmap.empty,Mmap.fold(funmsacc->tryMmap.addm(Idset.inters(Mmap.findmm2))accwithNot_found->acc)m1Mmap.empty)ininter_map(funn1n2->matchn1,n2with|Terminal(e1,s1),Terminal(_,s2)->Terminal(e1,Idset.inters1s2)|Nodee1,Nodee2->Node(T.map2intere1e2)|_->assertfalse)t1t2letrecunion(t1:t)(t2:t):t=letunion_mapf(Nodes(t1,m1):t)(Nodes(t2,m2):t):t=Nodes(Tmap.fold(funkeacc->tryTmap.addk(fe(Tmap.findkacc))accwithNot_found->Tmap.addkeacc)t1t2,Mmap.fold(funmsacc->tryMmap.addm(Idset.inters(Mmap.findmacc))accwithNot_found->Mmap.addmsacc)m1m2)inunion_map(funn1n2->matchn1,n2with|Terminal(e1,s1),Terminal(_,s2)->Terminal(e1,Idset.unions1s2)|Nodee1,Nodee2->Node(T.map2unione1e2)|_->assertfalse)t1t2letfind_match(p:term_pattern)(t:t):idset=letmetas=refMmap.emptyinlet(mset,lset)=fold_pattern~complete:false(funacc(mset,m,t)->letall=OIdset.fast_interacc(Some(lett=tryintert(Mmap.findm!metas)withNot_found->tinmetas:=Mmap.addmt!metas;find_allt))inOIdset.union(Somemset)all)NoneptinOption.get(OIdset.intermsetlset)letfold_patternfaccpdn=fold_pattern~complete:truefaccpdnletidset_mapfis=Idset.fold(funeacc->Idset.add(fe)acc)isIdset.emptylettmap_mapfgm=Tmap.fold(funkeacc->Tmap.add(fk)(ge)acc)mTmap.emptyletrecmapsidsetsterm(Nodes(t,m)):t=letsnode=function|Terminal(e,is)->Terminal(e,idset_mapsidsetis)|Nodee->Node(T.map(mapsidsetsterm)e)inNodes(tmap_mapstermsnodet,Mmap.map(idset_mapsidset)m)letrecmap_metasf(Nodes(t,m)):t=letf_node=function|Terminal(e,is)->Terminal(T.map(map_metasf)e,is)|Nodee->Node(T.map(map_metasf)e)inletm'=Mmap.fold(funmsacc->Mmap.add(fm)sacc)mMmap.emptyinlett'=Tmap.fold(funknacc->Tmap.addk(f_noden)acc)tTmap.emptyinNodes(t',m')end