// Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_RELAXED_HEAP_DEBUG # define BOOST_RELAXED_HEAP_DEBUG 0 #endif #include #include #include #include #include #include #include #include #include typedef std::vector > values_type; values_type values; struct less_extvalue { typedef bool result_type; bool operator()(unsigned x, unsigned y) const { assert(values[x] && values[y]); return values[x] < values[y]; } }; using namespace std; boost::optional get_min_value() { boost::optional min_value; for (unsigned i = 0; i < values.size(); ++i) { if (values[i]) { if (!min_value || *values[i] < *min_value) min_value = values[i]; } } return min_value; } void interactive_test() { unsigned max_values; cout << "Enter max number of values in the heap> "; cin >> max_values; values.resize(max_values); boost::relaxed_heap heap(max_values); char option; do { cout << "Enter command> "; if (cin >> option) { switch (option) { case 'i': case 'I': { unsigned index; double value; if (cin >> index >> value) { if (index >= values.size()) cout << "Index out of range.\n"; else if (values[index]) cout << "Already in queue.\n"; else { values[index] = value; heap.push(index); heap.dump_tree(); } } } break; case 'u': case 'U': { unsigned index; double value; if (cin >> index >> value) { if (index >= values.size()) cout << "Index out of range.\n"; else if (!values[index]) cout << "Not in queue.\n"; else { values[index] = value; heap.update(index); heap.dump_tree(); } } } break; case 'r': case 'R': { unsigned index; if (cin >> index) { if (index >= values.size()) cout << "Index out of range.\n"; else if (!values[index]) cout << "Not in queue.\n"; else { heap.remove(index); heap.dump_tree(); } } } break; case 't': case 'T': { if (boost::optional min_value = get_min_value()) { cout << "Top value is (" << heap.top() << ", " << *values[heap.top()] << ").\n"; BOOST_CHECK(*min_value == *values[heap.top()]); } else { cout << "Queue is empty.\n"; BOOST_CHECK(heap.empty()); } } break; case 'd': case 'D': { if (boost::optional min_value = get_min_value()) { unsigned victim = heap.top(); double value = *values[victim]; cout << "Removed top value (" << victim << ", " << value << ")\n"; BOOST_CHECK(*min_value == value); heap.pop(); heap.dump_tree(); values[victim].reset(); } else { cout << "Queue is empty.\n"; BOOST_CHECK(heap.empty()); } } break; case 'q': case 'Q': break; default: cout << "Unknown command '" << option << "'.\n"; } } } while (cin && option != 'q' && option != 'Q'); } void random_test(int n, int iterations, int seed) { values.resize(n); boost::relaxed_heap heap(n); boost::minstd_rand gen(seed); boost::uniform_int rand_index(0, n-1); boost::uniform_real<> rand_value(-1000.0, 1000.0); boost::uniform_int which_option(0, 3); cout << n << std::endl; #if BOOST_RELAXED_HEAP_DEBUG > 1 heap.dump_tree(); #endif BOOST_REQUIRE(heap.valid()); #if BOOST_RELAXED_HEAP_DEBUG == 0 boost::progress_display progress(iterations); #endif for (int iteration = 0; iteration < iterations; ++iteration) { #if BOOST_RELAXED_HEAP_DEBUG > 1 std::cout << "Iteration #" << iteration << std::endl; #endif unsigned victim = rand_index(gen); if (values[victim]) { switch (which_option(gen)) { case 0: case 3: { // Update with a smaller weight boost::uniform_real<> rand_smaller((rand_value.min)(), *values[victim]); values[victim] = rand_smaller(gen); assert(*values[victim] >= (rand_smaller.min)()); assert(*values[victim] <= (rand_smaller.max)()); #if BOOST_RELAXED_HEAP_DEBUG > 0 cout << "u " << victim << " " << *values[victim] << std::endl; cout.flush(); #endif heap.update(victim); } break; case 1: { // Delete minimum value in the queue. victim = heap.top(); double top_value = *values[victim]; BOOST_CHECK(*get_min_value() == top_value); if (*get_min_value() != top_value) return; #if BOOST_RELAXED_HEAP_DEBUG > 0 cout << "d" << std::endl; cout.flush(); #endif heap.pop(); values[victim].reset(); #if BOOST_RELAXED_HEAP_DEBUG > 1 cout << "(Removed " << victim << ")\n"; #endif // BOOST_RELAXED_HEAP_DEBUG > 1 } break; case 2: { // Just remove this value from the queue completely values[victim].reset(); #if BOOST_RELAXED_HEAP_DEBUG > 0 cout << "r " << victim << std::endl; cout.flush(); #endif heap.remove(victim); } break; default: cout << "Random number generator failed." << endl; BOOST_CHECK(false); return; break; } } else { values[victim] = rand_value(gen); assert(*values[victim] >= (rand_value.min)()); assert(*values[victim] <= (rand_value.max)()); #if BOOST_RELAXED_HEAP_DEBUG > 0 cout << "i " << victim << " " << *values[victim] << std::endl; cout.flush(); #endif heap.push(victim); } #if BOOST_RELAXED_HEAP_DEBUG > 1 heap.dump_tree(); #endif // BOOST_RELAXED_HEAP_DEBUG > 1 BOOST_REQUIRE(heap.valid()); #if BOOST_RELAXED_HEAP_DEBUG == 0 ++progress; #endif } } int test_main(int argc, char* argv[]) { if (argc >= 3) { int n = boost::lexical_cast(argv[1]); int iterations = boost::lexical_cast(argv[2]); int seed = (argc >= 4? boost::lexical_cast(argv[3]) : 1); random_test(n, iterations, seed); } else interactive_test(); return 0; }