1 /**
2 Copyright: Copyright (c) 2016- Alexander Orlov. All rights reserved.
3 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License).
4 Authors: Alexander Orlov, $(LINK2 mailto:sascha.orlov@gmail.com, sascha.orlov@gmail.com) 
5 */
6 
7 /**
8 This module implements a Van Emde Boas tree container.
9 
10 The module is still a work in progress. So, if you find an error by chance, please let me know in any way.
11 
12 The main idea of the container is, to restrict the capacity of the tree by the next power of two universe size, given a
13 maximum element at the initialization. As long as the usage is intended to contains keys, as in the current version,
14 this restriction is not only a restriction of the amount of elements but also on the contained element values. 
15 */
16 
17 // TODO: provide functionality to contain non-unique keys, i. e. exercise 20.3.1 from Cormen
18 // TODO: provide functionality to contain associated data with the keys, i. e. exercise 20.3.2 from Cormen
19 
20 /**
21 In this version, the maximum size of the universe possible is 2^32. With this restriction all unsigned integers could
22 be used as keys, if the appropriate maximum value is given on initialization. 
23 
24 The main advantage of the Van Emde Boas tree appears on a large amount of elements, as the provided standard operations
25 of the tree are constant in time and of order O(lg2(lg2(U))), where U is the capacity of the tree. For small amount of
26 elements the overhead coming along with the structure take over. For example, for a universe size of 2^14 and 15872
27 insertion operatios the duration for the Van Emde Boas tree is about 1*10^(-3) times smaller. As one of the unittests
28 shows. 
29 */
30 
31 /**
32 Be aware, the current container is intended to be used with keys. This implies, that the capacity, fixed on its
33 initialization has two meanings. As usual, it shows the maximum amount of elements the instanciated tree can keep. But 
34 also, it states, that no value bigger then capacity - 1 exists in the tree. This, and the fact, that only non-negative 
35 values can be used are infered from the term "key".
36 */
37 
38 /**
39 See_also: Thomas H. Cormen, Clifford Stein, Ronald L. Rivest, and Charles E. Leiserson. 2001. <em>Introduction to
40 Algorithms</em> (2nd ed.). McGraw-Hill Higher Education.
41 */
42 
43 module vebtree; 
44 
45 import std.typecons; /// used for Nullable!uint 
46 import core.bitop; 
47 import comp = std.algorithm.comparison;
48 import std.algorithm.iteration; 
49 import std.exception; 
50 import std.range; 
51 
52 version(unittest) 
53 { 
54     import std.random; 
55     import std.datetime; 
56     import std.conv : to;
57     import std.container;
58     import std.algorithm.setops; 
59     import std.algorithm.sorting;
60     import std.algorithm.searching;
61 }
62 
63 // defines the base universe size of a tree node. 
64 ubyte BASE_SIZE = 2; 
65 
66 // Convinience function to return the ceiling to the next power of two number of the given input. 
67 uint nextPowerOfTwo(uint value) { return 1 << (bsr(value) + 1); }
68 ///
69 unittest
70 {
71     assert(nextPowerOfTwo(1000) == 1024); 
72     assert(nextPowerOfTwo(1024) == 2048); 
73 }
74 
75 /*
76 This function returns the upper square root of the given input as integer. It is needed in the initialization step of
77 the VEB tree to calculate the number of children of a given layer. The upper square root is defined by 2^{\lceil(\lg
78 u)/2\rceil}
79 */
80 uint higherSquareRoot(uint value){return 1 << (value.lowerSqrtShift + (value > (1 << value.bsr) || value.bsr & 1));}
81 ///
82 unittest
83 {
84     assert(higherSquareRoot(5) == 4);
85     assert(higherSquareRoot(17) == 8);
86     assert(higherSquareRoot(88) == 16); 
87     assert(higherSquareRoot(64) == 8); 
88     assert(higherSquareRoot(128) == 16); 
89 }
90 
91 /*
92 This function returns the floored log2 value of the input. This is done by counting up to the position of the leading
93 bit position and dividing this value by two. This method is needed both by the higher and lower square root
94 calculation. 
95 */
96 uint lowerSqrtShift(uint value) { return bsr(value)/2; }
97 ///
98 unittest
99 {
100     assert(lowerSqrtShift(8) == 1); 
101 }
102 
103 /*
104 This function returns the lower square root of the given input as integer. It is needed by the indexing functions
105 high(x), low(x) and index(x,y) of elements in the tree. The lower square root is defined by 2^{\lfloor(\lg u)/2\rfloor}
106 */
107 uint lowerSquareRoot(uint value) { return 1 << lowerSqrtShift(value); }
108 ///
109 unittest
110 {
111     assert(lowerSquareRoot(5) == 2);
112     assert(lowerSquareRoot(17) == 4);
113     assert(lowerSquareRoot(88) == 8);
114     assert(lowerSquareRoot(64) == 8); 
115 }
116 
117 /*
118 This is an index function defined as \lfloor x/lowerSquareRoot(u)\rfloor. It is needed to find the appropriate cluster
119 of a element in the tree. 
120 */
121 uint high(uint value, uint universeSize) { return value/lowerSquareRoot(universeSize); }
122 ///
123 unittest
124 {
125     assert(high(7,16) == 1); 
126 }
127 
128 /*
129 This is an index function defined as fmod(value, lowerSquareRoot(universeSize)). It is needed to find the appropriate
130 value inside a cluster. 
131 */
132 uint low(uint value, uint universeSize){ return value & (lowerSquareRoot(universeSize) - 1); }
133 ///
134 unittest
135 {
136     assert(low(7,16) == 3); 
137 }
138 
139 /*
140 This is an index function to retain the searched value. It is defined as x * lowerSquareRoot(u) + y. Beyond this, the
141 relation holds: x = index(high(x), low(x))
142 */
143 uint index(uint universeSize, uint x, uint y){ return (x * lowerSquareRoot(universeSize) + y); }
144 ///
145 unittest
146 {
147     uint currentSeed = unpredictableSeed();
148     Random rndGenInUse; 
149     rndGenInUse.seed(currentSeed); //initialize the random generator
150     uint M = uniform(0U,1 << 14, rndGenInUse); //set universe size to some integer. 
151     uint U = nextPowerOfTwo(M); 
152     uint x = uniform(0U, U, rndGenInUse); 
153     uint y = uniform(0U, U, rndGenInUse); 
154     
155     assert(index(U, high(x, U), low(x, U)) == x); 
156 }
157 
158 /**
159 This is the struct to represent a VEB tree node. As memebers it contains the universeSize, the min and the max value as
160 well as a link to a summary node and a cluster, which is a range of VEB tree nodes of size higherSquareRoot(u). Each
161 child node has a universe size of lowerSquareRoot(u)
162 */
163 private struct vebNode
164 {
165     uint _universeSize;
166     @property uint universeSize(){ return _universeSize; }
167     
168     // min value is contained in the node as a separate value, this value can't be found in child nodes. 
169     Nullable!uint _min; 
170     @property void min(uint value){ _min = value; }
171     @property Nullable!uint min() { return _min; }
172     
173     // max value is contained in the node as a separate value, this can be found in child nodes.
174     Nullable!uint _max; 
175     @property void max(uint value){ _max = value; }
176     @property Nullable!uint max(){ return _max; }
177     
178     // the node is empty, iff neither min nor max is set. 
179     @property bool empty() { return min.isNull; }
180     
181     // VEB node containing the summary node. 
182     private vebNode* _summary; 
183     // VEB cluster containing the child nodes.
184     private vebNode[] _cluster;
185     
186     
187     @disable this(); // initializing without providing a universe size is prohibited. 
188     this(uint universeSize) // ditto
189     {
190         this._universeSize = universeSize; 
191         initializeChildren(universeSize); 
192     }
193     
194     // after constructing the node, construct every of its children. 
195     private void initializeChildren(uint universeSize)
196     {
197         if(universeSize > BASE_SIZE)
198         {
199             auto childUniverseSize = higherSquareRoot(universeSize); 
200             _summary = new vebNode(childUniverseSize); 
201             _cluster = iota(0,childUniverseSize).map!(a => vebNode(lowerSquareRoot(universeSize))).array; 
202         }
203     }
204     
205     /*
206     this function inserts a value into an empty node. The difference between empty and non empty insert is, that the
207     algorithm doesn't look into deepness of the tree, it just inserts the node to the separately stored min and max
208     members. 
209     */
210     private void emptyInsert(uint x)
211     {
212         min = x; 
213         max = x; 
214     }
215     
216     // this function inserts a value into a generic node. If the member exists, no insertion will be done. 
217     void insert(uint x)
218     {        
219         if(this.empty)
220             emptyInsert(x); 
221         else 
222         {
223             if(x < min)
224             {
225                 auto temp = x; x = min; min = temp; 
226             }
227             
228             if(universeSize > BASE_SIZE)
229             {
230                 if(_cluster[high(x)].min.isNull)
231                 {
232                     _summary.insert(high(x)); 
233                     _cluster[high(x)].emptyInsert(low(x)); 
234                 }
235                 else
236                     _cluster[high(x)].insert(low(x)); 
237             }
238             if(x > max)
239                 max = x; 
240         }
241     }
242     
243     // this function removes a value from the tree. If the value doesn't exist in the tree nothing will be happen. 
244     void remove(uint x)
245     {  
246         // case: there is only single element
247         if(min == max)
248         {
249             _min.nullify; 
250             _max.nullify; 
251         }
252         else if(BASE_SIZE == universeSize)
253         {
254             min = (x == 0) ? 1 : 0; 
255             max = min; 
256         }
257         else 
258         {
259             if(x == min)
260             {
261                 auto firstcluster = _summary.min; 
262                 x = index(firstcluster, _cluster[firstcluster].min); 
263                 min = x; 
264             }
265             _cluster[high(x)].remove(low(x)); 
266             if(_cluster[high(x)].min.isNull)
267             {
268                 _summary.remove(high(x)); 
269                 if(x == max)
270                 {
271                     auto summarymax = _summary.max;
272                     if(summarymax.isNull)
273                         max = min; 
274                     else
275                         max = index(summarymax, _cluster[summarymax].max); 
276                 }
277             }
278             else if(x == max)
279                 max = index(high(x), _cluster[high(x)].max); 
280         }
281     }
282     
283     /*
284     this function returns the successor of the given value, even, if the value is not present in the tree. 
285     If the value is maximum or greater then the maximum of the tree null is returned. 
286     */
287     Nullable!uint successor(uint x)
288     {
289         Nullable!uint result; 
290         
291         if(BASE_SIZE == universeSize)
292         {
293             if(x == 0 && max == 1)
294                 result = 1; 
295         }
296         else
297         {
298             if(!min.isNull && x < min)
299                 result = min; 
300             else
301             {
302                 if(!max.isNull && x < max)
303                 {
304                     auto maxlow = _cluster[high(x)].max;
305                     if(!maxlow.isNull && low(x) < maxlow)
306                     {
307                         auto offset = _cluster[high(x)].successor(low(x));
308                         result = index(high(x), offset); 
309                     }
310                     else
311                     {
312                         auto succcluster = _summary.successor(high(x)); 
313                         if(!succcluster.isNull)
314                         {
315                             auto offset = _cluster[succcluster].min; 
316                             result = index(succcluster, offset); 
317                         }
318                     }
319                 }
320             }
321         }
322         return result; 
323     }
324     
325     /*
326     this function returns the predecessor of the given value, even, if the value is not present in the tree. 
327     if the value is the minimum or smaller then the minimum of the tree null is returned.
328     */
329     Nullable!uint predecessor(uint x)
330     {
331         Nullable!uint result; 
332         if(BASE_SIZE == universeSize)
333         { 
334             if(x == 1 && !min.isNull && min == 0)
335                 result = 0; 
336         }
337         else
338         {
339             if(!max.isNull && x > max)
340                 result = max; 
341             else
342             {
343                 auto minlow = _cluster[high(x)].min; 
344                 if(!minlow.isNull && low(x) > minlow)
345                 {
346                     auto offset = _cluster[high(x)].predecessor(low(x)); 
347                     result = index(high(x), offset); 
348                 }
349                 else
350                 {
351                     auto predcluster = _summary.predecessor(high(x)); 
352                     if(predcluster.isNull)
353                     {
354                         if(!min.isNull && x > min)
355                             result = min; 
356                     }
357                     else
358                     {
359                         auto offset = _cluster[predcluster].max; 
360                         result = index(predcluster, offset); 
361                     }
362                 }
363             }
364         }
365         return result; 
366     }
367     
368     // This function returns whether the input key is currently member of the tree. 
369     bool member(uint x)
370     {
371         bool returnVal;
372        
373         if(x < universeSize)
374         {
375             if(!min.isNull && (min == x || max == x))
376                 returnVal = true; 
377             else 
378             {
379                 if(BASE_SIZE != universeSize)
380                     returnVal = _cluster[high(x)].member(low(x));
381             }
382         }
383         return returnVal; 
384     }
385     
386     // this function is an concretization of the module wide indexing function 
387     uint index(uint x, uint y){ return .index(universeSize, x, y); }
388 
389     // this function is an concretization of the module wide indexing function     
390     uint high(uint x){ return .high(x, universeSize); }
391 
392     // this function is an concretization of the module wide indexing function     
393     uint low(uint x){ return .low(x, universeSize); }
394 }
395 
396 /**
397 This struct represents the VEB tree itself. For the sake of convinience it saves the provided at the initialization step
398 wished maximum element. However at the point of development it is only used for testing. Beyond this, it stores only
399 the reference to the root element, as the theory tells. The tree implements not only the documented interface of a 
400 van VEB tree, but is also a bidirectional range. It supports two slice operations and a non-trivial opIndex operator. 
401 */
402 class vebTree
403 {
404     // the root element of the tree. 
405     private vebNode root; 
406     // this member is updated on every insertion and deletion to give the current element count on O(1)
407     private uint _elementCount; 
408     // this member stores the initialization size, as it would be lost forever after initialization, otherwise
409     immutable uint expectedSize; 
410     
411     /// default constructor of a VEB tree is disabled. 
412     @disable this(); 
413     
414     /// to construct a VEB tree one should provide the maximum element one wish to be able to store. 
415     this(uint expectedSize)
416     {
417         root = vebNode(nextPowerOfTwo(expectedSize - 1));
418         this.expectedSize = expectedSize; 
419     }
420     
421     /// another possibility is to construct a VEB tree by providing an array.
422     this(uint[] range)
423     {
424         // check, whether the range is not too long. I. e. expressable with an uint. 
425         enforce(bsr(range.length) < bsr(uint.max));
426         
427         // first, we have to determine the size of the tree. 
428         // it is either derived from the length of the given tree or its greatest element
429         uint limit = cast(uint)range.length; 
430         
431         foreach(uint i; range) limit = comp.max(limit,i); 
432 
433         enforce(bsr(limit) < bsr(uint.max), "you are crazy, dude!"); 
434         this(limit + 1);
435 
436         foreach(uint i; range) insert(i); 
437     }
438     
439     /** 
440     this method returns the capacity of the tree. It is equal to the next power of two with regard to the maximum
441     element 
442     */
443     uint capacity(){ return root.universeSize; }
444     
445     /// this method is used to add an element to the tree. duplicate values will be ignored. 
446     void insert(uint x)
447     { 
448         if(x < capacity && !member(x))
449         {
450             root.insert(x); 
451             _elementCount++; 
452         }
453     }
454     
455     /// this method overrides the insert method to directly use arrays
456     void insert(uint[] arr){ foreach(uint i; arr) insert(i); }
457     
458     /// this method is used to remove elements from the tree. not existing values will be ignored. 
459     void remove(uint x)
460     { 
461         if(member(x))
462         {
463             root.remove(x); 
464             _elementCount--; 
465         }
466     }
467     
468     /// this method is used to determine, whether an element is currently present in the tree
469     bool member(uint x){ return root.member(x); }
470     
471     /// this method is used to determine the minimum of the tree
472     @property Nullable!uint min(){ return front; }
473 
474     /// this method is used to determine the maximum of the tree    
475     @property Nullable!uint max(){ return back; }
476     
477     /// this method retrieves the successor of the given input.
478     Nullable!uint successor(uint x){ return root.successor(x); }
479     
480     /// this method retrieves the predecessor of the given input. 
481     Nullable!uint predecessor(uint x){ return root.predecessor(x); }
482     
483     // this method is used to determine, whether the tree is currently containing an element. 
484     @property bool empty(){ return root.empty; }
485     
486     // this method returns the minimium. 
487     @property Nullable!uint front(){ return root.min; }
488     
489     // this method removes the minimum element
490     void popFront(){ if(!empty) remove(min); }
491     
492     // forward range also needs save. This is a draft version of the save function, it uses the opslice of the struct
493     // to construct a new one via an array
494     @property vebTree save() { return new vebTree(this[]); }
495     
496     /**
497     opSlice operator to get the underlying array. 
498     This is a draft version, as it uses the successor method of the class. So getting the underlying array is 
499     proportional to n. As this functionaly is not seen as crucial, it is enough for the first time. 
500     */
501     uint[] opSlice()
502     {
503         uint[] retArray; 
504         if(!min.isNull)
505         {
506             retArray ~= min;
507             if(min != max)
508             {
509                 retArray.reserve(max - min + 1);
510                 while(retArray[$-1] != max)
511                     retArray ~= successor(retArray[$-1]); 
512             }
513         }
514         return retArray; 
515     }
516     
517     /**
518     opSlice operator to get the underlying array between given bounds. 
519     This is a draft version, as it uses the successor method of the class. So getting the underlying array is 
520     proportional to min(n, m), where n is the number of elements between bounds and m are the number of present 
521     elements in the tree. 
522     */
523     uint[] opSlice(uint begin, uint end)
524     {
525         uint[] retArray;
526          
527         if(!max.isNull)
528         {
529             uint limit = comp.min(end,this.max); 
530             if(begin < limit)
531             {
532                 if(this.member(begin))
533                     retArray ~= begin; 
534                 else
535                 {
536                     auto i = successor(begin);
537                     if(!i.isNull && i < end)
538                         retArray ~= i; 
539                 }
540                 if(min != max)
541                 {                    
542                     retArray.reserve(limit - begin + 1); 
543                     auto i = successor(retArray[$-1]); 
544                     while(!i.isNull && i < limit)
545                     {
546                         retArray ~= i; 
547                         i = successor(retArray[$-1]); 
548                     }
549                 }
550             }
551         }
552         return retArray; 
553     }
554     
555     /**
556     This is a nontrivial opIndex operator on indizies of the tree. Given an index a range (!) is returned, which is, 
557     either the range of elements in the tree build up by [predecessor(i) .. successor(i)] (i. e. excluding the 
558     successor(i)), when the given index is not set. Or, if the given index is set, [member(i), successor(i)]. If an 
559     index out of bounds is given, an empty array is returned. The tree must not be empty to use this function. 
560     */
561     auto opIndex(uint i)
562     {        
563         enforce(!this.empty);
564         
565         auto retVal = iota(0U, 0U);
566         if(i < this.capacity)
567             retVal = iota(aMin(i), aMax(i));
568         
569         return retVal; 
570     }
571     
572     // find the maximum for the slice for the opIndex operation
573     private uint aMax(uint i)
574     {
575         uint retVal = (this.max < expectedSize && i < expectedSize) ? expectedSize : this.capacity;
576         
577         if(i < this.min)
578         {
579             retVal = this.min; 
580         }
581         else
582         {
583             if(i < this.max)
584             {
585                 retVal = successor(i); 
586             }
587         }
588         return retVal; 
589     }
590     
591     // find the minimum for the slice for the opIndex operation
592     private uint aMin(uint i)
593     {
594         uint retVal; 
595         if(i >= this.min)
596         {
597             if(i >= this.max)
598             {
599                 retVal = this.max; 
600             }
601             else
602             {
603                 if(this.member(i))
604                     retVal = i; 
605                 else
606                     retVal = predecessor(i); 
607             }
608         }
609         return retVal; 
610     }
611     
612     // TODO: implement some kind of cool output as a graphViz pic, similiar to the graphs in Cormen. 
613     
614     // bidirectional range also needs
615     @property Nullable!uint back() { return root.max; }
616     
617     // this method removes the maximum element 
618     void popBack() { if(!empty) remove(max); }
619     
620     /**
621     This method returns the amount of elements currently present in the tree.
622     This is a draft version, as it uses the slice operator of the class. So getting this number has a complexity
623     proportional to n. As this functionaly is not seen as crucial, it is enough for the first time. 
624     */
625     @property uint length(){ return _elementCount; }
626     
627     version(unittest)
628     {
629         // this member stores the provided input on initialization. This value could be used to hard prevent of adding
630         // elements between this value and the capacity of the tree. 
631         @property auto elementCount(){ return this[].length; }
632         
633         uint fill(uint m, Random rndGenInUse)
634         {
635             uint n; 
636             for(uint i = 0; i < m; ++i)
637             {
638                 uint x = uniform(0, expectedSize, rndGenInUse);
639                 // the check for membership is done to add only on inserting to the counter, not just 
640                 // because visiting the the loop
641                 if(!member(x))
642                 {
643                     insert(x); 
644                     ++n; 
645                 }
646             }
647             return n; 
648         }
649         
650         uint fill(ref uint[] arr, Random rndGenInUse, uint fillPercentage = 31)
651         {
652             uint n; 
653             while(n != fillPercentage * capacity/32)
654             {
655                 uint x = uniform(0, cast(uint)(capacity - 1), rndGenInUse);
656                 // the check for membership is done to add only on inserting to the counter, not just 
657                 // because visiting the the loop
658                 if(!member(x))
659                 {
660                     insert(x); 
661                     arr ~= x; 
662                     ++n; 
663                 }
664             
665             }
666             assert(n == fillPercentage*capacity/32); 
667             return n; 
668         }
669     }
670 }
671 
672 ///
673 version(unittest)
674 {   
675     vebTree fill(uint M, Random rndGenInUse)
676     {
677         vebTree vT = new vebTree(M); 
678         for(auto i = 0; i < 1000; i++)
679         {
680             uint x = uniform(0U, vT.expectedSize, rndGenInUse); 
681             vT.insert(x); 
682         }
683         return vT; 
684     }
685 }
686 
687 ///
688 unittest
689 {
690     vebTree vT = new vebTree(100); 
691     vT.insert(2); 
692     assert(vT.member(2)); 
693     vebTree vT2 = vT.save(); 
694     assert(vT2.member(2)); 
695     vT2.insert(3); 
696     assert(vT2.member(3)); 
697     assert(!vT.member(3));
698 }
699 
700 ///
701 unittest
702 {
703     assert(!__traits(compiles, new vebTree())); 
704     vebTree vT = new vebTree(1000); 
705     assert(vT.capacity == 1024); 
706     assert(vT.min.isNull); 
707     
708     vT.insert(2); 
709     vT.insert(5); 
710     assert(!vT.member(8)); 
711     vT.insert(88);
712     vT.insert(8); 
713     assert(vT.predecessor(75) == 8); 
714     assert(vT.successor(6) == 8); 
715     assert(!vT.member(1029)); 
716     vT.insert(1029); 
717     assert(!vT.member(1029)); 
718 
719 
720     assert(!vT.member(865)); 
721     vT.insert(865); 
722     assert(vT.member(865)); 
723     vT.insert(865); 
724     assert(vT.member(865)); 
725     assert(!vT.member(866)); 
726     vT.remove(866); 
727     assert(vT.member(865)); 
728     vT.remove(865); 
729     assert(!vT.member(865)); 
730 }
731 
732 ///
733 unittest
734 {
735     Random rndGenInUse; 
736     uint currentSeed = 83843; // unpredictableSeed();
737     rndGenInUse.seed(currentSeed); //initialize the random generator
738     uint M = uniform(0U,1 << 14, rndGenInUse); //set universe size to some integer. 
739     //M = 30_000_000; 
740     vebTree vT = new vebTree(M); //create the tree
741     assert(vT.capacity == nextPowerOfTwo(M)); 
742     uint m = vT.fill(1000, rndGenInUse); //(try to) fill the tree with thousend values 
743     uint n; 
744     Nullable!uint i = vT.predecessor(vT.max)+1; 
745     // discover the thousend (or little less) values with the predecessor method
746     while(!i.isNull)
747     {
748         ++n; 
749         i = vT.predecessor(i); 
750     }
751     
752     // assert, that all members are discovered, iff when no predecessors are left
753     assert(n == m); 
754 }
755 
756 ///
757 unittest
758 {
759     Random rndGenInUse; 
760     uint currentSeed = 433849; //unpredictableSeed(); 
761     rndGenInUse.seed(currentSeed); //initialize the random generator
762     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
763     vebTree vT = fill(M, rndGenInUse); //fill the tree with some values 
764     Nullable!uint i = vT.max; 
765     
766     // remove all members beginning from the maximum
767     while(!i.isNull)
768     {
769         vT.remove(i); 
770         auto j = vT.predecessor(i); 
771         if(!j.isNull)
772             assert(j != i); 
773         i = j; 
774     }
775     
776     // assert, that all members are removed, iff when no predecessors are left. 
777     assert(vT.empty); 
778 }
779 
780 ///
781 unittest
782 {
783     Random rndGenInUse; 
784     uint currentSeed = 438749; //unpredictableSeed(); 
785     rndGenInUse.seed(currentSeed); //initialize the random generator
786     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
787     vebTree vT = fill(M, rndGenInUse); //fill the tree with some values 
788     Nullable!uint i = vT.min-1;
789     
790     // remove all members beginning from the minimum
791     while(!i.isNull)
792     {
793         vT.remove(i); 
794         auto j = vT.successor(i); 
795         if(!j.isNull)
796             assert(j != i); 
797         i = j; 
798     } 
799 
800     // assert, that all members are removed, iff when no successors are left.
801     assert(vT.empty); 
802 }
803 
804 ///
805 unittest
806 {
807     uint M = 1 << 16; 
808     vebTree vT = new vebTree(M); 
809     vT.insert(0x000f); 
810     assert(vT.predecessor(0x000f).isNull);
811     vT.insert(0x00f0);
812     assert(vT.predecessor(0x00f0) == 0x000f); 
813     vT.insert(0x0f00); 
814     assert(vT.predecessor(0x0f00) == 0x00f0); 
815     vT.insert(0xf000); 
816     assert(vT.predecessor(0xf000) == 0x0f00);
817     
818     vT.remove(0xf000); 
819     assert(vT.predecessor(0xf000) == 0x0f00);
820     vT.remove(0x0f00); 
821     assert(vT.predecessor(0x0f00) == 0x00f0); 
822     vT.remove(0x00f0); 
823     assert(vT.predecessor(0x00f0) == 0x000f); 
824     vT.remove(0x000f); 
825     assert(vT.predecessor(0x000f).isNull);
826 }
827 
828 ///
829 unittest
830 {
831     uint M = 1 << 16; 
832     vebTree vT = new vebTree(M); 
833     vT.insert(0xf000); 
834     assert(vT.member(0xf000)); 
835     vT.insert(0x0f00); 
836     assert(vT.member(0x0f00)); 
837     vT.insert(0x00f0);
838     assert(vT.member(0x00f0)); 
839     vT.insert(0x000f); 
840     assert(vT.member(0x000f)); 
841     
842     vT.remove(0xf000); 
843     assert(!vT.member(0xf000)); 
844     vT.remove(0x0f00); 
845     assert(!vT.member(0x0f00)); 
846     vT.remove(0x00f0); 
847     assert(!vT.member(0x00f0)); 
848     vT.remove(0x000f); 
849     assert(!vT.member(0x000f)); 
850 }
851 
852 /// 
853 unittest
854 {
855     Random rndGenInUse; 
856     //stress test
857     uint currentSeed = 1948642567; //unpredictableSeed(); 
858     rndGenInUse.seed(currentSeed); //initialize the random generator
859     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
860     // last test says: inserting and removing with veb of 8.126.464 elements lasts: 19secs,217ms
861     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
862     vebTree vT = new vebTree(M); 
863     uint[] arr; 
864     auto howMuchFilled = vT.fill(arr, rndGenInUse); 
865 
866     assert(arr.length == howMuchFilled); 
867     
868     vebTree vT2 = new vebTree(M); 
869     
870     assert(vT2.capacity == vT.capacity); 
871     
872     auto rbt = redBlackTree!uint(0); 
873     rbt.clear; 
874     
875     void fill1()
876     {
877         foreach(uint i; arr)
878         {
879             vT2.insert(i); 
880         }
881         /*
882         foreach(uint i; arr)
883         {
884             vT2.remove(i); 
885         }
886         assert(vT2.empty);
887         */
888     }
889     
890     void fill2()
891     {
892         foreach(uint i; arr)
893         {
894             rbt.insert(i); 
895         }
896     }
897     
898     /*
899     import std.stdio; 
900     writeln("howMuchFilled: ", howMuchFilled);
901     auto r = benchmark!(fill1, fill2)(1); 
902     //auto r = benchmark!(fill1)(1); 
903     auto f0Result = to!Duration(r[0]); 
904     auto f1Result = to!Duration(r[1]); 
905     writeln("VEB: ", f0Result); //10ms
906     writeln("rbt: ", f1Result); //40sec
907     assert(f0Result < f1Result); 
908     //*/
909 }
910 
911 ///
912 unittest
913 {
914     Random rndGenInUse; 
915     uint currentSeed = 1230394; //unpredictableSeed(); 
916     rndGenInUse.seed(currentSeed); //initialize the random generator
917     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer.
918     uint[] sourceArr; 
919     sourceArr.length = M; 
920     // generate a random array as the source for the tree
921     for(uint i = 0; i < M; i++) sourceArr[i] = uniform(0U, M, rndGenInUse); 
922     // constructor to test
923     vebTree vT = new vebTree(sourceArr); 
924     // make the array values unique. 
925     auto uniqueArr = sort(sourceArr).uniq;
926     // check, that all values are filled 
927     foreach(uint i; uniqueArr)
928     {
929         assert(vT.member(i)); 
930         vT.remove(i); 
931     }
932     // check, that no other elements are present. 
933     assert(vT.empty); 
934 }
935 
936 ///
937 unittest
938 {
939     Random rndGenInUse; 
940     uint currentSeed = 2349062; //unpredictableSeed(); 
941     rndGenInUse.seed(currentSeed); //initialize the random generator
942     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
943     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
944     vebTree vT = new vebTree(M); 
945     uint[] arr; 
946     vT.fill(arr, rndGenInUse, 16); 
947     
948     assert(setSymmetricDifference(vT[], sort(arr)).empty); 
949 }
950 
951 ///
952 unittest
953 {
954     Random rndGenInUse; 
955     uint currentSeed = 2309532090; //unpredictableSeed(); 
956     rndGenInUse.seed(currentSeed); //initialize the random generator
957     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
958     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
959     vebTree vT = new vebTree(M); 
960     uint[] arr; 
961     vT.fill(arr, rndGenInUse, 16); 
962     uint begin = 5; 
963     uint end = 100; 
964     auto filterRes = sort(arr).filter!(a => a >= begin && a < end); 
965     assert(setSymmetricDifference(filterRes, vT[begin..end]).empty); 
966 }
967 
968 ///
969 unittest
970 {
971     Random rndGenInUse; 
972     uint currentSeed = 1223409; //unpredictableSeed(); 
973     rndGenInUse.seed(currentSeed); //initialize the random generator
974     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
975     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
976     vebTree vT = new vebTree(M); 
977     uint[] arr; 
978     vT.fill(arr, rndGenInUse, 16); 
979     assert(vT.length == vT.elementCount); 
980 }
981 
982 ///
983 unittest
984 {
985     Random rndGenInUse;
986     uint currentSeed = 1435856534; //unpredictableSeed(); 
987     rndGenInUse.seed(currentSeed); //initialize the random generator
988     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
989     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
990     vebTree vT = new vebTree(M); 
991     uint[] arr; 
992     vT.fill(arr, rndGenInUse, 16); 
993     
994     assert(!vT.member(0));
995     assert(!vT.member(1)); 
996     assert(startsWith(vT[1], 0)); 
997     assert(vT.successor(vT[1][$-1]) == vT.successor(1));
998     assert(startsWith(vT[vT.successor(1)],vT.min)); 
999     assert(!vT.member(65535)); 
1000     assert(vT[65535].array == [65534, 65535]); 
1001     assert(vT.member(4)); 
1002     assert(startsWith(vT[4],4)); 
1003     assert(!vT.member(vT[4][$-1])); 
1004     assert(!vT.member(5)); 
1005     assert(startsWith(vT[5],4)); 
1006     assert(vT[5][$-1] == vT[4][$-1]);
1007 }
1008 
1009 ///
1010 unittest
1011 {
1012     assert(isBidirectionalRange!vebTree);
1013 }
1014 
1015 ///
1016 unittest
1017 {
1018     vebTree vT = new vebTree(14);
1019     vT.insert(2); 
1020     vT.insert(5); 
1021     vT.insert(10); 
1022     assert(vT[] == [2, 5, 10]); 
1023     assert(vT[6].array == [5, 6, 7, 8, 9]); 
1024     assert(vT[11].array == [10, 11, 12, 13]); 
1025     assert(vT[-1].array == []); 
1026     assert(vT[18].array == []); 
1027     assert(vT[1].array == [0, 1]);  
1028     assert(vT[15].array == [10, 11, 12, 13, 14, 15]); 
1029     assert(vT[16].array == []); 
1030 }
1031 
1032 ///
1033 unittest
1034 {
1035     vebTree vT = new vebTree(15); 
1036     vT.insert(2); 
1037     auto testrange = vT[3]; 
1038     assert(testrange.array == [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); 
1039     vT.insert(6); 
1040     testrange = vT[3];
1041     assert(testrange.array == [2, 3, 4, 5]); 
1042 }
1043 
1044 ///
1045 unittest
1046 {
1047     //another stress test
1048     Random rndGenInUse;
1049     auto currentSeed = 11351568; //unpredictableSeed(); 
1050     rndGenInUse.seed(currentSeed); //initialize the random generator
1051     
1052     void fill16(){ vebTree vT = new vebTree(1 << 16); }
1053     void fill17(){ vebTree vT = new vebTree(1 << 17); }
1054     void fill18(){ vebTree vT = new vebTree(1 << 18); }
1055     void fill19(){ vebTree vT = new vebTree(1 << 19); }    
1056     void fill20(){ vebTree vT = new vebTree(1 << 20); }
1057     void fill21(){ vebTree vT = new vebTree(1 << 21); }
1058     void fill22(){ vebTree vT = new vebTree(1 << 22); }
1059     void fill23(){ vebTree vT = new vebTree(1 << 23); }
1060     void fill24(){ vebTree vT = new vebTree(1 << 24); }
1061     void fill25(){ vebTree vT = new vebTree(1 << 25); }
1062     
1063     /*
1064     import std.stdio; 
1065     auto r = benchmark!(fill16, fill17, fill18, fill19, fill20, fill21, fill22, fill23, fill24, fill25)(1); 
1066     //auto r = benchmark!(fill1)(1); 
1067     auto f16Result = to!Duration(r[0]); 
1068     auto f17Result = to!Duration(r[1]); 
1069     auto f18Result = to!Duration(r[2]); 
1070     auto f19Result = to!Duration(r[3]); 
1071     auto f20Result = to!Duration(r[4]);
1072     auto f21Result = to!Duration(r[5]);
1073     auto f22Result = to!Duration(r[6]);
1074     auto f23Result = to!Duration(r[7]);
1075     auto f24Result = to!Duration(r[8]);
1076     auto f25Result = to!Duration(r[9]);
1077     writeln("VEB with M of ", 1 << 16, ": ", f16Result); 
1078     writeln("VEB with M of ", 1 << 17, ": ", f17Result);
1079     writeln("VEB with M of ", 1 << 18, ": ", f18Result);
1080     writeln("VEB with M of ", 1 << 19, ": ", f19Result);
1081     writeln("VEB with M of ", 1 << 20, ": ", f20Result);
1082     writeln("VEB with M of ", 1 << 21, ": ", f21Result);
1083     writeln("VEB with M of ", 1 << 22, ": ", f22Result);
1084     writeln("VEB with M of ", 1 << 23, ": ", f23Result);
1085     writeln("VEB with M of ", 1 << 24, ": ", f24Result);
1086     writeln("VEB with M of ", 1 << 25, ": ", f25Result); 
1087     //*/
1088 }
1089 
1090 ///
1091 unittest
1092 {
1093     /*
1094     uint[] arr = [1, 2, 8, 2147483647]; 
1095     auto vT = new vebTree(arr)); 
1096     */
1097 }