/
utils_netgen.hpp
164 lines (148 loc) · 4.83 KB
/
utils_netgen.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#ifndef UTILS_NETGEN_HPP
#define UTILS_NETGEN_HPP
#include "graph.hpp"
#include "matrixes.hpp"
#include "utils.hpp"
#include <iterator>
#include <boost/graph/random.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
/**
* Names the vertices.
*/
void
name_vertices(Graph &g);
/**
* Sets the distance property on edges.
*/
template<typename T>
void
set_distances(Graph &g, int min, int max, T &gen)
{
boost::uniform_int<> range(min, max);
boost::variate_generator<T &, boost::uniform_int<> > rgen(gen, range);
boost::randomize_property<edge_weight_t>(g, rgen);
}
/**
* Sets the lambdas property on edges.
*/
template<typename T>
void
set_lambdas(Graph &g, int min, int max, T &gen)
{
boost::uniform_int<> range(min, max);
boost::variate_generator<T &, boost::uniform_int<> > rgen(gen, range);
boost::randomize_property<edge_weight2_t>(g, rgen);
}
/**
* Move the vertex from the lonely group to either the set of
* connected or saturated vertexes.
*/
void
move(Vertex v, const Graph &g, std::set<Vertex> &lonely,
std::set<Vertex> &connected, std::set<Vertex> &saturated);
/**
* Check whether to move the vertex from the set of connected vertexes
* to the set of saturated vertexes.
*/
void
move_if_needed(Vertex v, const Graph &g, std::set<Vertex> &connected,
std::set<Vertex> &saturated);
/**
* Add a random edge.
* @return true on success, false otherwise.
*/
template<typename T>
bool
add_random_edge(Graph &g, std::set<Vertex> &lonely,
std::set<Vertex> &connected,
std::set<Vertex> &saturated,
T &gen)
{
// The condition for the first edge.
if (lonely.size() >= 2 && connected.empty() && saturated.empty())
{
// Select two lone vertexes, which will be the end nodes of the
// first edge created.
Vertex src = get_random_element(lonely, gen);
// Move the src node from lonely before we pick the dst node.
move(src, g, lonely, connected, saturated);
Vertex dst = get_random_element(lonely, gen);
move(dst, g, lonely, connected, saturated);
bool status = add_edge(src, dst, g).second;
assert(status);
return status;
}
// The condition for lonely vertexes and a connected component.
else if (!lonely.empty() && !connected.empty())
{
// Add a new edge where one vertex belongs to the connected
// component, while the other is a lone one.
Vertex src = get_random_element(lonely, gen);
Vertex dst = get_random_element(connected, gen);
bool status = add_edge(src, dst, g).second;
assert(status);
move(src, g, lonely, connected, saturated);
move_if_needed(dst, g, connected, saturated);
return status;
}
// The condition for a connected component only.
else if (lonely.empty() && connected.size() >= 2)
{
// Now we have to create an edge where both vertexes of the edge
// belong to the connected component. We have to be carefull
// not to create a parallel edge.
Vertex src = get_random_element(connected, gen);
// These are the vertexes that can be destination nodes.
set<Vertex> sifted = connected;
sifted.erase(src);
BGL_FORALL_OUTEDGES_T(src, e, g, Graph)
sifted.erase(target(e, g));
// Now pick from the sifted set.
Vertex dst = get_random_element(sifted, gen);
bool status = add_edge(src, dst, g).second;
assert(status);
move_if_needed(src, g, connected, saturated);
move_if_needed(dst, g, connected, saturated);
return status;
}
return false;
}
/**
* Generate the graph. The graph has one connected component, but
* there can be some lone vertexes. We don't allow loop edges
* (i.e. that start and end at some node), and we don't allow parallel
* edges.
*
* @return the number of edges actually created.
*/
template<typename T>
int
generate_graph(Graph &g, int nodes, int edges, T &gen)
{
assert(nodes >= 2);
assert(edges >= 0);
// Create a graph with the following number of nodes.
g = Graph(nodes);
// The set of lone vertexes.
std::set<Vertex> lonely = get_vertexes<std::set<Vertex> >(g);
// The set of vertexes in the connected component that have not been
// saturated yet.
std::set<Vertex> connected;
// The set of saturated vertexes. A saturated edge is connected to
// every other node with a single edge.
std::set<Vertex> saturated;
// In every iteration we add a new random edge.
for (int created = 0; created < edges; ++created)
if (!add_random_edge(g, lonely, connected, saturated, gen))
{
assert(lonely.empty());
assert(connected.size() <= 1);
assert(saturated.size() >= nodes - 1);
return created;
}
return edges;
}
#endif /* UTILS_NETGEN_HPP */