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 
48 version(unittest) { import std.random; Random rndGenInUse; }
49 
50 // this would be useful in case of coding the keys as a bitfield
51 // enum uint WORD = uint.sizeof * 8;
52 
53 // defines the base universe size of a tree node. 
54 ubyte BASE_SIZE = 2; 
55 
56 // Convinience function to return the ceiling to the next power of two number of the given input. 
57 size_t nextPowerOfTwo(size_t value) { return 1 << (bsr(value) + 1); }
58 ///
59 unittest
60 {
61     assert(nextPowerOfTwo(1000) == 1024); 
62 }
63 
64 /** 
65 This is the interface of a VEB tree. Besides the methods described below, the tree class implements the needed methods
66 for being a range. It is a bidirectional range with slice operations.
67 */
68 interface Iveb
69 {
70     //
71     void insert(uint x); 
72     //
73     void remove(uint x); 
74     //
75     bool member(uint x); 
76     //
77     Nullable!uint min(); 
78     //
79     Nullable!uint max(); 
80     //
81     Nullable!uint successor(uint x); 
82     //
83     Nullable!uint predecessor(uint x); 
84 }
85 
86 /*
87 This function returns the upper square root of the given input as integer. It is needed in the initialization step of
88 the VEB tree to calculate the number of children of a given layer. The upper square root is defined by 2^{\lceil(\lg
89 u)/2\rceil}
90 */
91 uint higherSquareRoot(size_t value){return 1 << (value.lowerSqrtShift + (value > (1 << value.bsr) || value.bsr & 1));}
92 ///
93 unittest
94 {
95     assert(higherSquareRoot(5) == 4);
96     assert(higherSquareRoot(17) == 8);
97     assert(higherSquareRoot(88) == 16); 
98     assert(higherSquareRoot(64) == 8); 
99     assert(higherSquareRoot(128) == 16); 
100 }
101 
102 /*
103 This function returns the floored log2 value of the input. This is done by counting up to the position of the leading
104 bit position and dividing this value by two. This method is needed both by the higher and lower square root
105 calculation. 
106 */
107 uint lowerSqrtShift(size_t value) { return bsr(value)/2; }
108 
109 /*
110 This function returns the lower square root of the given input as integer. It is needed by the indexing functions
111 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}
112 */
113 uint lowerSquareRoot(size_t value) { return 1 << lowerSqrtShift(value); }
114 ///
115 unittest
116 {
117     assert(lowerSquareRoot(5) == 2);
118     assert(lowerSquareRoot(17) == 4);
119     assert(lowerSquareRoot(88) == 8);
120     assert(lowerSquareRoot(64) == 8); 
121 }
122 
123 /*
124 This is an index function defined as \lfloor x/lowerSquareRoot(u)\rfloor. It is needed to find the appropriate cluster
125 of a element in the tree. 
126 */
127 uint high(uint value, size_t universeSize) { return value/lowerSquareRoot(universeSize); }
128 ///
129 unittest
130 {
131     assert(.high(7,16) == 1); 
132 }
133 
134 /*
135 This is an index function defined as fmod(value, lowerSquareRoot(universeSize)). It is needed to find the appropriate
136 value inside a cluster. 
137 */
138 uint low(uint value, size_t universeSize){ return value & (lowerSquareRoot(universeSize) - 1); }
139 ///
140 unittest
141 {
142     assert(.low(7,16) == 3); 
143 }
144 
145 /*
146 This is an index function to retain the searched value. It is defined as x * lowerSquareRoot(u) + y. Beyond this, the
147 relation holds: x = index(high(x), low(x))
148 */
149 uint index(size_t universeSize, uint x, uint y){ return (x * lowerSquareRoot(universeSize) + y); }
150 
151 /**
152 This is the class to represent a VEB tree node. As memebers it contains the universeSize, the min and the max value as
153 well as a link to a summary node and a cluster, which is a range of VEB tree nodes of size higherSquareRoot(u). Each
154 child node has a universe size of lowerSquareRoot(u)
155 */
156 private class vebNode
157 {    
158     immutable size_t _universeSize;
159     @property size_t universeSize(){ return _universeSize; }
160     
161     version(unittest){ size_t elementCount; }
162     
163     // min value is contained in the node as a separate value, this value can't be found in child nodes. 
164     Nullable!uint _min; 
165     @property void min(uint value){ _min = value; }
166     @property Nullable!uint min() { return _min; }
167     
168     // max value is contained in the node as a separate value, this can be found in child nodes.
169     Nullable!uint _max; 
170     @property void max(uint value){ _max = value; }
171     @property Nullable!uint max(){ return _max; }
172     
173     // the node is empty, iff neither min nor max is set. 
174     @property bool empty() { return min.isNull; }
175     
176     // VEB node containing the summary node. 
177     private vebNode _summary; 
178     // VEB cluster containing the child nodes.
179     private vebNode[] _cluster;
180     
181     
182     @disable this(); // initializing without providing a universe size is prohibited. 
183     this(size_t universeSize) // ditto
184     {
185         this._universeSize = universeSize; 
186         initializeChildren(universeSize); 
187     }
188     
189     // after constructing the node, construct every of its children. 
190     private void initializeChildren(size_t universeSize)
191     {
192         if(universeSize > BASE_SIZE)
193         {
194             auto childUniverseSize = higherSquareRoot(universeSize); 
195             _summary = new vebNode(childUniverseSize); 
196             _cluster = new vebNode[childUniverseSize]; 
197             foreach(ref vn; _cluster) 
198                 vn = new vebNode(lowerSquareRoot(universeSize)); 
199         }
200     }
201     
202     // this function inserts a value into an empty node. The difference between empty and non empty insert is, that the
203     // algorithm doesn't look into deepness of the tree, it just inserts the node to the separately stored min and max
204     // members. 
205     private void emptyInsert(uint x)
206     {
207         min = x; 
208         max = x; 
209     }
210     
211     // this function inserts a value into a generic node. If the member exists, no insertion will be done. 
212     void insert(uint x)
213     {
214         // TODO: to check, how this could be checked in a better way.
215         if(member(x)) 
216             return; 
217 
218         version(unittest){ elementCount++; }
219         
220         if(this.empty)
221             emptyInsert(x); 
222         else 
223         {
224             if(x < min)
225             {//import std.algorithm; swap(min.get, x); 
226                 auto temp = x; x = min; min = temp; 
227             }
228             
229             if(universeSize > BASE_SIZE)
230             {
231                 if(_cluster[high(x)].min.isNull)
232                 {
233                     _summary.insert(high(x)); 
234                     _cluster[high(x)].emptyInsert(low(x)); 
235                 }
236                 else
237                     _cluster[high(x)].insert(low(x)); 
238             }
239             if(x > max)
240                 max = x; 
241         }
242     }
243     
244     // this function removes a value from the tree. If the value doesn't exist in the tree nothing will be happen. 
245     void remove(uint x)
246     {
247         // TODO: to check, how this could be checked in a better way.
248         if(!member(x))
249             return; 
250         
251         version(unittest){ elementCount--; }
252         
253         // case: there is only single element
254         if(min == max)
255         {
256             _min.nullify; 
257             _max.nullify; 
258         }
259         else if(BASE_SIZE == universeSize)
260         {
261             min = (x == 0) ? 1 : 0; 
262             max = min; 
263         }
264         else 
265         {
266             if(x == min)
267             {
268                 auto firstcluster = _summary.min; 
269                 x = index(firstcluster, _cluster[firstcluster].min); 
270                 min = x; 
271             }
272             _cluster[high(x)].remove(low(x)); 
273             if(_cluster[high(x)].min.isNull)
274             {
275                 _summary.remove(high(x)); 
276                 if(x == max)
277                 {
278                     auto summarymax = _summary.max;
279                     if(summarymax.isNull)
280                         max = min; 
281                     else
282                         max = index(summarymax, _cluster[summarymax].max); 
283                 }
284             }
285             else if(x == max)
286                 max = index(high(x), _cluster[high(x)].max); 
287         }
288     }
289     
290     // this function returns the successor of the given value, even, if the value is not present in the tree. 
291     // If the value is maximum or greater then the maximum of the tree null is returned. 
292     Nullable!uint successor(uint x)
293     {
294         Nullable!uint result; 
295         
296         if(BASE_SIZE == universeSize)
297         {
298             if(x == 0 && max == 1)
299                 result = 1; 
300         }
301         else
302         {
303             if(!min.isNull && x < min)
304                 result = min; 
305             else
306             {
307                 if(!max.isNull && x < max)
308                 {
309                     auto maxlow = _cluster[high(x)].max;
310                     if(!maxlow.isNull && low(x) < maxlow)
311                     {
312                         auto offset = _cluster[high(x)].successor(low(x));
313                         result = index(high(x), offset); 
314                     }
315                     else
316                     {
317                         auto succcluster = _summary.successor(high(x)); 
318                         if(!succcluster.isNull)
319                         {
320                             auto offset = _cluster[succcluster].min; 
321                             result = index(succcluster, offset); 
322                         }
323                     }
324                 }
325             }
326         }
327         return result; 
328     }
329     
330     // this function returns the predecessor of the given value, even, if the value is not present in the tree. 
331     // if the value is the minimum or smaller then the minimum of the tree null is returned.
332     Nullable!uint predecessor(uint x)
333     {
334         Nullable!uint result; 
335         if(BASE_SIZE == universeSize)
336         { 
337             if(x == 1 && !min.isNull && min == 0)
338                 result = 0; 
339         }
340         else
341         {
342             if(!max.isNull && x > max)
343                 result = max; 
344             else
345             {
346                 auto minlow = _cluster[high(x)].min; 
347                 if(!minlow.isNull && low(x) > minlow)
348                 {
349                     auto offset = _cluster[high(x)].predecessor(low(x)); 
350                     result = index(high(x), offset); 
351                 }
352                 else
353                 {
354                     auto predcluster = _summary.predecessor(high(x)); 
355                     if(predcluster.isNull)
356                     {
357                         if(!min.isNull && x > min)
358                             result = min; 
359                     }
360                     else
361                     {
362                         auto offset = _cluster[predcluster].max; 
363                         result = index(predcluster, offset); 
364                     }
365                 }
366             }
367         }
368         return result; 
369     }
370     
371     // This function returns whether the input key is currently member of the tree. 
372     bool member(uint x)
373     {
374         bool returnVal;
375        
376         if(x < universeSize)
377         {
378             if(!min.isNull && (min == x || max == x))
379                 returnVal = true; 
380             else 
381             {
382                 if(BASE_SIZE != universeSize)
383                     returnVal = _cluster[high(x)].member(low(x));
384             }
385         }
386         return returnVal; 
387     }
388     
389     // this function is an concretization of the module wide indexing function 
390     uint index(uint x, uint y){ return .index(universeSize, x, y); }
391 
392     // this function is an concretization of the module wide indexing function     
393     uint high(uint x){ return .high(x, universeSize); }
394 
395     // this function is an concretization of the module wide indexing function     
396     uint low(uint x){ return .low(x, universeSize); }
397 }
398 
399 /**
400 This class represents the VEB tree itself. For the sake of convinience it saves the provided at the initialization step
401 wished maximum element. However at the point of development it is only used for testing. Beyond this, it stores only
402 the reference to the root element, as the theory tells. 
403 */
404 class vebTree : Iveb
405 {
406     // the root element of the tree. 
407     private vebNode root; 
408     
409     /// default constructor of a VEB tree is disabled. 
410     @disable this(); 
411     /// to construct a VEB tree one should provide the maximum element one wish to be able to store. 
412     this(uint maximumElement)
413     {
414         root = new vebNode(nextPowerOfTwo(maximumElement));
415         
416         version(unittest){ _maximumElement = maximumElement; }
417     }
418     
419     /// another possibility is to construct a VEB tree by providing an array.
420     this(uint[] range)
421     {
422         import std.algorithm.comparison; 
423         import std.algorithm.iteration; 
424         // first, we have to determine the size of the tree. 
425         // it is either derived from the length of the given tree or its greatest element
426         size_t limit = max(range.length, reduce!(max)(range)); 
427         
428         // without std.algorithm.iteration: 
429         // size_t limit = range.length; 
430         // foreach(uint i; range) limit = max(limit, i); 
431         
432         root = new vebNode(nextPowerOfTwo(limit));
433         foreach(uint i; range) root.insert(i); 
434     }
435     
436     /** 
437         this method returns the capacity of the tree. It is equal to the next power of two with regard to the maximum
438         element 
439     */
440     size_t capacity(){ return root.universeSize; }
441     
442     /// this method is used to add an element to the tree. duplicate values will be ignored. 
443     void insert(uint x){ if(x < capacity) root.insert(x); }
444     
445     /// this method is used to remove elements from the tree. not existing values will be ignored. 
446     void remove(uint x){ root.remove(x); }
447     
448     /// this method is used to determine, whether an element is currently present in the tree
449     bool member(uint x){ return root.member(x); }
450     
451     /// this method is used to determine the minimum of the tree
452     @property Nullable!uint min(){ return front; }
453 
454     /// this method is used to determine the maximum of the tree    
455     @property Nullable!uint max(){ return back; }
456     
457     /// this method retrieves the successor of the given input.
458     Nullable!uint successor(uint x){ return root.successor(x); }
459     
460     /// this method retrieves the predecessor of the given input. 
461     Nullable!uint predecessor(uint x){ return root.predecessor(x); }
462     
463     // this method is used to determine, whether the tree is currently containing an element. 
464     @property bool empty(){ return root.empty; }
465     
466     // this method returns the minimium. 
467     @property Nullable!uint front(){ return root.min; }
468     
469     // this method removes the minimum element
470     void popFront(){ if(!empty) root.remove(min); }
471     
472     // forward range also needs save. This is a draft version of the save function, it uses the opslice of the class to 
473     // construct a new one via an array
474     @property vebTree save(){ return new vebTree(this[]); }
475     
476     /**
477     opSlice operator to get the underlying array. 
478     This is a draft version, as it uses the successor method of the class. So getting the underlying array is 
479     proportional to n. As this functionaly is not seen as crucial, it is enough for the first time. 
480     */
481     uint[] opSlice()
482     {
483         uint[] retArray; 
484         if(!min.isNull)
485         {
486             retArray ~= min;
487             if(min != max)
488             {
489                 retArray.reserve(capacity);
490                 while(retArray[$-1] != max)
491                     retArray ~= successor(retArray[$-1]); 
492             }
493         }
494         return retArray; 
495     }
496     
497     /**
498     opSlice operator to get the underlying array between given bounds. 
499     This is a draft version, as it uses the successor method of the class. So getting the underlying array is 
500     proportional to min(n, m), where n is the number of elements between bounds and m are the number of present 
501     elements in the tree. 
502     */
503     uint[] opSlice(uint begin, uint end)
504     {
505         uint[] retArray; 
506         if(begin < end && begin < max)
507         {
508             if(!min.isNull)
509             {
510                 if(this.member(begin))
511                     retArray ~= begin; 
512                 else
513                 {
514                     uint i = successor(begin);
515                     if(i < end)
516                         retArray ~= i; 
517                 }
518                 if(min != max)
519                 {
520                     import std.algorithm.comparison;
521                     uint limit = min(end, this.max); 
522                     
523                     retArray.reserve(limit-begin); 
524                     uint i = successor(retArray[$-1]); 
525                     while(i < limit)
526                     {
527                         retArray ~= i; 
528                         i = successor(retArray[$-1]); 
529                     }
530                 }
531             }
532         }
533         return retArray; 
534     }
535     
536     /**
537     This is a nontrivial opIndex operator on indizies of the tree. Given an index a range (!) is returned, which is, 
538     either the range of elements in the tree build up by [predecessor(i) .. successor(i)] (i. e. excluding the 
539     successor(i)), when the given index is not set. Or, if the given index is set, [member(i), successor(i)]. If an 
540     index out of bounds is given, an empty array is returned. The tree must not be empty to use this function. 
541     */
542     uint[] opIndex(uint i)
543     {
544         import std.algorithm;
545         import std.range;
546         import std.exception; 
547         enforce(!this.empty);
548 
549         uint[] retArr;         
550         if(i < this.capacity)
551         {
552             uint absoluteMin; 
553             uint absoluteMax; 
554             
555             if(i < this.min)
556             {
557                 
558                 absoluteMin = 0; 
559                 absoluteMax = this.min; 
560             }
561             else
562             {
563                 if(i >= this.max)
564                 {
565                     absoluteMax = cast(uint)(capacity - 1); 
566                     absoluteMin = this.max; 
567                 }
568                 else
569                 {
570                     absoluteMax = successor(i); 
571                     if(this.member(i))
572                         absoluteMin = i; 
573                     else
574                         absoluteMin = predecessor(i); 
575                 }
576             }
577             retArr = iota(absoluteMin, absoluteMax).array;    
578             if(i >= this.max)
579                 retArr ~= absoluteMax; 
580         }
581         return retArr; 
582     }
583     
584     // TODO: implement some kind of cool output as a graphViz pic, similiar to the graphs in Cormen. 
585     
586     // bidirectional range also needs
587     @property Nullable!uint back() { return root.max; }
588     
589     // this method removes the maximum element 
590     void popBack() { if(!empty) root.remove(max); }
591     
592     /**
593     This method returns the amount of elements currently present in the tree.
594     This is a draft version, as it uses the slice operator of the class. So getting this number has a complexity
595     proportional to n. As this functionaly is not seen as crucial, it is enough for the first time. 
596     */
597     @property size_t elementCount(){ return this[].length; }
598     
599     version(unittest)
600     {
601         // this member stores the provided input on initialization. This value could be used to hard prevent of adding
602         // elements between this value and the capacity of the tree. 
603         private uint _maximumElement; 
604         @property size_t elementCount_ut(){ return root.elementCount; }
605         
606         uint fill(uint m)
607         {
608             uint n; 
609             for(uint i = 0; i < m; ++i)
610             {
611                 uint x = uniform(0, _maximumElement+1, rndGenInUse);
612                 // the check for membership is done to add only on inserting to the counter, not just 
613                 // because visiting the the loop
614                 if(!member(x))
615                 {
616                     insert(x); 
617                     ++n; 
618                 }
619             }
620             return n; 
621         }
622         
623         uint fill(ref uint[] arr, uint fillPercentage = 31)
624         {
625             uint n; 
626             while(n != fillPercentage * capacity/32)
627             {
628                 uint x = uniform(0, cast(uint)(capacity - 1), rndGenInUse);
629                 // the check for membership is done to add only on inserting to the counter, not just 
630                 // because visiting the the loop
631                 if(!member(x))
632                 {
633                     insert(x); 
634                     arr ~= x; 
635                     ++n; 
636                 }
637             
638             }
639             assert(n == fillPercentage*capacity/32); 
640             return n; 
641         }
642     }
643 }
644 
645 ///
646 unittest
647 {
648     assert(!__traits(compiles, new vebTree())); 
649     vebTree vT = new vebTree(1000); 
650     assert(vT.capacity == 1024); 
651     assert(vT.min.isNull); 
652     
653     vT.insert(2); 
654     vT.insert(5); 
655     assert(!vT.member(8)); 
656     vT.insert(88);
657     vT.insert(8); 
658     assert(vT.predecessor(75) == 8); 
659     assert(vT.successor(6) == 8); 
660     assert(!vT.member(1029)); 
661     vT.insert(1029); 
662     assert(!vT.member(1029)); 
663 
664 
665     assert(!vT.member(865)); 
666     vT.insert(865); 
667     assert(vT.member(865)); 
668     vT.insert(865); 
669     assert(vT.member(865)); 
670     assert(!vT.member(866)); 
671     vT.remove(866); 
672     assert(vT.member(865)); 
673     vT.remove(865); 
674     assert(!vT.member(865)); 
675 }
676 
677 ///
678 unittest
679 {
680     uint currentSeed = 83843; // unpredictableSeed();
681     rndGenInUse.seed(currentSeed); //initialize the random generator
682     uint M = uniform(0U,1 << 14, rndGenInUse); //set universe size to some integer. 
683     //M = 30_000_000; 
684     vebTree vT = new vebTree(M); //create the tree
685     assert(vT.capacity == nextPowerOfTwo(M)); 
686     uint m = vT.fill(1000); //(try to) fill the tree with thousend values 
687     uint n; 
688     Nullable!uint i = vT.predecessor(vT.max)+1; 
689     // discover the thousend (or little less) values with the predecessor method
690     while(!i.isNull)
691     {
692         ++n; 
693         i = vT.predecessor(i); 
694     }
695     // assert, that all members are discovered, iff when no predecessors are left
696     assert(n == m); 
697 }
698 
699 ///
700 version(unittest)
701 {   
702     ///
703     vebTree fill(uint M)
704     {
705         vebTree vT = new vebTree(M); 
706         for(auto i = 0; i < 1000; i++)
707         {
708             uint x = uniform(0U, vT._maximumElement, rndGenInUse); 
709             vT.insert(x); 
710         }
711         return vT; 
712     }
713 }
714 
715 ///
716 unittest
717 {
718     uint currentSeed = 433849; //unpredictableSeed(); 
719     rndGenInUse.seed(currentSeed); //initialize the random generator
720     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
721     vebTree vT = fill(M); //fill the tree with some values 
722     Nullable!uint i = vT.max; 
723     
724     // remove all members beginning from the maximum
725     while(!i.isNull)
726     {
727         vT.remove(i); 
728         auto j = vT.predecessor(i); 
729         if(!j.isNull)
730             assert(j != i); 
731         i = j; 
732     }
733     // assert, that all members are removed, iff when no predecessors are left. 
734     assert(vT.empty); 
735 }
736 
737 ///
738 unittest
739 {
740     uint currentSeed = 438749; //unpredictableSeed(); 
741     rndGenInUse.seed(currentSeed); //initialize the random generator
742     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
743     vebTree vT = fill(M); //fill the tree with some values 
744     Nullable!uint i = vT.min-1;
745     
746     // remove all members beginning from the minimum
747     while(!i.isNull)
748     {
749         vT.remove(i); 
750         auto j = vT.successor(i); 
751         if(!j.isNull)
752             assert(j != i); 
753         i = j; 
754     } 
755     // assert, that all members are removed, iff when no successors are left.
756     assert(vT.empty); 
757 }
758 
759 ///
760 unittest
761 {
762     uint M = 1 << 16; 
763     vebTree vT = new vebTree(M); 
764     vT.insert(0x000f); 
765     assert(vT.predecessor(0x000f).isNull);
766     vT.insert(0x00f0);
767     assert(vT.predecessor(0x00f0) == 0x000f); 
768     vT.insert(0x0f00); 
769     assert(vT.predecessor(0x0f00) == 0x00f0); 
770     vT.insert(0xf000); 
771     assert(vT.predecessor(0xf000) == 0x0f00);
772     
773     vT.remove(0xf000); 
774     assert(vT.predecessor(0xf000) == 0x0f00);
775     vT.remove(0x0f00); 
776     assert(vT.predecessor(0x0f00) == 0x00f0); 
777     vT.remove(0x00f0); 
778     assert(vT.predecessor(0x00f0) == 0x000f); 
779     vT.remove(0x000f); 
780     assert(vT.predecessor(0x000f).isNull);
781 }
782 
783 ///
784 unittest
785 {
786     uint M = 1 << 16; 
787     vebTree vT = new vebTree(M); 
788     vT.insert(0xf000); 
789     assert(vT.member(0xf000)); 
790     vT.insert(0x0f00); 
791     assert(vT.member(0x0f00)); 
792     vT.insert(0x00f0);
793     assert(vT.member(0x00f0)); 
794     vT.insert(0x000f); 
795     assert(vT.member(0x000f)); 
796     
797     vT.remove(0xf000); 
798     assert(!vT.member(0xf000)); 
799     vT.remove(0x0f00); 
800     assert(!vT.member(0x0f00)); 
801     vT.remove(0x00f0); 
802     assert(!vT.member(0x00f0)); 
803     vT.remove(0x000f); 
804     assert(!vT.member(0x000f)); 
805 }
806 
807 /// 
808 unittest
809 {
810     //stress test
811     uint currentSeed = 1948642567; //unpredictableSeed(); 
812     rndGenInUse.seed(currentSeed); //initialize the random generator
813     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
814     uint M = uniform(0U, 1 << 14, rndGenInUse); // set universe size to some integer. 
815     vebTree vT = new vebTree(M); 
816     uint[] arr; 
817     auto howMuchFilled = vT.fill(arr); 
818     assert(arr.length == howMuchFilled); 
819     
820     vebTree vT2 = new vebTree(M); 
821     assert(vT2.capacity == vT.capacity); 
822     
823     import std.datetime; import std.conv : to;
824     import std.container;
825     auto rbt = redBlackTree!uint(0); 
826     rbt.clear; 
827     
828     void fill1()
829     {
830         foreach(uint i; arr)
831         {
832             vT2.insert(i); 
833         }
834     }
835     
836     void fill2()
837     {
838         foreach(uint i; arr)
839         {
840             rbt.insert(i); 
841         }
842     }
843     
844     /*
845     import std.stdio; 
846     writeln("howMuchFilled: ", howMuchFilled);
847     auto r = benchmark!(fill1, fill2)(1); 
848     auto f0Result = to!Duration(r[0]); 
849     auto f1Result = to!Duration(r[1]); 
850     writeln("VEB: ", f0Result); 
851     writeln("rbt: ", f1Result); 
852     assert(f0Result < f1Result); 
853     */
854 }
855 
856 ///
857 unittest
858 {
859     import std.algorithm; 
860     uint currentSeed = 1230394; //unpredictableSeed(); 
861     rndGenInUse.seed(currentSeed); //initialize the random generator
862     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer.
863     uint[] sourceArr; 
864     sourceArr.length = M; 
865     // generate a random array as the source for the tree
866     for(uint i = 0; i < M; i++) sourceArr[i] = uniform(0U, M, rndGenInUse); 
867     
868     // constructor to test
869     vebTree vT = new vebTree(sourceArr); 
870     
871     // make the array values unique. 
872     auto uniqueArr = sort(sourceArr).uniq;
873     // check, that all values are filled 
874     foreach(uint i; uniqueArr)
875     {
876         assert(vT.member(i)); 
877         vT.remove(i); 
878     }
879     // check, that no other elements are present. 
880     assert(vT.empty); 
881 }
882 
883 ///
884 unittest
885 {
886     uint currentSeed = 2349062; //unpredictableSeed(); 
887     rndGenInUse.seed(currentSeed); //initialize the random generator
888     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
889     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
890     vebTree vT = new vebTree(M); 
891     uint[] arr; 
892     vT.fill(arr, 16); 
893     import std.algorithm;
894     assert(setSymmetricDifference(vT[], sort(arr)).empty); 
895 }
896 
897 ///
898 unittest
899 {
900     uint currentSeed = 2309532090; //unpredictableSeed(); 
901     rndGenInUse.seed(currentSeed); //initialize the random generator
902     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
903     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
904     vebTree vT = new vebTree(M); 
905     uint[] arr; 
906     vT.fill(arr, 16); 
907     
908     uint begin = 5; 
909     uint end = 100; 
910     
911     import std.algorithm; 
912     auto filterRes = sort(arr).filter!(a => a >= begin && a < end); 
913     assert(setSymmetricDifference(filterRes, vT[begin..end]).empty); 
914 }
915 
916 ///
917 unittest
918 {
919     uint currentSeed = 1223409; //unpredictableSeed(); 
920     rndGenInUse.seed(currentSeed); //initialize the random generator
921     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
922     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
923     vebTree vT = new vebTree(M); 
924     uint[] arr; 
925     vT.fill(arr, 16); 
926     assert(vT.elementCount == vT.elementCount_ut); 
927 }
928 
929 ///
930 unittest
931 {
932     uint currentSeed = 1435856534; //unpredictableSeed(); 
933     rndGenInUse.seed(currentSeed); //initialize the random generator
934     // do not use more then "1 << 15", as for the red-black tree the insertion duration is almost 4 (!) minutes. 
935     uint M = uniform(0U, 1 << 16, rndGenInUse); // set universe size to some integer. 
936     vebTree vT = new vebTree(M); 
937     uint[] arr; 
938     vT.fill(arr, 16); 
939     
940     assert(!vT.member(0));
941     assert(!vT.member(1)); 
942     import std.algorithm; 
943     assert(startsWith(vT[1], 0)); 
944     assert(vT.successor(vT[1][$-1]) == vT.successor(1));
945     assert(startsWith(vT[vT.successor(1)],vT.min)); 
946     assert(!vT.member(65535)); 
947     assert(vT[65535] == [65534, 65535]); 
948     assert(vT.member(4)); 
949     assert(startsWith(vT[4],4)); 
950     assert(!vT.member(vT[4][$-1])); 
951     assert(!vT.member(5)); 
952     assert(startsWith(vT[5],4)); 
953     assert(vT[5][$-1] == vT[4][$-1]);
954 }
955 
956 unittest
957 {
958     import std.range;
959     assert(isBidirectionalRange!vebTree);
960 }