VSL - The data.AA_map Structure

# Copyright 2011  Petter Urkedal
#
# This file is part of the Viz Standard Library <http://www.vizlang.org/>.
#
# The Viz Standard Library (VSL) is free software: you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# The VSL 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 Lesser General Public License for
# more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with the VSL.  If not, see <http://www.gnu.org/licenses/>.

open prelude.ubiquitous
open collection_sigs
open effect

sig S
    include an_ordered_map'.[elt α = α]

    val mapfold : (α × γ  β × γ)  t α × γ  t β × γ
    val is_valid : t α  bool
    val dump_tree : (index  α  io unit)  t α  io unit
    val find_ge : index  t α  option (index × elt α)
    val find_le : index  t α  option (index × elt α)

    in tagged
	include a_collection'.[t α = t α, elt α = index × elt α]
	val map : (elt α  elt β)  t α  t β
	val filter : (elt α  bool)  t α  t α
	val filter_map : (elt α  option (elt β))  t α  t β
	val min : t α  option (elt α)
	val max : t α  option (elt α)
	val pop_min : t α  option (elt α × t α)
	val pop_max : t α  option (elt α × t α)

    in scheme
	include a_collection'.[t α = t α, elt α = index]
	val eq : t α  t β  bool
	val subeq : t α  t β  bool
	val map : (index  index)  t α  t α
	val filter : (index  bool)  t α  t α
	val filter_map : (index  option index)  t α  t α
	val eq : t α  t β  bool
	val subeq : t α  t β  bool
	val min : t α  option index
	val max : t α  option index
	val min_ge : index  t α  option index
	val max_le : index  t α  option index
	val pop_min : t α  option (index × t α)
	val pop_max : t α  option (index × t α)
	val filter : (index  bool)  t α  t α
	val map : (index  index)  t α  t α
	val filter_map : (index  option index)  t α  t α

in make.(I : a_total_order) : S.[index = I.t] include where

# Based on "Balanced search trees made simple" by A. Andersson and on
# <http://en.wikipedia.org/wiki/AA_tree>, adapted for purity and avoiding some
# excessive skews and splits.

type index := I.t
type elt α := α

type t α
 inj O : t α
 inj Y : I.t  α  int  t α  t α  t α

type map α := t α

let is_valid
    at O% be true
    at Y% k d l tL tR
	be is_valid tL  is_valid tR
	  l = level tL + 1
	  l - 1  level tR  l
	  that tR which
	    at O% be l = 1
	    at Y% kR dR lR tA tB
		be l > level tB

let empty be O

let is_empty be O%  true; _  false

let singleton k d be Y k d 1 O O

let contains k'
    at O% be false
    at Y k d l tL tR taken I.cmp k' k
	at tprec% be contains k' tL
	at tsucc% be contains k' tR
	at tcoin% be true

let find k'
    at O% be none
    at Y k d l tL tR taken I.cmp k' k
	at tprec% be find k' tL
	at tsucc% be find k' tR
	at tcoin% be some d

let level at O% be 0
	  at Y _ _ l _ _ be l

#         *       *               *        *             T     | l + 1
#      L<-T  =>   L->T   or    L<-T->R =>  L->T->R =>  L   R   | l
#     A B  R     A  B R       A B         A  B        A B      | l - 1
let _skew
    at Y k d l (Y kL dL lL tA tB) tR if lL = l
	be _split (Y kL dL lL tA (Y k d l tB tR))
    at t be t

#      *              R     | l + 1
#      T->R->X  =>  T   X   | l
#     A  B         A B      | l - 1
let _split
    at Y k d l tA (Y kR dR lR tB tX) if l = level tX
	assert l = lR  # otherwise use _split_after_remove
	be Y kR dR (l + 1) (Y k d l tA tB) tX
    at t be t

# A variant of _split where the R node may already be at level (l + 1):
#                   *,->R        ,-R-.   | l + 1
#     as above or   T  B X  =>  T->B  X  | l
#                  A           A         | l - 1
# In this extra case, B may already have a horizontal link, so call _split,
# which may increase the level of T, so call _skew on the final result.
let _split_after_remove
    at Y k d l tA (Y kR dR lR tB tX)
	if l < lR be _skew (Y kR dR lR (_split (Y k d l tA tB)) tX)
	if l = level tX be Y kR dR (l + 1) (Y k d l tA tB) tX
    at t be t

# A variant of _skew where the left-hand node may have a horizontal link.
#         *       *                   *       *            | l + 1
#      L<-T  =>   L->T    or  [L->B]<-T   =>  L->[B<-T]    | l
#     A B  R     A  B R       A        R     A        R    | l - 1
# In the latter case, we need to _skew the [B<-T].  One time is enough since B
# cannot have a horizontal link due to the initial.  The result may increase
# the level, so _split the final result.
let _skew_after_remove
    at Y k d l (Y kL dL lL tA tB) tR if lL = l
	be _split (Y kL dL lL tA (_skew (Y k d l tB tR)))
    at t be t

let add k' d'
    at O% be Y k' d' 1 O O
    at Y k d l tL tR
	taken I.cmp k' k
	at tprec% be _skew (Y k d l (add k' d' tL) tR)
	at tsucc% be _split (Y k d l tL (add k' d' tR))
	at tcoin% be Y k' d' l tL tR

let _postrmL_Y k d l tL tR
  # Reconstruct after removing one element from tL.  The other arguments are
  # the original values from the Y-node.
    if l = level tL + 1 be Y k d l tL tR
    be _split_after_remove (Y k d (l - 1) tL tR)

let _postrmR_Y k d l tL tR
 ## Reconstruct after removing one element from tR.  The other arguments are
 ## the original values from the Y-node.
    if l  level tR + 1 be Y k d l tL tR
    be _skew_after_remove (Y k d (l - 1) tL tR)

let _tagged_min
    at O% be none
    at Y k d _ O% tR be some (k, d)
    at Y k d _ tL tR be _tagged_min tL

let _tagged_max
    at O% be none
    at Y k d _ tL O% be some (k, d)
    at Y k d _ tL tR be _tagged_max tR

let _tagged_pop_min
    at O% be none
    at Y k d _ O% tR be some (k, d, tR)
    at Y k d l tL tR
	be option.map that (_tagged_pop_min tL) which
	at (kX, dX, tL') be (kX, dX, _postrmL_Y k d l tL' tR)

let _tagged_pop_max
    at O% be none
    at Y k d _ tL O% be some (k, d, tL)
    at Y k d l tL tR
	be option.map that (_tagged_pop_max tR) which
	at (kX, dX, tR') be (kX, dX, _postrmR_Y k d l tL tR')

let find_ge k'
    at O% be none
    at Y k d l tL tR
	taken I.cmp k' k
	at tprec% be some (option.default (k, d) (find_ge k' tL))
	at tsucc% be find_ge k' tR
	at tcoin% be some (k, d)

let find_le k'
    at O% be none
    at Y k d l tL tR
	taken I.cmp k' k
	at tprec% be find_le k' tL
	at tsucc% be some (option.default (k, d) (find_le k' tR))
	at tcoin% be some (k, d)

let _scheme_min
    at O% be none
    at Y k d _ O% tR be some k
    at Y k d _ tL tR be _scheme_min tL

let _scheme_max
    at O% be none
    at Y k d _ tL O% be some k
    at Y k d _ tL tR be _scheme_max tR

let _scheme_pop_min
    at O% be none
    at Y k d _ O% tR be some (k, tR)
    at Y k d l tL tR
	be option.map that (_scheme_pop_min tL) which
	at (kX, tL') be (kX, _postrmL_Y k d l tL' tR)

let _scheme_pop_max
    at O% be none
    at Y k d _ tL O% be some (k, tL)
    at Y k d l tL tR
	be option.map that (_scheme_pop_max tR) which
	at (kX, tR') be (kX, _postrmR_Y k d l tL tR')

let pop k'
    at O% be none
    at Y k d l tL tR
	taken I.cmp k' k
	at tprec% be option.map that (pop k' tL) which
		  at (dX, tL') be (dX, _postrmL_Y k d l tL' tR)
	at tsucc% be option.map that (pop k' tR) which
		  at (dX, tR') be (dX, _postrmR_Y k d l tL tR')
	at tcoin%
	    taken _tagged_pop_max tL
	    at some (kP, dP, tL')
		be some (d, _postrmL_Y kP dP l tL' tR)
	    at none%
		be option.map that (_tagged_pop_min tR) which
		at (kS, dS, tR') be (d, _postrmR_Y kS dS l tL tR')

let remove k' t taken pop k' t be none%  t; some (_, t)  t

let fold f
    at O% be ident
    at Y _ d _ tL tR be fold f tR  f d  fold f tL

let foldr f
    at O% be ident
    at Y _ d _ tL tR be foldr f tL  f d  foldr f tR

let for_all f
    at O% be true
    at Y _ d _ tL tR be f d  for_all f tL  for_all f tR

let for_some f
    at O% be false
    at Y _ d _ tL tR be f d  for_some f tL  for_some f tR

let count f
    at O% be 0
    at Y _ d _ tL tR be (f d  1; 0) + count f tL + count f tR

let card
    at O% be 0
    at Y _ _ _ tL tR be 1 + card tL + card tR

let iter f
    at O% be return ()
    at Y _ d _ tL tR be iter f tL >> f d >> iter f tR

let iterr f
    at O% be return ()
    at Y _ d _ tL tR be iterr f tR >> f d >> iterr f tL

let _tagged_fold f
    at O% be ident
    at Y k d _ tL tR be _tagged_fold f tR  f (k, d)  _tagged_fold f tL

# TODO:  Optimize filter, union, isecn, etc.

let filter f t
    be _tagged_fold ((k, v)  (f v  add k v; ident)) t empty

let _tagged_filter f t
    be _tagged_fold ((k, v)  (f (k, v)  add k v; ident)) t empty

let _tagged_map f t
    be _tagged_fold (uncurry add  f) t empty

let _tagged_filter_map f t
    be _tagged_fold (option.fold (uncurry add)  f) t empty

let _scheme_filter f t
    be _tagged_fold ((k, v)  (f k  add k v; ident)) t empty

let _scheme_map f t
    be _tagged_fold ((k, v)  add (f k) v) t empty

let _scheme_filter_map f t
    be _tagged_fold ((k, v)  option.fold (k'  add k' v) (f k)) t empty

let _scheme_subeq
    at O% at _ be true
    at Y kt _ _ tL tR
	at O% be false
	at u@(Y ku _ _ uL uR)
	    taken I.cmp kt ku
	    at tcoin% be _scheme_subeq tL uL  _scheme_subeq tR uR
	    at tprec% be contains kt uL
		        _scheme_subeq tL uL  _scheme_subeq tR u
	    at tsucc% be contains kt uR
		        _scheme_subeq tL u   _scheme_subeq tR uR

let subeq_for f
    at O% at _ be true
    at Y kt dt _ tL tR
	at O% be false
	at u@(Y ku du _ uL uR)
	    taken I.cmp kt ku
	    at tcoin% be f dt du
		        subeq_for f tL uL  subeq_for f tR uR
	    at tprec% be option.for_some (f dt) (find kt uL)
		        subeq_for f tL uL  subeq_for f tR u
	    at tsucc% be option.for_some (f dt) (find kt uR)
		        subeq_for f tL u   subeq_for f tR uR

let _scheme_eq t u be card t = card u  _scheme_subeq t u

let eq_for f t u be card t = card u  subeq_for f t u

let left_union t u
    be _tagged_fold ((k, v)  add k v) t u

let left_isecn t u
    be _tagged_fold ((k, v)  (contains k u  add k v; ident)) t empty

let complement t u
    be _tagged_fold ((k, v)  (contains k u  ident; add k v)) t empty

in tagged
    type elt α := index × α
    type t α := map α

    let fold be _tagged_fold

    let foldr f
	at O% be ident
	at Y k d _ tL tR be foldr f tL  f (k, d)  foldr f tR

    let for_all f
	at O% be true
	at Y k d _ tL tR be f (k, d)  for_all f tL  for_all f tR

    let for_some f
	at O% be false
	at Y k d _ tL tR be f (k, d)  for_some f tL  for_some f tR

    let count f
	at O% be 0
	at Y k d _ tL tR be (f (k, d)  1; 0) + count f tL + count f tR

    let card be card%

    let iter f
	at O% be return ()
	at Y k d _ tL tR be iter f tL >> f (k, d) >> iter f tR

    let iterr f
	at O% be return ()
	at Y k d _ tL tR be iterr f tR >> f (k, d) >> iterr f tL

    let min be _tagged_min
    let max be _tagged_max

    let pop_min be _tagged_pop_min
    let pop_max be _tagged_pop_max

    let map be _tagged_map
    let filter be _tagged_filter
    let filter_map be _tagged_filter_map

in scheme
    type elt α := index
    type t α := map α

    let fold f
	at O% be ident
	at Y k _ _ tL tR be fold f tR  f k  fold f tL

    let foldr f
	at O% be ident
	at Y k _ _ tL tR be foldr f tL  f k  foldr f tR

    let for_all f
	at O% be true
	at Y k _ _ tL tR be f k  for_all f tL  for_all f tR

    let for_some f
	at O% be false
	at Y k _ _ tL tR be f k  for_some f tL  for_some f tR

    let count f
	at O% be 0
	at Y k _ _ tL tR be (f k  1; 0) + count f tL + count f tR

    let card be card%

    let iter f
	at O% be return ()
	at Y k _ _ tL tR be iter f tL >> f k >> iter f tR

    let iterr f
	at O% be return ()
	at Y k _ _ tL tR be iterr f tR >> f k >> iterr f tL

    let min be _scheme_min
    let max be _scheme_max

    let min_ge k t be option.map fst (find_ge k t)
    let max_le k t be option.map fst (find_le k t)

    let pop_min be _scheme_pop_min
    let pop_max be _scheme_pop_max

    let map be _scheme_map
    let filter be _scheme_filter
    let filter_map be _scheme_filter_map

    let eq be _scheme_eq
    let subeq be _scheme_subeq

let map f
    at O% be O
    at Y k d l tL tR be Y k (f d) l (map f tL) (map f tR)

let mapi f
    at O% be O
    at Y k d l tL tR be Y k (f k d) l (mapi f tL) (mapi f tR)

let mapfold f
    at O%, accu be O, accu
    at Y k d l tL tR, accu0
	let tL', accu1 be mapfold f (tL, accu0)
	let d',  accu2 be f (d, accu1)
	let tR', accu3 be mapfold f (tR, accu2)
	be Y k d' l tL' tR', accu3

let! dump_tree' dump_elt ind
    at O% do print (string.tile ind "  ") >> print "0 {}\n"
    at Y k d n tL tR
	do dump_tree' dump_elt (ind + 1) tL
	do print (string.tile ind "  ")
	do print (int.show n) >> print " {"
	do dump_elt k d >> print "}\n"
	do dump_tree' dump_elt (ind + 1) tR

let dump_tree dump_elt be dump_tree' dump_elt 0