NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.cpp
Go to the documentation of this file.
1 //#define NDEBUG 1
2 
3 #ifndef __cplusplus
4 #error A C++ compiler is required.
5 #endif
6 
7 #include <vector>
8 #include <queue>
9 #include <iostream>
10 #include <stdint.h>
11 #include <time.h>
12 #include <algorithm>
13 
14 #include "priority_deque.hpp"
16 
17 int main();
18 
20 
21 #define BENCHMARK
22 #define VERIFY_HEAP
23 
24 template <typename pq_t>
25 void benchmark_priority_queue (unsigned benchmark_elements) {
26  pq_t pq;
27  clock_t bench_begin, bench_mid, bench_end;
28  std::cout << "Benchmark results: ";
29 // First, fill the queue with most of the elements, to get a better idea of the average case.
30  for (unsigned n = benchmark_elements / 2; n--;)
31  pq.push(rand());
32 // Test how long it takes to fill the rest of the way.
33  bench_begin = clock();
34  for (unsigned n = benchmark_elements / 2; n--;)
35  pq.push(rand());
36  bench_mid = clock();
37  std::cout << "Push: " << (bench_mid - bench_begin) << " (" << static_cast<double>(bench_mid - bench_begin) / CLOCKS_PER_SEC << "s)";
38 
39 // Test time required to remove the same number of elements.
40  bench_mid = clock();
41  for (unsigned n = benchmark_elements / 2; n--;)
42  pq.pop();
43  bench_end = clock();
44  std::cout << ", Pop: " << (bench_end - bench_mid) << " (" << static_cast<double>(bench_end - bench_mid) / CLOCKS_PER_SEC << "s)\n";
45 }
46 
47 int main() {
48  std::cout << "__cplusplus = " << __cplusplus << "\n";
49 #ifndef NDEBUG
50  std::cout << "Debug mode (asserts active).\n";
51 #endif
52  srand(clock());
53 
56  using std::priority_queue;
57 
58 // Begin tests
59 {
60  priority_deque<int> test_deque;
61 // Sufficient sample size for observing all potential interesting behaviors.
62  for (int i = 0; i < 256; ++i) {
63  try {
64  test_deque.push(i);
65  if (std::find(test_deque.begin(), test_deque.end(), i) == test_deque.end()) {
66  std::cerr << "Element lost <push>.\n";
67  break;
68  }
69  if (!is_interval_heap(test_deque.begin(), test_deque.end(), std::less<int>())) {
70  std::cerr << "Heap corrupted <push>.\n";
71  break;
72  }
73  if (test_deque.maximum() != i)
74  std::cerr << "Incorrect maximum. i = " << i << "\n";
75  } catch (...) {
76  std::cerr << "Exception thrown <push>.\n";
77  break;
78  }
79  }
80  std::vector<int> test_vector;
81  for (int i = 0; i < 256; ++i) {
82  test_vector.push_back(i);
83  std::random_shuffle(test_vector.begin(), test_vector.end());
84  try {
85  test_deque.clear();
86  test_deque.merge(test_vector);
87  if (test_deque.size() != test_vector.size())
88  std::cerr << "Merge changed number of elements.\n";
89  for (int j = 0; j <= i; ++j) {
90  if (std::find(test_deque.begin(), test_deque.end(), j) == test_deque.end()) {
91  std::cerr << "Element removed <merge>.\n";
92  break;
93  }
94  }
95  if (!is_interval_heap(test_deque.begin(), test_deque.end(), std::less<int>())) {
96  std::cerr << "Heap corrupted <merge>.\n";
97  break;
98  }
99  } catch (...) {
100  std::cerr << "Exception thrown <merge>.\n";
101  break;
102  }
103  }
104 }
105 // Benchmark performance relative to std::priority_queue.
106 #ifdef BENCHMARK
107 {
108  typedef intmax_t benchmark_type;
109  const unsigned benchmark_elements = 20000000;
110  std::cout << "PD: ";
111  benchmark_priority_queue<priority_deque<benchmark_type> >(benchmark_elements);
112  std::cout << "PQ: ";
113  benchmark_priority_queue<priority_queue<benchmark_type> >(benchmark_elements);
114 }
115 #endif
116 
117 #ifdef VERIFY_HEAP
118  std::cout << "\n\nTesting heap integrity after:\n";
119  const int element_total = 3001;//8192 * 2000;
120  priority_deque<uint32_t> pd;
121 
122  std::cout << "'push' (" << element_total << "x)\n";
123  for (int n = 1; n <= element_total; ++n) {
124  pd.push(rand());
125  if (is_valid_until(pd) != pd.end()) {
126  std::cout << "Failed push (error in replace_leaf)\n";
127  break;
128  }
129  }
130 
131  srand(25346);
132  std::vector<uint32_t> v;
133  for (int n = 1; n <= 5; ++n)
134  v.push_back(rand());
135  for (int n = 1; n <= 1; ++n) {
136  std::cout << "'merge' (" << v.size() << " elements)\n";
137 
138  /*for (auto it = v.begin(); it != v.end(); ++it)
139  std::cout << *it << ", ";
140  std::cout << "\n";*/
141  boost::heap::make_interval_heap(v.begin(), v.end(), std::less<uint32_t>());
142  if (!boost::heap::is_interval_heap(v.begin(), v.end(), std::less<uint32_t>())) {
143  std::cout << "Failed\n";
144  for (auto it = v.begin(); it != v.end(); ++it)
145  std::cout << *it << ", ";
146  std::cout << "\n";
147  }
148  std::random_shuffle(v.begin(), v.end());
149  v.push_back(rand());
150  }
151  /*for (int n = 1; n < 64; ++n) {
152  std::cout << "'merge' (" << v.size() << " elements)\n";
153  pd.clear();
154  pd.merge(v.begin(), v.end());
155  if (is_valid_until(pd) != pd.end())
156  std::cout << "Failed merge (error in make_valid)\n";
157  v.push_back(rand());
158  }*/
159 
160  std::cout << "'set' (" << element_total << "x)\n";
161  for (int t = 0; t < element_total; ++t) {
162  pd.update(pd.begin() + rand() % pd.size(), rand());
163  if (is_valid_until(pd) != pd.end()) {
164  std::cout << "Failed random-access set (error in replace)\n";
165  break;
166  }
167  }
168 
169  std::cout << "'pop_minimum' (" << pd.size() << "x)\n";
170  while (!pd.empty()) {
171  pd.pop_minimum();
172  if (is_valid_until(pd) != pd.end()) {
173  std::cout << "Failed pop_minimum (error in replace)\n";
174  break;
175  }
176  }
177  pd.clear();
178 
179  std::cout << "'push', 'pop_maximum', 'pop_minimum', 'erase', 'set' (indefinitely)\n";
181  for (int n = 0; n < 13; ++n) {
182  test_pd.push(rand());
183  if (is_valid_until(pd) != pd.end())
184  std::cout << "Failed push (error in replace_leaf)\n";
185  }
186  int last_rand = -1;
187  while (true) {
188  if (test_pd.size() < 3000) {
189  last_rand = -1;
190  test_pd.push(rand());
191  } else {
192  last_rand = rand() % 8;
193  switch (last_rand) {
194  case 0: test_pd.pop_maximum(); break;
195  case 1: test_pd.pop_minimum(); break;
196  case 2: test_pd.erase(test_pd.begin() + rand() % test_pd.size()); break;
197  default: test_pd.update(test_pd.begin() + rand() % test_pd.size(), rand());
198  }
199  }
200  if (is_valid_until(pd) != pd.end()) {
201  std::cout << "An error has occurred! (code " << last_rand << ").\n";
202  break;
203  }
204  }
205 #endif
206  return 0;
207 }