Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
sort_benchmark.C
Go to the documentation of this file.
1
180#include <iostream>
181#include <iomanip>
182#include <chrono>
183#include <string>
184#include <functional>
185#include <random>
186
187#include <tclap/CmdLine.h>
188
189#include <tpl_dynArray.H>
190#include <tpl_array.H>
191#include <tpl_dynDlist.H>
192#include <htlist.H>
193#include <tpl_sort_utils.H>
194#include <ahSort.H>
195
196using namespace std;
197using namespace Aleph;
198using namespace std::chrono;
199
200// =============================================================================
201// Configuration
202// =============================================================================
203
205{
206 size_t num_elements = 10000;
207 bool run_slow_algorithms = false; // O(n²) algorithms
208 bool test_arrays = true;
209 bool test_lists = true;
210 bool verbose = false;
211 unsigned seed = 42;
212};
213
214// =============================================================================
215// Timer utility
216// =============================================================================
217
218class Timer
219{
220 high_resolution_clock::time_point start_time;
221
222public:
223 void start() { start_time = high_resolution_clock::now(); }
224
225 double elapsed_ms() const
226 {
227 auto end_time = high_resolution_clock::now();
229 }
230};
231
232// =============================================================================
233// Data generators
234// =============================================================================
235
237{
239
240public:
241 explicit DataGenerator(unsigned seed) : rng(seed) {}
242
244 void random(DynArray<int>& arr, size_t n)
245 {
246 arr.empty();
247 uniform_int_distribution<int> dist(1, static_cast<int>(n * 10));
248 for (size_t i = 0; i < n; ++i)
249 arr.append(dist(rng));
250 }
251
253 void sorted_asc(DynArray<int>& arr, size_t n)
254 {
255 arr.empty();
256 for (size_t i = 0; i < n; ++i)
257 arr.append(static_cast<int>(i));
258 }
259
261 void sorted_desc(DynArray<int>& arr, size_t n)
262 {
263 arr.empty();
264 for (size_t i = n; i > 0; --i)
265 arr.append(static_cast<int>(i));
266 }
267
269 void nearly_sorted(DynArray<int>& arr, size_t n)
270 {
271 sorted_asc(arr, n);
272 size_t swaps = n / 20; // 5%
274 for (size_t i = 0; i < swaps; ++i)
275 {
276 size_t a = dist(rng);
277 size_t b = dist(rng);
278 swap(arr(a), arr(b));
279 }
280 }
281
283 void few_unique(DynArray<int>& arr, size_t n)
284 {
285 arr.empty();
287 for (size_t i = 0; i < n; ++i)
288 arr.append(dist(rng));
289 }
290
292 void sawtooth(DynArray<int>& arr, size_t n)
293 {
294 arr.empty();
295 size_t run_size = max(n / 10, size_t(1));
296 for (size_t i = 0; i < n; ++i)
297 arr.append(static_cast<int>(i % run_size));
298 }
299};
300
301// =============================================================================
302// Container converters
303// =============================================================================
304
305template <typename T>
306void to_dynlist(const DynArray<T>& arr, DynList<T>& list)
307{
308 list.empty();
309 for (size_t i = 0; i < arr.size(); ++i)
310 list.append(arr(i));
311}
312
313template <typename T>
314void to_dyndlist(const DynArray<T>& arr, DynDlist<T>& list)
315{
316 list.empty();
317 for (size_t i = 0; i < arr.size(); ++i)
318 list.append(arr(i));
319}
320
321template <typename T>
323{
324 dst.empty();
325 for (size_t i = 0; i < src.size(); ++i)
326 dst.append(src(i));
327}
328
329// =============================================================================
330// Output formatting
331// =============================================================================
332
334{
335 cout << "\n" << string(79, '=') << "\n";
336 cout << setw(18) << left << "Algorithm"
337 << setw(15) << left << "Distribution"
338 << setw(12) << left << "Container"
339 << setw(14) << right << "Time (ms)"
340 << setw(10) << "Status"
341 << endl;
342 cout << string(79, '-') << endl;
343}
344
345void print_result(const string& algo, const string& dist,
346 const string& container, double time_ms, bool ok)
347{
348 cout << setw(18) << left << algo
349 << setw(15) << left << dist
350 << setw(12) << left << container
351 << setw(14) << right << fixed << setprecision(2) << time_ms
352 << setw(10) << (ok ? "OK" : "FAIL")
353 << endl;
354}
355
357{
358 cout << string(79, '-') << endl;
359}
360
361// =============================================================================
362// Array sorting benchmarks
363// =============================================================================
364
366 const string& dist_name,
368{
369 Timer timer;
370 DynArray<int> arr;
371
372 // Note: DynArray uses segmented blocks (not contiguous memory)
373 // So we must use Aleph's sorting functions, not std::sort
374
375 // Introsort (hybrid: quicksort + heapsort fallback) - RECOMMENDED
376 arr = source_data;
377 timer.start();
378 introsort(arr);
379 print_result("Introsort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
380
381 // Quicksort (optimized iterative version) - uses DynArray::operator()
382 arr = source_data;
383 timer.start();
384 quicksort_op(arr);
385 print_result("Quicksort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
386
387 // Heapsort - uses DynArray::operator()
388 arr = source_data;
389 timer.start();
390 heapsort(arr);
391 print_result("Heapsort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
392
393 // Shell Sort - uses DynArray::operator()
394 arr = source_data;
395 timer.start();
396 shellsort(arr);
397 print_result("Shell Sort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
398
399 // O(n²) algorithms - only for small inputs
400 if (config.run_slow_algorithms and config.num_elements <= 30000)
401 {
402 arr = source_data;
403 timer.start();
404 insertion_sort(arr);
405 print_result("Insertion Sort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
406
407 arr = source_data;
408 timer.start();
409 selection_sort(arr);
410 print_result("Selection Sort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
411
412 if (config.num_elements <= 10000)
413 {
414 arr = source_data;
415 timer.start();
416 bubble_sort(arr);
417 print_result("Bubble Sort", dist_name, "DynArray", timer.elapsed_ms(), is_sorted(arr));
418 }
419 }
420}
421
422// =============================================================================
423// Contiguous Array benchmarks (Array<T>)
424// =============================================================================
425
427 const string& dist_name,
429{
430 (void)config; // Currently unused
431 Timer timer;
432 Array<int> arr;
433
434 // Array<T> uses contiguous memory - faster than DynArray's segmented blocks
435 // Introsort with STL-style pointer interface achieves best cache locality
436
437 // Introsort on Array<T> - using container interface
438 to_array(source_data, arr);
439 timer.start();
440 introsort(arr);
441 print_result("Introsort", dist_name, "Array", timer.elapsed_ms(), is_sorted(arr));
442
443 // Introsort with STL-style pointer interface (begin/end)
444 to_array(source_data, arr);
445 timer.start();
446 introsort(&arr(0), &arr(0) + arr.size());
447 print_result("Intro(ptr)", dist_name, "Array", timer.elapsed_ms(), is_sorted(arr));
448
449 // Heapsort on Array<T> - contiguous memory allows optimal heap operations
450 to_array(source_data, arr);
451 timer.start();
452 faster_heapsort(&arr(0), arr.size());
453 print_result("Heapsort", dist_name, "Array", timer.elapsed_ms(), is_sorted(arr));
454}
455
456// =============================================================================
457// List sorting benchmarks
458// =============================================================================
459
461 const string& dist_name,
463{
464 Timer timer;
465 DynList<int> slist;
466 DynDlist<int> dlist;
467
468 // DynList - Merge Sort
469 to_dynlist(source_data, slist);
470 timer.start();
471 mergesort(slist);
472 print_result("Merge Sort", dist_name, "DynList", timer.elapsed_ms(), is_sorted(slist));
473
474 // DynList - Quicksort
475 to_dynlist(source_data, slist);
476 timer.start();
477 quicksort(slist);
478 print_result("Quicksort", dist_name, "DynList", timer.elapsed_ms(), is_sorted(slist));
479
480 // DynDlist - Merge Sort
481 to_dyndlist(source_data, dlist);
482 timer.start();
483 mergesort(dlist);
484 print_result("Merge Sort", dist_name, "DynDlist", timer.elapsed_ms(), is_sorted(dlist));
485
486 // DynDlist - Quicksort
487 to_dyndlist(source_data, dlist);
488 timer.start();
489 quicksort(dlist);
490 print_result("Quicksort", dist_name, "DynDlist", timer.elapsed_ms(), is_sorted(dlist));
491
492 // O(n²) - only for small inputs
493 if (config.run_slow_algorithms and config.num_elements <= 10000)
494 {
495 to_dynlist(source_data, slist);
496 timer.start();
497 insertion_sort(slist);
498 print_result("Insertion Sort", dist_name, "DynList", timer.elapsed_ms(), is_sorted(slist));
499
500 to_dyndlist(source_data, dlist);
501 timer.start();
502 in_place_sort(dlist);
503 print_result("Insertion Sort", dist_name, "DynDlist", timer.elapsed_ms(), is_sorted(dlist));
504 }
505}
506
507// =============================================================================
508// Main benchmark runner
509// =============================================================================
510
512{
513 cout << "\n";
514 cout << "============================================================\n";
515 cout << " ALEPH-W SORTING ALGORITHMS BENCHMARK\n";
516 cout << "============================================================\n";
517 cout << "\nConfiguration:\n";
518 cout << " Elements: " << config.num_elements << "\n";
519 cout << " O(n^2) algos: " << (config.run_slow_algorithms ? "Yes" : "No") << "\n";
520 cout << " Test arrays: " << (config.test_arrays ? "Yes" : "No") << "\n";
521 cout << " Test lists: " << (config.test_lists ? "Yes" : "No") << "\n";
522 cout << " Random seed: " << config.seed << "\n";
523
524 DataGenerator gen(config.seed);
525 DynArray<int> data;
526
527 // Distribution names and generators
528 struct DistInfo
529 {
530 const char* name;
532 };
533
535 {"Random", &DataGenerator::random},
536 {"Sorted", &DataGenerator::sorted_asc},
537 {"Reverse", &DataGenerator::sorted_desc},
538 {"Nearly Sorted", &DataGenerator::nearly_sorted},
539 {"Few Unique", &DataGenerator::few_unique},
540 {"Sawtooth", &DataGenerator::sawtooth}
541 };
542
543 print_header();
544
545 for (const auto& dist : distributions)
546 {
547 // Generate data for this distribution
548 (gen.*(dist.generator))(data, config.num_elements);
549
550 if (config.test_arrays)
551 {
552 benchmark_array_algorithms(config, dist.name, data);
553 benchmark_contiguous_array(config, dist.name, data);
554 }
555
556 if (config.test_lists)
557 benchmark_list_algorithms(config, dist.name, data);
558
560 }
561
562 cout << "\nBenchmark completed successfully!\n\n";
563}
564
565// =============================================================================
566// Complexity demonstration
567// =============================================================================
568
570{
571 cout << "\n";
572 cout << "============================================================\n";
573 cout << " COMPLEXITY DEMONSTRATION\n";
574 cout << "============================================================\n";
575 cout << "\nShows how sorting time scales with input size.\n";
576 cout << "For O(n log n): doubling n roughly doubles time.\n";
577 cout << "For O(n^2): doubling n roughly quadruples time.\n\n";
578
580 DynArray<int> data;
581 DynArray<int> arr;
582 Array<int> carr; // Contiguous array
583 DynList<int> list;
584 Timer timer;
585
586 size_t sizes[] = {1000, 2000, 4000, 8000, 16000, 32000};
587
588 cout << setw(10) << "Size"
589 << setw(15) << "Introsort"
590 << setw(15) << "Intro(Array)"
591 << setw(15) << "Quicksort"
592 << setw(15) << "Merge (list)"
593 << endl;
594 cout << string(70, '-') << endl;
595
596 for (size_t n : sizes)
597 {
598 gen.random(data, n);
599 cout << setw(10) << n;
600
601 // Introsort (DynArray) - hybrid with O(n log n) guaranteed
602 arr = data;
603 timer.start();
604 introsort(arr);
605 cout << setw(15) << fixed << setprecision(2) << timer.elapsed_ms();
606
607 // Introsort (Array<T> - contiguous memory)
608 to_array(data, carr);
609 timer.start();
611 cout << setw(15) << timer.elapsed_ms();
612
613 // Quicksort (DynArray)
614 arr = data;
615 timer.start();
616 quicksort_op(arr);
617 cout << setw(15) << timer.elapsed_ms();
618
619 // Merge Sort (DynList)
620 to_dynlist(data, list);
621 timer.start();
622 mergesort(list);
623 cout << setw(15) << timer.elapsed_ms();
624
625 cout << endl;
626 }
627
628 cout << "\nIntrosort = quicksort + heapsort fallback + insertion sort for small.\n";
629 cout << "Array uses contiguous memory, DynArray uses segmented blocks.\n";
630}
631
632// =============================================================================
633// Algorithm selection guide
634// =============================================================================
635
637{
638 cout << "\n";
639 cout << "============================================================\n";
640 cout << " ALGORITHM SELECTION GUIDE\n";
641 cout << "============================================================\n";
642 cout << R"(
643+-------------------+------------------------+-------------------------+
644| Scenario | Best Choice | Why |
645+-------------------+------------------------+-------------------------+
646| General purpose | introsort() | Fast + O(n log n) guarantee |
647| Nearly sorted | insertion_sort() | O(n) for sorted data |
648| Guaranteed O(nlogn)| introsort()/heapsort()| No worst case O(n^2) |
649| Linked lists | mergesort() | O(1) extra space |
650| Stability needed | mergesort() | Preserves equal order |
651| Limited memory | heapsort() | O(1) extra space |
652| Small arrays (<50)| insertion_sort() | Low overhead |
653| External sorting | mergesort() | Sequential access |
654| Medium arrays | shellsort() | Good balance |
655| Adversarial data | introsort() | Immune to quicksort killers |
656+-------------------+------------------------+-------------------------+
657
658For Aleph-w containers:
659 - DynArray: Use introsort() (recommended), quicksort_op(), or heapsort()
660 - DynList: Use mergesort() (O(1) extra space for lists!)
661 - DynDlist: Use mergesort() or quicksort()
662
663Note: introsort() = quicksort + heapsort fallback + insertion sort for small
664 partitions. Same speed as quicksort but with O(n log n) guarantee.
665)";
666}
667
668// =============================================================================
669// Main
670// =============================================================================
671
672int main(int argc, char* argv[])
673{
674 try
675 {
676 TCLAP::CmdLine cmd(
677 "Comprehensive sorting algorithm benchmark for Aleph-w.\n"
678 "Tests multiple algorithms across different data distributions "
679 "and container types.",
680 ' ', "1.0"
681 );
682
683 TCLAP::ValueArg<size_t> nArg(
684 "n", "count",
685 "Number of elements to sort",
686 false, 10000, "count", cmd
687 );
688
689 TCLAP::SwitchArg allArg(
690 "a", "all",
691 "Include O(n^2) algorithms (selection, insertion, bubble)",
692 cmd, false
693 );
694
695 TCLAP::SwitchArg arrayOnlyArg(
696 "", "array-only",
697 "Only test array-based containers",
698 cmd, false
699 );
700
701 TCLAP::SwitchArg listOnlyArg(
702 "", "list-only",
703 "Only test linked list containers",
704 cmd, false
705 );
706
707 TCLAP::SwitchArg complexityArg(
708 "c", "complexity",
709 "Run complexity demonstration (time vs size)",
710 cmd, false
711 );
712
713 TCLAP::SwitchArg guideArg(
714 "g", "guide",
715 "Print algorithm selection guide",
716 cmd, false
717 );
718
719 TCLAP::ValueArg<unsigned> seedArg(
720 "s", "seed",
721 "Random seed for reproducible results",
722 false, 42, "seed", cmd
723 );
724
725 TCLAP::SwitchArg verboseArg(
726 "v", "verbose",
727 "Verbose output",
728 cmd, false
729 );
730
731 cmd.parse(argc, argv);
732
733 BenchmarkConfig config;
734 config.num_elements = nArg.getValue();
735 config.run_slow_algorithms = allArg.getValue();
736 config.test_arrays = not listOnlyArg.getValue();
737 config.test_lists = not arrayOnlyArg.getValue();
738 config.seed = seedArg.getValue();
739 config.verbose = verboseArg.getValue();
740
741 if (listOnlyArg.getValue() and arrayOnlyArg.getValue())
742 {
743 cerr << "Error: Cannot specify both --array-only and --list-only\n";
744 return 1;
745 }
746
747 if (guideArg.getValue())
748 {
750 return 0;
751 }
752
753 if (complexityArg.getValue())
754 {
756 return 0;
757 }
758
759 run_benchmarks(config);
760
761 return 0;
762 }
763 catch (TCLAP::ArgException& e)
764 {
765 cerr << "Error: " << e.error() << " for argument " << e.argId() << endl;
766 return 1;
767 }
768 catch (exception& e)
769 {
770 cerr << "Error: " << e.what() << endl;
771 return 1;
772 }
773}
High-level sorting functions for Aleph containers.
int main()
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:333
size_t size() const noexcept
Return the current dimension of array.
T & append()
Allocate a new entry to the end of array.
void empty() noexcept
Empty the array.
Dynamic doubly linked list with O(1) size and bidirectional access.
void empty() noexcept
Empty the list.
T & append(const T &item)
Append a copied item at the end of the list.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
void empty() noexcept
empty the list
Definition htlist.H:1689
void nearly_sorted(DynArray< int > &arr, size_t n)
Nearly sorted: 5% of elements are swapped.
void sawtooth(DynArray< int > &arr, size_t n)
Sawtooth pattern: multiple ascending runs.
void sorted_desc(DynArray< int > &arr, size_t n)
Sorted in descending order.
DataGenerator(unsigned seed)
void random(DynArray< int > &arr, size_t n)
Uniformly distributed random integers.
void sorted_asc(DynArray< int > &arr, size_t n)
Already sorted in ascending order.
void few_unique(DynArray< int > &arr, size_t n)
Few unique values (high repetition)
void start()
double elapsed_ms() const
high_resolution_clock::time_point start_time
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_max_function > > max(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4110
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool is_sorted(const Container< T > &cont, const Compare &cmp=Compare())
Check if a container is sorted in ascending order.
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Definition ahTypes.H:121
void heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Sort an array using the heapsort algorithm.
void faster_heapsort(T *array, const size_t n, const Compare &cmp=Compare())
Optimized version of heapsort.
void mergesort(T *a, const long l, const long r, std::vector< T > &buf, Compare cmp)
DynArray< T > & in_place_sort(DynArray< T > &c, Cmp cmp=Cmp())
Sorts a DynArray in place.
Definition ahSort.H:321
void bubble_sort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using bubble sort.
void quicksort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using iterative quicksort with optimizations.
void insertion_sort(T *a, const long l, const long r, const Compare &cmp=Compare()) noexcept(noexcept(cmp(a[0], a[0])) &&std::is_nothrow_move_assignable_v< T >)
Sort an array using insertion sort.
void shellsort(DynArray< T > &a, const Compare &cmp=Compare())
Sort a dynamic array using Shell sort.
void selection_sort(T *a, const size_t n, const Compare &cmp=Compare()) noexcept(noexcept(cmp(a[0], a[0])) &&std::is_nothrow_swappable_v< T >)
Sort an array using the selection sort algorithm.
void introsort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using introsort (introspective sort).
DynList< T > maps(const C &c, Op op)
Classic map operation.
void quicksort_op(C< T > &a, const Compare &cmp=Compare(), const size_t threshold=Quicksort_Threshold)
Optimized quicksort for containers using operator().
STL namespace.
void to_dynlist(const DynArray< T > &arr, DynList< T > &list)
void run_benchmarks(const BenchmarkConfig &config)
void benchmark_contiguous_array(const BenchmarkConfig &config, const string &dist_name, const DynArray< int > &source_data)
void to_dyndlist(const DynArray< T > &arr, DynDlist< T > &list)
void benchmark_array_algorithms(const BenchmarkConfig &config, const string &dist_name, const DynArray< int > &source_data)
void to_array(const DynArray< T > &src, Array< T > &dst)
void demonstrate_complexity(const BenchmarkConfig &base_config)
void print_result(const string &algo, const string &dist, const string &container, double time_ms, bool ok)
void benchmark_list_algorithms(const BenchmarkConfig &config, const string &dist_name, const DynArray< int > &source_data)
void print_recommendations()
void print_header()
void print_separator()
Dynamic array container with automatic resizing.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Comprehensive sorting algorithms and search utilities for Aleph-w.