Loading [MathJax]/extensions/tex2jax.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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.