Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
timeAllTree.C
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
146# include <gsl/gsl_rng.h>
147
148# include <cmath>
149# include <cstring>
150
151# include <algorithm>
152# include <array>
153# include <chrono>
154# include <iostream>
155# include <limits>
156# include <tuple>
157# include <vector>
158
159# include <tpl_binNodeUtils.H>
160# include <tpl_sort_utils.H>
161# include <tpl_binTree.H>
162# include <tpl_avl.H>
163# include <tpl_treap.H>
164# include <tpl_treapRk.H>
165# include <tpl_avlRk.H>
166# include <tpl_splay_tree.H>
167# include <tpl_splay_treeRk.H>
168# include <tpl_rb_tree.H>
169# include <tpl_rbRk.H>
170
171# include <tpl_tdRbTree.H>
172# include <tpl_tdRbTreeRk.H>
173# include <tpl_rand_tree.H>
174# include <tpl_dynMapTree.H>
175
176# include <argp.h>
177
178
179using namespace std;
180
181template <class Node>
182static void printNode(Node *node, int, int)
183{
184 cout << "(" << node->get_key() << "," << node->get_data() << ")";
185}
186
187
188constexpr int Num_Samples = 37;
189
190inline bool is_two_power(const unsigned int x)
191{
192 return x != 0 and not (x & (x - 1));
193}
194
196
198
199template <typename Key>
201{
202 bool operator ()(const Sample & t1, const Sample & t2) const
203 {
204 return get<1>(t1) < get<1>(t2);
205 }
206};
207
208template <template <typename, class> class TreeType,
209 typename Key,
210 class Compare = Aleph::less<Key>>
212 gsl_rng *r, int n, int k)
213{
214 cout << "Sampling at 2^" << k << " = " << n << " ..." << endl;
216 auto *p = new typename Tree::Node;
217
218 cout << " Computing height ..." << endl;
219 size_t height = computeHeightRec(tree.getRoot());
220 cout << " done = " << height << endl
221 << endl
222 << " Computing IPL ..." << endl;
223 size_t ipl = internal_path_length(tree.getRoot());
224 cout << " done = " << ipl << endl
225 << endl;
226
227 // The Num_Samples times are stored in a array
228 using Chrono = std::chrono::high_resolution_clock;
230 double rem_time;
231 double ins_avg = 0, rem_avg = 0;
232
233 // take Num_Samples distinct values and perform 5 insertions and
234 // deletion for each one
235 for (int i = 0; i < Num_Samples; ++i)
236 {
237 int value = gsl_rng_get(r); // select a random sample not in tree
238 while (tree.search(value) != nullptr)
239 value = gsl_rng_get(r);
240 KEY(p) = value;
241
242 static constexpr int Num_Measures = 100;
243 // take 20 mesures for the same value and average them
244 double ins_time = rem_time = 0;
245 for (int k = 0; k < Num_Measures; ++k)
246 {
247 auto sample_time = Chrono::now();
248 (void) tree.insert(p); // Ignore nodiscard - benchmarking
249 auto dd = Chrono::now() - sample_time;
250 ins_time += dd.count();
251
252 sample_time = Chrono::now();
253 (void) tree.remove(KEY(p)); // Ignore nodiscard - benchmarking
254 rem_time += (Chrono::now() - sample_time).count();
255 }
256
259
260 ins_sample[i] = Sample(value, ins_time);
261 rem_sample[i] = Sample(value, rem_time);
262 ins_avg += ins_time;
263 rem_avg += rem_time;
264 }
265
267 (ins_sample, 0, Num_Samples - 1);
269 (rem_sample, 0, Num_Samples - 1);
270
271 double ins_desv = 0, rem_desv = 0,
278
279 for (int i = 0; i < Num_Samples; ++i)
280 {
281 double s = ins_avg - get<1>(ins_sample[i]);
282 ins_desv += s * s;
283 s = rem_avg - get<1>(rem_sample[i]);
284 rem_desv += s * s;
285 }
286 ins_desv /= (Num_Samples - 1);
287 rem_desv /= (Num_Samples - 1);
288
291
294
295 delete p;
296
297 cout << " min Ins time = " << 1e6 * ins_min << endl
298 << " avg ins time = " << 1e6 * ins_avg << endl
299 << " med ins time = " << 1e6 * ins_med << endl
300 << " sig ins time = " << 1e6 * sqrt(ins_desv) << endl
301 << " max ins time = " << 1e6 * ins_max << endl
302 << " min Rem time = " << 1e6 * rem_min << endl
303 << " avg rem time = " << 1e6 * rem_avg << endl
304 << " med rem time = " << 1e6 * rem_med << endl
305 << " sig rem time = " << 1e6 * sqrt(rem_desv) << endl
306 << " max rem time = " << 1e6 * rem_max << endl
307 << " height = " << height << endl
308 << " ipl = " << ipl << endl
309 << "done!" << endl << endl;
310
314 height, ipl);
315}
316
317template <template <typename /* key */, class /* Compare */> class TreeType>
319{
321 Tree tree;
322
323 static const size_t N = 64;
325 int height[N], ipl[N];
326 size_t num_pow = 0;
327
328 for (unsigned int i = 0; i < n; i++)
329 {
330 while (true)
331 if (int value = gsl_rng_get(r); tree.search(value) == nullptr)
332 {
333 (void) tree.insert(new typename Tree::Node(value)); // Ignore nodiscard
334 break;
335 }
336
337 if (is_two_power(i))
338 {
340 sample_tree(tree, r, i, log(i) / log(2));
341 ins_stats[num_pow] = get<0>(stats);
342 rem_stats[num_pow] = get<1>(stats);
343 height[num_pow] = get<2>(stats);
344 ipl[num_pow] = get<3>(stats);
345 ++num_pow;
346 }
347 }
348
349 destroyRec(tree.getRoot());
350
351 printf("#2^k n h ipc [min ins med sigma max] [min ins med sigma max]\n");
352 for (int i = 0; i < num_pow; ++i)
353 {
354 Stat & si = ins_stats[i];
355 Stat & sr = rem_stats[i];
356 printf("%02d %08d %02d %08d %02.2f %02.2f %02.2f %02.2f %02.2f"
357 " %02.2f %02.2f %02.2f %02.2f %02.2f\n",
358 i, (int) pow(2, i), height[i], ipl[i],
359 1e6 * get<0>(si), 1e6 * get<1>(si), 1e6 * get<2>(si),
360 1e6 * get<3>(si), 1e6 * get<4>(si),
361 1e6 * get<0>(sr), 1e6 * get<1>(sr), 1e6 * get<2>(sr),
362 1e6 * get<3>(sr), 1e6 * get<4>(sr));
363 }
364}
365
366enum class TreeType
367{
368 BIN,
369 AVL,
370 AVL_RK,
371 SPLAY,
372 SPLAY_RK,
373 TREAP,
374 TREAP_RK,
375 RB,
376 RB_RK,
377 TD_RB,
378 TD_RB_RK,
379 RAND
380};
381
382template <template <typename, class> class Tree>
383void run_tree(unsigned long n, gsl_rng *r)
384{
385 test<Tree>(n, r);
386}
387
389{
391 const char *label;
392
393 void (*runner)(unsigned long, gsl_rng *);
394};
395
396static const std::array<TreeBenchmark, 12> kBenchmarks = {
397 {
398 {TreeType::BIN, "BinTree", run_tree<BinTree>},
399 {TreeType::AVL, "Avl_Tree", run_tree<Avl_Tree>},
400 {TreeType::AVL_RK, "Avl_Tree_Rk", run_tree<Avl_Tree_Rk>},
401 {TreeType::SPLAY, "Splay_Tree", run_tree<Splay_Tree>},
405 {TreeType::RB, "Rb_Tree", run_tree<Rb_Tree>},
406 {TreeType::RB_RK, "Rb_Tree_Rk", run_tree<Rb_Tree_Rk>},
407 {TreeType::TD_RB, "TdRbTree", run_tree<TdRbTree>},
409 {TreeType::RAND, "Rand_Tree", run_tree<Rand_Tree>}
410 }
411 };
412
414{
415 const auto it = ranges::find_if(kBenchmarks,
416 [type](const TreeBenchmark & bench)
417 {
418 return bench.type == type;
419 });
420 return it == kBenchmarks.end() ? nullptr : &(*it);
421}
422
424{
425 long n;
426 int seed;
427 bool run_all = false;
428 std::vector<TreeType> selected;
429
431 : n(_n), seed(_seed)
432 {
433 // Empty
434 }
435};
436
437
438const char * argp_program_version = "timeAllTree 0.0";
439const char * argp_program_bug_address = "lrleon@lavabit.com";
440
441static char doc[] = "timeAllTree -- Benchmark Aleph tree implementations";
442static char argDoc[] = "-n num_nodes -m seed_for_random [tree options]\n";
443
454
455static struct argp_option options[] = {
456 {"bin", 'b', 0, OPTION_ARG_OPTIONAL, "Pure binary tree", 0},
457 {"avl", 'a', 0, OPTION_ARG_OPTIONAL, "AVL tree", 0},
458 {"avlrk", OPT_AVL_RK, 0, OPTION_ARG_OPTIONAL, "AVL tree (rank)", 0},
459 {"splay", 's', 0, OPTION_ARG_OPTIONAL, "Splay tree", 0},
460 {"splayrk", OPT_SPLAY_RK, 0, OPTION_ARG_OPTIONAL, "Splay tree (rank)", 0},
461 {"redblack", 'r', 0, OPTION_ARG_OPTIONAL, "Red-black tree", 0},
462 {"redblackrk", OPT_RB_RK, 0, OPTION_ARG_OPTIONAL, "Red-black tree (rank)", 0},
463 {"tdrb", OPT_TD_RB, 0, OPTION_ARG_OPTIONAL, "Top-down red-black tree", 0},
464 {"tdrbrk", OPT_TD_RB_RK, 0, OPTION_ARG_OPTIONAL, "Top-down red-black tree (rank)", 0},
465 {"rand", 'd', 0, OPTION_ARG_OPTIONAL, "Randomized tree", 0},
466 {"treap", 'p', 0, OPTION_ARG_OPTIONAL, "Treap tree", 0},
467 {"treaprk", OPT_TREAP_RK, 0, OPTION_ARG_OPTIONAL, "Treap tree (rank)", 0},
468 {"all", OPT_ALL, 0, OPTION_ARG_OPTIONAL, "Benchmark all tree types", 0},
469 {
470 "nodes", 'n', "num_nodes", OPTION_ARG_OPTIONAL,
471 "Specify the number of nodes to be generated", 0
472 },
473 {
474 "seed", 'm', "seed_for_random", OPTION_ARG_OPTIONAL,
475 "Specify the seed for randon number generator", 0
476 },
477 {0, 0, 0, 0, 0, 0}
478 };
479
480static error_t parser_opt(int key, char *, struct argp_state *state)
481{
482 auto *parsPtr = static_cast<Parameters *>(state->input);
483
484 auto add_tree = [parsPtr](TreeType type)
485 {
486 parsPtr->selected.push_back(type);
487 };
488
489 switch (key)
490 {
491 case ARGP_KEY_END:
492 break;
493 case 'n':
494 char *end;
495 if (state->argv[state->next] == nullptr)
496 argp_usage(state);
497 parsPtr->n = strtol(state->argv[state->next], &end, 10);
498 if (*end != '\0' && *end != '\n')
499 argp_usage(state);
500 state->next++;
501 break;
502 case 'b':
504 break;
505 case 'a':
507 break;
508 case OPT_AVL_RK:
510 break;
511 case 'r':
513 break;
514 case OPT_RB_RK:
516 break;
517 case 's':
519 break;
520 case OPT_SPLAY_RK:
522 break;
523 case 'p':
525 break;
526 case OPT_TREAP_RK:
528 break;
529 case OPT_TD_RB:
531 break;
532 case OPT_TD_RB_RK:
534 break;
535 case 'd':
537 break;
538 case OPT_ALL:
539 parsPtr->run_all = true;
540 break;
541 case 'm':
542 if (state->argv[state->next] == nullptr)
543 argp_usage(state);
544 parsPtr->seed = strtol(state->argv[state->next], &end, 10);
545 if (*end != '\0' && *end != '\n')
546 argp_usage(state);
547 state->next++;
548 break;
549 case ARGP_KEY_ARG:
550 default: return ARGP_ERR_UNKNOWN;
551 }
552 return 0;
553}
554
555static struct argp argDefs = {options, parser_opt, argDoc, doc, 0, 0, 0};
556
557int main(int argc, char *argv[])
558{
559 Parameters pars(1000, time(0));
560
561 if (error_t status = argp_parse(&argDefs, argc, argv, 0, 0, &pars); status != 0)
562 AH_ERROR(("Internal error"));
563
564 unsigned long n = pars.n;
565
567 gsl_rng_set(r, pars.seed % gsl_rng_max(r));
568
569 std::vector<const TreeBenchmark *> benches;
570 if (pars.run_all)
571 for (const auto & bench: kBenchmarks)
572 benches.push_back(&bench);
573 else if (! pars.selected.empty())
574 for (const TreeType type: pars.selected)
575 if (const TreeBenchmark *bench = find_benchmark(type))
576 benches.push_back(bench);
577 else
579
580 benches.erase(ranges::remove(benches, nullptr).begin(),
581 benches.end());
582
583 if (benches.empty())
584 AH_ERROR(("No valid tree types selected"));
585
586 try
587 {
588 for (const TreeBenchmark *bench: benches)
589 {
590 cout << "timeAllTree<" << bench->label << "> "
591 << n << " " << pars.seed << endl;
592 gsl_rng_set(r, pars.seed % gsl_rng_max(r));
593 bench->runner(n, r);
594 cout << "timeAllTree<" << bench->label << "> "
595 << n << " " << pars.seed << endl;
596 }
597 }
598 catch (exception & e)
599 {
600 cout << "**** Exception: " << e.what() << endl;
601 }
602
603 gsl_rng_free(r);
604}
#define AH_ERROR(format, args...)
Print an error message (always enabled).
Definition ahDefs.H:271
int main()
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
void empty() noexcept
empty the list
Definition htlist.H:1689
NodeType< Key > Node
Node * insert(Node *p) noexcept
Insert a node in the tree.
Node *& getRoot() noexcept
Return the tree's root.
Node * search(const Key &key) const noexcept
Search a key.
iterator end() noexcept
Return an STL-compatible end iterator.
#define N
Definition fib.C:294
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log_function > > log(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4063
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sqrt_function > > sqrt(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4058
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_pow_function > > pow(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4061
size_t internal_path_length(Node *p) noexcept
Compute the internal path length.
void destroyRec(Node *&root) noexcept
Free recursively all the memory occupied by the tree root
size_t computeHeightRec(Node *root) noexcept
Compute recursively the height of root
@ Tree
Basic arc (in spanning tree).
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
bool operator()(const Sample &t1, const Sample &t2) const
std::vector< TreeType > selected
Parameters(int _n, int _seed)
TreeType type
void(* runner)(unsigned long, gsl_rng *)
const char * label
OptionKey
@ OPT_TREAP_RK
@ OPT_ALL
@ OPT_TD_RB
@ OPT_AVL_RK
@ OPT_TD_RB_RK
@ OPT_RB_RK
@ OPT_SPLAY_RK
void test(unsigned long n, gsl_rng *r)
static char argDoc[]
static void printNode(Node *node, int, int)
tuple< int, double > Sample
bool is_two_power(const unsigned int x)
static const TreeBenchmark * find_benchmark(TreeType type)
const char * argp_program_version
static error_t parser_opt(int key, char *, struct argp_state *state)
void run_tree(unsigned long n, gsl_rng *r)
tuple< Stat, Stat, int, int > sample_tree(TreeType< Key, Compare > &tree, gsl_rng *r, int n, int k)
tuple< double, double, double, double, double > Stat
const char * argp_program_bug_address
static const std::array< TreeBenchmark, 12 > kBenchmarks
static struct argp_option options[]
TreeType
static struct argp argDefs
constexpr int Num_Samples
static char doc[]
AVL tree with rank (order statistics).
AVL tree implementation (height-balanced BST).
Utility functions for binary tree operations.
Generic unbalanced binary search tree.
Dynamic key-value map based on balanced binary search trees.
Randomized binary search tree.
Red-Black tree with rank (order statistics).
Red-Black tree implementation (bottom-up balancing).
Comprehensive sorting algorithms and search utilities for Aleph-w.
Top-down splay tree with rank support.
Top-down splay tree implementation (without rank support).
Top-down Red-Black tree with rank support.
Top-down Red-Black tree implementation.
Treap with rank (order statistics).
Treap: randomized BST combining tree and heap properties.