sl@0
|
1 |
// Boost.Graph library isomorphism test
|
sl@0
|
2 |
|
sl@0
|
3 |
// Copyright (C) 2001-20044 Douglas Gregor (dgregor at cs dot indiana dot edu)
|
sl@0
|
4 |
//
|
sl@0
|
5 |
// Distributed under the Boost Software License, Version 1.0. (See
|
sl@0
|
6 |
// accompanying file LICENSE_1_0.txt or copy at
|
sl@0
|
7 |
// http://www.boost.org/LICENSE_1_0.txt)
|
sl@0
|
8 |
|
sl@0
|
9 |
// For more information, see http://www.boost.org
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Revision History:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// 29 Nov 2001 Jeremy Siek
|
sl@0
|
14 |
// Changed to use Boost.Random.
|
sl@0
|
15 |
// 29 Nov 2001 Doug Gregor
|
sl@0
|
16 |
// Initial checkin.
|
sl@0
|
17 |
/*
|
sl@0
|
18 |
* © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved.
|
sl@0
|
19 |
*/
|
sl@0
|
20 |
|
sl@0
|
21 |
#include <iostream>
|
sl@0
|
22 |
#include <fstream>
|
sl@0
|
23 |
#include <map>
|
sl@0
|
24 |
#include <algorithm>
|
sl@0
|
25 |
#include <cstdlib>
|
sl@0
|
26 |
#include <time.h> // clock used without std:: qualifier?
|
sl@0
|
27 |
#include <boost/test/minimal.hpp>
|
sl@0
|
28 |
#include <boost/graph/adjacency_list.hpp>
|
sl@0
|
29 |
#include <boost/graph/isomorphism.hpp>
|
sl@0
|
30 |
#include <boost/property_map.hpp>
|
sl@0
|
31 |
#include <boost/random/variate_generator.hpp>
|
sl@0
|
32 |
#include <boost/random/uniform_real.hpp>
|
sl@0
|
33 |
#include <boost/random/uniform_int.hpp>
|
sl@0
|
34 |
#include <boost/random/mersenne_twister.hpp>
|
sl@0
|
35 |
#include <boost/lexical_cast.hpp>
|
sl@0
|
36 |
#ifdef __SYMBIAN32__
|
sl@0
|
37 |
#include "std_log_result.h"
|
sl@0
|
38 |
#define LOG_FILENAME_LINE __FILE__, __LINE__
|
sl@0
|
39 |
#endif
|
sl@0
|
40 |
using namespace boost;
|
sl@0
|
41 |
|
sl@0
|
42 |
template <typename Generator>
|
sl@0
|
43 |
struct random_functor {
|
sl@0
|
44 |
random_functor(Generator& g) : g(g) { }
|
sl@0
|
45 |
std::size_t operator()(std::size_t n) {
|
sl@0
|
46 |
boost::uniform_int<std::size_t> distrib(0, n-1);
|
sl@0
|
47 |
boost::variate_generator<boost::mt19937&, boost::uniform_int<std::size_t> >
|
sl@0
|
48 |
x(g, distrib);
|
sl@0
|
49 |
return x();
|
sl@0
|
50 |
}
|
sl@0
|
51 |
Generator& g;
|
sl@0
|
52 |
};
|
sl@0
|
53 |
|
sl@0
|
54 |
template<typename Graph1, typename Graph2>
|
sl@0
|
55 |
void randomly_permute_graph(const Graph1& g1, Graph2& g2)
|
sl@0
|
56 |
{
|
sl@0
|
57 |
// Need a clean graph to start with
|
sl@0
|
58 |
BOOST_REQUIRE(num_vertices(g2) == 0);
|
sl@0
|
59 |
BOOST_REQUIRE(num_edges(g2) == 0);
|
sl@0
|
60 |
|
sl@0
|
61 |
typedef typename graph_traits<Graph1>::vertex_descriptor vertex1;
|
sl@0
|
62 |
typedef typename graph_traits<Graph2>::vertex_descriptor vertex2;
|
sl@0
|
63 |
typedef typename graph_traits<Graph1>::edge_iterator edge_iterator;
|
sl@0
|
64 |
|
sl@0
|
65 |
boost::mt19937 gen;
|
sl@0
|
66 |
random_functor<boost::mt19937> rand_fun(gen);
|
sl@0
|
67 |
|
sl@0
|
68 |
// Decide new order
|
sl@0
|
69 |
std::vector<vertex1> orig_vertices;
|
sl@0
|
70 |
std::copy(vertices(g1).first, vertices(g1).second, std::back_inserter(orig_vertices));
|
sl@0
|
71 |
std::random_shuffle(orig_vertices.begin(), orig_vertices.end(), rand_fun);
|
sl@0
|
72 |
std::map<vertex1, vertex2> vertex_map;
|
sl@0
|
73 |
|
sl@0
|
74 |
for (std::size_t i = 0; i < num_vertices(g1); ++i) {
|
sl@0
|
75 |
vertex_map[orig_vertices[i]] = add_vertex(g2);
|
sl@0
|
76 |
}
|
sl@0
|
77 |
|
sl@0
|
78 |
for (edge_iterator e = edges(g1).first; e != edges(g1).second; ++e) {
|
sl@0
|
79 |
add_edge(vertex_map[source(*e, g1)], vertex_map[target(*e, g1)], g2);
|
sl@0
|
80 |
}
|
sl@0
|
81 |
}
|
sl@0
|
82 |
|
sl@0
|
83 |
template<typename Graph>
|
sl@0
|
84 |
void generate_random_digraph(Graph& g, double edge_probability)
|
sl@0
|
85 |
{
|
sl@0
|
86 |
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
sl@0
|
87 |
boost::mt19937 random_gen;
|
sl@0
|
88 |
boost::uniform_real<double> distrib(0.0, 1.0);
|
sl@0
|
89 |
boost::variate_generator<boost::mt19937&, boost::uniform_real<double> >
|
sl@0
|
90 |
random_dist(random_gen, distrib);
|
sl@0
|
91 |
|
sl@0
|
92 |
for (vertex_iterator u = vertices(g).first; u != vertices(g).second; ++u) {
|
sl@0
|
93 |
vertex_iterator v = u;
|
sl@0
|
94 |
++v;
|
sl@0
|
95 |
for (; v != vertices(g).second; ++v) {
|
sl@0
|
96 |
if (random_dist() <= edge_probability)
|
sl@0
|
97 |
add_edge(*u, *v, g);
|
sl@0
|
98 |
}
|
sl@0
|
99 |
}
|
sl@0
|
100 |
}
|
sl@0
|
101 |
|
sl@0
|
102 |
void test_isomorphism(int n, double edge_probability)
|
sl@0
|
103 |
{
|
sl@0
|
104 |
typedef adjacency_list<vecS, vecS, bidirectionalS> graph1;
|
sl@0
|
105 |
typedef adjacency_list<listS, listS, bidirectionalS,
|
sl@0
|
106 |
property<vertex_index_t, int> > graph2;
|
sl@0
|
107 |
|
sl@0
|
108 |
graph1 g1(n);
|
sl@0
|
109 |
generate_random_digraph(g1, edge_probability);
|
sl@0
|
110 |
graph2 g2;
|
sl@0
|
111 |
randomly_permute_graph(g1, g2);
|
sl@0
|
112 |
|
sl@0
|
113 |
int v_idx = 0;
|
sl@0
|
114 |
for (graph2::vertex_iterator v = vertices(g2).first;
|
sl@0
|
115 |
v != vertices(g2).second; ++v) {
|
sl@0
|
116 |
put(vertex_index_t(), g2, *v, v_idx++);
|
sl@0
|
117 |
}
|
sl@0
|
118 |
|
sl@0
|
119 |
std::map<graph1::vertex_descriptor, graph2::vertex_descriptor> mapping;
|
sl@0
|
120 |
|
sl@0
|
121 |
bool isomorphism_correct = true;
|
sl@0
|
122 |
clock_t start = clock();
|
sl@0
|
123 |
|
sl@0
|
124 |
isomorphism_correct = isomorphism(g1, g2, isomorphism_map(make_assoc_property_map(mapping)));
|
sl@0
|
125 |
|
sl@0
|
126 |
BOOST_CHECK(isomorphism_correct);
|
sl@0
|
127 |
|
sl@0
|
128 |
clock_t end = clock();
|
sl@0
|
129 |
|
sl@0
|
130 |
std::cout << "Elapsed time (clock cycles): " << (end - start) << std::endl;
|
sl@0
|
131 |
|
sl@0
|
132 |
bool verify_correct = true;
|
sl@0
|
133 |
|
sl@0
|
134 |
verify_correct = verify_isomorphism(g1, g2, make_assoc_property_map(mapping));
|
sl@0
|
135 |
|
sl@0
|
136 |
BOOST_CHECK(verify_correct);
|
sl@0
|
137 |
|
sl@0
|
138 |
if (!isomorphism_correct || !verify_correct) {
|
sl@0
|
139 |
// Output graph 1
|
sl@0
|
140 |
{
|
sl@0
|
141 |
std::ofstream out("isomorphism_failure.bg1");
|
sl@0
|
142 |
out << num_vertices(g1) << std::endl;
|
sl@0
|
143 |
for (graph1::edge_iterator e = edges(g1).first;
|
sl@0
|
144 |
e != edges(g1).second; ++e) {
|
sl@0
|
145 |
out << get(vertex_index_t(), g1, source(*e, g1)) << ' '
|
sl@0
|
146 |
<< get(vertex_index_t(), g1, target(*e, g1)) << std::endl;
|
sl@0
|
147 |
}
|
sl@0
|
148 |
}
|
sl@0
|
149 |
|
sl@0
|
150 |
// Output graph 2
|
sl@0
|
151 |
{
|
sl@0
|
152 |
std::ofstream out("isomorphism_failure.bg2");
|
sl@0
|
153 |
out << num_vertices(g2) << std::endl;
|
sl@0
|
154 |
for (graph2::edge_iterator e = edges(g2).first;
|
sl@0
|
155 |
e != edges(g2).second; ++e) {
|
sl@0
|
156 |
out << get(vertex_index_t(), g2, source(*e, g2)) << ' '
|
sl@0
|
157 |
<< get(vertex_index_t(), g2, target(*e, g2)) << std::endl;
|
sl@0
|
158 |
}
|
sl@0
|
159 |
}
|
sl@0
|
160 |
}
|
sl@0
|
161 |
}
|
sl@0
|
162 |
|
sl@0
|
163 |
int test_main(int argc, char* argv[])
|
sl@0
|
164 |
{
|
sl@0
|
165 |
if (argc < 3) {
|
sl@0
|
166 |
test_isomorphism(30, 0.45);
|
sl@0
|
167 |
#ifdef __SYMBIAN32__
|
sl@0
|
168 |
std_log(LOG_FILENAME_LINE,"[End Test Case ]");
|
sl@0
|
169 |
|
sl@0
|
170 |
testResultXml("isomorphism");
|
sl@0
|
171 |
close_log_file();
|
sl@0
|
172 |
#endif
|
sl@0
|
173 |
return 0;
|
sl@0
|
174 |
}
|
sl@0
|
175 |
|
sl@0
|
176 |
int n = boost::lexical_cast<int>(argv[1]);
|
sl@0
|
177 |
double edge_prob = boost::lexical_cast<double>(argv[2]);
|
sl@0
|
178 |
test_isomorphism(n, edge_prob);
|
sl@0
|
179 |
|
sl@0
|
180 |
#ifdef __SYMBIAN32__
|
sl@0
|
181 |
std_log(LOG_FILENAME_LINE,"[End Test Case ]");
|
sl@0
|
182 |
|
sl@0
|
183 |
testResultXml("isomorphism");
|
sl@0
|
184 |
close_log_file();
|
sl@0
|
185 |
#endif
|
sl@0
|
186 |
return 0;
|
sl@0
|
187 |
}
|