mirror of
https://github.com/boostorg/graph.git
synced 2025-05-11 13:24:01 +00:00
266 lines
6.8 KiB
C++
266 lines
6.8 KiB
C++
// 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 <boost/pending/relaxed_heap.hpp>
|
|
#include <boost/test/minimal.hpp>
|
|
#include <utility>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <boost/optional.hpp>
|
|
#include <boost/random.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/progress.hpp>
|
|
|
|
typedef std::vector<boost::optional<double> > 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<double> get_min_value()
|
|
{
|
|
boost::optional<double> 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<unsigned, less_extvalue> 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<double> 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<double> 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<unsigned, less_extvalue> heap(n);
|
|
boost::minstd_rand gen(seed);
|
|
boost::uniform_int<unsigned> rand_index(0, n-1);
|
|
boost::uniform_real<> rand_value(-1000.0, 1000.0);
|
|
boost::uniform_int<unsigned> 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<int>(argv[1]);
|
|
int iterations = boost::lexical_cast<int>(argv[2]);
|
|
int seed = (argc >= 4? boost::lexical_cast<int>(argv[3]) : 1);
|
|
random_test(n, iterations, seed);
|
|
} else interactive_test();
|
|
return 0;
|
|
}
|