123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Perfect Discrimination Tree} *)moduleST=InnerTermmoduleT=TermmoduleS=Substletprof_dtree_retrieve=ZProf.make"dtree_retrieve"(** {2 Term traversal}
Term traversal in prefix order. This is akin to lazy transformation
to a flatterm. *)typecharacter=|SymbolofID.t|VariableofType.tHVar.t|SubtermofT.t(* opaque term, just do matching *)typeiterator={cur_char:character;cur_term:T.t;stack:T.tlistlist;(* skip: drop head, next: first of head *)stack_len:int;}let[@inline]char_to_int_=function|Symbol_->0|Variable_->2|Subterm_->3letcompare_charc1c2=(* compare variables by index *)letcompare_varsv1v2=letc=HVar.compareType.comparev1v2inifc=0thenType.compare(HVar.tyv1)(HVar.tyv2)elsecinmatchc1,c2with|Symbols1,Symbols2->ID.compares1s2|Variablev1,Variablev2->compare_varsv1v2|Subtermt1,Subtermt2->T.comparet1t2|_->Pervasives.compare(char_to_int_c1)(char_to_int_c2)let[@inline]eq_charc1c2=compare_charc1c2=0(** first symbol of t, or variable *)letterm_to_char(t:T.t):character*T.tlist=matchST.view(t:>ST.t)with|ST.Varv->Variable(Type.cast_var_unsafev),[]|_whenType.is_fun(T.tyt)->Subtermt,[](* partial app *)|ST.Consts->Symbols,[]|ST.App(f,l)->beginmatchST.viewfwith|ST.Consts->Symbols,(T.of_term_unsafe_ll)|_->Subtermt,[]end|ST.AppBuiltin_|ST.DB_|ST.Bind_->Subtermt,[]letpp_charout=function|Variablev->Type.pp_typed_varoutv|Symbolf->ID.ppoutf|Subtermt->CCFormat.hboxT.ppoutt(* parameter: maximum depth before we start using {!Subterm} *)letmax_depth_=ref3letopen_term~stack~lent=iflen>!max_depth_then((* opaque. Do not enter the term. *)letcur_char=Subtermtin{cur_char;cur_term=t;stack=[]::stack;stack_len=len+1})else(letcur_char,l=term_to_chartin{cur_char;cur_term=t;stack=l::stack;stack_len=len+1})letrecnext_recstacklen=matchstackwith|[]->None|[]::stack'->next_recstack'(len-1)|(t::next')::stack'->Some(open_term~stack:(next'::stack')~lent)letskipiter=matchiter.stackwith|[]->None|_next::stack'->next_recstack'(iter.stack_len-1)let[@inline]nextiter=next_reciter.stackiter.stack_len(* Iterate on a term *)let[@inline]iterateterm=Some(open_term~stack:[]~len:0term)(* convert term to list of var/symbol *)letto_listt:_list=letrecgetnextacciter:_list=letacc'=iter.cur_char::accinmatchnextiterwith|None->List.revacc'|Someiter'->getnextacc'iter'inmatchiteratetwith|None->assertfalse|Somei->getnext[]imoduleCharMap=CCMap.Make(structtypet=characterletcompare=compare_charend)(** {2 Discrimination tree} *)moduleMake(E:Index.EQUATION)=structmoduleE=Etyperhs=E.rhstypetrie={map:trieCharMap.t;(** map atom -> trie *)leaf:(T.t*E.t*int)list;(** leaf with (term, value, priority) list *)}(* The discrimination tree *)letempty_trie={map=CharMap.empty;leaf=[]}letis_emptyn=n.leaf=[]&&CharMap.is_emptyn.map(** get/add/remove the leaf for the given flatterm. The
continuation k takes the leaf, and returns a leaf option
that replaces the old leaf.
This function returns the new trie. *)letgoto_leaftrietk=(* the root of the tree *)letroot=triein(* function to go to the given leaf, building it if needed *)letrecgototrietrebuild=matchtwith|[]->(* look at leaf *)beginmatchktrie.leafwith|new_leafwhentrie.leaf==new_leaf->root(* no change, return same tree *)|new_leaf->rebuild{triewithleaf=new_leaf}(* replace by new leaf *)end|c::t'->beginmatchCharMap.getctrie.mapwith|Somesubtrie->letrebuild'subtrie=matchsubtriewith|_whenis_emptysubtrie->rebuild{triewithmap=CharMap.removectrie.map}|_->rebuild{triewithmap=CharMap.addcsubtrietrie.map}ingotosubtriet'rebuild'|None->letsubtrie=empty_trieinletrebuild'subtrie=matchsubtriewith|_whenis_emptysubtrie->root(* same tree *)|_->rebuild{triewithmap=CharMap.addcsubtrietrie.map}ingotosubtriet'rebuild'endingototriet(funt->t)typet=trieletempty()=empty_trieletadddteqn=lett,_,_=E.extracteqninletpriority=E.priorityeqninletchars=to_listtinletkl=letl'=(t,eqn,priority)::linList.stable_sort(fun(_,_,p1)(_,_,p2)->p1-p2)l'(* TODO: linear-time insertion into a sorted list *)inlettree=goto_leafdtcharskintreeletremovedteqn=lett,_,_=E.extracteqninletchars=to_listtinletkl=(* remove tuples that match *)List.filter(fun(t',eqn',_)->t'!=t||E.compareeqneqn'<>0)linlettree=goto_leafdtcharskintreeletadd_seq=Iter.foldaddletadd_list=List.fold_leftaddletremove_seqdtseq=Iter.foldremovedtseqletretrieve?(subst=S.empty)~signdttk=ZProf.enter_profprof_dtree_retrieve;(* recursive traversal of the trie, following paths compatible with t *)letrectraversetrieitersubst=matchiterwith|None->(* yield all equations, they all match *)List.iter(fun(_,eqn,_)->letl,r,sign'=E.extracteqninifsign=sign'thenk(l,r,eqn,subst))trie.leaf|Somei->(* "lazy" transformation to flatterm *)lett_pos=i.cur_terminletc1=i.cur_charinCharMap.iter(func2subtrie->matchc2with|Variablev2->(* deal with the variable branche in the trie *)beginmatchS.FO.get_varsubst(Scoped.setdt(v2:>ST.tHVar.t))with|None->(* not bound: try to match types + bind, then continue *)begintryletsubst=Unif.Ty.matching~subst~pattern:(Scoped.setdt(HVar.tyv2))(Scoped.sett(T.tyt_pos))inletsubst=Unif.FO.bind~check:falsesubst(Scoped.setdtv2)(Scoped.settt_pos)intraversesubtrie(skipi)substwithUnif.Fail->()(* incompatible binding, or occur check *)end|Somet'->(* already bound, check consistency *)ifUnif.FO.equal~subst(Scoped.settt_pos)t'thentraversesubtrie(skipi)substend|Subtermt2->(* fallback to matching *)begintryletsubst=Unif.FO.matching~subst~pattern:(Scoped.setdtt2)(Scoped.settt_pos)intraversesubtrie(skipi)substwithUnif.Fail->()end|_wheneq_charc2c1->(* explore branch that has the same symbol, if any *)assert(not(T.is_vart_pos));traversesubtrie(nexti)subst;|_->())trie.mapintraverse(fstdt)(iterate(fstt))subst;ZProf.exit_profprof_dtree_retrieve;()(** iterate on all (term -> value) in the tree *)letiterdtk=letrecitertrie=List.iter(fun(t,v,_)->ktv)trie.leaf;CharMap.iter(fun_sub_dt->itersub_dt)trie.mapiniterdtletsizedt=letn=ref0initerdt(fun__->incrn);!nlet_as_graph=CCGraph.make(funtrie->CharMap.to_itertrie.map)(* TODO: print leaf itself *)letrecequal_ab=a==b||(a.leaf==b.leaf&&CharMap.equalequal_a.mapb.map)letto_dotoutt=Util.debugf2"@[<2>print graph of size %d@]"(funk->k(sizet));letpp=CCGraph.Dot.pp~eq:equal_~tbl:(CCGraph.mk_table~eq:equal_~hash:Hashtbl.hash128)~attrs_v:(funtrie->letshape=ifCharMap.is_emptytrie.mapthen"box"else"circle"inletlen=List.lengthtrie.leafin[`Shapeshape;`Label(string_of_intlen)])~attrs_e:(fune->lete=CCFormat.to_stringpp_charein[`Labele])~name:"NPDtree"~graph:_as_graphinFormat.fprintfout"@[<2>%a@]@."ppt;endmoduleDefault=Make(Index.BasicEquation)let()=Options.add_opts["--dtree-max-depth",Arg.Set_intmax_depth_," set maximal depth of terms for Dtree (demodulation)"]