Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
SpannerBaswanaSen.h
Go to the documentation of this file.
1
33#pragma once
34
36#include <ogdf/basic/Graph.h>
41#include <ogdf/basic/List.h>
42#include <ogdf/basic/basic.h>
45
46#include <cmath>
47#include <limits>
48#include <string>
49#include <utility>
50
51namespace ogdf {
52
73template<typename TWeight>
74class SpannerBaswanaSen : public SpannerModule<TWeight> {
79
81
82public:
84 virtual bool preconditionsOk(const GraphAttributes& GA, double stretch,
85 std::string& error) override {
86 if (GA.directed()) {
87 error = "The graph must be undirected";
88 return false;
89 }
90 double integralPart;
91 if (std::modf(stretch, &integralPart) != 0.0) {
92 error = "The stretch is required to be an integer, not " + to_string(m_stretch);
93 return false;
94 }
95 int intStretch = static_cast<int>(stretch);
96 if (intStretch < 1) {
97 error = "The stretch must be >= 1.0";
98 return false;
99 }
100 if (intStretch % 2 == 0) {
101 error = "The stretch must be odd";
102 return false;
103 }
104 return true;
105 }
106
107private:
108 virtual void init(const GraphAttributes& GA, double stretch, GraphCopySimple& spanner,
109 EdgeArray<bool>& inSpanner) override {
110 SpannerModule<TWeight>::init(GA, stretch, spanner, inSpanner);
111 m_G.clear();
112 m_G.init(GA.constGraph());
113 m_cluster.init(m_G);
114 }
115
116 virtual typename SpannerModule<TWeight>::ReturnType execute() override {
117 phase1();
118 phase2();
120 }
121
125 inline void addToSpanner(edge e) {
127 (*m_inSpanner)[m_G.original(e)] = true;
128 }
129
133 inline TWeight weight(edge e) { return getWeight(*m_GA, m_G.original(e)); }
134
138 void phase1() {
139 // init
140 NodeSet clusterCenters(m_G);
141 for (node v : m_G.nodes) {
142 m_cluster[v] = v; // At the beginning each node is it's own cluster
143 clusterCenters.insert(v);
144 }
145
146 // A and B will be explained below. They are created here, so they can be reused.
147 NodeArray<edge> A(m_G, nullptr);
148 NodeArray<bool> B(m_G, false);
149
150 // stretch = 2k-1
151 // the stretch must be integer and uneven.
152 // => k=(stretch+1)/2
153 int k = (static_cast<int>(m_stretch) + 1) / 2;
154 const double probability = pow(m_G.numberOfNodes(), -1.0 / k);
155 for (int iteration = 1; iteration <= k - 1; iteration++) {
157
158 NodeArray<node> oldCluster = m_cluster; // oldCluster is the cluster of iteration i-1
159
160 // 1: Sample new cluster centers
161 NodeSet sampledClusterCenters(m_G);
162 for (node oldCenter : clusterCenters.nodes()) {
163 if (randomDouble(0.0, 1.0) <= probability) {
164 sampledClusterCenters.insert(oldCenter);
165 }
166 }
167
168 // 2 & 3: Nearest neighbors and growing clusters
169 for (node v : m_G.nodes) {
170 if (sampledClusterCenters.isMember(oldCluster[v])) {
171 continue;
172 }
173
174 // v is not a member of a sampled cluster, so we have to search for a nearest
175 // neighbor
176 // - v will be added to the cluster of the NN
177 // - A[x] saves the least weight edge from v to the cluster member of the cluster x
178 // (or nullptr if there is no such edge.)
179
180 // both "min" values are with respect to sampled clusters, not for all adjacent
181 // clusters
182 TWeight minWeight = std::numeric_limits<TWeight>::max();
183 edge minEdge = nullptr;
184
185 for (adjEntry a : v->adjEntries) {
186 node center = oldCluster[a->twinNode()];
187 edge e = a->theEdge();
188
189 // maybe add v to a new cluster
190 if (sampledClusterCenters.isMember(center)) {
191 // twin is an element of a sampled cluster, so it is a (possible nearest)
192 // neighbor
193 if (m_eps.less(weight(e), minWeight)) {
194 m_cluster[v] = center; // this line will automatically add v to the new
195 // sampled cluster since the last assignment is
196 // done on the min edge.
197 minWeight = weight(e);
198 minEdge = e;
199 }
200 }
201
202 // fill A[x]
203 if (A[center] == nullptr || m_eps.less(weight(e), weight(A[center]))) {
204 A[center] = e;
205 }
206 }
207
208 // B[<clustercenter>] stores whether all edges to a cluster should be deleted.
209
210 // add sampled clusters (or all clusters) to v
211 for (node center : m_G.nodes) {
212 // center is only a possible center. It is a center, if A[center] != nullptr.
213 // Some possibilities:
214 // - minEdge == nullptr (case (a) in paper): v is not adjacent to any sampled cluster.
215 // So, add every least weight edge to the spanner.
216 // - minEdge == A[center] (case (b), first part, in paper): v is adjacent to a sampled
217 // cluster and we have the min edge here: Add it!
218 // - not minEdge, but less weight (case (b), second part, in paper): v is adjacent to a
219 // sampled cluster. The edge to the cluster has strictly less weight than the min edge.
220 if (A[center] != nullptr
221 && (minEdge == nullptr || minEdge == A[center]
222 || m_eps.less(weight(A[center]), minWeight))) {
223 addToSpanner(A[center]);
224 B[center] = true;
225 }
226 A[center] = nullptr;
227 }
228
229#ifdef OGDF_DEBUG
230 for (node _v : m_G.nodes) {
231 OGDF_ASSERT(A[_v] == nullptr);
232 }
233#endif
234
235 // Finally, delete all edges from v indicated by B
236 ListPure<adjEntry> adjs; // copy, so we can iterate and delete.
237 v->allAdjEntries(adjs);
238 for (adjEntry a : adjs) {
239 node center = oldCluster[a->twinNode()];
240 if (B[center]) {
241 m_G.delEdge(a->theEdge());
242 }
243 B[center] = false;
244 }
245
246#ifdef OGDF_DEBUG
247 for (node _v : m_G.nodes) {
248 OGDF_ASSERT(!B[_v]);
249 }
250#endif
251 }
252
253 // 4: Removing intra-cluster edges
254 for (edge _e : m_GA->constGraph().edges) {
255 edge e = m_G.copy(_e);
256 if (e == nullptr) {
257 continue;
258 }
259
260 if (m_cluster[e->source()] == m_cluster[e->target()]) {
261 // inter-cluster connection.
262 m_G.delEdge(e);
263 }
264 }
265
266 clusterCenters = std::move(sampledClusterCenters);
267 }
268 }
269
273 void phase2() {
274 NodeArray<edge> A(m_G, nullptr);
275 for (node v : m_G.nodes) {
277
278 for (adjEntry a : v->adjEntries) {
279 node center = m_cluster[a->twinNode()];
280 edge e = a->theEdge();
281
282 // fill A[x]
283 if (A[center] == nullptr || weight(e) < weight(A[center])) {
284 A[center] = e;
285 }
286 }
287
288 for (node center : m_G.nodes) {
289 if (A[center] != nullptr) {
290 addToSpanner(A[center]);
291 A[center] = nullptr;
292 }
293 }
294
295 // Delete all edges from v in the original graph.
296 adjEntry a;
297 while ((a = v->firstAdj()) != nullptr) {
298 m_G.delEdge(a->theEdge());
299 }
300
301#ifdef OGDF_DEBUG
302 for (node _v : m_G.nodes) {
303 OGDF_ASSERT(A[_v] == nullptr);
304 }
305#endif
306 }
307 }
308
309 using SpannerModule<TWeight>::getWeight;
310 using SpannerModule<TWeight>::assertTimeLeft;
311 using SpannerModule<TWeight>::m_GA;
312 using SpannerModule<TWeight>::m_stretch;
313 using SpannerModule<TWeight>::m_spanner;
314 using SpannerModule<TWeight>::m_inSpanner;
315};
316
323template<typename TWeight>
325public:
327 : SpannerIteratedWrapper<TWeight>(new SpannerBaswanaSen<TWeight>(), 1000) {};
328};
329
330}
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
Includes declaration of graph class.
Declaration of class GraphAttributes which extends a Graph by additional attributes.
Declaration of graph copy classes.
Decralation of GraphElement and GraphList classes.
Declaration and implementation of NodeSet, EdgeSet, and AdjEntrySet classes.
Declaration of doubly linked lists and iterators.
A wrapper class for iterating calls to spanner algorithms.
Basic module for spanner algorithms.
Basic declarations, included by all source files.
Class for adjacency list elements.
Definition Graph_d.h:143
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition Graph_d.h:161
Class for the representation of edges.
Definition Graph_d.h:364
node target() const
Returns the target node of the edge.
Definition Graph_d.h:402
node source() const
Returns the source node of the edge.
Definition Graph_d.h:399
std::enable_if< std::is_integral< T >::value, bool >::type less(const T &x, const T &y) const
Compare if x is LESS than y for integral types.
Definition EpsilonTest.h:55
Stores additional attributes of a graph (like layout information).
bool directed() const
Returns if the graph is directed.
const Graph & constGraph() const
Returns a reference to the associated graph.
void init(const Graph &G)
Re-initializes the copy using G, creating copies for all nodes and edges in G.
Definition GraphCopy.h:72
const Graph & original() const
Returns a reference to the original graph.
Definition GraphCopy.h:104
Copies of graphs with mapping between nodes and edges.
Definition GraphCopy.h:260
edge newEdge(edge eOrig)
Creates a new edge in the graph copy with original edge eOrig.
Definition GraphCopy.h:320
void delEdge(edge e) override
Removes edge e.
void clear() override
Removes all nodes and edges from this copy but does not break the link with the original graph.
edge copy(edge e) const override
Returns the edge in the graph copy corresponding to e.
Definition GraphCopy.h:294
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition Graph_d.h:979
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition Graph_d.h:929
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:932
Doubly linked lists.
Definition List.h:233
ReturnType
The return type of a module.
Definition Module.h:52
Class for the representation of nodes.
Definition Graph_d.h:241
Node sets.
Definition GraphSets.h:54
const list_type & nodes()
Returns a reference to the list of nodes contained in this set.
Definition GraphSets.h:64
bool isMember(element_type v) const
Returns true iff element v is contained in this set.
void insert(element_type v)
Inserts element v into this set.
Randomized multiplicative spanner calculation by forming clusters.
virtual bool preconditionsOk(const GraphAttributes &GA, double stretch, std::string &error) override
virtual SpannerModule< TWeight >::ReturnType execute() override
Executes the core algorithm.
virtual void init(const GraphAttributes &GA, double stretch, GraphCopySimple &spanner, EdgeArray< bool > &inSpanner) override
Initializes members and create an empty spanner.
NodeArray< node > m_cluster
the current cluster for each iteration in phase 1 and the final cluster from phase 1 which is used in...
GraphCopySimple m_G
The copy of GA.constGraph() to work on. Edges will be removed in each iteration.
void phase2()
Phase 2: Vertex-Cluster Joining.
void phase1()
Phase 1: Forming clusters.
void addToSpanner(edge e)
Adds e from m_G to the spanner and sets inSpanner.
Use the ogdf::SpannerIteratedWrapper to execute the ogdf::SpannerBaswanaSen algorithm up to 1000 time...
A implementation-independed wrapper class to execute a spanner algorithm multiple times.
Interface for spanner algorithms.
void assertTimeLeft()
Assert, that time is left.
virtual void init(const GraphAttributes &GA, double stretch, GraphCopySimple &spanner, EdgeArray< bool > &inSpanner)
Initializes members and create an empty spanner.
const GraphAttributes * m_GA
EdgeArray< bool > * m_inSpanner
static TWeight getWeight(const GraphAttributes &GA, edge e)
GraphCopySimple * m_spanner
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition Graph_d.h:717
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
The namespace for all OGDF objects.