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/NodeSet.h>
38 
39 namespace ogdf {
40 
61 template<typename TWeight>
62 class SpannerBaswanaSen : public SpannerModule<TWeight> {
67 
69 
70 public:
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 
95 private:
96  virtual void init(const GraphAttributes& GA, double stretch, GraphCopySimple& spanner,
97  EdgeArray<bool>& inSpanner) override {
98  SpannerModule<TWeight>::init(GA, stretch, spanner, inSpanner);
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
128  NodeSet<true> clusterCenters(m_G);
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++) {
144  assertTimeLeft();
145 
146  NodeArray<node> oldCluster = m_cluster; // oldCluster is the cluster of iteration i-1
147 
148  // 1: Sample new cluster centers
149  NodeSet<true> sampledClusterCenters(m_G);
150  for (node oldCenter : clusterCenters.nodes()) {
151  if (randomDouble(0.0, 1.0) <= probability) {
152  sampledClusterCenters.insert(oldCenter);
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 
254  clusterCenters = std::move(sampledClusterCenters);
255  }
256  }
257 
261  void phase2() {
262  NodeArray<edge> A(m_G, nullptr);
263  for (node v : m_G.nodes) {
264  assertTimeLeft();
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 
311 template<typename TWeight>
313 public:
315  : SpannerIteratedWrapper<TWeight>(new SpannerBaswanaSen<TWeight>(), 1000) {};
316 };
317 
318 }
NodeSet.h
Declaration and implementation of ogdf::NodeSet.
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
ogdf::GraphAttributes
Stores additional attributes of a graph (like layout information).
Definition: GraphAttributes.h:66
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:96
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:58
ogdf::EpsilonTest
Definition: EpsilonTest.h:41
ogdf::GraphCopySimple::copy
edge copy(edge e) const override
Returns the edge in the graph copy corresponding to e.
Definition: GraphCopy.h:288
ogdf::SpannerModule::m_spanner
GraphCopySimple * m_spanner
Definition: SpannerModule.h:130
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
ogdf::SpannerBaswanaSenIterated::SpannerBaswanaSenIterated
SpannerBaswanaSenIterated()
Definition: SpannerBaswanaSen.h:314
ogdf::SpannerBaswanaSen::phase1
void phase1()
Phase 1: Forming clusters.
Definition: SpannerBaswanaSen.h:126
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:136
ogdf::SpannerBaswanaSen::m_eps
EpsilonTest m_eps
Definition: SpannerBaswanaSen.h:68
ogdf::NodeSet::nodes
const RS::list_type & nodes()
Returns a reference to the list of nodes contained in this set.
Definition: GraphSets.h:65
ogdf::NodeSet< true >
ogdf::SpannerModule::assertTimeLeft
void assertTimeLeft()
Assert, that time is left.
Definition: SpannerModule.h:172
ogdf::GraphCopySimple
Copies of graphs with mapping between nodes and edges.
Definition: GraphCopy.h:254
ogdf::GraphAttributes::directed
bool directed() const
Returns if the graph is directed.
Definition: GraphAttributes.h:226
ogdf::GraphAttributes::constGraph
const Graph & constGraph() const
Returns a reference to the associated graph.
Definition: GraphAttributes.h:217
SpannerModule.h
Basic module for spanner algorithms.
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:135
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:57
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:66
ogdf::SpannerBaswanaSen
Randomized multiplicative spanner calculation by forming clusters.
Definition: SpannerBaswanaSen.h:62
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:153
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:924
ogdf::SpannerBaswanaSen::addToSpanner
void addToSpanner(edge e)
Adds e from m_G to the spanner and sets inSpanner.
Definition: SpannerBaswanaSen.h:113
ogdf::Graph::numberOfNodes
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition: Graph_d.h:974
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:66
ogdf::SpannerBaswanaSen::weight
TWeight weight(edge e)
Definition: SpannerBaswanaSen.h:121
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:243
ogdf::RegisteredSet::insert
void insert(element_type v)
Inserts element v into this set.
Definition: RegisteredSet.h:84
ogdf::NodeElement::adjEntries
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition: Graph_d.h:264
ogdf::SpannerBaswanaSen::phase2
void phase2()
Phase 2: Vertex-Cluster Joining.
Definition: SpannerBaswanaSen.h:261
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:391
ogdf::SpannerModule::m_stretch
double m_stretch
Definition: SpannerModule.h:129
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:651
ogdf::RegisteredSet::isMember
bool isMember(element_type v) const
Returns true iff element v is contained in this set.
Definition: RegisteredSet.h:136
ogdf::SpannerModule
Interface for spanner algorithms.
Definition: SpannerModule.h:57
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:168
ogdf::ListPure
Doubly linked lists.
Definition: List.h:44
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:927
ogdf::SpannerModule::m_GA
const GraphAttributes * m_GA
Definition: SpannerModule.h:128
ogdf::NodeElement::firstAdj
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition: Graph_d.h:279
ogdf::SpannerBaswanaSen::preconditionsOk
virtual bool preconditionsOk(const GraphAttributes &GA, double stretch, std::string &error) override
Definition: SpannerBaswanaSen.h:72
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:356
ogdf::SpannerBaswanaSenIterated
Use the ogdf::SpannerIteratedWrapper to execute the ogdf::SpannerBaswanaSen algorithm up to 1000 time...
Definition: SpannerBaswanaSen.h:312
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:394
ogdf::Module::ReturnType
ReturnType
The return type of a module.
Definition: Module.h:50
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:233
ogdf::GraphCopySimple::newEdge
edge newEdge(edge eOrig)
Creates a new edge in the graph copy with original edge eOrig.
Definition: GraphCopy.h:314
ogdf::SpannerBaswanaSen::execute
virtual SpannerModule< TWeight >::ReturnType execute() override
Executes the core algorithm.
Definition: SpannerBaswanaSen.h:104
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:64
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:98
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:709
ogdf::SpannerModule::getWeight
static TWeight getWeight(const GraphAttributes &GA, edge e)