package alba

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file red_black.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
open Module_types



module Map (Key: SORTABLE) =
struct

    (* Basics *)
    (**********)

    type 'a pair =
      Key.t * 'a

    let compare (key: Key.t) (p: 'a pair): int =
        Key.compare key (fst p)


    type color =
        | Red
        | Black

    type 'a t =
        (* A tree of type ['a t] always satisfies the red and the black
         * invariant. *)
        | Empty
        | Node of
            color
            * 'a t      (* left subtree *)
            * 'a pair   (* key value pair *)
            * 'a t      (* right subtree *)

    let empty: 'a t =
        Empty

    let node
            (color: color) (left: 'a t) (p: 'a pair) (right: 'a t)
            : 'a t =
        Node (color, left, p, right)


    let is_empty (tree: 'a t): bool =
        match tree with
        | Empty ->
            true
        | _ ->
            false


    let fold_right (f: Key.t -> 'a -> 'b -> 'b) (tree: 'a t) (start: 'b): 'b =
        let rec fld tree start =
            match tree with
            | Empty ->
                start
            | Node (_, left, (k,v), right) ->
                fld left (f k v (fld right start))
        in
        fld tree start



    let fold (f: Key.t -> 'a -> 'b -> 'b) (tree: 'a t) (start: 'b): 'b =
        let rec fld start tree =
            match tree with
            | Empty ->
                start
            | Node (_, left, (k,v), right) ->
                fld (f k v (fld start left)) right
        in
        fld start tree


    let cardinal (tree: 'a t): int =
        fold
            (fun _ _ sum -> sum + 1)
            tree
            0

    let bindings (tree: 'a t): (Key.t * 'a) list =
        fold_right
            (fun k v lst -> (k,v) :: lst)
            tree
            []


    let maybe_find (k: Key.t) (tree: 'a t): 'a option =
        let rec find tree =
            match tree with
            | Empty ->
                None
            | Node (_, left, x, right) ->
                let cmp = compare k x
                in
                if cmp < 0 then
                    find left
                else if cmp = 0 then
                    Some (snd x)
                else
                    find right
        in
        find tree


    let find (k: Key.t) (tree: 'a t): 'a =
        match maybe_find k tree with
        | None ->
            assert false (* Illegal call! *)
        | Some value ->
            value


    let mem (k: Key.t) (tree: 'a t): bool =
        maybe_find k tree <> None




    let rec check_invariant (t: 'a t): (int * color) option =
        match t with
        | Empty ->
            Some (0, Black)
        | Node (color, left, _, right) ->
            Option.(
                check_invariant left  >>= fun (h1, c1) ->
                check_invariant right >>= fun (h2, c2) ->
                if h1 = h2 then
                    match color, c1, c2 with
                    | Red, Black, Black ->
                        Some (h1, Red)

                    | Red, _, _ ->
                        (* Violation: A red parent has at least one red child.
                         *)
                        None

                    | Black, _, _ ->
                        Some (h1 + 1, Black)

                else
                    (* Violation: The black height of the children is different.
                     *)
                    None
            )



    let is_balanced (t: 'a t): bool =
        match check_invariant t with
        | None ->
            false
        | Some _ ->
            true





    (* Insertion *)
    (*************)



    type 'a almost =
      | AOk of (* Root color unchanged, no violation. *)
            'a t

      | BROk of (* Root color changed from black to red, no violation *)
            'a t * 'a pair * 'a t

      | RVio of
            (* Root color has been red originally. [a x b y c] is an orderd
             * sequence. All three subtrees [a], [b] and [c] are black rooted
             * and have the original black height. *)
            'a t * 'a pair * 'a t * 'a pair * 'a t



    let use_almost
            (ok1: 'a t -> 'b)
            (ok2: 'a t -> 'a pair -> 'a t -> 'b)
            (vio: 'a t -> 'a pair -> 'a t -> 'a pair -> 'a t -> 'b)
            : 'a almost -> 'b =
        function
        | AOk tree ->
            ok1 tree
        | BROk (left, x, right) ->
            ok2 left x right
        | RVio (a, x, b, y, c) ->
            vio a x b y c


    let rbt_of_almost (almost: 'a almost): 'a t =
        use_almost
            (fun x -> x)
            (node Red)
            (fun a x b y c ->
                 node Black (node Red a x b) y c)
            almost


    let balance_left color left z d =
        use_almost
            (fun left ->
                 AOk (node color left z d))
            (fun left p right ->
                 (* Root color of (left,p,right) changed from black to red, no
                  * violation. *)
                 match color with
                 | Black ->
                     AOk (node Black (node Red left p right) z d)

                 | Red ->
                     (* red violation *)
                     RVio (left, p, right, z, d))
            (fun a x b y c ->
                 assert (color = Black);
                 BROk (node Black a x b, y, (node Black c z d)))
            left


    let balance_right color a x right =
        use_almost
            (fun right ->
                 AOk (node color a x right))
            (fun left p right ->
                 (* Root color of (left,p,right) changed from black to red, no
                  * violation. *)
                 match color with
                 | Black ->
                     AOk (node color a x (node Red left p right))

                 | Red ->
                     (* red violation *)
                     RVio (a, x, left, p, right))
            (fun b y c z d ->
                 assert (color = Black);
                 BROk (node Black a x b, y, (node Black c z d)))
            right





    let rec add (k: Key.t) (v: 'a) (rbt: 'a t): 'a t =
        rbt_of_almost (ins k v rbt)

    and ins (k: Key.t) (v: 'a): 'a t -> 'a almost =
        function
        | Empty ->
            BROk (Empty, (k, v), Empty)

        | Node (color, left, x, right) ->
            let cmp = compare k x
            in
            if cmp < 0 then
                balance_left color (ins k v left) x right

            else if cmp = 0 then
                AOk (node color left (k,v) right)

            else
                balance_right color left x (ins k v right)




    (* Deletion  *)
    (*************)

    type 'a removed =
      | ROk of
            (* The tree has the same height as before the removal and the same
             * color or its color has been changed to black. *)
            'a t * 'a pair

      | RMinus of
            (* The tree has a reduced black height. Its color is black and has
             * not been changed. *)
            'a t * 'a pair


    let swap_pair
            (pnew: 'a pair) (rtree: 'a removed)
            : 'a removed * 'a pair =
        match rtree with
        | ROk (r, p) ->
            ROk (r, pnew), p

        | RMinus (r, p) ->
            RMinus (r, pnew), p


    let use_left_sibling
            (black1: 'a t -> 'a pair -> 'a t -> 'b)
            (black2: 'a t -> 'a pair -> 'a t -> 'a pair -> 'a t -> 'b)
            (red1:  'a t -> 'a pair -> 'a t -> 'a pair -> 'a t -> 'b)
            (red2:  'a t -> 'a pair -> 'a t -> 'a pair -> 'a t ->
                    'a pair -> 'a t -> 'b)
            (tree: 'a t)
        : 'b =
        (* [tree] is the left sibling of a height reduced right node. The right
         * node has black height [h] and therefore the sibling must have black
         * height [h + 1]. Otherwise the tree had not been a valid red black
         * tree before the removal of a node.
         *
         * The function splits up the sibling into the ordered sequence
         *
         *      a x b y c z d
         *
         *  where at least [a x b] is present. All subtrees have black height
         *  [h] except in the red case where the subtree [a] which has black
         *  height [h + 1].
         *
         * [tree] is black:
         *
         *          Bx                          Bx
         *      a       Bb                  a        Ry
         *                                        Bb    Bc
         *
         *  [tree] is red:
         *
         *          Rx                          Rx
         *      Ba+     By                  Ba+     By
         *            b    Bc                     b     Rz
         *                                            Bc   Bd
         *)
        match tree with
        | Empty ->
            (* Cannot happen. [tree] has black height [h+1]. An empty node is
             * not possible. *)
            assert false

        | Node (Black, a, x, right) ->
            (
                match right with
                | Node (Red, b, y, c) ->
                    black2 a x b y c
                | _ ->
                    black1 a x right
            )

        | Node (Red, a, x, right) ->
            (
                match right with
                | Node (Black, b, y, Node (Red, c, z, d)) ->
                    red2 a x b y c z d
                | Node (Black, b, y, c) ->
                    red1 a x b y c
                | _ ->
                    (* Cannot happen. [right] must be black, because its parent
                     * is red. Since the black height is [h+1], [right] cannot
                     * be empty either. *)
                    assert false
            )


    let use_right_sibling
            (black1: 'a t -> 'a pair -> 'a t -> 'b)
            (black2: 'a t -> 'a pair -> 'a t -> 'a pair -> 'a t -> 'b)
            (red1:  'a t -> 'a pair -> 'a t -> 'a pair -> 'a t -> 'b)
            (red2:  'a t -> 'a pair -> 'a t -> 'a pair -> 'a t ->
                    'a pair -> 'a t -> 'b)
            (tree: 'a t)
        : 'b =
        (* Mirror image of [use_left_sibling].
         * [tree] is black:
         *
         *          Bz                          Bz
         *      Bc      d                   Ry      d
         *                               Bb   Bc
         *
         * [tree] is red:
         *
         *          Rz                          Rz
         *      By      d+                  By      d+
         *   Bb    c                    Rx     c
         *                           Ba   Bb
         *)
        match tree with
        | Empty ->
            (* Cannot happen. [tree] has black height [h+1]. An empty node is
             * not possible. *)
            assert false

        | Node (Black, left, z, d) ->
            (
                match left with
                | Node (Red, b, y, c) ->
                    black2 b y c z d
                | _ ->
                    black1 left z d
            )

        | Node (Red, left, z, d) ->
            (
                match left with
                | Node (Black, Node (Red, a, x, b), y, c) ->
                    red2 a x b y c z d
                | Node (Black, b, y, c) ->
                    red1 b y c z d
                | _ ->
                    (* Cannot happen. [left] must be black, because its parent
                     * is red. Since the black height is [h+1], [left] cannot
                     * be empty either. *)
                    assert false
            )


    let use_left_sibling_black_parent
        (left: 'a t) (p: 'a pair) (reduced: 'a t) (deleted: 'a pair)
        : 'a removed
        =
        (* black_height(left):      h + 1
         * black_height(reduced):   h
         * black height goal:       h + 2 *)
        use_left_sibling
            (fun a x b_black ->
                 RMinus ( (* black height h + 1 *)
                     Node (Black, a, x,
                           Node (Red, b_black, p, reduced))
                     , deleted)
            )
            (fun a x b y cblack ->
                 ROk ( (* black height: h + 2 *)
                     Node (
                         Black,
                         Node (Black, a, x, b),
                         y,
                         Node (Black, cblack, p, reduced)),
                     deleted))
            (fun aplus x b y c_black ->
                 ROk ( (* black height: h + 2 *)
                     Node (Black, aplus, x,
                           Node (Black, b, y,
                                 Node (Red, c_black, p, reduced))),
                     deleted
                 ))
            (fun aplus x b y c z dblack ->
                 ROk (  (* black height: h + 2 *)
                     Node (Black, aplus, x,
                           Node (Red,
                                 Node (Black, b, y, c),
                                 z,
                                 Node (Black, dblack, p, reduced))),
                     deleted))
            left



    let use_left_sibling_red_parent
        (left: 'a t) (p: 'a pair) (reduced: 'a t) (deleted: 'a pair)
        : 'a removed
        =
        (* black_height(left):      h + 1
         * black_height(reduced):   h
         * black height goal:       h + 1 *)
        use_left_sibling
            (fun a x bblack ->
                 ROk ( (* black height: h + 1 *)
                    Node (Black, a, x,
                          Node (Red, bblack, p, reduced)),
                    deleted))
            (fun a x b y c ->
                 ROk ( (* black height: h + 1 *)
                     Node (Red,
                           Node (Black, a, x, b),
                           y,
                           Node (Black, c, p, reduced)),
                     deleted))
            (fun _ _ _ _ ->
                 (* [left] cannot be red. *)
                 assert false)
            (fun _ _ _ _ _ ->
                 (* [left] cannot be red. *)
                 assert false)
            left


    let use_right_sibling_black_parent
        (reduced: 'a t) (deleted: 'a pair) (p: 'a pair) (right: 'a t)
        : 'a removed
        =
        (* black_height(reduced):   h
         * black_height(right):     h + 1
         * black height goal:       h + 2 *)
        use_right_sibling
            (fun cblack z d ->
                 RMinus (
                     Node (Black,
                           Node (Red, reduced, p, cblack),
                           z, d)
                     , deleted)
            )
            (fun bblack y c z d ->
                 ROk (Node (Black,
                            Node (Black, reduced, p, bblack),
                            y,
                            Node (Black, c, z, d))
                     , deleted)
            )
            (fun bblack y c z dplus ->
                 ROk (Node (Black,
                            Node (Black,
                                  Node (Red, reduced, p, bblack),
                                  y, c),
                            z, dplus),
                      deleted)
            )
            (fun ablack x b y c z dplus ->
                 ROk (Node (Black,
                            Node (Red,
                                  Node (Black, reduced, p, ablack),
                                  x,
                                  Node (Black, b, y, c)),
                            z, dplus),
                      deleted)
            )
            right



    let use_right_sibling_red_parent
        (reduced: 'a t) (deleted: 'a pair) (p: 'a pair) (right: 'a t)
        : 'a removed
        =
        (* black_height(reduced):   h
         * black_height(right):     h + 1
         * black height goal:       h + 1 *)
        use_right_sibling
            (fun cblack z d ->
                 ROk (
                     Node (Black,
                           Node (Red, reduced, p, cblack),
                           z, d),
                     deleted
                 )
            )
            (fun b y c z d ->
                 ROk (
                     Node (Red,
                           Node (Black, reduced, p, b),
                           y,
                           Node (Black, c, z, d)),
                     deleted
                 )
            )
            (fun _ _ _ _ ->
                 (* [right] cannot be red. *)
                 assert false)
            (fun _ _ _ _ _ ->
                 (* [right] cannot be red. *)
                 assert false)
            right



    let removed_left
            (color: color) (reduced: 'a removed) (p: 'a pair) (right: 'a t)
            : 'a removed =
        (* The left child has a potentially reduced black height compared to
         * its right sibling. *)
        match reduced with
        | ROk (left, x) ->
            ROk (Node (color, left, p, right), x)

        | RMinus (reduced, deleted) ->
            match color with
            | Black ->
                use_right_sibling_black_parent
                    reduced deleted p right

            | Red ->
                use_right_sibling_red_parent
                    reduced deleted p right





    let removed_right
            (color: color) (left: 'a t) (p: 'a pair) (reduced: 'a removed)
            : 'a removed =
        (* The right child has a potentially reduced black height compared to
         * its left sibling. *)
        match reduced with
        | ROk (right, x) ->
            ROk (Node (color, left, p, right), x)

        | RMinus (reduced, deleted) ->
            match color with
            | Black ->
                use_left_sibling_black_parent
                    left p reduced deleted

            | Red ->
                use_left_sibling_red_parent
                    left p reduced deleted




    let remove_bottom (color: color) (x: 'a pair) (child: 'a t): 'a removed =
        (* Remove a bottom node with [color] and [x] which has at most one
         * [child]. *)
        match color, child with
        | Black, Empty ->
            RMinus (Empty, x)

        | Black, Node (Red, Empty, p, Empty) ->
            ROk (Node (Black, Empty, p, Empty), x)

        | Black, _ ->
            (* Cannot happen. If a black node has one child, then the child must
             * be red. *)
            assert false

        | Red, Empty ->
            ROk (Empty, x)

        | Red, _ ->
            (* Cannot happen. A red node has either no children or two black
             * children. *)
            assert false




    let rec remove (key: Key.t) (tree: 'a t): 'a t =
        match rem key tree with
        | None ->
            tree
        | Some (ROk (tree, _))
        | Some (RMinus (tree, _)) ->
            tree

    and rem (k: Key.t) (tree: 'a t): 'a removed option =
        match tree with
        | Empty ->
            None

        | Node (color, left, x, right) ->
            let cmp = compare k x
            in
            if cmp < 0 then
                Option.map
                    (fun left -> removed_left color left x right)
                    (rem k left)

            else if cmp = 0 then
                match remove_leftmost right with
                | None ->
                    Some (remove_bottom color x left)
                | Some rtree ->
                    let tree, p = swap_pair x rtree in
                    Some (removed_right color left p tree)

            else
                Option.map
                    (fun right -> removed_right color left x right)
                    (rem k right)

    and remove_leftmost (tree: 'a t): 'a removed option =
        match tree with
        | Empty ->
            None

        | Node (color, Empty, x, right) ->
            Some (remove_bottom color x right)

        | Node (color, left, x, right) ->
            Option.map
                (fun left -> removed_left color left x right)
                (remove_leftmost left)
end (* Map *)










module Set (Element: SORTABLE) =
struct
    module Map = Map (Element)

    type t = unit Map.t

    let is_empty (set: t): bool =
        Map.is_empty set

    let cardinal (set: t): int =
        Map.cardinal set

    let empty: t =
        Map.empty

    let add (e: Element.t) (set: t): t =
        Map.add e () set

    let mem (e: Element.t) (set: t): bool =
        Map.mem e set

    let remove (e: Element.t) (set: t): t =
        Map.remove e set
end







(* ------------------------------------------------------------------*)
(* Unit Tests *)
(* ------------------------------------------------------------------*)

module M = Map (Int)

let ins (n: int) (map: int M.t): int M.t =
    let rec ins i map =
        if i = n then
            map
        else
            ins (i + 1) (M.add i i map)
    in
    ins 0 map


let insert (n: int): int M.t =
    ins n M.empty


let check (start: int) (beyond: int) (map: int M.t): bool =
    let rec check_from i =
        if i = beyond then
            true
        else
            let res = M.maybe_find i map in
            match res with
            | None ->
                Printf.printf "nothing found for %d\n" i;
                false
            | Some k ->
                if i <> k then
                    Printf.printf "found wrong pair %d %d\n" i k;
                check_from (i + 1)
    in
    check_from start



let string_of_bindings (tree: int M.t): string =
    let open Printf
    in
    sprintf "[%s]"
        (String.concat ","
             (List.map
                  (fun (k,v) -> sprintf "(%d,%d)" k v)
                  (M.bindings tree)))

let _ = string_of_bindings



let%test _ =
    let n = 100
    in
    let rec test_from i map =
        if i = n then
            true
        else
            let map = M.add i i map
            in
            M.is_balanced map &&
            test_from (i + 1) map
    in
    test_from 0 M.empty



let%test _ =
    let n = 100
    in
    check 0 n (insert n)



let%test _ =
    let n = 10
    in
    check 0 n (ins n (insert n))


let%test _ =
    let n = 20
    in
    let rec test_from i map =
        let check_not_in map =
            match M.maybe_find i map with
            | None ->
                true
            | Some k ->
                Printf.printf "deleted pair (%d,%d) still in\n" i k;
                false
        and check_rest map =
            let res = check (i + 1) n map
            in
            if not res then
                Printf.printf "some values below %d not available\n" i;
            res
        and  remove map =
            let map = M.remove i map in
            (*Printf.printf "bindings %s\n" (string_of_bindings map);
            Printf.printf "cardinal %d\n" (M.cardinal map);*)
            map
        and check_invariant map =
            let res = M.is_balanced map in
            if not res then
                Printf.printf "invariant violated after deleting %d\n" i;
            res
        in
        if i = n then
            true
        else
            let map = remove map
            in
            check_not_in map
            &&
            check_rest map
            &&
            check_invariant map
            &&
            test_from (i + 1) map
    in
    test_from 0 (insert n)
OCaml

Innovation. Community. Security.