Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

PlanarSubgraphFast.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 #include <ogdf/basic/Array.h>
35 #include <ogdf/basic/Graph.h>
36 #include <ogdf/basic/GraphList.h>
37 #include <ogdf/basic/List.h>
38 #include <ogdf/basic/Module.h>
39 #include <ogdf/basic/SList.h>
40 #include <ogdf/basic/STNumbering.h>
41 #include <ogdf/basic/Thread.h>
42 #include <ogdf/basic/basic.h>
49 
50 #include <algorithm>
51 #include <atomic>
52 #include <limits>
53 #include <mutex>
54 #include <utility>
55 
56 namespace ogdf {
57 
81 template<typename TCost>
83  using BlockType = std::pair<Graph*, EdgeArray<edge>*>;
84 
85  class ThreadMaster {
88  int m_nBlocks;
91  std::atomic<int> m_runs;
92  std::mutex m_mutex;
93 
94  public:
96  : m_bestSolution(block.size())
97  , m_bestDelEdges(block.size())
98  , m_nBlocks(block.size())
99  , m_block(block)
100  , m_pCost(pCost)
101  , m_runs(runs) {
102  for (int i = 0; i < m_nBlocks; ++i) {
103  m_bestDelEdges[i] = nullptr;
104  m_bestSolution[i] =
105  (m_block[i].first != nullptr) ? std::numeric_limits<int>::max() : 0;
106  }
107  }
108 
109  int numBlocks() const { return m_nBlocks; }
110 
111  const Graph& block(int i) const { return *m_block[i].first; }
112 
113  bool considerBlock(int i) const { return m_bestSolution[i] > 1; }
114 
115  List<edge>* postNewResult(int i, List<edge>* pNewDelEdges) {
116  TCost newSolution = pNewDelEdges->size();
117  if (m_pCost != nullptr) {
118  const EdgeArray<edge>& origEdge = *m_block[i].second;
119  newSolution = TCost(0);
120  for (edge e : *pNewDelEdges) {
121  newSolution += (*m_pCost)[origEdge[e]];
122  }
123  }
124 
125  // m_mutex is automatically released when guard goes out of scope
126  std::lock_guard<std::mutex> guard(m_mutex);
127 
128  if (newSolution < m_bestSolution[i]) {
129  std::swap(pNewDelEdges, m_bestDelEdges[i]);
130  m_bestSolution[i] = newSolution;
131  }
132 
133  return pNewDelEdges;
134  }
135 
136  // creates a solution for the original graph from best solutions per block
137  // also deletes (intermediate) solution lists
138  void buildSolution(List<edge>& delEdges) {
139  for (int i = 0; i < m_nBlocks; ++i) {
140  if (m_bestDelEdges[i] != nullptr) {
141  const EdgeArray<edge>& origEdge = *m_block[i].second;
142  for (edge e : *m_bestDelEdges[i]) {
143  delEdges.pushBack(origEdge[e]);
144  }
145  delete m_bestDelEdges[i];
146  }
147  }
148  }
149 
150  bool getNextRun() { return --m_runs >= 0; }
151  };
152 
153  class Worker {
154  ThreadMaster* m_pMaster; // associated master
155 
156  public:
157  Worker(ThreadMaster* pMaster) : m_pMaster(pMaster) { }
158 
159  ~Worker() = default;
160 
162 
163  private:
164  Worker(const Worker& other); // = delete
165  Worker& operator=(const Worker& other); // = delete
166  };
167 
168 public:
171 
173  virtual PlanarSubgraphFast* clone() const override {
174  auto* res = new PlanarSubgraphFast<TCost>(*this);
175  res->m_nRuns = m_nRuns;
176  return res;
177  }
178 
180  void runs(int nRuns) { m_nRuns = nRuns; }
181 
183  int runs() const { return m_nRuns; }
184 
185 
186 protected:
188 
191  virtual Module::ReturnType doCall(const Graph& G, const List<edge>& preferedEdges,
192  List<edge>& delEdges, const EdgeArray<TCost>* pCost, bool preferedImplyPlanar) override {
193  delEdges.clear();
194 
195  if (G.numberOfEdges() < 9) {
197  }
198 
199  // Determine Biconnected Components
200  EdgeArray<int> componentID(G);
201  int nBlocks = biconnectedComponents(G, componentID);
202 
203  // Determine edges per biconnected component
204  Array<SList<edge>> blockEdges(0, nBlocks - 1);
205  for (edge e : G.edges) {
206  if (!e->isSelfLoop()) {
207  blockEdges[componentID[e]].pushFront(e);
208  }
209  }
210 
211  // Build non-trivial blocks
212  Array<BlockType> block(nBlocks);
213  NodeArray<node> copyV(G, nullptr);
214 
215  for (int i = 0; i < nBlocks; i++) {
216  if (blockEdges[i].size() < 9) {
217  block[i] = BlockType((Graph*)nullptr,
218  (EdgeArray<edge>*)nullptr); // explicit casts required for VS2010
219  continue;
220  }
221 
222  Graph* bc = new Graph;
223  EdgeArray<edge>* origE = new EdgeArray<edge>(*bc, nullptr);
224  block[i] = BlockType(bc, origE);
225 
226  SList<node> marked;
227  for (edge e : blockEdges[i]) {
228  if (copyV[e->source()] == nullptr) {
229  copyV[e->source()] = bc->newNode();
230  marked.pushBack(e->source());
231  }
232  if (copyV[e->target()] == nullptr) {
233  copyV[e->target()] = bc->newNode();
234  marked.pushBack(e->target());
235  }
236 
237  (*origE)[bc->newEdge(copyV[e->source()], copyV[e->target()])] = e;
238  }
239 
240  for (node v : marked) {
241  copyV[v] = nullptr;
242  }
243  }
244  copyV.init();
245 
246  int nRuns = max(1, m_nRuns);
247  unsigned int nThreads = min(this->maxThreads(), (unsigned int)nRuns);
248 
249  if (nThreads == 1) {
250  seqCall(block, pCost, nRuns, (m_nRuns == 0), delEdges);
251  } else {
252  parCall(block, pCost, nRuns, nThreads, delEdges);
253  }
254 
255  // clean-up
256  for (int i = 0; i < nBlocks; i++) {
257  delete block[i].first;
258  delete block[i].second;
259  }
260 
262  }
263 
264 
265 private:
266  int m_nRuns;
267 
269  void seqCall(const Array<BlockType>& block, const EdgeArray<TCost>* pCost, int nRuns,
270  bool randomize, List<edge>& delEdges) {
271  const int nBlocks = block.size();
272 
273  Array<TCost> bestSolution(nBlocks);
274  Array<List<edge>*> bestDelEdges(nBlocks);
275 
276  for (int i = 0; i < nBlocks; ++i) {
277  bestDelEdges[i] = nullptr;
278  bestSolution[i] = (block[i].first != nullptr) ? std::numeric_limits<TCost>::max() : 0;
279  }
280 
281  for (int run = 0; run < nRuns; ++run) {
282  for (int i = 0; i < nBlocks; ++i) {
283  if (bestSolution[i] > 1) {
284  const Graph& B = *block[i].first;
285  const EdgeArray<edge>& origEdge = *block[i].second;
286 
287  // compute (randomized) st-numbering
288  NodeArray<int> numbering(B, 0);
289  computeSTNumbering(B, numbering, nullptr, nullptr, randomize);
290 
291  List<edge>* pCurrentDelEdges = new List<edge>;
292  planarize(B, numbering, *pCurrentDelEdges);
293 
294  TCost currentSolution;
295  if (pCost == nullptr) {
296  currentSolution = pCurrentDelEdges->size();
297  } else {
298  currentSolution = 0;
299  for (edge e : *pCurrentDelEdges) {
300  currentSolution += (*pCost)[origEdge[e]];
301  }
302  }
303 
304  if (currentSolution < bestSolution[i]) {
305  delete bestDelEdges[i];
306  bestDelEdges[i] = pCurrentDelEdges;
307  bestSolution[i] = currentSolution;
308  } else {
309  delete pCurrentDelEdges;
310  }
311  }
312  }
313  }
314 
315  // build final solution from block solutions
316  for (int i = 0; i < nBlocks; ++i) {
317  if (bestDelEdges[i] != nullptr) {
318  const EdgeArray<edge>& origEdge = *block[i].second;
319  for (edge e : *bestDelEdges[i]) {
320  delEdges.pushBack(origEdge[e]);
321  }
322  delete bestDelEdges[i];
323  }
324  }
325  }
326 
328  void parCall(const Array<BlockType>& block, const EdgeArray<TCost>* pCost, int nRuns,
329  unsigned int nThreads, List<edge>& delEdges) {
330  ThreadMaster master(block, pCost, nRuns - nThreads);
331 
332  Array<Worker*> worker(nThreads - 1);
333  Array<Thread> thread(nThreads - 1);
334  for (unsigned int i = 0; i < nThreads - 1; ++i) {
335  worker[i] = new Worker(&master);
336  thread[i] = Thread(*worker[i]);
337  }
338 
339  doWorkHelper(master);
340 
341  for (unsigned int i = 0; i < nThreads - 1; ++i) {
342  thread[i].join();
343  delete worker[i];
344  }
345 
346  master.buildSolution(delEdges);
347  }
348 
350 
352  static void planarize(const Graph& G, NodeArray<int>& numbering, List<edge>& delEdges) {
353  using PlanarLeafKey = booth_lueker::PlanarLeafKey<whaInfo*>;
354 
357  Array<node> table(G.numberOfNodes() + 1);
358 
359  for (node v : G.nodes) {
360  for (adjEntry adj : v->adjEntries) {
361  edge e = adj->theEdge();
362  if (numbering[e->opposite(v)] > numbering[v]) { // sideeffect: ignores selfloops
363  PlanarLeafKey* L = new PlanarLeafKey(e);
364  inLeaves[v].pushFront(L);
365  }
366  }
367  table[numbering[v]] = v;
368  }
369 
370  for (node v : G.nodes) {
371  for (PlanarLeafKey* L : inLeaves[v]) {
372  outLeaves[L->userStructKey()->opposite(v)].pushFront(L);
373  }
374  }
375 
376  SList<PQLeafKey<edge, whaInfo*, bool>*> totalEliminatedKeys;
377 
379  T.Initialize(inLeaves[table[1]]);
380  for (int i = 2; i < G.numberOfNodes(); i++) {
381  SList<PQLeafKey<edge, whaInfo*, bool>*> eliminatedKeys;
382  T.Reduction(outLeaves[table[i]], eliminatedKeys);
383  totalEliminatedKeys.conc(eliminatedKeys);
384  T.ReplaceRoot(inLeaves[table[i]]);
386  }
387 
388  for (PQLeafKey<edge, whaInfo*, bool>* key : totalEliminatedKeys) {
389  edge e = key->userStructKey();
390  delEdges.pushBack(e);
391  }
392 
393  //cleanup
394  for (node v : G.nodes) {
395  while (!inLeaves[v].empty()) {
396  PlanarLeafKey* L = inLeaves[v].popFrontRet();
397  delete L;
398  }
399  }
400 
401  T.Cleanup(); // Explicit call for destructor necessary. This allows to call virtual
402  // function CleanNode for freeing node information class.
403  }
404 
405  static void doWorkHelper(ThreadMaster& master) {
406  const int nBlocks = master.numBlocks();
407 
408  do {
409  for (int i = 0; i < nBlocks; ++i) {
410  if (master.considerBlock(i)) {
411  const Graph& B = master.block(i);
412 
413  NodeArray<int> numbering(B, 0); // compute (randomized) st-numbering
414  computeSTNumbering(B, numbering, nullptr, nullptr, true);
415 
416  List<edge>* pCurrentDelEdges = new List<edge>;
417  planarize(B, numbering, *pCurrentDelEdges);
418 
419  pCurrentDelEdges = master.postNewResult(i, pCurrentDelEdges);
420  delete pCurrentDelEdges;
421  }
422  }
423 
424  } while (master.getNextRun());
425  }
426 };
427 
428 }
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::PlanarSubgraphModule
Interface for planar subgraph algorithms.
Definition: PlanarSubgraphModule.h:53
Graph.h
Includes declaration of graph class.
ogdf::Module::ReturnType::Feasible
@ Feasible
The solution is feasible.
ogdf::PlanarSubgraphFast::ThreadMaster::m_mutex
std::mutex m_mutex
thread synchronization
Definition: PlanarSubgraphFast.h:92
ogdf::PlanarSubgraphFast::ThreadMaster::m_pCost
const EdgeArray< TCost > * m_pCost
edge cost (may be 0)
Definition: PlanarSubgraphFast.h:90
ogdf::PlanarSubgraphFast::ThreadMaster::buildSolution
void buildSolution(List< edge > &delEdges)
Definition: PlanarSubgraphFast.h:138
ogdf::PlanarSubgraphFast::ThreadMaster::m_nBlocks
int m_nBlocks
number of blocks
Definition: PlanarSubgraphFast.h:88
ogdf::PlanarSubgraphFast::ThreadMaster::m_runs
std::atomic< int > m_runs
Definition: PlanarSubgraphFast.h:91
ogdf::PlanarSubgraphFast::ThreadMaster::numBlocks
int numBlocks() const
Definition: PlanarSubgraphFast.h:109
ogdf::PQLeafKey
The class template PQLeafKey is a derived class of class template PQBasicKey.
Definition: PQInternalNode.h:40
PlanarSubgraphPQTree.h
Declaration of class PlanarSubgraphPQTree.
ogdf::SList
Singly linked lists (maintaining the length of the list).
Definition: SList.h:845
ogdf::PlanarSubgraphFast::Worker
Definition: PlanarSubgraphFast.h:153
ogdf::PlanarSubgraphFast::ThreadMaster::postNewResult
List< edge > * postNewResult(int i, List< edge > *pNewDelEdges)
Definition: PlanarSubgraphFast.h:115
ogdf::PlanarSubgraphFast
Computation of a planar subgraph using PQ-trees.
Definition: PlanarSubgraphFast.h:82
ogdf::PQTree::Cleanup
virtual void Cleanup()
Removes the entire PQ-tree.
Definition: PQTree.h:1474
ogdf::PlanarSubgraphFast::Worker::operator=
Worker & operator=(const Worker &other)
ogdf::PlanarSubgraphFast::Worker::m_pMaster
ThreadMaster * m_pMaster
Definition: PlanarSubgraphFast.h:154
ogdf::PlanarSubgraphFast::Worker::~Worker
~Worker()=default
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:142
ogdf::PlanarSubgraphFast::doWorkHelper
static void doWorkHelper(ThreadMaster &master)
Definition: PlanarSubgraphFast.h:405
ogdf::Module::ReturnType::Optimal
@ Optimal
The solution is optimal.
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:160
STNumbering.h
Declaration of st-Numbering functions.
ogdf::PlanarSubgraphFast::runs
int runs() const
Returns the current number of randomized runs.
Definition: PlanarSubgraphFast.h:183
ogdf::PlanarSubgraphFast::ThreadMaster::ThreadMaster
ThreadMaster(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int runs)
Definition: PlanarSubgraphFast.h:95
ogdf::EdgeElement::isSelfLoop
bool isSelfLoop() const
Returns true iff the edge is a self-loop (source node = target node).
Definition: Graph_d.h:419
ogdf::PlanarSubgraphFast::ThreadMaster::block
const Graph & block(int i) const
Definition: PlanarSubgraphFast.h:111
PlanarSubgraphModule.h
Declaration of interface for planar subgraph algorithms.
ogdf::PlanarSubgraphPQTree::Initialize
virtual int Initialize(SListPure< PlanarLeafKey * > &leafKeys)
Initializes a new PQ-tree with a set of leaves.
ogdf::PlanarSubgraphFast::BlockType
std::pair< Graph *, EdgeArray< edge > * > BlockType
Definition: PlanarSubgraphFast.h:83
SList.h
Declaration of singly linked lists and iterators.
ogdf::Array< TCost >
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::PlanarSubgraphFast::ThreadMaster
Definition: PlanarSubgraphFast.h:85
ogdf::PlanarSubgraphFast::ThreadMaster::getNextRun
bool getNextRun()
Definition: PlanarSubgraphFast.h:150
ogdf::PlanarSubgraphFast::Worker::Worker
Worker(ThreadMaster *pMaster)
Definition: PlanarSubgraphFast.h:157
ogdf::PlanarSubgraphPQTree::Reduction
virtual bool Reduction(SListPure< PlanarLeafKey * > &leafKeys, SList< PQLeafKey< edge, whaInfo *, bool > * > &eliminatedKeys)
Reduces a set of leaves.
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:398
ogdf::List< edge >
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
PQLeafKey.h
Declaration and implementation of the class PQLeafKey.
ogdf::PlanarSubgraphPQTree::ReplaceRoot
void ReplaceRoot(SListPure< PlanarLeafKey * > &leafKeys)
Replaces the pertinent subtree by a set of new leaves.
ogdf::PlanarSubgraphPQTree
Definition: PlanarSubgraphPQTree.h:52
whaInfo.h
Declaration of class whaInfo.
ogdf::PlanarSubgraphFast::PlanarSubgraphFast
PlanarSubgraphFast()
Creates an instance of the fast planar subgraph algorithm with default settings (runs = 10).
Definition: PlanarSubgraphFast.h:170
ogdf::biconnectedComponents
int biconnectedComponents(const Graph &G, EdgeArray< int > &component, int &nonEmptyComponents)
Computes the biconnected components of G.
Thread.h
Declaration of Thread class representing threads.
ogdf::PlanarSubgraphFast::Worker::operator()
void operator()()
Definition: PlanarSubgraphFast.h:161
basic.h
Basic declarations, included by all source files.
ogdf::Graph::newNode
node newNode(int index=-1)
Creates a new node and returns it.
Definition: Graph_d.h:1064
ogdf::PlanarSubgraphFast::ThreadMaster::m_bestDelEdges
Array< List< edge > * > m_bestDelEdges
best solution for block
Definition: PlanarSubgraphFast.h:87
Array.h
Declaration and implementation of Array class and Array algorithms.
ogdf::EdgeElement::opposite
node opposite(node v) const
Returns the adjacent node different from v.
Definition: Graph_d.h:413
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:363
ogdf::PlanarSubgraphFast::ThreadMaster::m_block
const Array< BlockType > & m_block
the blocks (graph and edge mapping)
Definition: PlanarSubgraphFast.h:89
List.h
Declaration of doubly linked lists and iterators.
ogdf::PlanarSubgraphFast::m_nRuns
int m_nRuns
The number of runs for randomization.
Definition: PlanarSubgraphFast.h:266
ogdf::PlanarSubgraphFast::seqCall
void seqCall(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int nRuns, bool randomize, List< edge > &delEdges)
Realizes the sequential implementation.
Definition: PlanarSubgraphFast.h:269
ogdf::PlanarSubgraphFast::ThreadMaster::considerBlock
bool considerBlock(int i) const
Definition: PlanarSubgraphFast.h:113
ogdf::SList::conc
void conc(SList< E > &L2)
Appends L2 to this list and makes L2 empty.
Definition: SList.h:1018
ogdf::RegisteredArray< GraphRegistry< Key >, Value, WithDefault, Graph >::init
void init(const Graph *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
Definition: RegisteredArray.h:858
ogdf::PlanarSubgraphModule::maxThreads
unsigned int maxThreads() const
Returns the maximal number of used threads.
Definition: PlanarSubgraphModule.h:155
ogdf::PlanarSubgraphFast::doCall
virtual Module::ReturnType doCall(const Graph &G, const List< edge > &preferedEdges, List< edge > &delEdges, const EdgeArray< TCost > *pCost, bool preferedImplyPlanar) override
Returns true, if G is planar, false otherwise.
Definition: PlanarSubgraphFast.h:191
ogdf::Array::size
INDEX size() const
Returns the size (number of elements) of the array.
Definition: Array.h:302
ogdf::List::size
int size() const
Returns the number of elements in the list.
Definition: List.h:1488
Module.h
Declares base class for all module types.
ogdf::Thread
Threads supporting OGDF's memory management.
Definition: Thread.h:53
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:401
ogdf::PlanarSubgraphFast::ThreadMaster::m_bestSolution
Array< TCost > m_bestSolution
value of best solution for block
Definition: PlanarSubgraphFast.h:86
ogdf::computeSTNumbering
int computeSTNumbering(const Graph &G, NodeArray< int > &numbering, node s=nullptr, node t=nullptr, bool randomized=false)
Computes an st-Numbering of G.
ogdf::booth_lueker::PlanarLeafKey
Definition: EmbedPQTree.h:40
ogdf::Module::ReturnType
ReturnType
The return type of a module.
Definition: Module.h:52
ogdf::Graph::newEdge
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) and returns it.
Definition: Graph_d.h:1083
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:240
PlanarLeafKey.h
Declaration of class PlanarLeafKey.
ogdf::PlanarSubgraphFast::runs
void runs(int nRuns)
Sets the number of randomized runs to nRuns.
Definition: PlanarSubgraphFast.h:180
ogdf::MaxSequencePQTree::emptyAllPertinentNodes
virtual void emptyAllPertinentNodes()
Does a clean up after a reduction.
Definition: MaxSequencePQTree.h:498
simple_graph_alg.h
Declaration of simple graph algorithms.
ogdf::SList::pushBack
SListIterator< E > pushBack(const E &x)
Adds element x at the end of the list.
Definition: SList.h:939
ogdf::List::pushBack
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition: List.h:1547
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:716
ogdf::List::clear
void clear()
Removes all elements from the list.
Definition: List.h:1626
ogdf::PlanarSubgraphFast::clone
virtual PlanarSubgraphFast * clone() const override
Returns a new instance of fast planar subgraph with the same option settings.
Definition: PlanarSubgraphFast.h:173
ogdf::PlanarSubgraphFast::parCall
void parCall(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int nRuns, unsigned int nThreads, List< edge > &delEdges)
Realizes the parallel implementation.
Definition: PlanarSubgraphFast.h:328
ogdf::PlanarSubgraphFast::planarize
static void planarize(const Graph &G, NodeArray< int > &numbering, List< edge > &delEdges)
Performs a planarization on a biconnected component of G.
Definition: PlanarSubgraphFast.h:352