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/Queue.h>
39 
40 namespace ogdf {
41 
94 template<typename TWeight>
95 class SpannerElkinNeiman : public SpannerModule<TWeight> {
97  const Graph* m_G;
98 
100 
101  double m_c;
102  double m_beta;
103  int m_k;
105 
114  const double DEFAULT_EPSILON = 0.8;
115 
116 public:
118 
119  SpannerElkinNeiman(double epsilon) : SpannerModule<TWeight>() { setEpsilon(epsilon); }
120 
126  void setEpsilon(double epsilon) {
127  OGDF_ASSERT(epsilon > 0);
128  m_c = 3.0 / epsilon; // see corollary 8.
129  }
130 
132  virtual bool preconditionsOk(const GraphAttributes& GA, double stretch,
133  std::string& error) override {
134  if (GA.directed()) {
135  error = "The graph must be undirected";
136  return false;
137  }
138  double integralPart;
139  if (std::modf(stretch, &integralPart) != 0.0) {
140  error = "The stretch is required to be an integer, not " + to_string(stretch);
141  return false;
142  }
143  int intStretch = static_cast<int>(stretch);
144  if (intStretch < 1) {
145  error = "The stretch must be >= 1.0";
146  return false;
147  }
148  if (intStretch % 2 == 0) {
149  error = "The stretch must be odd";
150  return false;
151  }
153  error = "The graph must be unweighted";
154  return false;
155  }
156  return true;
157  }
158 
159 private:
161  virtual void init(const GraphAttributes& GA, double stretch, GraphCopySimple& spanner,
162  EdgeArray<bool>& inSpanner) override {
163  SpannerModule<TWeight>::init(GA, stretch, spanner, inSpanner);
164  m_intStretch = static_cast<int>(stretch);
165  m_k = (m_intStretch + 1) / 2;
166  m_G = &GA.constGraph();
167  m_beta = log(m_c * m_G->numberOfNodes()) / m_k; // log is logarithm naturale
168  }
169 
170  struct BfsNode {
171  node n;
172  int depth;
173  edge p;
174 
175  BfsNode(node _n, double _depth, edge _p) : n(_n), depth(_depth), p(_p) { }
176  };
177 
179  virtual typename SpannerModule<TWeight>::ReturnType execute() override {
181  // First, assign each node the random variable. This is done here, so the first
182  // feasibility check can be done fast (This is the one that mostly fails).
183  for (node u : m_G->nodes) {
185  // Feasibility check 1: See proof of Theorem 1 and "Standard Centralized Model" in 2.1.1
186  if (m_eps.geq(r[u], static_cast<double>(m_k))) {
188  }
189  }
190 
191  // Paper: u broadcasts a message x within distance k
192  // Here: Fix a receiving node x and find all nodes u within distance k, that send messages to x
193  for (node x : m_G->nodes) {
194  // values[u]: x recieves the value from u (m_u(x))
195  NodeArray<double> values(*m_G, std::numeric_limits<double>::lowest());
196 
197  // firstEdge[u]: The first edge from the path x->u (p_u(x))
198  // This is the last edge from the path u->x as described in the paper
199  NodeArray<edge> firstEdge(*m_G, nullptr);
200 
201  QueuePure<BfsNode> queue;
202  NodeArray<bool> marked(*m_G, false); // Just visit a node once.
203 
204  queue.emplace(x, 0, nullptr); // p==nullptr: we do not have a first edge
205  marked[x] = true; // Do not revisit x
206  while (!queue.empty()) {
207  BfsNode bfsNode = queue.pop();
208  int distance = bfsNode.depth + 1;
209 
210  for (adjEntry adj : bfsNode.n->adjEntries) {
211  node u = adj->twinNode();
212  if (marked[u]) {
213  continue;
214  }
215 
216  edge p = bfsNode.p;
217  if (p == nullptr) {
218  p = adj->theEdge(); // Set the first edge: Only happens in the first expansion step of the bfs
219  }
220 
221  values[u] = r[u] - distance;
222  firstEdge[u] = p;
223 
224  if (distance < m_k) { // distance is <= m_k when a dfs node is popped from the stack.
225  queue.emplace(u, distance, p);
226  marked[u] = true;
227  }
228  }
229  }
230 
231  assertTimeLeft();
232 
233  // find edges that must be added to the spanner:
234  // m(x) = max{m_u(x) | u in V}
235  double maxValue = std::numeric_limits<double>::lowest();
236  for (node u : m_G->nodes) {
237  Math::updateMax(maxValue, values[u]);
238  }
239  maxValue -= 1.0; // m(x)-1
240 
241  assertTimeLeft();
242 
243  // Add the edges (sets C(x) in the paper) to the spanner.
244  for (node u : m_G->nodes) {
245  if (values[u] != std::numeric_limits<double>::lowest()
246  && m_eps.geq(values[u], maxValue)) {
247  edge e = firstEdge[u];
248  if (!(*m_inSpanner)[e]) {
249  m_spanner->newEdge(e);
250  (*m_inSpanner)[e] = true;
251  }
252  }
253  }
254 
255  assertTimeLeft();
256  }
257 
258  // Feasibility check 2: See proof of Theorem 1 and "Standard Centralized Model" in 2.1.1
259  // Note: The paper states, that the spanner must have >= n-1 edges. This does not work, for
260  // all graphs, e.g. a forest as an input. The paper never states, that the graph must be connected
261  // nor that it can be disconnected. Using n-<amount components> does work and solves the issue above.
262  int components = connectedComponents(*m_G);
263  if (m_spanner->numberOfEdges() < m_G->numberOfNodes() - components) {
265  }
266 
268  }
269 
275 };
276 
283 template<typename TWeight>
285 public:
287  : SpannerIteratedWrapper<TWeight>(new SpannerElkinNeiman<TWeight>(), 200) {};
288 };
289 
290 }
ogdf::GraphAttributes::edgeIntWeight
static const long edgeIntWeight
Corresponds to edge attribute intWeight(edge).
Definition: GraphAttributes.h:119
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::SpannerIteratedWrapper
A implementation-independed wrapper class to execute a spanner algorithm multiple times.
Definition: SpannerIteratedWrapper.h:58
ogdf::EpsilonTest
Definition: EpsilonTest.h:41
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:130
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
ogdf::SpannerElkinNeimanIterated::SpannerElkinNeimanIterated
SpannerElkinNeimanIterated()
Definition: SpannerElkinNeiman.h:286
ogdf::SpannerElkinNeiman::m_beta
double m_beta
The parameter for the exponential distribution.
Definition: SpannerElkinNeiman.h:102
ogdf::SpannerElkinNeiman::m_k
int m_k
the parameter k derived from the stretch
Definition: SpannerElkinNeiman.h:103
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::SpannerElkinNeiman::BfsNode::n
node n
The current node to visit all neighbors from.
Definition: SpannerElkinNeiman.h:171
ogdf::SpannerModule::assertTimeLeft
void assertTimeLeft()
Assert, that time is left.
Definition: SpannerModule.h:172
ogdf::SpannerElkinNeiman::preconditionsOk
virtual bool preconditionsOk(const GraphAttributes &GA, double stretch, std::string &error) override
Definition: SpannerElkinNeiman.h:132
Queue.h
Declaration and implementation of list-based queues (classes QueuePure<E> and Queue<E>).
ogdf::SpannerElkinNeiman::SpannerElkinNeiman
SpannerElkinNeiman()
Definition: SpannerElkinNeiman.h:117
ogdf::GraphCopySimple
Copies of graphs with mapping between nodes and edges.
Definition: GraphCopy.h:254
ogdf::SpannerElkinNeiman::execute
virtual SpannerModule< TWeight >::ReturnType execute() override
Executes the core algorithm.
Definition: SpannerElkinNeiman.h:179
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
ogdf::QueuePure::empty
bool empty() const
Returns true iff the queue is empty.
Definition: Queue.h:88
ogdf::QueuePure::emplace
iterator emplace(Args &&... args)
Adds a new element at the end of the queue.
Definition: Queue.h:173
SpannerModule.h
Basic module for spanner algorithms.
ogdf::SpannerElkinNeiman::m_c
double m_c
the parameter for the exponential distribution.
Definition: SpannerElkinNeiman.h:101
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:135
ogdf::SpannerElkinNeiman::m_eps
EpsilonTest m_eps
Definition: SpannerElkinNeiman.h:99
ogdf::SpannerElkinNeiman::BfsNode::depth
int depth
The depth of the node n.
Definition: SpannerElkinNeiman.h:172
ogdf::SpannerElkinNeiman::setEpsilon
void setEpsilon(double epsilon)
Sets the epsilon for this algorithm.
Definition: SpannerElkinNeiman.h:126
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:153
r
int r[]
Definition: hierarchical-ranking.cpp:8
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:924
ogdf::Graph::numberOfEdges
int numberOfEdges() const
Returns the number of edges in the graph.
Definition: Graph_d.h:977
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:974
ogdf::SpannerElkinNeimanIterated
Use the ogdf::SpannerIteratedWrapper to execute the ogdf::SpannerElkinNeiman algorithm up to 200 time...
Definition: SpannerElkinNeiman.h:284
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::MeasureEnum::log
@ log
ogdf::SpannerElkinNeiman::m_G
const Graph * m_G
The original graph.
Definition: SpannerElkinNeiman.h:97
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:651
ogdf::Graph
Data type for general directed graphs (adjacency list representation).
Definition: Graph_d.h:862
ogdf::SpannerElkinNeiman::BfsNode::BfsNode
BfsNode(node _n, double _depth, edge _p)
Definition: SpannerElkinNeiman.h:175
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::SpannerElkinNeiman::SpannerElkinNeiman
SpannerElkinNeiman(double epsilon)
Definition: SpannerElkinNeiman.h:119
ogdf::SpannerElkinNeiman::BfsNode
Definition: SpannerElkinNeiman.h:170
ogdf::Math::updateMax
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition: Math.h:90
ogdf::QueuePure
Implementation of list-based queues.
Definition: Queue.h:50
ogdf::SpannerElkinNeiman::BfsNode::p
edge p
The first edge of the path.
Definition: SpannerElkinNeiman.h:173
ogdf::SpannerElkinNeiman::m_intStretch
int m_intStretch
m_stretch, but as an integer
Definition: SpannerElkinNeiman.h:104
ogdf::SpannerElkinNeiman
Randomized multiplicative spanner calculation by propagating random messages through the graph.
Definition: SpannerElkinNeiman.h:95
ogdf::SpannerElkinNeiman::DEFAULT_EPSILON
const double DEFAULT_EPSILON
The default value for epsilon.
Definition: SpannerElkinNeiman.h:114
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:356
ogdf::SpannerModule::m_inSpanner
EdgeArray< bool > * m_inSpanner
Definition: SpannerModule.h:131
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:135
ogdf::GraphAttributes::edgeDoubleWeight
static const long edgeDoubleWeight
Corresponds to edge attribute doubleWeight(edge).
Definition: GraphAttributes.h:122
ogdf::QueuePure::pop
E pop()
Removes front element and returns it.
Definition: Queue.h:178
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:161
ogdf::Module::ReturnType
ReturnType
The return type of a module.
Definition: Module.h:50
ogdf::Math::maxValue
Container::value_type maxValue(const Container &values)
Returns the maximum of an iterable container of given values.
Definition: Math.h:235
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
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:194
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:709