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
35#include <ogdf/basic/NodeSet.h>
38
39namespace ogdf {
40
61template<typename TWeight>
62class SpannerBaswanaSen : public SpannerModule<TWeight> {
67
69
70public:
72 virtual bool preconditionsOk(const GraphAttributes& GA, double stretch,
73 std::string& error) override {
74 if (GA.directed()) {
75 error = "The graph must be undirected";
76 return false;
77 }
78 double integralPart;
79 if (std::modf(stretch, &integralPart) != 0.0) {
80 error = "The stretch is required to be an integer, not " + to_string(m_stretch);
81 return false;
82 }
83 int intStretch = static_cast<int>(stretch);
84 if (intStretch < 1) {
85 error = "The stretch must be >= 1.0";
86 return false;
87 }
88 if (intStretch % 2 == 0) {
89 error = "The stretch must be odd";
90 return false;
91 }
92 return true;
93 }
94
95private:
96 virtual void init(const GraphAttributes& GA, double stretch, GraphCopySimple& spanner,
97 EdgeArray<bool>& inSpanner) override {
99 m_G.clear();
100 m_G.init(GA.constGraph());
101 m_cluster.init(m_G);
102 }
103
104 virtual typename SpannerModule<TWeight>::ReturnType execute() override {
105 phase1();
106 phase2();
108 }
109
113 inline void addToSpanner(edge e) {
115 (*m_inSpanner)[m_G.original(e)] = true;
116 }
117
121 inline TWeight weight(edge e) { return getWeight(*m_GA, m_G.original(e)); }
122
126 void phase1() {
127 // init
129 for (node v : m_G.nodes) {
130 m_cluster[v] = v; // At the beginning each node is it's own cluster
131 clusterCenters.insert(v);
132 }
133
134 // A and B will be explained below. They are created here, so they can be reused.
135 NodeArray<edge> A(m_G, nullptr);
136 NodeArray<bool> B(m_G, false);
137
138 // stretch = 2k-1
139 // the stretch must be integer and uneven.
140 // => k=(stretch+1)/2
141 int k = (static_cast<int>(m_stretch) + 1) / 2;
142 const double probability = pow(m_G.numberOfNodes(), -1.0 / k);
143 for (int iteration = 1; iteration <= k - 1; iteration++) {
145
146 NodeArray<node> oldCluster = m_cluster; // oldCluster is the cluster of iteration i-1
147
148 // 1: Sample new cluster centers
150 for (node oldCenter : clusterCenters.nodes()) {
151 if (randomDouble(0.0, 1.0) <= probability) {
153 }
154 }
155
156 // 2 & 3: Nearest neighbors and growing clusters
157 for (node v : m_G.nodes) {
158 if (sampledClusterCenters.isMember(oldCluster[v])) {
159 continue;
160 }
161
162 // v is not a member of a sampled cluster, so we have to search for a nearest
163 // neighbor
164 // - v will be added to the cluster of the NN
165 // - A[x] saves the least weight edge from v to the cluster member of the cluster x
166 // (or nullptr if there is no such edge.)
167
168 // both "min" values are with respect to sampled clusters, not for all adjacent
169 // clusters
170 TWeight minWeight = std::numeric_limits<TWeight>::max();
171 edge minEdge = nullptr;
172
173 for (adjEntry a : v->adjEntries) {
174 node center = oldCluster[a->twinNode()];
175 edge e = a->theEdge();
176
177 // maybe add v to a new cluster
178 if (sampledClusterCenters.isMember(center)) {
179 // twin is an element of a sampled cluster, so it is a (possible nearest)
180 // neighbor
181 if (m_eps.less(weight(e), minWeight)) {
182 m_cluster[v] = center; // this line will automatically add v to the new
183 // sampled cluster since the last assignment is
184 // done on the min edge.
185 minWeight = weight(e);
186 minEdge = e;
187 }
188 }
189
190 // fill A[x]
191 if (A[center] == nullptr || m_eps.less(weight(e), weight(A[center]))) {
192 A[center] = e;
193 }
194 }
195
196 // B[<clustercenter>] stores whether all edges to a cluster should be deleted.
197
198 // add sampled clusters (or all clusters) to v
199 for (node center : m_G.nodes) {
200 // center is only a possible center. It is a center, if A[center] != nullptr.
201 // Some possibilities:
202 // - minEdge == nullptr (case (a) in paper): v is not adjacent to any sampled cluster.
203 // So, add every least weight edge to the spanner.
204 // - minEdge == A[center] (case (b), first part, in paper): v is adjacent to a sampled
205 // cluster and we have the min edge here: Add it!
206 // - not minEdge, but less weight (case (b), second part, in paper): v is adjacent to a
207 // sampled cluster. The edge to the cluster has strictly less weight than the min edge.
208 if (A[center] != nullptr
209 && (minEdge == nullptr || minEdge == A[center]
210 || m_eps.less(weight(A[center]), minWeight))) {
211 addToSpanner(A[center]);
212 B[center] = true;
213 }
214 A[center] = nullptr;
215 }
216
217#ifdef OGDF_DEBUG
218 for (node _v : m_G.nodes) {
219 OGDF_ASSERT(A[_v] == nullptr);
220 }
221#endif
222
223 // Finally, delete all edges from v indicated by B
224 ListPure<adjEntry> adjs; // copy, so we can iterate and delete.
225 v->allAdjEntries(adjs);
226 for (adjEntry a : adjs) {
227 node center = oldCluster[a->twinNode()];
228 if (B[center]) {
229 m_G.delEdge(a->theEdge());
230 }
231 B[center] = false;
232 }
233
234#ifdef OGDF_DEBUG
235 for (node _v : m_G.nodes) {
236 OGDF_ASSERT(!B[_v]);
237 }
238#endif
239 }
240
241 // 4: Removing intra-cluster edges
242 for (edge _e : m_GA->constGraph().edges) {
243 edge e = m_G.copy(_e);
244 if (e == nullptr) {
245 continue;
246 }
247
248 if (m_cluster[e->source()] == m_cluster[e->target()]) {
249 // inter-cluster connection.
250 m_G.delEdge(e);
251 }
252 }
253
255 }
256 }
257
261 void phase2() {
262 NodeArray<edge> A(m_G, nullptr);
263 for (node v : m_G.nodes) {
265
266 for (adjEntry a : v->adjEntries) {
267 node center = m_cluster[a->twinNode()];
268 edge e = a->theEdge();
269
270 // fill A[x]
271 if (A[center] == nullptr || weight(e) < weight(A[center])) {
272 A[center] = e;
273 }
274 }
275
276 for (node center : m_G.nodes) {
277 if (A[center] != nullptr) {
278 addToSpanner(A[center]);
279 A[center] = nullptr;
280 }
281 }
282
283 // Delete all edges from v in the original graph.
284 adjEntry a;
285 while ((a = v->firstAdj()) != nullptr) {
286 m_G.delEdge(a->theEdge());
287 }
288
289#ifdef OGDF_DEBUG
290 for (node _v : m_G.nodes) {
291 OGDF_ASSERT(A[_v] == nullptr);
292 }
293#endif
294 }
295 }
296
303};
304
311template<typename TWeight>
317
318}
Declaration and implementation of ogdf::NodeSet.
A wrapper class for iterating calls to spanner algorithms.
Basic module for spanner algorithms.
Class for adjacency list elements.
Definition Graph_d.h:79
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition Graph_d.h:97
Dynamic arrays indexed with edges.
Definition EdgeArray.h:125
Class for the representation of edges.
Definition Graph_d.h:300
node target() const
Returns the target node of the edge.
Definition Graph_d.h:338
node source() const
Returns the source node of the edge.
Definition Graph_d.h:335
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:57
Stores additional attributes of a graph (like layout information).
const Graph & constGraph() const
Returns a reference to the associated graph.
Copies of graphs with mapping between nodes and edges.
Definition GraphCopy.h:59
edge newEdge(edge eOrig)
Creates a new edge in the graph copy with original edge eOrig.
Definition GraphCopy.h:188
virtual void delEdge(edge e) override
Removes edge e.
node copy(node v) const
Returns the node in the graph copy corresponding to v.
Definition GraphCopy.h:124
void init(const Graph &G)
Re-initializes the copy using G.
const Graph & original() const
Returns a reference to the original graph.
Definition GraphCopy.h:85
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition Graph_d.h:622
virtual void clear()
Removes all nodes and all edges from the graph.
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition Graph_d.h:589
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:592
Doubly linked lists.
Definition List.h:217
ReturnType
The return type of a module.
Definition Module.h:50
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
Class for the representation of nodes.
Definition Graph_d.h:177
Node sets.
Definition NodeSet.h:54
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
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.