Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

SpannerBaswanaSen.h
Go to the documentation of this file.
1 
33 #pragma once
34 
35 #include <ogdf/basic/EpsilonTest.h>
36 #include <ogdf/basic/Graph.h>
38 #include <ogdf/basic/GraphCopy.h>
39 #include <ogdf/basic/GraphList.h>
40 #include <ogdf/basic/GraphSets.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 
51 namespace ogdf {
52 
73 template<typename TWeight>
74 class SpannerBaswanaSen : public SpannerModule<TWeight> {
79 
81 
82 public:
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 
107 private:
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<true> 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++) {
156  assertTimeLeft();
157 
158  NodeArray<node> oldCluster = m_cluster; // oldCluster is the cluster of iteration i-1
159 
160  // 1: Sample new cluster centers
161  NodeSet<true> 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) {
276  assertTimeLeft();
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 
315 };
316 
323 template<typename TWeight>
325 public:
327  : SpannerIteratedWrapper<TWeight>(new SpannerBaswanaSen<TWeight>(), 1000) {};
328 };
329 
330 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::GraphAttributes
Stores additional attributes of a graph (like layout information).
Definition: GraphAttributes.h:72
GraphAttributes.h
Declaration of class GraphAttributes which extends a Graph by additional attributes.
ogdf::SpannerBaswanaSen::init
virtual void init(const GraphAttributes &GA, double stretch, GraphCopySimple &spanner, EdgeArray< bool > &inSpanner) override
Initializes members and create an empty spanner.
Definition: SpannerBaswanaSen.h:108
ogdf::GraphCopySimple::delEdge
void delEdge(edge e) override
Removes edge e.
ogdf::SpannerIteratedWrapper
A implementation-independed wrapper class to execute a spanner algorithm multiple times.
Definition: SpannerIteratedWrapper.h:66
EpsilonTest.h
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
Graph.h
Includes declaration of graph class.
ogdf::EpsilonTest
Definition: EpsilonTest.h:39
ogdf::GraphCopySimple::copy
edge copy(edge e) const override
Returns the edge in the graph copy corresponding to e.
Definition: GraphCopy.h:295
ogdf::SpannerModule::m_spanner
GraphCopySimple * m_spanner
Definition: SpannerModule.h:136
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:66
ogdf::SpannerBaswanaSenIterated::SpannerBaswanaSenIterated
SpannerBaswanaSenIterated()
Definition: SpannerBaswanaSen.h:326
ogdf::SpannerBaswanaSen::phase1
void phase1()
Phase 1: Forming clusters.
Definition: SpannerBaswanaSen.h:138
ogdf::whaType::A
@ A
ogdf::SpannerModule::init
virtual void init(const GraphAttributes &GA, double stretch, GraphCopySimple &spanner, EdgeArray< bool > &inSpanner)
Initializes members and create an empty spanner.
Definition: SpannerModule.h:142
ogdf::SpannerBaswanaSen::m_eps
EpsilonTest m_eps
Definition: SpannerBaswanaSen.h:80
ogdf::NodeSet::nodes
const RS::list_type & nodes()
Returns a reference to the list of nodes contained in this set.
Definition: GraphSets.h:70
ogdf::NodeSet< true >
ogdf::SpannerModule::assertTimeLeft
void assertTimeLeft()
Assert, that time is left.
Definition: SpannerModule.h:178
ogdf::GraphCopySimple
Copies of graphs with mapping between nodes and edges.
Definition: GraphCopy.h:261
ogdf::GraphAttributes::directed
bool directed() const
Returns if the graph is directed.
Definition: GraphAttributes.h:232
ogdf::GraphAttributes::constGraph
const Graph & constGraph() const
Returns a reference to the associated graph.
Definition: GraphAttributes.h:223
GraphSets.h
Declaration and implementation of NodeSet, EdgeSet, and AdjEntrySet classes.
SpannerModule.h
Basic module for spanner algorithms.
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:142
ogdf::EpsilonTest::less
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
ogdf::GraphCopyBase::init
void init(const Graph &G)
Re-initializes the copy using G, creating copies for all nodes and edges in G.
Definition: GraphCopy.h:73
ogdf::SpannerBaswanaSen
Randomized multiplicative spanner calculation by forming clusters.
Definition: SpannerBaswanaSen.h:74
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:160
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:932
ogdf::SpannerBaswanaSen::addToSpanner
void addToSpanner(edge e)
Adds e from m_G to the spanner and sets inSpanner.
Definition: SpannerBaswanaSen.h:125
ogdf::Graph::numberOfNodes
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition: Graph_d.h:982
ogdf::SpannerBaswanaSen::m_cluster
NodeArray< node > m_cluster
the current cluster for each iteration in phase 1 and the final cluster from phase 1 which is used in...
Definition: SpannerBaswanaSen.h:78
ogdf::SpannerBaswanaSen::weight
TWeight weight(edge e)
Definition: SpannerBaswanaSen.h:133
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:243
GraphList.h
Decralation of GraphElement and GraphList classes.
ogdf::RegisteredSet::insert
void insert(element_type v)
Inserts element v into this set.
Definition: RegisteredSet.h:86
ogdf::NodeElement::adjEntries
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition: Graph_d.h:271
ogdf::SpannerBaswanaSen::phase2
void phase2()
Phase 2: Vertex-Cluster Joining.
Definition: SpannerBaswanaSen.h:273
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:398
GraphCopy.h
Declaration of graph copy classes.
ogdf::SpannerModule::m_stretch
double m_stretch
Definition: SpannerModule.h:135
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:658
ogdf::RegisteredSet::isMember
bool isMember(element_type v) const
Returns true iff element v is contained in this set.
Definition: RegisteredSet.h:138
ogdf::SpannerModule
Interface for spanner algorithms.
Definition: SpannerModule.h:63
SpannerIteratedWrapper.h
A wrapper class for iterating calls to spanner algorithms.
ogdf::AdjElement::twinNode
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition: Graph_d.h:175
ogdf::ListPure
Doubly linked lists.
Definition: List.h:55
ogdf::GraphCopySimple::clear
void clear() override
Removes all nodes and edges from this copy but does not break the link with the original graph.
ogdf::Graph::edges
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition: Graph_d.h:935
basic.h
Basic declarations, included by all source files.
ogdf::SpannerModule::m_GA
const GraphAttributes * m_GA
Definition: SpannerModule.h:134
ogdf::NodeElement::firstAdj
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition: Graph_d.h:286
ogdf::SpannerBaswanaSen::preconditionsOk
virtual bool preconditionsOk(const GraphAttributes &GA, double stretch, std::string &error) override
Definition: SpannerBaswanaSen.h:84
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:363
List.h
Declaration of doubly linked lists and iterators.
ogdf::SpannerBaswanaSenIterated
Use the ogdf::SpannerIteratedWrapper to execute the ogdf::SpannerBaswanaSen algorithm up to 1000 time...
Definition: SpannerBaswanaSen.h:324
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:401
ogdf::Module::ReturnType
ReturnType
The return type of a module.
Definition: Module.h:52
ogdf::sync_plan::internal::to_string
std::string to_string(const std::function< std::ostream &(std::ostream &)> &func)
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:240
ogdf::GraphCopySimple::newEdge
edge newEdge(edge eOrig)
Creates a new edge in the graph copy with original edge eOrig.
Definition: GraphCopy.h:321
ogdf::SpannerBaswanaSen::execute
virtual SpannerModule< TWeight >::ReturnType execute() override
Executes the core algorithm.
Definition: SpannerBaswanaSen.h:116
ogdf::SpannerBaswanaSen::m_G
GraphCopySimple m_G
The copy of GA.constGraph() to work on. Edges will be removed in each iteration.
Definition: SpannerBaswanaSen.h:76
ogdf::randomDouble
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
ogdf::GraphCopyBase::original
const Graph & original() const
Returns a reference to the original graph.
Definition: GraphCopy.h:105
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:716
ogdf::SpannerModule::getWeight
static TWeight getWeight(const GraphAttributes &GA, edge e)