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