Skip to content

Commit 8c958ac

Browse files
committed
fix: modernize test
1 parent 35b782d commit 8c958ac

1 file changed

Lines changed: 81 additions & 124 deletions

File tree

‎test/gursoy_atun_layout_test.cpp‎

Lines changed: 81 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright 2004 The Trustees of Indiana University.
2+
// Copyright (c) 2026 Arnaud Becheler
23

34
// Use, modification and distribution is subject to the Boost Software
45
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -7,146 +8,102 @@
78
// Authors: Jeremiah Willcock
89
// Douglas Gregor
910
// Andrew Lumsdaine
10-
#include <boost/graph/gursoy_atun_layout.hpp>
11-
#include "boost/graph/adjacency_list.hpp"
12-
#include "boost/graph/random.hpp"
13-
#include "boost/graph/graphviz.hpp"
14-
#include "boost/random/mersenne_twister.hpp"
15-
#include "boost/random/linear_congruential.hpp"
16-
#include "boost/random/uniform_01.hpp"
17-
#include <iostream>
18-
#include <fstream>
19-
#include <sstream>
20-
21-
#if 0
22-
#include <boost/graph/plod_generator.hpp>
23-
#include <boost/graph/small_world_generator.hpp>
24-
#endif
25-
using namespace boost;
26-
27-
template < class Property, class Vertex > struct position_writer
28-
{
29-
const Property& property;
30-
31-
position_writer(const Property& property) : property(property) {}
32-
33-
void operator()(std::ostream& os, const Vertex& v) const
34-
{
35-
os << "[pos=\"" << int(property[v][0]) << "," << int(property[v][1])
36-
<< "\"]";
37-
}
38-
};
3911

40-
struct graph_writer
41-
{
42-
void operator()(std::ostream& os) const
43-
{
44-
os << "node [shape=point, width=\".01\", height=\".01\", "
45-
"fixedsize=\"true\"]"
46-
<< std::endl;
47-
}
48-
};
49-
50-
int main(int, char*[])
12+
#include <boost/graph/gursoy_atun_layout.hpp>
13+
#include <boost/graph/adjacency_list.hpp>
14+
#include <boost/core/lightweight_test.hpp>
15+
16+
#include <algorithm>
17+
#include <cmath>
18+
#include <map>
19+
#include <random>
20+
#include <vector>
21+
22+
using graph_type = boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, boost::property< boost::edge_weight_t, double > >;
23+
using vertex_index_map = boost::property_map< graph_type, boost::vertex_index_t >::type;
24+
using topology = boost::heart_topology<>;
25+
using point = topology::point_type;
26+
using position_map = boost::iterator_property_map< std::vector< point >::iterator, vertex_index_map, point, point& >;
27+
28+
// Builds the 20x20 weighted grid Gursoy and Atun used
29+
void build_grid(graph_type& g)
5130
{
52-
// Generate a graph structured like a grid, cylinder, or torus; lay it out
53-
// in a square grid; and output it in dot format
54-
55-
typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS,
56-
boost::no_property, boost::property< boost::edge_weight_t, double > >
57-
graph_type;
58-
typedef boost::graph_traits< graph_type >::vertex_descriptor
59-
vertex_descriptor;
60-
// boost::mt19937 rng;
61-
// boost::generate_random_graph(graph, 100, 600, rng, false, false);
62-
63-
#if 1
64-
graph_type graph;
65-
66-
// Make grid, like Gursoy and Atun used
31+
using vertex_descriptor = boost::graph_traits< graph_type >::vertex_descriptor;
32+
constexpr int grid_size = 20;
6733
std::map< int, std::map< int, vertex_descriptor > > verts;
68-
const int grid_size = 20;
69-
boost::minstd_rand edge_weight_gen(42);
70-
boost::uniform_01< boost::minstd_rand > random_edge_weight(edge_weight_gen);
34+
std::mt19937 engine(42);
35+
std::uniform_real_distribution< double > dist(0.0, 1.0);
36+
auto random_edge_weight = [&] { return dist(engine); };
37+
7138
for (int i = 0; i < grid_size; ++i)
7239
for (int j = 0; j < grid_size; ++j)
73-
verts[i][j] = add_vertex(graph);
40+
verts[i][j] = boost::add_vertex(g);
41+
7442
for (int i = 0; i < grid_size; ++i)
7543
{
7644
for (int j = 0; j < grid_size; ++j)
7745
{
7846
if (i != 0)
79-
add_edge(
80-
verts[i][j], verts[i - 1][j], random_edge_weight(), graph);
47+
boost::add_edge(verts[i][j], verts[i - 1][j], random_edge_weight(), g);
8148
if (j != 0)
82-
add_edge(
83-
verts[i][j], verts[i][j - 1], random_edge_weight(), graph);
84-
#if 0
85-
// Uncomment parts of this to get a cylinder or torus
86-
if (i == 0)
87-
add_edge(verts[0][j], verts[grid_size-1][j], random_edge_weight(),
88-
graph);
89-
if (j == 0)
90-
add_edge(verts[i][0], verts[i][grid_size-1], random_edge_weight(),
91-
graph);
92-
#endif
49+
boost::add_edge(verts[i][j], verts[i][j - 1], random_edge_weight(), g);
9350
}
9451
}
95-
#else
96-
using namespace boost;
52+
}
9753

98-
#if 0
99-
int n = 10000;
100-
double alpha = 0.4;
101-
double beta = 50;
102-
minstd_rand gen(42);
103-
graph_type graph(plod_iterator<minstd_rand, graph_type>(gen, n, alpha, beta),
104-
plod_iterator<minstd_rand, graph_type>(),
105-
n);
106-
#else
107-
int n = 1000;
108-
int k = 6;
109-
double p = 0.001;
110-
minstd_rand gen(42);
111-
graph_type graph(small_world_iterator< minstd_rand >(gen, n, k, p),
112-
small_world_iterator< minstd_rand >(n, k), n);
113-
#endif
114-
#endif
115-
// boost::read_graphviz(stdin, graph);
54+
// Positions are heuristic, so we assert invariants instead of exact coordinates
55+
// every point finite, inside the bounds, not all collapsed in one spot.
56+
bool layout_is_valid(const std::vector< point >& pos)
57+
{
58+
constexpr double eps = 1e-6;
59+
constexpr double y_min = -2000.0;
60+
// The heart's two circles bulge past the square to x = +-500(1 + sqrt2)
61+
// and up to y = 500(sqrt2 - 1) and the square's tip reaches y = -2000.
62+
const double x_max = 500.0 * (1.0 + std::sqrt(2.0));
63+
const double x_min = -x_max;
64+
const double y_max = 500.0 * (std::sqrt(2.0) - 1.0);
65+
double min_x = pos[0][0], max_x = pos[0][0], min_y = pos[0][1], max_y = pos[0][1];
66+
67+
for (const point& p : pos)
68+
{
69+
if (!std::isfinite(p[0]) || !std::isfinite(p[1]))
70+
return false;
71+
if (p[0] < x_min - eps || p[0] > x_max + eps)
72+
return false;
73+
if (p[1] < y_min - eps || p[1] > y_max + eps)
74+
return false;
75+
min_x = std::min(min_x, p[0]);
76+
max_x = std::max(max_x, p[0]);
77+
min_y = std::min(min_y, p[1]);
78+
max_y = std::max(max_y, p[1]);
79+
}
80+
constexpr double spread_threshold = 1.0;
81+
return (max_x - min_x) > spread_threshold || (max_y - min_y) > spread_threshold;
82+
}
11683

117-
typedef boost::property_map< graph_type, boost::vertex_index_t >::type
118-
VertexIndexMap;
119-
VertexIndexMap vertex_index = get(boost::vertex_index_t(), graph);
84+
int main()
85+
{
86+
graph_type g;
87+
build_grid(g);
12088

121-
typedef boost::heart_topology<> topology;
89+
auto index_map = boost::get(boost::vertex_index, g);
90+
std::vector< point > positions(boost::num_vertices(g));
91+
position_map position(positions.begin(), index_map);
12292
topology space;
12393

124-
typedef topology::point_type point;
125-
std::vector< point > position_vector(num_vertices(graph));
126-
typedef boost::iterator_property_map< std::vector< point >::iterator,
127-
VertexIndexMap, point, point& >
128-
Position;
129-
Position position(position_vector.begin(), vertex_index);
130-
131-
boost::gursoy_atun_layout(graph, space, position);
132-
133-
#if 0
134-
std::cerr << "--------Unweighted layout--------\n";
135-
boost::write_graphviz(std::cout, graph,
136-
position_writer<Position, vertex_descriptor>(position),
137-
boost::default_writer(),
138-
graph_writer());
139-
#endif
140-
141-
boost::gursoy_atun_layout(
142-
graph, space, position, weight_map(get(boost::edge_weight, graph)));
143-
144-
#if 0
145-
std::cerr << "--------Weighted layout--------\n";
146-
boost::write_graphviz(std::cout, graph,
147-
position_writer<Position, vertex_descriptor>(position),
148-
boost::default_writer(),
149-
graph_writer());
150-
#endif
151-
return 0;
94+
// unweighted layout uses BFS hop distances
95+
boost::gursoy_atun_layout(g, space, position);
96+
BOOST_TEST(layout_is_valid(positions));
97+
98+
// weighted layout uses Dijkstra distances over the edge weights
99+
auto edge_weights = boost::get(boost::edge_weight, g);
100+
const int nsteps = static_cast< int >(boost::num_vertices(g));
101+
const double diameter_initial = std::sqrt(static_cast< double >(boost::num_vertices(g)));
102+
const double diameter_final = 1.0;
103+
const double learning_initial = 0.8;
104+
const double learning_final = 0.2;
105+
boost::gursoy_atun_layout(g, space, position, nsteps, diameter_initial, diameter_final, learning_initial, learning_final, index_map, edge_weights);
106+
BOOST_TEST(layout_is_valid(positions));
107+
108+
return boost::report_errors();
152109
}

0 commit comments

Comments
 (0)