(******************************************************************************) (* SXSI : XPath evaluator *) (* Kim Nguyen (Kim.Nguyen@nicta.com.au) *) (* Copyright NICTA 2008 *) (* Distributed under the terms of the LGPL (see LICENCE) *) (******************************************************************************) INCLUDE "utils.ml" exception InfiniteSet module type S = sig type elt type t type set val empty : t val any : t val is_empty : t -> bool val is_any : t -> bool val is_finite : t -> bool val kind : t -> [ `Finite | `Cofinite ] val singleton : elt -> t val mem : elt -> t -> bool val add : elt -> t -> t val remove : elt -> t -> t val cup : t -> t -> t val cap : t -> t -> t val diff : t -> t -> t val neg : t -> t val compare : t -> t -> int val subset : t -> t -> bool val kind_split : t list -> t * t val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a val for_all : (elt -> bool) -> t -> bool val exists : (elt -> bool) -> t -> bool val filter : (elt -> bool) -> t -> t val partition : (elt -> bool) -> t -> t * t val cardinal : t -> int val elements : t -> elt list val from_list : elt list -> t val choose : t -> elt val hash : t -> int val equal : t -> t -> bool val uid : t -> Uid.t val positive : t -> set val negative : t -> set val inj_positive : set -> t val inj_negative : set -> t end module Make (E : Ptset.S) : S with type elt = E.elt and type set = E.t = struct type elt = E.elt type node = Finite of E.t | CoFinite of E.t type set = E.t module Node = Hcons.Make(struct type t = node let equal a b = match a,b with (Finite(s1),Finite(s2)) | (CoFinite(s1),CoFinite(s2)) -> E.equal s1 s2 | _ -> false let hash = function Finite (s) -> (E.hash s) lsl 1 | CoFinite(s) -> ((E.hash s) lsl 1 ) + 1 end) type t = Node.t let empty = Node.make (Finite E.empty) let any = Node.make (CoFinite E.empty) let finite x = Node.make (Finite x) let cofinite x = Node.make (CoFinite x) let is_empty = function { Node.node = Finite s } when E.is_empty s -> true | _ -> false let is_any = function { Node.node = CoFinite s } when E.is_empty s -> true | _ -> false let is_finite t = match t.Node.node with | Finite _ -> true | _ -> false let kind t = match t.Node.node with Finite _ -> `Finite | _ -> `Cofinite let mem x t = match t.Node.node with | Finite s -> E.mem x s | CoFinite s -> not (E.mem x s) let singleton x = finite (E.singleton x) let add e t = match t.Node.node with | Finite s -> finite (E.add e s) | CoFinite s -> cofinite (E.remove e s) let remove e t = match t.Node.node with | Finite s -> finite (E.remove e s) | CoFinite s -> cofinite (E.add e s) let cup s t = match (s.Node.node,t.Node.node) with | Finite s, Finite t -> finite (E.union s t) | CoFinite s, CoFinite t -> cofinite ( E.inter s t) | Finite s, CoFinite t -> cofinite (E.diff t s) | CoFinite s, Finite t-> cofinite (E.diff s t) let cap s t = match (s.Node.node,t.Node.node) with | Finite s, Finite t -> finite (E.inter s t) | CoFinite s, CoFinite t -> cofinite (E.union s t) | Finite s, CoFinite t -> finite (E.diff s t) | CoFinite s, Finite t-> finite (E.diff t s) let diff s t = match (s.Node.node,t.Node.node) with | Finite s, Finite t -> finite (E.diff s t) | Finite s, CoFinite t -> finite(E.inter s t) | CoFinite s, Finite t -> cofinite(E.union t s) | CoFinite s, CoFinite t -> finite (E.diff t s) let neg t = match t.Node.node with | Finite s -> cofinite s | CoFinite s -> finite s let compare s t = match (s.Node.node,t.Node.node) with | Finite s , Finite t -> E.compare s t | CoFinite s , CoFinite t -> E.compare t s | Finite _, CoFinite _ -> -1 | CoFinite _, Finite _ -> 1 let subset s t = match (s.Node.node,t.Node.node) with | Finite s , Finite t -> E.subset s t | CoFinite s , CoFinite t -> E.subset t s | Finite s, CoFinite t -> E.is_empty (E.inter s t) | CoFinite _, Finite _ -> false (* given a list l of type t list, returns two sets (f,c) where : - f is the union of all the finite sets of l - c is the union of all the cofinite sets of l - f and c are disjoint Invariant : cup f c = List.fold_left cup empty l We treat the CoFinite part explicitely : *) let kind_split l = let rec next_finite_cofinite facc cacc = function | [] -> finite facc, cofinite (E.diff cacc facc) | { Node.node = Finite s } ::r -> next_finite_cofinite (E.union s facc) cacc r | { Node.node = CoFinite _ } ::r when E.is_empty cacc -> next_finite_cofinite facc cacc r | { Node.node = CoFinite s } ::r -> next_finite_cofinite facc (E.inter cacc s) r in let rec first_cofinite facc = function | [] -> empty,empty | { Node.node = Finite s } :: r-> first_cofinite (E.union s facc) r | { Node.node = CoFinite s } :: r -> next_finite_cofinite facc s r in first_cofinite E.empty l let fold f t a = match t.Node.node with | Finite s -> E.fold f s a | CoFinite _ -> raise InfiniteSet let for_all f t = match t.Node.node with | Finite s -> E.for_all f s | CoFinite _ -> raise InfiniteSet let exists f t = match t.Node.node with | Finite s -> E.exists f s | CoFinite _ -> raise InfiniteSet let filter f t = match t.Node.node with | Finite s -> finite (E.filter f s) | CoFinite _ -> raise InfiniteSet let partition f t = match t.Node.node with | Finite s -> let a,b = E.partition f s in finite a,finite b | CoFinite _ -> raise InfiniteSet let cardinal t = match t.Node.node with | Finite s -> E.cardinal s | CoFinite _ -> raise InfiniteSet let elements t = match t.Node.node with | Finite s -> E.elements s | CoFinite _ -> raise InfiniteSet let from_list l = finite (List.fold_left (fun x a -> E.add a x ) E.empty l) let choose t = match t.Node.node with Finite s -> E.choose s | _ -> raise InfiniteSet let equal = (==) let hash t = t.Node.key let uid t = t.Node.id let positive t = match t.Node.node with | Finite x -> x | _ -> E.empty let negative t = match t.Node.node with | CoFinite x -> x | _ -> E.empty let inj_positive t = finite t let inj_negative t = cofinite t end