Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file discrimination_tree.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235(* elpi: embedded lambda prolog interpreter *)(* license: GNU Lesser General Public License Version 2.1 or later *)(* ------------------------------------------------------------------------- *)letarity_bits=4letk_bits=2(* 4 constructors encoded as: arg_value , arity, kno *)letkConstant=0letkPrimitive=1letkVariable=2letkOther=3letk_lshift=Sys.int_size-k_bitsletka_lshift=Sys.int_size-k_bits-arity_bitsletk_mask=((1lslk_bits)-1)lslk_lshiftletarity_mask=(((1lslarity_bits)lslk_bits)-1)lslka_lshiftletdata_mask=(1lslka_lshift)-1letencodekca=(klslk_lshift)lor(alslka_lshift)lor(clanddata_mask)letk_ofn=(nlandk_mask)lsrk_lshiftletarity_ofn=letk=k_ofninifk==kConstantthen(nlandarity_mask)lsrka_lshiftelse0letmkConstant~safeca=letrc=encodekConstantcainifsafe&&(absc>data_mask||a>=1lslarity_bits)thenElpi_util.Util.anomaly(Printf.sprintf"Indexing at depth > 1 is unsupported since constant %d/%d is too large or wide"ca);rcletmkVariable=encodekVariable00letmkOther=encodekOther00letmkPrimitivec=encodekPrimitive(Elpi_util.Util.CData.hashclslk_bits)0letmkInputMode=encodekOther10letmkOutputMode=encodekOther20let()=assert(k_of(mkConstant~safe:false~-170)==kConstant)let()=assert(k_ofmkVariable==kVariable)let()=assert(k_ofmkOther==kOther)letisVariablex=x==mkVariableletisOtherx=x==mkOtherletisInputx=x==mkInputModeletisOutputx=x==mkOutputModetypecell=intletpp_cellfmtn=letk=k_ofninifk==kConstantthenletdata=data_masklandninletarity=(arity_masklandn)lsrka_lshiftinFormat.fprintffmt"Constant(%d,%d)"dataarityelseifk==kVariablethenFormat.fprintffmt"Variable"elseifk==kOtherthenifisInputnthenFormat.fprintffmt"Input"elseifisOutputnthenFormat.fprintffmt"Output"elseFormat.fprintffmt"Other"elseifk==kPrimitivethenFormat.fprintffmt"Primitive"elseFormat.fprintffmt"%o"kletshow_celln=Format.asprintf"%a"pp_cellnmoduleTrie=struct(*
* Trie: maps over lists.
* Note: This code is a heavily modified version of the original code.
* Copyright (C) 2000 Jean-Christophe FILLIATRE
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2, as published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Library General Public License version 2 for more details
* (enclosed in the file LGPL).
*)(*s A trie is a tree-like structure to implement dictionaries over
keys which have list-like structures. The idea is that each node
branches on an element of the list and stores the value associated
to the path from the root, if any. Therefore, a trie can be
defined as soon as a map over the elements of the list is
given. *)(*s Then a trie is just a tree-like structure, where a possible
information is stored at the node (['a option]) and where the sons
are given by a map from type [key] to sub-tries, so of type
['a t Ptmap.t]. The empty trie is just the empty map. *)typekey=intlisttype'at=Nodeof{data:'alist;other:'atoption;map:'atPtmap.t}letempty=Node{data=[];other=None;map=Ptmap.empty}(*s To find a mapping in a trie is easy: when all the elements of the
key have been read, we just inspect the optional info at the
current node; otherwise, we descend in the appropriate sub-trie
using [Ptmap.find]. *)letrecfindlt=match(l,t)with|[],Node{data=[]}->raiseNot_found|[],Node{data}->data|x::r,Node{map}->findr(Ptmap.findxmap)letmemlt=tryFun.consttrue(findlt)withNot_found->false(*s Insertion is more subtle. When the final node is reached, we just
put the information ([Some v]). Otherwise, we have to insert the
binding in the appropriate sub-trie [t']. But it may not exists,
and in that case [t'] is bound to an empty trie. Then we get a new
sub-trie [t''] by a recursive insertion and we modify the
branching, so that it now points to [t''], with [Ptmap.add]. *)letaddlvt=letrecins=function|[],Node({data}ast)->Node{twithdata=v::data}|x::r,Node({other}ast)whenisVariablex||isOtherx->lett'=matchotherwithNone->empty|Somex->xinlett''=ins(r,t')inNode{twithother=Somet''}|x::r,Node({map}ast)->lett'=tryPtmap.findxmapwithNot_found->emptyinlett''=ins(r,t')inNode{twithmap=Ptmap.addxt''map}inins(l,t)letrecpp(ppelem:Format.formatter->'a->unit)(fmt:Format.formatter)(Node{data;other;map}:'at):unit=Format.fprintffmt"[values:{";Elpi_util.Util.pplistppelem"; "fmtdata;Format.fprintffmt"} other:{";(matchotherwithNone->()|Somem->ppppelemfmtm);Format.fprintffmt"} key:{";Ptmap.to_listmap|>Elpi_util.Util.pplist(funfmt(k,v)->pp_cellfmtk;ppppelemfmtv)"; "fmt;Format.fprintffmt"}]"letshow(fmt:Format.formatter->'a->unit)(n:'at):string=letb=Buffer.create22inFormat.fprintf(Format.formatter_of_bufferb)"@[%a@]"(ppfmt)n;Buffer.contentsbendtypepath=celllist[@@derivingshow]letcomparexy=x-yletskip(path:path):path=letrecauxaritypath=ifarity=0thenpathelsematchpathwith[]->assertfalse|m::tl->aux(arity-1+arity_ofm)tlinmatchpathwith|[]->Elpi_util.Util.anomaly"Skipping empty path is not possible"|hd::tl->aux(arity_ofhd)tltype'at=('a*int)Trie.tletpppp_afmt(t:'at):unit=Trie.pp(funfmt(a,_)->pp_afmta)fmttletshowpp_a(t:'at):string=Trie.show(funfmt(a,_)->pp_afmta)tletempty=Trie.emptyletindextreepsinfo~time=Trie.addps(info,time)treeletin_indextreepstest=tryletps_set=Trie.findpstreeinList.exists(fun(x,_)->testx)ps_setwithNot_found->false(* the equivalent of skip, but on the index, thus the list of trees
that are rooted just after the term represented by the tree root
are returned (we are skipping the root) *)letall_childrenothermap=letrecgetn=function|Trie.Node{other=None;map}astree->ifn=0then[tree]elsePtmap.fold(funkvres->get(n-1+arity_ofk)v@res)map[]|Trie.Node{other=Someother;map}astree->ifn=0then[tree;other]elsePtmap.fold(funkvres->get(n-1+arity_ofk)v@res)map[other]inPtmap.fold(funkvres->get(arity_ofk)v@res)map(matchotherwithSomex->[x]|None->[])(* NOTE: l1 and l2 are supposed to be sorted *)letrecmerge(l1:('a*int)list)l2=match(l1,l2)with|[],l|l,[]->l|((_,tx)asx)::xs,(_,ty)::_whentx>ty->x::mergexsl2|_,y::ys->y::mergel1ysletget_all_childrenvmode=isOtherv||(isVariablev&&isOutputmode)(* get_all_children returns if a key should be unified with all the values of
the current sub-tree. This key should be either K.to_unfy or K.variable.
In the latter case, the mode boolean to be true (we are in output mode). *)letrecretrieve_aux(mode:cell)path=function|[]->[]|hd::tl->merge(retrievemodepathhd)(retrieve_auxmodepathtl)andretrievemodepathtree=match(tree,path)with|Trie.Node{data},[]->data|node,hd::tlwhenisInputhd||isOutputhd->retrievehdtltree|Trie.Node{other;map},v::pathwhenget_all_childrenvmode->retrieve_auxmodepath(all_childrenothermap)|Trie.Node{other=None;map},node::sub_path->ifisInputmode&&isVariablenodethen[]elseletsubtree=tryPtmap.findnodemapwithNot_found->Trie.emptyinretrievemodesub_pathsubtree|Trie.Node{other=Someother;map},(node::sub_pathaspath)->merge(ifisInputmode&&isVariablenodethen[]elseletsubtree=tryPtmap.findnodemapwithNot_found->Trie.emptyinretrievemodesub_pathsubtree)(retrievemode(skippath)other)letretrievepathindex=matchpathwith|[]->Elpi_util.Util.anomaly"A path should at least of length 2"|mode::tl->retrievemodetlindex|>List.mapfst