blob: cc7ce8cf561e3a99060aa34c5cf312d14ed8b0fe [file] [log] [blame]
// Copyright (C) 2004-2008 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
#include <boost/graph/use_mpi.hpp>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/graph/distributed/adjacency_list.hpp>
#include <boost/graph/distributed/mpi_process_group.hpp>
#include <boost/graph/distributed/local_subgraph.hpp>
#include <boost/graph/parallel/distribution.hpp>
#include <iostream>
#include <cassert>
#include <boost/test/minimal.hpp>
#ifdef BOOST_NO_EXCEPTIONS
void
boost::throw_exception(std::exception const& ex)
{
std::cout << ex.what() << std::endl;
abort();
}
#endif
using namespace boost;
using boost::graph::distributed::mpi_process_group;
template<typename Graph>
struct never
{
typedef typename graph_traits<Graph>::edge_descriptor argument_type;
typedef bool result_type;
result_type operator()(argument_type) { return false; }
};
int test_main(int argc, char** argv)
{
boost::mpi::environment env(argc, argv);
mpi_process_group pg;
parallel::block dist(pg, 20);
typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
bidirectionalS> Graph1;
typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
directedS> Graph2;
typedef adjacency_list<listS, distributedS<mpi_process_group, vecS>,
undirectedS> Graph3;
if (num_processes(pg) > 20) return -1;
if (process_id(pg) == 0) std::cout << "Graph 1------------------\n";
std::cout << "Processor #" << process_id(pg) << ": "
<< dist.block_size(20) << " vertices." << std::endl;
{
Graph1 g1(20);
// if (process_id(pg) == num_processes(pg)() - 1)
// add_vertex(g1);
graph_traits<Graph1>::vertex_iterator v, v_end;
int counter = 0;
for (boost::tie(v, v_end) = vertices(g1); v != v_end; ++v) {
std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
<< std::endl;
out_edges(*v, g1);
out_degree(*v, g1);
in_edges(*v, g1);
in_degree(*v, g1);
graph_traits<Graph1>::vertex_descriptor other = *v;
other.owner = (other.owner + 1) % num_processes(pg);
other.local = 0;
add_edge(*v, other, g1);
std::cout << "Adding edge from processor " << process_id(pg)
<< " to processor " << other.owner << std::endl;
}
synchronize(g1);
assert((std::size_t)std::distance(edges(g1).first, edges(g1).second) == num_vertices(g1));
if (num_vertices(g1) >= 2) {
graph_traits<Graph1>::vertex_iterator vi = vertices(g1).first;
graph_traits<Graph1>::vertex_descriptor u = *vi++;
graph_traits<Graph1>::vertex_descriptor v = *vi++;
add_edge(u, v, g1);
assert(out_degree(u, g1) == 2);
assert(in_degree(v, g1) == 1);
}
int prior_processor = (process_id(pg) + num_processes(pg) - 1)
% num_processes(pg);
const int n = 20;
std::size_t vertices_in_prior = (n / num_processes(pg))
+ (n % num_processes(pg) > prior_processor? 1 : 0);
graph_traits<Graph1>::vertex_descriptor u = *vertices(g1).first;
if (in_degree(u, g1) != vertices_in_prior) {
std::cout << "Processor #" << process_id(pg) << ": " << in_degree(u, g1)
<< " vs. " << vertices_in_prior << std::endl;
}
assert(in_degree(u, g1) == vertices_in_prior);
std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g1)
<< " edges.\n";
local_subgraph<Graph1> local_g1(g1);
edges(local_g1);
vertices(local_g1);
if (num_vertices(local_g1) > 0) {
out_edges(*vertices(local_g1).first, local_g1);
in_edges(*vertices(local_g1).first, local_g1);
adjacent_vertices(*vertices(local_g1).first, local_g1);
if (false) {
remove_out_edge_if(*vertices(g1).first, never<Graph1>(), g1);
remove_in_edge_if(*vertices(g1).first, never<Graph1>(), g1);
clear_out_edges(*vertices(g1).first, g1);
clear_in_edges(*vertices(g1).first, g1);
clear_vertex(*vertices(g1).first, g1);
remove_vertex(*vertices(g1).first, g1);
}
}
remove_edge_if(never<Graph1>(), g1);
}
if (process_id(pg) == 0) std::cout << "Graph 2------------------\n";
{
Graph2 g2(20);
if (process_id(pg) == num_processes(pg) - 1)
add_vertex(g2);
graph_traits<Graph2>::vertex_iterator v, v_end;
int counter = 0;
for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) {
std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
<< std::endl;
out_edges(*v, g2);
}
synchronize(g2);
if (num_vertices(g2) >= 2) {
graph_traits<Graph2>::vertex_iterator vi = vertices(g2).first;
graph_traits<Graph2>::vertex_descriptor u = *vi++;
graph_traits<Graph2>::vertex_descriptor v = *vi++;
add_edge(u, v, g2);
assert(out_degree(u, g2) == 1);
assert(*adjacent_vertices(u, g2).first == v);
std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g2)
<< " edges.\n";
assert(std::distance(edges(g2).first, edges(g2).second) == 1);
}
synchronize(g2);
local_subgraph<Graph2> local_g2(g2);
edges(local_g2);
vertices(local_g2);
if (num_vertices(local_g2) > 0) {
out_edges(*vertices(local_g2).first, local_g2);
adjacent_vertices(*vertices(local_g2).first, local_g2);
remove_out_edge_if(*vertices(g2).first, never<Graph2>(), g2);
clear_out_edges(*vertices(g2).first, g2);
remove_vertex(*vertices(g2).first, g2);
}
remove_edge_if(never<Graph2>(), g2);
}
if (process_id(pg) == 0) std::cout << "Graph 3------------------\n";
{
Graph3 g3(20);
// if (process_id(pg) == num_processes(pg) - 1)
// add_vertex(g3);
graph_traits<Graph3>::vertex_iterator v, v_end;
int counter = 0;
for (boost::tie(v, v_end) = vertices(g3); v != v_end; ++v) {
std::cout << "Processor #" << process_id(pg) << ": vertex " << ++counter
<< std::endl;
out_edges(*v, g3);
out_degree(*v, g3);
in_edges(*v, g3);
in_degree(*v, g3);
}
graph_traits<Graph3>::vertices_size_type added_edges = 0;
if (num_vertices(g3) >= 2) {
graph_traits<Graph3>::vertex_iterator vi = vertices(g3).first;
graph_traits<Graph3>::vertex_descriptor u = *vi++;
graph_traits<Graph3>::vertex_descriptor v = *vi++;
add_edge(u, v, g3); ++added_edges;
assert(out_degree(u, g3) == 1);
assert(in_degree(u, g3) == 1);
graph_traits<Graph3>::edge_descriptor e = *out_edges(u, g3).first;
assert(source(e, g3) == u);
assert(target(e, g3) == v);
e = *in_edges(u, g3).first;
assert(source(e, g3) == v);
assert(target(e, g3) == u);
assert(out_degree(v, g3) == 1);
assert(in_degree(v, g3) == 1);
e = *out_edges(v, g3).first;
assert(source(e, g3) == v);
assert(target(e, g3) == u);
e = *in_edges(v, g3).first;
assert(source(e, g3) == u);
assert(target(e, g3) == v);
assert(*adjacent_vertices(u, g3).first == v);
assert(*adjacent_vertices(v, g3).first == u);
std::cout << "Processor #" << process_id(pg) << ": " << num_edges(g3)
<< " edges.\n";
}
// Add some remote edges
for (boost::tie(v, v_end) = vertices(g3); v != v_end; ++v) {
graph_traits<Graph1>::vertex_descriptor other = *v;
other.owner = (other.owner + 1) % num_processes(pg);
other.local = 0;
add_edge(*v, other, g3); ++added_edges;
std::cout << "Adding edge from processor " << process_id(pg)
<< " to processor " << other.owner << std::endl;
}
synchronize(g3);
assert(std::distance(edges(g3).first, edges(g3).second) == (ptrdiff_t)added_edges);
assert(num_edges(g3) == added_edges);
// Verify the remote edges
if (num_vertices(g3) >= 2) {
graph_traits<Graph3>::vertex_iterator vi = vertices(g3).first;
graph_traits<Graph3>::vertex_descriptor u = *vi++;
int prior_processor = (process_id(pg) + num_processes(pg) - 1)
% num_processes(pg);
const int n = 20;
graph_traits<Graph3>::vertices_size_type vertices_in_prior = (n / num_processes(pg))
+ (n % num_processes(pg) > prior_processor? 1 : 0);
if (in_degree(u, g3) != vertices_in_prior + 2) {
std::cerr << "#" << process_id(pg) << ": " << in_degree(u, g3)
<< " != " << vertices_in_prior + 2 << std::endl;
}
assert(in_degree(u, g3) == vertices_in_prior + 2);
assert(out_degree(u, g3) == vertices_in_prior + 2);
}
local_subgraph<Graph3> local_g3(g3);
edges(local_g3);
vertices(local_g3);
if (num_vertices(local_g3) > 0) {
out_edges(*vertices(local_g3).first, local_g3);
in_edges(*vertices(local_g3).first, local_g3);
adjacent_vertices(*vertices(local_g3).first, local_g3);
remove_out_edge_if(*vertices(g3).first, never<Graph3>(), g3);
remove_in_edge_if(*vertices(g3).first, never<Graph3>(), g3);
if (false) {
// Removing an edge from two processes concurrently is not yet
// supported.
clear_vertex(*vertices(g3).first, g3);
remove_vertex(*vertices(g3).first, g3);
}
}
remove_edge_if(never<Graph3>(), g3);
}
return 0;
}