123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140(************************************************************************)(* * 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 module is a very simple implementation of "segment trees".
A segment tree of type ['a t] represents a mapping from a union of
disjoint segments to some values of type 'a.
*)(** Misc. functions. *)letlist_iterifl=letrecloopi=function|[]->()|x::xs->fix;loop(i+1)xsinloop0lletlog2x=logx/.log2.letlog2nx=int_of_float(ceil(log2(float_of_intx)))(** We focus on integers but this module can be generalized. *)typeelt=int(** A value of type [domain] is interpreted differently given its position
in the tree. On internal nodes, a domain represents the set of
integers which are _not_ in the set of keys handled by the tree. On
leaves, a domain represents the st of integers which are in the set of
keys. *)typedomain=|Intervalofelt*elt(** On internal nodes, a domain [Interval (a, b)] represents
the interval [a + 1; b - 1]. On leaves, it represents [a; b].
We always have [a] <= [b]. *)|Universe(** On internal node or root, a domain [Universe] represents all
the integers. When the tree is not a trivial root,
[Universe] has no interpretation on leaves. (The lookup
function should never reach the leaves.) *)(** We use an array to store the almost complete tree. This array
contains at least one element. *)type'at=(domain*'aoption)array(** The root is the first item of the array. *)(** Standard layout for left child. *)letleft_childi=2*i+1(** Standard layout for right child. *)letright_childi=2*i+2(** Extract the annotation of a node, be it internal or a leaf. *)letvalue_ofit=matcht.(i)with(_,Somex)->x|_->raiseNot_found(** Initialize the array to store [n] leaves. *)letcreateninit=Array.make(1lsl(log2nn+1)-1)init(** Make a complete interval tree from a list of disjoint segments.
Precondition : the segments must be sorted. *)letmakesegments=letnsegments=List.lengthsegmentsinlettree=creatensegments(Universe,None)inletleaves_offset=(1lsl(log2nnsegments))-1in(* The algorithm proceeds in two steps using an intermediate tree
to store minimum and maximum of each subtree as annotation of
the node. *)(* We start from leaves: the last level of the tree is initialized
with the given segments... *)list_iteri(funi((start,stop),value)->letk=leaves_offset+iinleti=Interval(start,stop)intree.(k)<-(i,Somei))segments;(* ... the remaining leaves are initialized with neutral information. *)fork=leaves_offset+nsegmentstoArray.lengthtree-1dotree.(k)<-(Universe,SomeUniverse)done;(* We traverse the tree bottom-up and compute the interval and
annotation associated to each node from the annotations of its
children. *)fork=leaves_offset-1downto0doletnode,annotation=matchvalue_of(left_childk)tree,value_of(right_childk)treewith|Interval(left_min,left_max),Interval(right_min,right_max)->(Interval(left_max,right_min),Interval(left_min,right_max))|Interval(min,max),Universe->(Interval(max,max),Interval(min,max))|Universe,Universe->Universe,Universe|Universe,_->assertfalseintree.(k)<-(node,Someannotation)done;(* Finally, annotation are replaced with the image related to each leaf. *)letfinal_tree=Array.mapi(funi(segment,value)->(segment,None))treeinlist_iteri(funi((start,stop),value)->final_tree.(leaves_offset+i)<-(Interval(start,stop),Somevalue))segments;final_tree(** [lookup k t] looks for an image for key [k] in the interval tree [t].
Raise [Not_found] if it fails. *)letlookupkt=leti=ref0inwhile(sndt.(!i)=None)domatchfstt.(!i)with|Interval(start,stop)->ifk<=starttheni:=left_child!ielseifk>=stoptheni:=right_child!ielseraiseNot_found|Universe->raiseNot_founddone;matchfstt.(!i)with|Interval(start,stop)->ifk>=start&&k<=stopthenmatchsndt.(!i)with|Somev->v|None->assertfalseelseraiseNot_found|Universe->assertfalse