Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

SpannerElkinNeiman.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/GraphList.h>
39 #include <ogdf/basic/Math.h>
40 #include <ogdf/basic/Queue.h>
41 #include <ogdf/basic/basic.h>
45 
46 #include <cmath>
47 #include <limits>
48 #include <string>
49 
50 namespace ogdf {
51 class GraphCopySimple;
52 
105 template<typename TWeight>
106 class SpannerElkinNeiman : public SpannerModule<TWeight> {
108  const Graph* m_G;
109 
111 
112  double m_c;
113  double m_beta;
114  int m_k;
116 
125  const double DEFAULT_EPSILON = 0.8;
126 
127 public:
129 
130  SpannerElkinNeiman(double epsilon) : SpannerModule<TWeight>() { setEpsilon(epsilon); }
131 
137  void setEpsilon(double epsilon) {
138  OGDF_ASSERT(epsilon > 0);
139  m_c = 3.0 / epsilon; // see corollary 8.
140  }
141 
143  virtual bool preconditionsOk(const GraphAttributes& GA, double stretch,
144  std::string& error) override {
145  if (GA.directed()) {
146  error = "The graph must be undirected";
147  return false;
148  }
149  double integralPart;
150  if (std::modf(stretch, &integralPart) != 0.0) {
151  error = "The stretch is required to be an integer, not " + to_string(stretch);
152  return false;
153  }
154  int intStretch = static_cast<int>(stretch);
155  if (intStretch < 1) {
156  error = "The stretch must be >= 1.0";
157  return false;
158  }
159  if (intStretch % 2 == 0) {
160  error = "The stretch must be odd";
161  return false;
162  }
164  error = "The graph must be unweighted";
165  return false;
166  }
167  return true;
168  }
169 
170 private:
172  virtual void init(const GraphAttributes& GA, double stretch, GraphCopySimple& spanner,
173  EdgeArray<bool>& inSpanner) override {
174  SpannerModule<TWeight>::init(GA, stretch, spanner, inSpanner);
175  m_intStretch = static_cast<int>(stretch);
176  m_k = (m_intStretch + 1) / 2;
177  m_G = &GA.constGraph();
178  m_beta = log(m_c * m_G->numberOfNodes()) / m_k; // log is logarithm naturale
179  }
180 
181  struct BfsNode {
182  node n;
183  int depth;
184  edge p;
185 
186  BfsNode(node _n, double _depth, edge _p) : n(_n), depth(_depth), p(_p) { }
187  };
188 
190  virtual typename SpannerModule<TWeight>::ReturnType execute() override {
192  // First, assign each node the random variable. This is done here, so the first
193  // feasibility check can be done fast (This is the one that mostly fails).
194  for (node u : m_G->nodes) {
196  // Feasibility check 1: See proof of Theorem 1 and "Standard Centralized Model" in 2.1.1
197  if (m_eps.geq(r[u], static_cast<double>(m_k))) {
199  }
200  }
201 
202  // Paper: u broadcasts a message x within distance k
203  // Here: Fix a receiving node x and find all nodes u within distance k, that send messages to x
204  for (node x : m_G->nodes) {
205  // values[u]: x recieves the value from u (m_u(x))
206  NodeArray<double> values(*m_G, std::numeric_limits<double>::lowest());
207 
208  // firstEdge[u]: The first edge from the path x->u (p_u(x))
209  // This is the last edge from the path u->x as described in the paper
210  NodeArray<edge> firstEdge(*m_G, nullptr);
211 
212  QueuePure<BfsNode> queue;
213  NodeArray<bool> marked(*m_G, false); // Just visit a node once.
214 
215  queue.emplace(x, 0, nullptr); // p==nullptr: we do not have a first edge
216  marked[x] = true; // Do not revisit x
217  while (!queue.empty()) {
218  BfsNode bfsNode = queue.pop();
219  int distance = bfsNode.depth + 1;
220 
221  for (adjEntry adj : bfsNode.n->adjEntries) {
222  node u = adj->twinNode();
223  if (marked[u]) {
224  continue;
225  }
226 
227  edge p = bfsNode.p;
228  if (p == nullptr) {
229  p = adj->theEdge(); // Set the first edge: Only happens in the first expansion step of the bfs
230  }
231 
232  values[u] = r[u] - distance;
233  firstEdge[u] = p;
234 
235  if (distance < m_k) { // distance is <= m_k when a dfs node is popped from the stack.
236  queue.emplace(u, distance, p);
237  marked[u] = true;
238  }
239  }
240  }
241 
242  assertTimeLeft();
243 
244  // find edges that must be added to the spanner:
245  // m(x) = max{m_u(x) | u in V}
246  double maxValue = std::numeric_limits<double>::lowest();
247  for (node u : m_G->nodes) {
248  Math::updateMax(maxValue, values[u]);
249  }
250  maxValue -= 1.0; // m(x)-1
251 
252  assertTimeLeft();
253 
254  // Add the edges (sets C(x) in the paper) to the spanner.
255  for (node u : m_G->nodes) {
256  if (values[u] != std::numeric_limits<double>::lowest()
257  && m_eps.geq(values[u], maxValue)) {
258  edge e = firstEdge[u];
259  if (!(*m_inSpanner)[e]) {
260  m_spanner->newEdge(e);
261  (*m_inSpanner)[e] = true;
262  }
263  }
264  }
265 
266  assertTimeLeft();
267  }
268 
269  // Feasibility check 2: See proof of Theorem 1 and "Standard Centralized Model" in 2.1.1
270  // Note: The paper states, that the spanner must have >= n-1 edges. This does not work, for
271  // all graphs, e.g. a forest as an input. The paper never states, that the graph must be connected
272  // nor that it can be disconnected. Using n-<amount components> does work and solves the issue above.
273  int components = connectedComponents(*m_G);
274  if (m_spanner->numberOfEdges() < m_G->numberOfNodes() - components) {
276  }
277 
279  }
280 
286 };
287 
294 template<typename TWeight>
296 public:
298  : SpannerIteratedWrapper<TWeight>(new SpannerElkinNeiman<TWeight>(), 200) {};
299 };
300 
301 }
ogdf::GraphAttributes::edgeIntWeight
static const long edgeIntWeight
Corresponds to edge attribute intWeight(edge).
Definition: GraphAttributes.h:125
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::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::connectedComponents
int connectedComponents(const Graph &G, NodeArray< int > &component, List< node > *isolated=nullptr, ArrayBuffer< node > *reprs=nullptr)
Computes the connected components of G and optionally generates a list of isolated nodes.
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::SpannerElkinNeimanIterated::SpannerElkinNeimanIterated
SpannerElkinNeimanIterated()
Definition: SpannerElkinNeiman.h:297
ogdf::SpannerElkinNeiman::m_beta
double m_beta
The parameter for the exponential distribution.
Definition: SpannerElkinNeiman.h:113
ogdf::SpannerElkinNeiman::m_k
int m_k
the parameter k derived from the stretch
Definition: SpannerElkinNeiman.h:114
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::SpannerElkinNeiman::BfsNode::n
node n
The current node to visit all neighbors from.
Definition: SpannerElkinNeiman.h:182
ogdf::SpannerModule::assertTimeLeft
void assertTimeLeft()
Assert, that time is left.
Definition: SpannerModule.h:178
ogdf::SpannerElkinNeiman::preconditionsOk
virtual bool preconditionsOk(const GraphAttributes &GA, double stretch, std::string &error) override
Definition: SpannerElkinNeiman.h:143
Queue.h
Declaration and implementation of list-based queues (classes QueuePure<E> and Queue<E>).
ogdf::SpannerElkinNeiman::SpannerElkinNeiman
SpannerElkinNeiman()
Definition: SpannerElkinNeiman.h:128
ogdf::GraphCopySimple
Copies of graphs with mapping between nodes and edges.
Definition: GraphCopy.h:261
ogdf::SpannerElkinNeiman::execute
virtual SpannerModule< TWeight >::ReturnType execute() override
Executes the core algorithm.
Definition: SpannerElkinNeiman.h:190
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
ogdf::QueuePure::empty
bool empty() const
Returns true iff the queue is empty.
Definition: Queue.h:93
ogdf::QueuePure::emplace
iterator emplace(Args &&... args)
Adds a new element at the end of the queue.
Definition: Queue.h:178
SpannerModule.h
Basic module for spanner algorithms.
ogdf::SpannerElkinNeiman::m_c
double m_c
the parameter for the exponential distribution.
Definition: SpannerElkinNeiman.h:112
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:142
ogdf::SpannerElkinNeiman::m_eps
EpsilonTest m_eps
Definition: SpannerElkinNeiman.h:110
ogdf::SpannerElkinNeiman::BfsNode::depth
int depth
The depth of the node n.
Definition: SpannerElkinNeiman.h:183
ogdf::SpannerElkinNeiman::setEpsilon
void setEpsilon(double epsilon)
Sets the epsilon for this algorithm.
Definition: SpannerElkinNeiman.h:137
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:160
r
int r[]
Definition: hierarchical-ranking.cpp:13
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:932
ogdf::Graph::numberOfEdges
int numberOfEdges() const
Returns the number of edges in the graph.
Definition: Graph_d.h:985
ogdf::randomDoubleExponential
double randomDoubleExponential(double beta)
Returns a random double value from the exponential distribution.
ogdf::Graph::numberOfNodes
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition: Graph_d.h:982
ogdf::SpannerElkinNeimanIterated
Use the ogdf::SpannerIteratedWrapper to execute the ogdf::SpannerElkinNeiman algorithm up to 200 time...
Definition: SpannerElkinNeiman.h:295
GraphList.h
Decralation of GraphElement and GraphList classes.
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::MeasureEnum::log
@ log
ogdf::SpannerElkinNeiman::m_G
const Graph * m_G
The original graph.
Definition: SpannerElkinNeiman.h:108
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:658
ogdf::Graph
Data type for general directed graphs (adjacency list representation).
Definition: Graph_d.h:869
ogdf::SpannerElkinNeiman::BfsNode::BfsNode
BfsNode(node _n, double _depth, edge _p)
Definition: SpannerElkinNeiman.h:186
ogdf::SpannerModule
Interface for spanner algorithms.
Definition: SpannerModule.h:63
SpannerIteratedWrapper.h
A wrapper class for iterating calls to spanner algorithms.
Math.h
Mathematical Helpers.
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::SpannerElkinNeiman::SpannerElkinNeiman
SpannerElkinNeiman(double epsilon)
Definition: SpannerElkinNeiman.h:130
ogdf::SpannerElkinNeiman::BfsNode
Definition: SpannerElkinNeiman.h:181
ogdf::Math::updateMax
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition: Math.h:94
ogdf::QueuePure
Implementation of list-based queues.
Definition: Queue.h:55
basic.h
Basic declarations, included by all source files.
ogdf::SpannerElkinNeiman::BfsNode::p
edge p
The first edge of the path.
Definition: SpannerElkinNeiman.h:184
ogdf::SpannerElkinNeiman::m_intStretch
int m_intStretch
m_stretch, but as an integer
Definition: SpannerElkinNeiman.h:115
ogdf::SpannerElkinNeiman
Randomized multiplicative spanner calculation by propagating random messages through the graph.
Definition: SpannerElkinNeiman.h:106
ogdf::SpannerElkinNeiman::DEFAULT_EPSILON
const double DEFAULT_EPSILON
The default value for epsilon.
Definition: SpannerElkinNeiman.h:125
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:363
ogdf::SpannerModule::m_inSpanner
EdgeArray< bool > * m_inSpanner
Definition: SpannerModule.h:137
ogdf::EpsilonTest::geq
std::enable_if< std::is_integral< T >::value, bool >::type geq(const T &x, const T &y) const
Compare if x is GEQ to y for integral types.
Definition: EpsilonTest.h:133
ogdf::GraphAttributes::edgeDoubleWeight
static const long edgeDoubleWeight
Corresponds to edge attribute doubleWeight(edge).
Definition: GraphAttributes.h:128
ogdf::QueuePure::pop
E pop()
Removes front element and returns it.
Definition: Queue.h:183
ogdf::SpannerElkinNeiman::init
virtual void init(const GraphAttributes &GA, double stretch, GraphCopySimple &spanner, EdgeArray< bool > &inSpanner) override
Initializes members and create an empty spanner.
Definition: SpannerElkinNeiman.h:172
ogdf::Module::ReturnType
ReturnType
The return type of a module.
Definition: Module.h:52
ogdf::Math::maxValue
Container::value_type maxValue(const Container &values)
Returns the maximum of an iterable container of given values.
Definition: Math.h:239
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
simple_graph_alg.h
Declaration of simple graph algorithms.
ogdf::GraphAttributes::has
bool has(long attr) const
Returns true iff all attributes in attr are available.
Definition: GraphAttributes.h:200
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:716