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
179# include <ctime>
180using namespace std;
181
182template <class Node>
183static void printNode(Node *node, int, int)
184{
185 cout << "(" << node->get_key() << "," << node->get_data() << ")";
186}
187
188
189constexpr int Num_Samples = 37;
190
191inline bool is_two_power(const unsigned int x)
192{
193 return x != 0 and not (x & (x - 1));
194}
195
197
199
200template <typename Key>
202{
203 bool operator ()(const Sample & t1, const Sample & t2) const
204 {
205 return get<1>(t1) < get<1>(t2);
206 }
207};
208
209template <template <typename, class> class TreeType,
210 typename Key,
211 class Compare = Aleph::less<Key>>
213 gsl_rng *r, int n, int k)
214{
215 cout << "Sampling at 2^" << k << " = " << n << " ..." << endl;
217 auto *p = new typename Tree::Node;
218
219 cout << " Computing height ..." << endl;
220 size_t height = computeHeightRec(tree.getRoot());
221 cout << " done = " << height << endl
222 << endl
223 << " Computing IPL ..." << endl;
224 size_t ipl = internal_path_length(tree.getRoot());
225 cout << " done = " << ipl << endl
226 << endl;
227
228 // The Num_Samples times are stored in a array
229 using Chrono = std::chrono::high_resolution_clock;
231 double rem_time;
232 double ins_avg = 0, rem_avg = 0;
233
234 // take Num_Samples distinct values and perform 5 insertions and
235 // deletion for each one
236 for (int i = 0; i < Num_Samples; ++i)
237 {
238 int value = gsl_rng_get(r); // select a random sample not in tree
239 while (tree.search(value) != nullptr)
240 value = gsl_rng_get(r);
241 KEY(p) = value;
242
243 static constexpr int Num_Measures = 100;
244 // take 20 mesures for the same value and average them
245 double ins_time = rem_time = 0;
246 for (int k = 0; k < Num_Measures; ++k)
247 {
248 auto sample_time = Chrono::now();
249 (void) tree.insert(p); // Ignore nodiscard - benchmarking
250 auto dd = Chrono::now() - sample_time;
251 ins_time += dd.count();
252
253 sample_time = Chrono::now();
254 (void) tree.remove(KEY(p)); // Ignore nodiscard - benchmarking
255 rem_time += (Chrono::now() - sample_time).count();
256 }
257
260
261 ins_sample[i] = Sample(value, ins_time);
262 rem_sample[i] = Sample(value, rem_time);
263 ins_avg += ins_time;
264 rem_avg += rem_time;
265 }
266
268 (ins_sample, 0, Num_Samples - 1);
270 (rem_sample, 0, Num_Samples - 1);
271
272 double ins_desv = 0, rem_desv = 0,
279
280 for (int i = 0; i < Num_Samples; ++i)
281 {
282 double s = ins_avg - get<1>(ins_sample[i]);
283 ins_desv += s * s;
284 s = rem_avg - get<1>(rem_sample[i]);
285 rem_desv += s * s;
286 }
287 ins_desv /= (Num_Samples - 1);
288 rem_desv /= (Num_Samples - 1);
289
292
295
296 delete p;
297
298 cout << " min Ins time = " << 1e6 * ins_min << endl
299 << " avg ins time = " << 1e6 * ins_avg << endl
300 << " med ins time = " << 1e6 * ins_med << endl
301 << " sig ins time = " << 1e6 * sqrt(ins_desv) << endl
302 << " max ins time = " << 1e6 * ins_max << endl
303 << " min Rem time = " << 1e6 * rem_min << endl
304 << " avg rem time = " << 1e6 * rem_avg << endl
305 << " med rem time = " << 1e6 * rem_med << endl
306 << " sig rem time = " << 1e6 * sqrt(rem_desv) << endl
307 << " max rem time = " << 1e6 * rem_max << endl
308 << " height = " << height << endl
309 << " ipl = " << ipl << endl
310 << "done!" << endl << endl;
311
315 height, ipl);
316}
317
318template <template <typename /* key */, class /* Compare */> class TreeType>
320{
322 Tree tree;
323
324 static const size_t N = 64;
326 int height[N], ipl[N];
327 size_t num_pow = 0;
328
329 for (unsigned int i = 0; i < n; i++)
330 {
331 while (true)
332 if (int value = gsl_rng_get(r); tree.search(value) == nullptr)
333 {
334 (void) tree.insert(new typename Tree::Node(value)); // Ignore nodiscard
335 break;
336 }
337
338 if (is_two_power(i))
339 {
341 sample_tree(tree, r, i, log(i) / log(2));
342 ins_stats[num_pow] = get<0>(stats);
343 rem_stats[num_pow] = get<1>(stats);
344 height[num_pow] = get<2>(stats);
345 ipl[num_pow] = get<3>(stats);
346 ++num_pow;
347 }
348 }
349
350 destroyRec(tree.getRoot());
351
352 printf("#2^k n h ipc [min ins med sigma max] [min ins med sigma max]\n");
353 for (int i = 0; i < num_pow; ++i)
354 {
355 Stat & si = ins_stats[i];
356 Stat & sr = rem_stats[i];
357 printf("%02d %08d %02d %08d %02.2f %02.2f %02.2f %02.2f %02.2f"
358 " %02.2f %02.2f %02.2f %02.2f %02.2f\n",
359 i, (int) pow(2, i), height[i], ipl[i],
360 1e6 * get<0>(si), 1e6 * get<1>(si), 1e6 * get<2>(si),
361 1e6 * get<3>(si), 1e6 * get<4>(si),
362 1e6 * get<0>(sr), 1e6 * get<1>(sr), 1e6 * get<2>(sr),
363 1e6 * get<3>(sr), 1e6 * get<4>(sr));
364 }
365}
366
367enum class TreeType
368{
369 BIN,
370 AVL,
371 AVL_RK,
372 SPLAY,
373 SPLAY_RK,
374 TREAP,
375 TREAP_RK,
376 RB,
377 RB_RK,
378 TD_RB,
379 TD_RB_RK,
380 RAND
381};
382
383template <template <typename, class> class Tree>
384void run_tree(unsigned long n, gsl_rng *r)
385{
386 test<Tree>(n, r);
387}
388
390{
392 const char *label;
393
394 void (*runner)(unsigned long, gsl_rng *);
395};
396
397static const std::array<TreeBenchmark, 12> kBenchmarks = {
398 {
399 {TreeType::BIN, "BinTree", run_tree<BinTree>},
400 {TreeType::AVL, "Avl_Tree", run_tree<Avl_Tree>},
401 {TreeType::AVL_RK, "Avl_Tree_Rk", run_tree<Avl_Tree_Rk>},
402 {TreeType::SPLAY, "Splay_Tree", run_tree<Splay_Tree>},
406 {TreeType::RB, "Rb_Tree", run_tree<Rb_Tree>},
407 {TreeType::RB_RK, "Rb_Tree_Rk", run_tree<Rb_Tree_Rk>},
408 {TreeType::TD_RB, "TdRbTree", run_tree<TdRbTree>},
410 {TreeType::RAND, "Rand_Tree", run_tree<Rand_Tree>}
411 }
412 };
413
415{
416 const auto it = ranges::find_if(kBenchmarks,
417 [type](const TreeBenchmark & bench)
418 {
419 return bench.type == type;
420 });
421 return it == kBenchmarks.end() ? nullptr : &(*it);
422}
423
424struct Parameters
425{
426 long n;
427 int seed;
428 bool run_all = false;
429 std::vector<TreeType> selected;
430
432 : n(_n), seed(_seed)
433 {
434 // Empty
435 }
436};
437
438
439const char * argp_program_version = "timeAllTree 0.0";
440const char * argp_program_bug_address = "lrleon@lavabit.com";
441
442static char doc[] = "timeAllTree -- Benchmark Aleph tree implementations";
443static char argDoc[] = "-n num_nodes -m seed_for_random [tree options]\n";
444
455
456static struct argp_option options[] = {
457 {"bin", 'b', 0, OPTION_ARG_OPTIONAL, "Pure binary tree", 0},
458 {"avl", 'a', 0, OPTION_ARG_OPTIONAL, "AVL tree", 0},
459 {"avlrk", OPT_AVL_RK, 0, OPTION_ARG_OPTIONAL, "AVL tree (rank)", 0},
460 {"splay", 's', 0, OPTION_ARG_OPTIONAL, "Splay tree", 0},
461 {"splayrk", OPT_SPLAY_RK, 0, OPTION_ARG_OPTIONAL, "Splay tree (rank)", 0},
462 {"redblack", 'r', 0, OPTION_ARG_OPTIONAL, "Red-black tree", 0},
463 {"redblackrk", OPT_RB_RK, 0, OPTION_ARG_OPTIONAL, "Red-black tree (rank)", 0},
464 {"tdrb", OPT_TD_RB, 0, OPTION_ARG_OPTIONAL, "Top-down red-black tree", 0},
465 {"tdrbrk", OPT_TD_RB_RK, 0, OPTION_ARG_OPTIONAL, "Top-down red-black tree (rank)", 0},
466 {"rand", 'd', 0, OPTION_ARG_OPTIONAL, "Randomized tree", 0},
467 {"treap", 'p', 0, OPTION_ARG_OPTIONAL, "Treap tree", 0},
468 {"treaprk", OPT_TREAP_RK, 0, OPTION_ARG_OPTIONAL, "Treap tree (rank)", 0},
469 {"all", OPT_ALL, 0, OPTION_ARG_OPTIONAL, "Benchmark all tree types", 0},
470 {
471 "nodes", 'n', "num_nodes", OPTION_ARG_OPTIONAL,
472 "Specify the number of nodes to be generated", 0
473 },
474 {
475 "seed", 'm', "seed_for_random", OPTION_ARG_OPTIONAL,
476 "Specify the seed for randon number generator", 0
477 },
478 {0, 0, 0, 0, 0, 0}
479 };
480
481static error_t parser_opt(int key, char *, struct argp_state *state)
482{
483 auto *parsPtr = static_cast<Parameters *>(state->input);
484
485 auto add_tree = [parsPtr](TreeType type)
486 {
487 parsPtr->selected.push_back(type);
488 };
489
490 switch (key)
491 {
492 case ARGP_KEY_END:
493 break;
494 case 'n':
495 char *end;
496 if (state->argv[state->next] == nullptr)
497 argp_usage(state);
498 parsPtr->n = strtol(state->argv[state->next], &end, 10);
499 if (*end != '\0' && *end != '\n')
500 argp_usage(state);
501 state->next++;
502 break;
503 case 'b':
505 break;
506 case 'a':
508 break;
509 case OPT_AVL_RK:
511 break;
512 case 'r':
514 break;
515 case OPT_RB_RK:
517 break;
518 case 's':
520 break;
521 case OPT_SPLAY_RK:
523 break;
524 case 'p':
526 break;
527 case OPT_TREAP_RK:
529 break;
530 case OPT_TD_RB:
532 break;
533 case OPT_TD_RB_RK:
535 break;
536 case 'd':
538 break;
539 case OPT_ALL:
540 parsPtr->run_all = true;
541 break;
542 case 'm':
543 if (state->argv[state->next] == nullptr)
544 argp_usage(state);
545 parsPtr->seed = strtol(state->argv[state->next], &end, 10);
546 if (*end != '\0' && *end != '\n')
547 argp_usage(state);
548 state->next++;
549 break;
550 case ARGP_KEY_ARG:
551 default: return ARGP_ERR_UNKNOWN;
552 }
553 return 0;
554}
555
556static struct argp argDefs = {options, parser_opt, argDoc, doc, 0, 0, 0};
557
558int main(int argc, char *argv[])
559{
560 if (argc == 1)
561 {
562 cout << "timeAllTree -- benchmark Aleph-w binary search tree implementations\n"
563 << "\n"
564 << "Grows a tree to n keys (sampling at each power of 2) and reports\n"
565 << "height, internal path length (IPL), and insertion/removal timing\n"
566 << "statistics (min / avg / median / sigma / max).\n"
567 << "\n"
568 << "Usage:\n"
569 << " " << argv[0] << " <tree-flags> [-n num_nodes] [-m seed]\n"
570 << "\n"
571 << "Tree type flags (at least one required, or use --all):\n"
572 << " -b, --bin Unbalanced BST (BinTree)\n"
573 << " -a, --avl AVL tree\n"
574 << " --avlrk AVL tree (ranked)\n"
575 << " -s, --splay Splay tree\n"
576 << " --splayrk Splay tree (ranked)\n"
577 << " -r, --redblack Red-black tree\n"
578 << " --redblackrk Red-black tree (ranked)\n"
579 << " --tdrb Top-down red-black tree\n"
580 << " --tdrbrk Top-down red-black tree (ranked)\n"
581 << " -p, --treap Treap\n"
582 << " --treaprk Treap (ranked)\n"
583 << " -d, --rand Randomized tree\n"
584 << " -l, --all Benchmark all tree types\n"
585 << "\n"
586 << "Options:\n"
587 << " -n num_nodes Number of keys to insert (default: 1000)\n"
588 << " -m seed RNG seed (default: current time)\n"
589 << "\n"
590 << "Examples:\n"
591 << " " << argv[0] << " --all -n 10000 -m 42\n"
592 << " " << argv[0] << " -a -r -n 50000\n"
593 << " " << argv[0] << " --avlrk --treaprk -n 20000 -m 456\n";
594 return 0;
595 }
596
597 Parameters pars(1000, std::time(0));
598
599 if (error_t status = argp_parse(&argDefs, argc, argv, 0, 0, &pars); status != 0)
600 AH_ERROR(("Internal error"));
601
602 unsigned long n = pars.n;
603
605 gsl_rng_set(r, pars.seed % gsl_rng_max(r));
606
607 std::vector<const TreeBenchmark *> benches;
608 if (pars.run_all)
609 for (const auto & bench: kBenchmarks)
610 benches.push_back(&bench);
611 else if (! pars.selected.empty())
612 for (const TreeType type: pars.selected)
613 if (const TreeBenchmark *bench = find_benchmark(type))
614 benches.push_back(bench);
615 else
617
618 benches.erase(ranges::remove(benches, nullptr).begin(),
619 benches.end());
620
621 if (benches.empty())
622 AH_ERROR(("No valid tree types selected"));
623
624 try
625 {
626 for (const TreeBenchmark *bench: benches)
627 {
628 cout << "timeAllTree<" << bench->label << "> "
629 << n << " " << pars.seed << endl;
630 gsl_rng_set(r, pars.seed % gsl_rng_max(r));
631 bench->runner(n, r);
632 cout << "timeAllTree<" << bench->label << "> "
633 << n << " " << pars.seed << endl;
634 }
635 }
636 catch (exception & e)
637 {
638 cout << "**** Exception: " << e.what() << endl;
639 }
640
642}
#define AH_ERROR(format, args...)
Print an error message (always enabled).
Definition ahDefs.H:271
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
Node for QuadTree spatial data structure.
Definition quadnode.H:94
QuadTree - Hierarchical spatial index for 2D points.
Definition quadtree.H:126
Point * search(const Point &p) noexcept
Search for a point in the tree.
Definition quadtree.H:461
QuadNode Node
Definition quadtree.H:128
Point * insert(Node *&r, const Point &p)
Recursive insert helper.
Definition quadtree.H:237
#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
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
@ Tree
Basic arc (in spanning tree).
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
void test()
Definition test-comb.C:35
TreeType
@ TD_RB_RK
@ BIN
@ TREAP_RK
@ RAND
@ TREAP
@ RB
@ AVL
@ AVL_RK
@ SPLAY
@ SPLAY_RK
@ TD_RB
@ RB_RK
static int * k
gsl_rng * r
OptionKey
@ OPT_TREAP_RK
@ OPT_ALL
@ OPT_TD_RB
@ OPT_AVL_RK
@ OPT_TD_RB_RK
@ OPT_RB_RK
@ OPT_SPLAY_RK
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.