View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Vitor Santos Costa
    4    E-mail:        vscosta@gmail.com
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2007-2021, Vitor Santos Costa
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(rbtrees,
   36          [ rb_new/1,                   % -Tree
   37            rb_empty/1,                 % ?Tree
   38            rb_lookup/3,                % +Key, -Value, +T
   39            rb_update/4,                % +Tree, +Key, +NewVal, -NewTree
   40            rb_update/5,                % +Tree, +Key, ?OldVal, +NewVal, -NewTree
   41            rb_apply/4,                 % +Tree, +Key, :G, -NewTree
   42            rb_insert/4,                % +T0, +Key, ?Value, -NewTree
   43            rb_insert_new/4,            % +T0, +Key, ?Value, -NewTree
   44            rb_delete/3,                % +Tree, +Key, -NewTree
   45            rb_delete/4,                % +Tree, +Key, -Val, -NewTree
   46            rb_visit/2,                 % +Tree, -Pairs
   47            rb_keys/2,                  % +Tree, +Keys
   48            rb_map/2,                   % +Tree, :Goal
   49            rb_map/3,                   % +Tree, :Goal, -MappedTree
   50            rb_partial_map/4,           % +Tree, +Keys, :Goal, -MappedTree
   51            rb_fold/4,                  % :Goal, +Tree, +State0, -State
   52            rb_clone/3,                 % +TreeIn, -TreeOut, -Pairs
   53            rb_min/3,                   % +Tree, -Key, -Value
   54            rb_max/3,                   % +Tree, -Key, -Value
   55            rb_del_min/4,               % +Tree, -Key, -Val, -TreeDel
   56            rb_del_max/4,               % +Tree, -Key, -Val, -TreeDel
   57            rb_next/4,                  % +Tree, +Key, -Next, -Value
   58            rb_previous/4,              % +Tree, +Key, -Next, -Value
   59            list_to_rbtree/2,           % +Pairs, -Tree
   60            ord_list_to_rbtree/2,       % +Pairs, -Tree
   61            is_rbtree/1,                % @Tree
   62            rb_size/2,                  % +Tree, -Size
   63            rb_in/3                     % ?Key, ?Value, +Tree
   64          ]).   65:- autoload(library(error), [domain_error/2]).

Red black trees

Red-Black trees are balanced search binary trees. They are named because nodes can be classified as either red or black. The code we include is based on "Introduction to Algorithms", second edition, by Cormen, Leiserson, Rivest and Stein. The library includes routines to insert, lookup and delete elements in the tree.

A Red black tree is represented as a term t(Nil, Tree), where Nil is the Nil-node, a node shared for each nil-node in the tree. Any node has the form colour(Left, Key, Value, Right), where colour is one of red or black.

author
- Vitor Santos Costa, Jan Wielemaker, Samer Abdallah, Peter Ludemann.
See also
- "Introduction to Algorithms", Second Edition Cormen, Leiserson, Rivest, and Stein, MIT Press */
   86% rbtrees.pl is derived from YAP's rbtrees.yap, with some minor editing.
   87% One difference is that the SWI-Prolog version  assumes that a key only
   88% appears once in the tree - the   YAP  code is somewhat inconsistent in
   89% that  (and  even  allows  rb_lookup/3  to    backtrack,  plus  it  has
   90% rb_lookupall/3, which isn't in the SWI-Prolog code).
   91
   92% The code has also been modified to   use SWI-Prolog's '=>' operator to
   93% throw an existence_error(matching_rule, _)  exception   if  Tree isn't
   94% instantiated (if ':-' is used, an  uninstanted   Tree  gets  set to an
   95% empty tree, which probably isn't the desired result).
   96
   97:- meta_predicate
   98    rb_map(+,2,-),
   99    rb_map(?,1),
  100    rb_partial_map(+,+,2,-),
  101    rb_apply(+,+,2,-),
  102    rb_fold(3,+,+,-).  103
  104/*
  105:- use_module(library(type_check)).
  106
  107:- type rbtree(K,V) ---> t(tree(K,V),tree(K,V)).
  108:- type tree(K,V)   ---> black(tree(K,V),K,V,tree(K,V))
  109                       ; red(tree(K,V),K,V,tree(K,V))
  110                       ; ''.
  111:- type cmp ---> (=) ; (<) ; (>).
  112
  113
  114:- pred rb_new(rbtree(_K,_V)).
  115:- pred rb_empty(rbtree(_K,_V)).
  116:- pred rb_lookup(K,V,rbtree(K,V)).
  117:- pred lookup(K,V, tree(K,V)).
  118:- pred lookup(cmp, K, V, tree(K,V)).
  119:- pred rb_min(rbtree(K,V),K,V).
  120:- pred min(tree(K,V),K,V).
  121:- pred rb_max(rbtree(K,V),K,V).
  122:- pred max(tree(K,V),K,V).
  123:- pred rb_next(rbtree(K,V),K,pair(K,V),V).
  124:- pred next(tree(K,V),K,pair(K,V),V,tree(K,V)).
  125*/
 rb_new(-Tree) is det
Create a new Red-Black tree Tree.
deprecated
- Use rb_empty/1.
  133:- det(rb_new/1).  134rb_new(t(Nil,Nil)) :-
  135    Nil = black('',_,_,'').
 rb_empty(?Tree) is semidet
Succeeds if Tree is an empty Red-Black tree.
  141rb_empty(t(Nil,Nil)) :-
  142    Nil = black('',_,_,'').
 rb_lookup(+Key, -Value, +Tree) is semidet
True when Value is associated with Key in the Red-Black tree Tree. The given Key may include variables, in which case the RB tree is searched for a key with equivalent, as in (==)/2, variables. Time complexity is O(log N) in the number of elements in the tree.
  151rb_lookup(Key, Val, t(_,Tree)) =>
  152    lookup(Key, Val, Tree).
  153
  154lookup(_, _, black('',_,_,'')) :- !, fail.
  155lookup(Key, Val, Tree) :-
  156    arg(2,Tree,KA),
  157    compare(Cmp,KA,Key),
  158    lookup(Cmp,Key,Val,Tree).
  159
  160lookup(>, K, V, Tree) :-
  161    arg(1,Tree,NTree),
  162    lookup(K, V, NTree).
  163lookup(<, K, V, Tree) :-
  164    arg(4,Tree,NTree),
  165    lookup(K, V, NTree).
  166lookup(=, _, V, Tree) :-
  167    arg(3,Tree,V).
 rb_min(+Tree, -Key, -Value) is semidet
Key is the minimum key in Tree, and is associated with Val.
  173rb_min(t(_,Tree), Key, Val) =>
  174    min(Tree, Key, Val).
  175
  176min(red(black('',_,_,_),Key,Val,_), Key, Val) :- !.
  177min(black(black('',_,_,_),Key,Val,_), Key, Val) :- !.
  178min(red(Right,_,_,_), Key, Val) :-
  179    min(Right,Key,Val).
  180min(black(Right,_,_,_), Key, Val) :-
  181    min(Right,Key,Val).
 rb_max(+Tree, -Key, -Value) is semidet
Key is the maximal key in Tree, and is associated with Val.
  187rb_max(t(_,Tree), Key, Val) =>
  188    max(Tree, Key, Val).
  189
  190max(red(_,Key,Val,black('',_,_,_)), Key, Val) :- !.
  191max(black(_,Key,Val,black('',_,_,_)), Key, Val) :- !.
  192max(red(_,_,_,Left), Key, Val) :-
  193    max(Left,Key,Val).
  194max(black(_,_,_,Left), Key, Val) :-
  195    max(Left,Key,Val).
 rb_next(+Tree, +Key, -Next, -Value) is semidet
Next is the next element after Key in Tree, and is associated with Val. Fails if Key isn't in Tree or if Key is the maximum key.
  202rb_next(t(_,Tree), Key, Next, Val) =>
  203    next(Tree, Key, Next, Val, []).
  204
  205next(black('',_,_,''), _, _, _, _) :- !, fail.
  206next(Tree, Key, Next, Val, Candidate) :-
  207    arg(2,Tree,KA),
  208    arg(3,Tree,VA),
  209    compare(Cmp,KA,Key),
  210    next(Cmp, Key, KA, VA, Next, Val, Tree, Candidate).
  211
  212next(>, K, KA, VA, NK, V, Tree, _) :-
  213    arg(1,Tree,NTree),
  214    next(NTree,K,NK,V,KA-VA).
  215next(<, K, _, _, NK, V, Tree, Candidate) :-
  216    arg(4,Tree,NTree),
  217    next(NTree,K,NK,V,Candidate).
  218next(=, _, _, _, NK, Val, Tree, Candidate) :-
  219    arg(4,Tree,NTree),
  220    (   min(NTree, NK, Val)
  221    ->  true
  222    ;   Candidate = (NK-Val)
  223    ).
 rb_previous(+Tree, +Key, -Previous, -Value) is semidet
Previous is the previous element after Key in Tree, and is associated with Val. Fails if Key isn't in Tree or if Key is the minimum key.
  231rb_previous(t(_,Tree), Key, Previous, Val) =>
  232    previous(Tree, Key, Previous, Val, []).
  233
  234previous(black('',_,_,''), _, _, _, _) :- !, fail.
  235previous(Tree, Key, Previous, Val, Candidate) :-
  236    arg(2,Tree,KA),
  237    arg(3,Tree,VA),
  238    compare(Cmp,KA,Key),
  239    previous(Cmp, Key, KA, VA, Previous, Val, Tree, Candidate).
  240
  241previous(>, K, _, _, NK, V, Tree, Candidate) :-
  242    arg(1,Tree,NTree),
  243    previous(NTree,K,NK,V,Candidate).
  244previous(<, K, KA, VA, NK, V, Tree, _) :-
  245    arg(4,Tree,NTree),
  246    previous(NTree,K,NK,V,KA-VA).
  247previous(=, _, _, _, K, Val, Tree, Candidate) :-
  248    arg(1,Tree,NTree),
  249    (   max(NTree, K, Val)
  250    ->  true
  251    ;   Candidate = (K-Val)
  252    ).
 rb_update(+Tree, +Key, +NewVal, -NewTree) is semidet
 rb_update(+Tree, +Key, ?OldVal, +NewVal, -NewTree) is semidet
Tree NewTree is tree Tree, but with value for Key associated with NewVal. Fails if it cannot find Key in Tree.
  260rb_update(t(Nil,OldTree), Key, OldVal, Val, NewTree2) =>
  261    NewTree2 = t(Nil,NewTree),
  262    update(OldTree, Key, OldVal, Val, NewTree).
  263
  264rb_update(t(Nil,OldTree), Key, Val, NewTree2) =>
  265    NewTree2 = t(Nil,NewTree),
  266    update(OldTree, Key, _, Val, NewTree).
  267
  268update(black(Left,Key0,Val0,Right), Key, OldVal, Val, NewTree) :-
  269    Left \= [],
  270    compare(Cmp,Key0,Key),
  271    (   Cmp == (=)
  272    ->  OldVal = Val0,
  273        NewTree = black(Left,Key0,Val,Right)
  274    ;   Cmp == (>)
  275    ->  NewTree = black(NewLeft,Key0,Val0,Right),
  276        update(Left, Key, OldVal, Val, NewLeft)
  277    ;   NewTree = black(Left,Key0,Val0,NewRight),
  278        update(Right, Key, OldVal, Val, NewRight)
  279    ).
  280update(red(Left,Key0,Val0,Right), Key, OldVal, Val, NewTree) :-
  281    compare(Cmp,Key0,Key),
  282    (   Cmp == (=)
  283    ->  OldVal = Val0,
  284        NewTree = red(Left,Key0,Val,Right)
  285    ;   Cmp == (>)
  286    ->  NewTree = red(NewLeft,Key0,Val0,Right),
  287        update(Left, Key, OldVal, Val, NewLeft)
  288    ;   NewTree = red(Left,Key0,Val0,NewRight),
  289        update(Right, Key, OldVal, Val, NewRight)
  290    ).
 rb_apply(+Tree, +Key, :G, -NewTree) is semidet
If the value associated with key Key is Val0 in Tree, and if call(G,Val0,ValF) holds, then NewTree differs from Tree only in that Key is associated with value ValF in tree NewTree. Fails if it cannot find Key in Tree, or if call(G,Val0,ValF) is not satisfiable.
  299rb_apply(t(Nil,OldTree), Key, Goal, NewTree2) =>
  300    NewTree2 = t(Nil,NewTree),
  301    apply(OldTree, Key, Goal, NewTree).
  302
  303%apply(black('',_,_,''), _, _, _) :- !, fail.
  304apply(black(Left,Key0,Val0,Right), Key, Goal,
  305      black(NewLeft,Key0,Val,NewRight)) :-
  306    Left \= [],
  307    compare(Cmp,Key0,Key),
  308    (   Cmp == (=)
  309    ->  NewLeft = Left,
  310        NewRight = Right,
  311        call(Goal,Val0,Val)
  312    ;   Cmp == (>)
  313    ->  NewRight = Right,
  314        Val = Val0,
  315        apply(Left, Key, Goal, NewLeft)
  316    ;   NewLeft = Left,
  317        Val = Val0,
  318        apply(Right, Key, Goal, NewRight)
  319    ).
  320apply(red(Left,Key0,Val0,Right), Key, Goal,
  321      red(NewLeft,Key0,Val,NewRight)) :-
  322    compare(Cmp,Key0,Key),
  323    (   Cmp == (=)
  324    ->  NewLeft = Left,
  325        NewRight = Right,
  326        call(Goal,Val0,Val)
  327    ;   Cmp == (>)
  328    ->  NewRight = Right,
  329        Val = Val0,
  330        apply(Left, Key, Goal, NewLeft)
  331    ;   NewLeft = Left,
  332        Val = Val0,
  333        apply(Right, Key, Goal, NewRight)
  334    ).
 rb_in(?Key, ?Value, +Tree) is nondet
True when Key-Value is a key-value pair in red-black tree Tree. Same as below, but does not materialize the pairs.
rb_visit(Tree, Pairs), member(Key-Value, Pairs)

Leaves a choicepoint, even if Key is instantiated; to avoid a choicepoint, use rb_lookup/3.

  346rb_in(Key, Val, t(_,T)) =>
  347    enum(Key, Val, T).
  348
  349enum(Key, Val, black(L,K,V,R)) :-
  350    L \= '',
  351    enum_cases(Key, Val, L, K, V, R).
  352enum(Key, Val, red(L,K,V,R)) :-
  353    enum_cases(Key, Val, L, K, V, R).
  354
  355enum_cases(Key, Val, L, _, _, _) :-
  356    enum(Key, Val, L).
  357enum_cases(Key, Val, _, Key, Val, _).
  358enum_cases(Key, Val, _, _, _, R) :-
  359    enum(Key, Val, R).
  360
  361
  362
  363                 /*******************************
  364                 *       TREE INSERTION         *
  365                 *******************************/
  366
  367% We don't use parent nodes, so we may have to fix the root.
 rb_insert(+Tree, +Key, ?Value, -NewTree) is det
Add an element with key Key and Value to the tree Tree creating a new red-black tree NewTree. If Key is a key in Tree, the associated value is replaced by Value. See also rb_insert_new/4.
  375:- det(rb_insert/4).  376rb_insert(t(Nil,Tree0),Key,Val,NewTree) =>
  377    NewTree = t(Nil,Tree),
  378    insert(Tree0,Key,Val,Nil,Tree).
  379
  380
  381insert(Tree0,Key,Val,Nil,Tree) :-
  382    insert2(Tree0,Key,Val,Nil,TreeI,_),
  383    fix_root(TreeI,Tree).
  384
  385%
  386% Cormen et al present the algorithm as
  387% (1) standard tree insertion;
  388% (2) from the viewpoint of the newly inserted node:
  389%     partially fix the tree;
  390%     move upwards
  391% until reaching the root.
  392%
  393% We do it a little bit different:
  394%
  395% (1) standard tree insertion;
  396% (2) move upwards:
  397%      when reaching a black node;
  398%        if the tree below may be broken, fix it.
  399% We take advantage of Prolog unification
  400% to do several operations in a single go.
  401%
  402
  403
  404
  405%
  406% actual insertion
  407%
  408insert2(black('',_,_,''), K, V, Nil, T, Status) :-
  409    !,
  410    T = red(Nil,K,V,Nil),
  411    Status = not_done.
  412insert2(red(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  413    (   K @< K0
  414    ->  NT = red(NL,K0,V0,R),
  415        insert2(L, K, V, Nil, NL, Flag)
  416    ;   K == K0
  417    ->  NT = red(L,K0,V,R),
  418        Flag = done
  419    ;   NT = red(L,K0,V0,NR),
  420        insert2(R, K, V, Nil, NR, Flag)
  421    ).
  422insert2(black(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  423    (   K @< K0
  424    ->  insert2(L, K, V, Nil, IL, Flag0),
  425        fix_left(Flag0, black(IL,K0,V0,R), NT, Flag)
  426    ;   K == K0
  427    ->  NT = black(L,K0,V,R),
  428        Flag = done
  429    ;   insert2(R, K, V, Nil, IR, Flag0),
  430        fix_right(Flag0, black(L,K0,V0,IR), NT, Flag)
  431    ).
  432
  433% We don't use parent nodes, so we may have to fix the root.
 rb_insert_new(+Tree, +Key, ?Value, -NewTree) is semidet
Add a new element with key Key and Value to the tree Tree creating a new red-black tree NewTree. Fails if Key is a key in Tree.
  440rb_insert_new(t(Nil,Tree0),Key,Val,NewTree) =>
  441    NewTree = t(Nil,Tree),
  442    insert_new(Tree0,Key,Val,Nil,Tree).
  443
  444insert_new(Tree0,Key,Val,Nil,Tree) :-
  445    insert_new_2(Tree0,Key,Val,Nil,TreeI,_),
  446    fix_root(TreeI,Tree).
  447
  448%
  449% actual insertion, copied from insert2
  450%
  451insert_new_2(black('',_,_,''), K, V, Nil, T, Status) :-
  452    !,
  453    T = red(Nil,K,V,Nil),
  454    Status = not_done.
  455insert_new_2(red(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  456    (   K @< K0
  457    ->  NT = red(NL,K0,V0,R),
  458        insert_new_2(L, K, V, Nil, NL, Flag)
  459    ;   K == K0
  460    ->  fail
  461    ;   NT = red(L,K0,V0,NR),
  462        insert_new_2(R, K, V, Nil, NR, Flag)
  463    ).
  464insert_new_2(black(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  465    (   K @< K0
  466    ->  insert_new_2(L, K, V, Nil, IL, Flag0),
  467        fix_left(Flag0, black(IL,K0,V0,R), NT, Flag)
  468    ;   K == K0
  469    ->  fail
  470    ;   insert_new_2(R, K, V, Nil, IR, Flag0),
  471        fix_right(Flag0, black(L,K0,V0,IR), NT, Flag)
  472    ).
  473
  474%
  475% make sure the root is always black.
  476%
  477fix_root(black(L,K,V,R),black(L,K,V,R)).
  478fix_root(red(L,K,V,R),black(L,K,V,R)).
  479
  480%
  481% How to fix if we have inserted on the left
  482%
  483fix_left(done,T,T,done) :- !.
  484fix_left(not_done,Tmp,Final,Done) :-
  485    fix_left(Tmp,Final,Done).
  486
  487%
  488% case 1 of RB: just need to change colors.
  489%
  490fix_left(black(red(Al,AK,AV,red(Be,BK,BV,Ga)),KC,VC,red(De,KD,VD,Ep)),
  491        red(black(Al,AK,AV,red(Be,BK,BV,Ga)),KC,VC,black(De,KD,VD,Ep)),
  492        not_done) :- !.
  493fix_left(black(red(red(Al,KA,VA,Be),KB,VB,Ga),KC,VC,red(De,KD,VD,Ep)),
  494        red(black(red(Al,KA,VA,Be),KB,VB,Ga),KC,VC,black(De,KD,VD,Ep)),
  495        not_done) :- !.
  496%
  497% case 2 of RB: got a knee so need to do rotations
  498%
  499fix_left(black(red(Al,KA,VA,red(Be,KB,VB,Ga)),KC,VC,De),
  500        black(red(Al,KA,VA,Be),KB,VB,red(Ga,KC,VC,De)),
  501        done) :- !.
  502%
  503% case 3 of RB: got a line
  504%
  505fix_left(black(red(red(Al,KA,VA,Be),KB,VB,Ga),KC,VC,De),
  506        black(red(Al,KA,VA,Be),KB,VB,red(Ga,KC,VC,De)),
  507        done) :- !.
  508%
  509% case 4 of RB: nothing to do
  510%
  511fix_left(T,T,done).
  512
  513%
  514% How to fix if we have inserted on the right
  515%
  516fix_right(done,T,T,done) :- !.
  517fix_right(not_done,Tmp,Final,Done) :-
  518    fix_right(Tmp,Final,Done).
  519
  520%
  521% case 1 of RB: just need to change colors.
  522%
  523fix_right(black(red(Ep,KD,VD,De),KC,VC,red(red(Ga,KB,VB,Be),KA,VA,Al)),
  524          red(black(Ep,KD,VD,De),KC,VC,black(red(Ga,KB,VB,Be),KA,VA,Al)),
  525          not_done) :- !.
  526fix_right(black(red(Ep,KD,VD,De),KC,VC,red(Ga,Ka,Va,red(Be,KB,VB,Al))),
  527          red(black(Ep,KD,VD,De),KC,VC,black(Ga,Ka,Va,red(Be,KB,VB,Al))),
  528          not_done) :- !.
  529%
  530% case 2 of RB: got a knee so need to do rotations
  531%
  532fix_right(black(De,KC,VC,red(red(Ga,KB,VB,Be),KA,VA,Al)),
  533          black(red(De,KC,VC,Ga),KB,VB,red(Be,KA,VA,Al)),
  534          done) :- !.
  535%
  536% case 3 of RB: got a line
  537%
  538fix_right(black(De,KC,VC,red(Ga,KB,VB,red(Be,KA,VA,Al))),
  539          black(red(De,KC,VC,Ga),KB,VB,red(Be,KA,VA,Al)),
  540          done) :- !.
  541%
  542% case 4 of RB: nothing to do.
  543%
  544fix_right(T,T,done).
 rb_delete(+Tree, +Key, -NewTree)
 rb_delete(+Tree, +Key, -Val, -NewTree)
Delete element with key Key from the tree Tree, returning the value Val associated with the key and a new tree NewTree. Fails if Key is not in Tree.
  554rb_delete(t(Nil,T), K, NewTree) =>
  555    NewTree = t(Nil,NT),
  556    delete(T, K, _, NT, _).
  557
  558rb_delete(t(Nil,T), K, V, NewTree) =>
  559    NewTree = t(Nil,NT),
  560    delete(T, K, V0, NT, _),
  561    V = V0.
  562
  563%
  564% I am afraid our representation is not as nice for delete
  565%
  566delete(red(L,K0,V0,R), K, V, NT, Flag) :-
  567    K @< K0,
  568    !,
  569    delete(L, K, V, NL, Flag0),
  570    fixup_left(Flag0,red(NL,K0,V0,R),NT, Flag).
  571delete(red(L,K0,V0,R), K, V, NT, Flag) :-
  572    K @> K0,
  573    !,
  574    delete(R, K, V, NR, Flag0),
  575    fixup_right(Flag0,red(L,K0,V0,NR),NT, Flag).
  576delete(red(L,_,V,R), _, V, OUT, Flag) :-
  577    % K == K0,
  578    delete_red_node(L,R,OUT,Flag).
  579delete(black(L,K0,V0,R), K, V, NT, Flag) :-
  580    K @< K0,
  581    !,
  582    delete(L, K, V, NL, Flag0),
  583    fixup_left(Flag0,black(NL,K0,V0,R),NT, Flag).
  584delete(black(L,K0,V0,R), K, V, NT, Flag) :-
  585    K @> K0,
  586    !,
  587    delete(R, K, V, NR, Flag0),
  588    fixup_right(Flag0,black(L,K0,V0,NR),NT, Flag).
  589delete(black(L,_,V,R), _, V, OUT, Flag) :-
  590    % K == K0,
  591    delete_black_node(L,R,OUT,Flag).
 rb_del_min(+Tree, -Key, -Val, -NewTree)
Delete the least element from the tree Tree, returning the key Key, the value Val associated with the key and a new tree NewTree. Fails if Tree is empty.
  599rb_del_min(t(Nil,T), K, Val, NewTree) =>
  600    NewTree = t(Nil,NT),
  601    del_min(T, K, Val, Nil, NT, _).
  602
  603del_min(red(black('',_,_,_),K,V,R), K, V, Nil, OUT, Flag) :-
  604    !,
  605    delete_red_node(Nil,R,OUT,Flag).
  606del_min(red(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  607    del_min(L, K, V, Nil, NL, Flag0),
  608    fixup_left(Flag0,red(NL,K0,V0,R), NT, Flag).
  609del_min(black(black('',_,_,_),K,V,R), K, V, Nil, OUT, Flag) :-
  610    !,
  611    delete_black_node(Nil,R,OUT,Flag).
  612del_min(black(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  613    del_min(L, K, V, Nil, NL, Flag0),
  614    fixup_left(Flag0,black(NL,K0,V0,R),NT, Flag).
 rb_del_max(+Tree, -Key, -Val, -NewTree)
Delete the largest element from the tree Tree, returning the key Key, the value Val associated with the key and a new tree NewTree. Fails if Tree is empty.
  624rb_del_max(t(Nil,T), K, Val, NewTree) =>
  625    NewTree = t(Nil,NT),
  626    del_max(T, K, Val, Nil, NT, _).
  627
  628del_max(red(L,K,V,black('',_,_,_)), K, V, Nil, OUT, Flag) :-
  629    !,
  630    delete_red_node(L,Nil,OUT,Flag).
  631del_max(red(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  632    del_max(R, K, V, Nil, NR, Flag0),
  633    fixup_right(Flag0,red(L,K0,V0,NR),NT, Flag).
  634del_max(black(L,K,V,black('',_,_,_)), K, V, Nil, OUT, Flag) :-
  635    !,
  636    delete_black_node(L,Nil,OUT,Flag).
  637del_max(black(L,K0,V0,R), K, V, Nil, NT, Flag) :-
  638    del_max(R, K, V, Nil, NR, Flag0),
  639    fixup_right(Flag0,black(L,K0,V0,NR), NT, Flag).
  640
  641delete_red_node(L1,L2,L1,done) :- L1 == L2, !.
  642delete_red_node(black('',_,_,''),R,R,done) :-  !.
  643delete_red_node(L,black('',_,_,''),L,done) :-  !.
  644delete_red_node(L,R,OUT,Done) :-
  645    delete_next(R,NK,NV,NR,Done0),
  646    fixup_right(Done0,red(L,NK,NV,NR),OUT,Done).
  647
  648delete_black_node(L1,L2,L1,not_done) :-         L1 == L2, !.
  649delete_black_node(black('',_,_,''),red(L,K,V,R),black(L,K,V,R),done) :- !.
  650delete_black_node(black('',_,_,''),R,R,not_done) :- !.
  651delete_black_node(red(L,K,V,R),black('',_,_,''),black(L,K,V,R),done) :- !.
  652delete_black_node(L,black('',_,_,''),L,not_done) :- !.
  653delete_black_node(L,R,OUT,Done) :-
  654    delete_next(R,NK,NV,NR,Done0),
  655    fixup_right(Done0,black(L,NK,NV,NR),OUT,Done).
  656
  657delete_next(red(black('',_,_,''),K,V,R),K,V,R,done) :-  !.
  658delete_next(black(black('',_,_,''),K,V,red(L1,K1,V1,R1)),
  659        K,V,black(L1,K1,V1,R1),done) :- !.
  660delete_next(black(black('',_,_,''),K,V,R),K,V,R,not_done) :- !.
  661delete_next(red(L,K,V,R),K0,V0,OUT,Done) :-
  662    delete_next(L,K0,V0,NL,Done0),
  663    fixup_left(Done0,red(NL,K,V,R),OUT,Done).
  664delete_next(black(L,K,V,R),K0,V0,OUT,Done) :-
  665    delete_next(L,K0,V0,NL,Done0),
  666    fixup_left(Done0,black(NL,K,V,R),OUT,Done).
  667
  668fixup_left(done,T,T,done).
  669fixup_left(not_done,T,NT,Done) :-
  670    fixup2(T,NT,Done).
  671
  672%
  673% case 1: x moves down, so we have to try to fix it again.
  674% case 1 -> 2,3,4 -> done
  675%
  676fixup2(black(black(Al,KA,VA,Be),KB,VB,
  677             red(black(Ga,KC,VC,De),KD,VD,
  678                 black(Ep,KE,VE,Fi))),
  679        black(T1,KD,VD,black(Ep,KE,VE,Fi)),done) :-
  680    !,
  681    fixup2(red(black(Al,KA,VA,Be),KB,VB,black(Ga,KC,VC,De)),
  682            T1,
  683            _).
  684%
  685% case 2: x moves up, change one to red
  686%
  687fixup2(red(black(Al,KA,VA,Be),KB,VB,
  688           black(black(Ga,KC,VC,De),KD,VD,
  689                 black(Ep,KE,VE,Fi))),
  690        black(black(Al,KA,VA,Be),KB,VB,
  691              red(black(Ga,KC,VC,De),KD,VD,
  692                  black(Ep,KE,VE,Fi))),done) :- !.
  693fixup2(black(black(Al,KA,VA,Be),KB,VB,
  694             black(black(Ga,KC,VC,De),KD,VD,
  695                   black(Ep,KE,VE,Fi))),
  696        black(black(Al,KA,VA,Be),KB,VB,
  697              red(black(Ga,KC,VC,De),KD,VD,
  698                  black(Ep,KE,VE,Fi))),not_done) :- !.
  699%
  700% case 3: x stays put, shift left and do a 4
  701%
  702fixup2(red(black(Al,KA,VA,Be),KB,VB,
  703           black(red(Ga,KC,VC,De),KD,VD,
  704                 black(Ep,KE,VE,Fi))),
  705        red(black(black(Al,KA,VA,Be),KB,VB,Ga),KC,VC,
  706            black(De,KD,VD,black(Ep,KE,VE,Fi))),
  707        done) :- !.
  708fixup2(black(black(Al,KA,VA,Be),KB,VB,
  709             black(red(Ga,KC,VC,De),KD,VD,
  710                   black(Ep,KE,VE,Fi))),
  711        black(black(black(Al,KA,VA,Be),KB,VB,Ga),KC,VC,
  712              black(De,KD,VD,black(Ep,KE,VE,Fi))),
  713        done) :- !.
  714%
  715% case 4: rotate left, get rid of red
  716%
  717fixup2(red(black(Al,KA,VA,Be),KB,VB,
  718           black(C,KD,VD,red(Ep,KE,VE,Fi))),
  719        red(black(black(Al,KA,VA,Be),KB,VB,C),KD,VD,
  720            black(Ep,KE,VE,Fi)),
  721        done).
  722fixup2(black(black(Al,KA,VA,Be),KB,VB,
  723             black(C,KD,VD,red(Ep,KE,VE,Fi))),
  724       black(black(black(Al,KA,VA,Be),KB,VB,C),KD,VD,
  725             black(Ep,KE,VE,Fi)),
  726       done).
  727
  728fixup_right(done,T,T,done).
  729fixup_right(not_done,T,NT,Done) :-
  730    fixup3(T,NT,Done).
  731
  732% case 1: x moves down, so we have to try to fix it again.
  733% case 1 -> 2,3,4 -> done
  734%
  735fixup3(black(red(black(Fi,KE,VE,Ep),KD,VD,
  736                 black(De,KC,VC,Ga)),KB,VB,
  737             black(Be,KA,VA,Al)),
  738        black(black(Fi,KE,VE,Ep),KD,VD,T1),done) :-
  739    !,
  740    fixup3(red(black(De,KC,VC,Ga),KB,VB,
  741               black(Be,KA,VA,Al)),T1,_).
  742
  743%
  744% case 2: x moves up, change one to red
  745%
  746fixup3(red(black(black(Fi,KE,VE,Ep),KD,VD,
  747                 black(De,KC,VC,Ga)),KB,VB,
  748           black(Be,KA,VA,Al)),
  749       black(red(black(Fi,KE,VE,Ep),KD,VD,
  750                 black(De,KC,VC,Ga)),KB,VB,
  751             black(Be,KA,VA,Al)),
  752       done) :- !.
  753fixup3(black(black(black(Fi,KE,VE,Ep),KD,VD,
  754                   black(De,KC,VC,Ga)),KB,VB,
  755             black(Be,KA,VA,Al)),
  756       black(red(black(Fi,KE,VE,Ep),KD,VD,
  757                 black(De,KC,VC,Ga)),KB,VB,
  758             black(Be,KA,VA,Al)),
  759       not_done):- !.
  760%
  761% case 3: x stays put, shift left and do a 4
  762%
  763fixup3(red(black(black(Fi,KE,VE,Ep),KD,VD,
  764                 red(De,KC,VC,Ga)),KB,VB,
  765           black(Be,KA,VA,Al)),
  766       red(black(black(Fi,KE,VE,Ep),KD,VD,De),KC,VC,
  767           black(Ga,KB,VB,black(Be,KA,VA,Al))),
  768       done) :- !.
  769fixup3(black(black(black(Fi,KE,VE,Ep),KD,VD,
  770                   red(De,KC,VC,Ga)),KB,VB,
  771             black(Be,KA,VA,Al)),
  772       black(black(black(Fi,KE,VE,Ep),KD,VD,De),KC,VC,
  773             black(Ga,KB,VB,black(Be,KA,VA,Al))),
  774       done) :- !.
  775%
  776% case 4: rotate right, get rid of red
  777%
  778fixup3(red(black(red(Fi,KE,VE,Ep),KD,VD,C),KB,VB,black(Be,KA,VA,Al)),
  779       red(black(Fi,KE,VE,Ep),KD,VD,black(C,KB,VB,black(Be,KA,VA,Al))),
  780       done).
  781fixup3(black(black(red(Fi,KE,VE,Ep),KD,VD,C),KB,VB,black(Be,KA,VA,Al)),
  782       black(black(Fi,KE,VE,Ep),KD,VD,black(C,KB,VB,black(Be,KA,VA,Al))),
  783       done).
 rb_visit(+Tree, -Pairs) is det
Pairs is an infix visit of tree Tree, where each element of Pairs is of the form Key-Value.
  790:- det(rb_visit/2).  791rb_visit(t(_,T),Lf) =>
  792    visit(T,[],Lf).
  793
  794visit(black('',_,_,_),L0,L) => L0 = L.
  795visit(red(L,K,V,R),L0,Lf) =>
  796    visit(L,[K-V|L1],Lf),
  797    visit(R,L0,L1).
  798visit(black(L,K,V,R),L0,Lf) =>
  799    visit(L,[K-V|L1],Lf),
  800    visit(R,L0,L1).
  801
  802:- meta_predicate map(?,2,?,?).  % this is required.
 rb_map(+T, :Goal) is semidet
True if call(Goal, Value) is true for all nodes in T.
  808rb_map(t(Nil,Tree),Goal,NewTree2) =>
  809    NewTree2 = t(Nil,NewTree),
  810    map(Tree,Goal,NewTree,Nil).
  811
  812
  813map(black('',_,_,''),_,Nil,Nil) :- !.
  814map(red(L,K,V,R),Goal,red(NL,K,NV,NR),Nil) :-
  815    call(Goal,V,NV),
  816    !,
  817    map(L,Goal,NL,Nil),
  818    map(R,Goal,NR,Nil).
  819map(black(L,K,V,R),Goal,black(NL,K,NV,NR),Nil) :-
  820    call(Goal,V,NV),
  821    !,
  822    map(L,Goal,NL,Nil),
  823    map(R,Goal,NR,Nil).
  824
  825:- meta_predicate map(?,1).  % this is required.
 rb_map(+Tree, :G, -NewTree) is semidet
For all nodes Key in the tree Tree, if the value associated with key Key is Val0 in tree Tree, and if call(G,Val0,ValF) holds, then the value associated with Key in NewTree is ValF. Fails if call(G,Val0,ValF) is not satisfiable for all Val0.
  834rb_map(t(_,Tree),Goal) =>
  835    map(Tree,Goal).
  836
  837
  838map(black('',_,_,''),_) :- !.
  839map(red(L,_,V,R),Goal) :-
  840    call(Goal,V),
  841    !,
  842    map(L,Goal),
  843    map(R,Goal).
  844map(black(L,_,V,R),Goal) :-
  845    call(Goal,V),
  846    !,
  847    map(L,Goal),
  848    map(R,Goal).
 rb_fold(:Goal, +Tree, +State0, -State)
Fold the given predicate over all the key-value pairs in Tree, starting with initial state State0 and returning the final state State. Pred is called as
call(Pred, Key-Value, State1, State2)

Determinism depends on Goal.

  860rb_fold(Pred, t(_,T), S1, S2) =>
  861    fold(T, Pred, S1, S2).
  862
  863fold(black(L,K,V,R), Pred) -->
  864    (   {L == ''}
  865    ->  []
  866    ;   fold_parts(Pred, L, K-V, R)
  867    ).
  868fold(red(L,K,V,R), Pred) -->
  869    fold_parts(Pred, L, K-V, R).
  870
  871fold_parts(Pred, L, KV, R) -->
  872    fold(L, Pred),
  873    call(Pred, KV),
  874    fold(R, Pred).
 rb_clone(+TreeIn, -TreeOut, -Pairs) is det
`Clone' the red-back tree TreeIn into a new tree TreeOut with the same keys as the original but with all values set to unbound values. Pairs is a list containing all new nodes as pairs K-V.
  882:- det(rb_clone/3).  883rb_clone(t(Nil,T),TreeOut,Ns) =>
  884    TreeOut = t(Nil,NT),
  885    clone(T,Nil,NT,Ns,[]).
  886
  887clone(black('',_,_,''),Nil,Nil,Ns,Ns) :- !.
  888clone(red(L,K,_,R),Nil,red(NL,K,NV,NR),NsF,Ns0) :-
  889    clone(L,Nil,NL,NsF,[K-NV|Ns1]),
  890    clone(R,Nil,NR,Ns1,Ns0).
  891clone(black(L,K,_,R),Nil,black(NL,K,NV,NR),NsF,Ns0) :-
  892    clone(L,Nil,NL,NsF,[K-NV|Ns1]),
  893    clone(R,Nil,NR,Ns1,Ns0).
 rb_partial_map(+Tree, +Keys, :G, -NewTree)
For all nodes Key in Keys, if the value associated with key Key is Val0 in tree Tree, and if call(G,Val0,ValF) holds, then the value associated with Key in NewTree is ValF, otherwise it is the value associated with the key in Tree. Fails if Key isn't in Tree or if call(G,Val0,ValF) is not satisfiable for all Val0 in Keys. Assumes keys are sorted and not repeated (fails if this is not true).
  904rb_partial_map(t(Nil,T0), Map, Goal, NewTree) =>
  905    NewTree = t(Nil,TF),
  906    partial_map(T0, Map, [], Nil, Goal, TF).
  907
  908partial_map(T,[],[],_,_,T) :- !.
  909partial_map(black('',_,_,_),Map,Map,Nil,_,Nil) :- !.
  910partial_map(red(L,K,V,R),Map,MapF,Nil,Goal,red(NL,K,NV,NR)) :-
  911    partial_map(L,Map,MapI,Nil,Goal,NL),
  912    (   MapI == []
  913    ->  NR = R, NV = V, MapF = []
  914    ;   MapI = [K1|MapR],
  915        (   K == K1
  916        ->  (   call(Goal,V,NV)
  917            ->  true
  918            ;   NV = V
  919            ),
  920            MapN = MapR
  921        ;   NV = V,
  922            MapN = MapI
  923        ),
  924        partial_map(R,MapN,MapF,Nil,Goal,NR)
  925    ).
  926partial_map(black(L,K,V,R),Map,MapF,Nil,Goal,black(NL,K,NV,NR)) :-
  927    partial_map(L,Map,MapI,Nil,Goal,NL),
  928    (   MapI == []
  929    ->  NR = R, NV = V, MapF = []
  930    ;   MapI = [K1|MapR],
  931        (   K == K1
  932        ->  (   call(Goal,V,NV)
  933            ->  true
  934            ;   NV = V
  935            ),
  936            MapN = MapR
  937        ;   NV = V,
  938            MapN = MapI
  939        ),
  940        partial_map(R,MapN,MapF,Nil,Goal,NR)
  941    ).
 rb_keys(+Tree, -Keys) is det
Keys is unified with an ordered list of all keys in the Red-Black tree Tree.
  949:- det(rb_keys/2).  950rb_keys(t(_,T),Lf) =>
  951    keys(T,[],Lf).
  952
  953keys(black('',_,_,''),L,L) :- !.
  954keys(red(L,K,_,R),L0,Lf) :-
  955    keys(L,[K|L1],Lf),
  956    keys(R,L0,L1).
  957keys(black(L,K,_,R),L0,Lf) :-
  958    keys(L,[K|L1],Lf),
  959    keys(R,L0,L1).
 list_to_rbtree(+List, -Tree) is det
Tree is the red-black tree corresponding to the mapping in List, which should be a list of Key-Value pairs. List should not contain more than one entry for each distinct key, but this is not validated by list_to_rbtree/2.
  969:- det(list_to_rbtree/2).  970list_to_rbtree(List, T) :-
  971    sort(List,Sorted),
  972    ord_list_to_rbtree(Sorted, T).
 ord_list_to_rbtree(+List, -Tree) is det
Tree is the red-black tree corresponding to the mapping in list List, which should be a list of Key-Value pairs. List should not contain more than one entry for each distinct key, but this is not validated by ord_list_to_rbtree/2. List is assumed to be sorted according to the standard order of terms.
  982:- det(ord_list_to_rbtree/2).  983ord_list_to_rbtree([], Tree) =>
  984    Tree = t(Nil,Nil),
  985    Nil = black('', _, _, '').
  986ord_list_to_rbtree([K-V], Tree), nonvar(K) =>
  987    Tree = t(Nil,black(Nil,K,V,Nil)),
  988    Nil = black('', _, _, '').
  989ord_list_to_rbtree(List, Tree2) =>
  990    Tree2 = t(Nil,Tree),
  991    Nil = black('', _, _, ''),
  992    Ar =.. [seq|List],
  993    functor(Ar,_,L),
  994    Height is truncate(log(L)/log(2)),
  995    construct_rbtree(1, L, Ar, Height, Nil, Tree).
  996
  997construct_rbtree(L, M, _, _, Nil, Nil) :- M < L, !.
  998construct_rbtree(L, L, Ar, Depth, Nil, Node) :-
  999    !,
 1000    arg(L, Ar, K-Val),
 1001    build_node(Depth, Nil, K, Val, Nil, Node).
 1002construct_rbtree(I0, Max, Ar, Depth, Nil, Node) :-
 1003    I is (I0+Max)//2,
 1004    arg(I, Ar, K-Val),
 1005    build_node(Depth, Left, K, Val, Right, Node),
 1006    I1 is I-1,
 1007    NewDepth is Depth-1,
 1008    construct_rbtree(I0, I1, Ar, NewDepth, Nil, Left),
 1009    I2 is I+1,
 1010    construct_rbtree(I2, Max, Ar, NewDepth, Nil, Right).
 1011
 1012build_node( 0, Left, K, Val, Right, red(Left, K, Val, Right)) :- !.
 1013build_node( _, Left, K, Val, Right, black(Left, K, Val, Right)).
 rb_size(+Tree, -Size) is det
Size is the number of elements in Tree.
 1020:- det(rb_size/2). 1021rb_size(t(_,T),Size) =>
 1022    size(T,0,Size).
 1023
 1024size(black('',_,_,_),Sz,Sz) :- !.
 1025size(red(L,_,_,R),Sz0,Szf) :-
 1026    Sz1 is Sz0+1,
 1027    size(L,Sz1,Sz2),
 1028    size(R,Sz2,Szf).
 1029size(black(L,_,_,R),Sz0,Szf) :-
 1030    Sz1 is Sz0+1,
 1031    size(L,Sz1,Sz2),
 1032    size(R,Sz2,Szf).
 is_rbtree(@Term) is semidet
True if Term is a valid Red-Black tree. Processes the entire tree, checking the coloring of the nodes, the balance and the ordering of keys. It does not validate that keys are sufficiently instantiated to ensure the tree remains valid if a key is further instantiated.
 1041is_rbtree(X), var(X) =>
 1042    fail.
 1043is_rbtree(t(Nil,Nil)) => true.
 1044is_rbtree(t(_,T)) =>
 1045    Err = error(_,_),
 1046    catch(check_rbtree(T), Err, is_rbtree_error(Err)).
 1047
 1048is_rbtree_error(Err), Err = error(resource_error(_),_) => throw(Err).
 1049is_rbtree_error(_) => fail.
 1050
 1051%
 1052% This code checks if a tree is ordered and a rbtree
 1053%
 1054% TODO: Use (?=)/2 to verify that pairwise keys are strictly
 1055%       ordered, no matter how the keys become instantiated.
 1056%       This is not a complete test; to be completely safe, all
 1057%       use of compare/3 (and (@<)/2 etc) would need to also
 1058%       use (?=)/2, which would be expensive.
 1059
 1060check_rbtree(black(L,K,_,R)) =>
 1061    find_path_blacks(L, 0, Bls),
 1062    check_rbtree(L,-inf,K,Bls),
 1063    check_rbtree(R,K,+inf,Bls).
 1064check_rbtree(Node), Node = red(_,_,_,_) =>
 1065    domain_error(rb_black, Node).
 1066
 1067
 1068find_path_blacks(black('',_,_,''), Bls0, Bls) => Bls = Bls0.
 1069find_path_blacks(black(L,_,_,_), Bls0, Bls) =>
 1070    Bls1 is Bls0+1,
 1071    find_path_blacks(L, Bls1, Bls).
 1072find_path_blacks(red(L,_,_,_), Bls0, Bls) =>
 1073    find_path_blacks(L, Bls0, Bls).
 1074
 1075check_rbtree(black('',_,_,''),Min,Max,Bls0) =>
 1076    check_height(Bls0,Min,Max).
 1077check_rbtree(red(L,K,_,R),Min,Max,Bls) =>
 1078    check_val(K,Min,Max),
 1079    check_red_child(L),
 1080    check_red_child(R),
 1081    check_rbtree(L,Min,K,Bls),
 1082    check_rbtree(R,K,Max,Bls).
 1083check_rbtree(black(L,K,_,R),Min,Max,Bls0) =>
 1084    check_val(K,Min,Max),
 1085    Bls is Bls0-1,
 1086    check_rbtree(L,Min,K,Bls),
 1087    check_rbtree(R,K,Max,Bls).
 1088
 1089check_height(0,_,_) => true.
 1090check_height(Bls0,Min,Max) =>
 1091    throw(error(rbtree(balance(Bls0, Min, Max)), _)).
 1092
 1093check_val(K, Min, Max), (K @> Min ; Min == -inf), (K @< Max ; Max == +inf) =>
 1094    true.
 1095check_val(K, Min, Max) =>
 1096    throw(error(rbtree(order(K, Min, Max)), _)).
 1097
 1098check_red_child(black(_,_,_,_)) => true.
 1099check_red_child(Node), Node = red(_,_,_,_) =>
 1100    domain_error(rb_black, Node).
 1101
 1102
 1103		 /*******************************
 1104		 *            MESSAGES		*
 1105		 *******************************/
 1106
 1107:- multifile
 1108    prolog:error_message//1. 1109
 1110prolog:error_message(rbtree(balance(Bls0, Min, Max))) -->
 1111    [ 'Unbalance ~d between ~w and ~w'-[Bls0,Min,Max] ].
 1112prolog:error_message(rbtree(order(K, Min, Max))) -->
 1113    [ 'not ordered: ~w not between ~w and ~w'-[K,Min,Max] ]