Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
PlanarSubgraphFast.h
Go to the documentation of this file.
1
32#pragma once
33
35#include <ogdf/basic/Thread.h>
40
41#include <atomic>
42
43namespace ogdf {
44
68template<typename TCost>
70 using BlockType = std::pair<Graph*, EdgeArray<edge>*>;
71
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;
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
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]);
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:
145
146 ~Worker() = default;
147
149
150 private:
151 Worker(const Worker& other); // = delete
152 Worker& operator=(const Worker& other); // = delete
153 };
154
155public:
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
173protected:
175
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
189
190 // Determine edges per biconnected component
192 for (edge e : G.edges) {
193 if (!e->isSelfLoop()) {
194 blockEdges[componentID[e]].pushFront(e);
195 }
196 }
197
198 // Build non-trivial blocks
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
252private:
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);
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
276 computeSTNumbering(B, numbering, nullptr, nullptr, randomize);
277
280
282 if (pCost == nullptr) {
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];
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
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
364
366 T.Initialize(inLeaves[table[1]]);
367 for (int i = 2; i < G.numberOfNodes(); i++) {
369 T.Reduction(outLeaves[table[i]], eliminatedKeys);
371 T.ReplaceRoot(inLeaves[table[i]]);
373 }
374
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
405
407 delete pCurrentDelEdges;
408 }
409 }
410
411 } while (master.getNextRun());
412 }
413};
414
415}
Declaration of class PlanarLeafKey.
Declaration of interface for planar subgraph algorithms.
Declaration of class PlanarSubgraphPQTree.
Declaration of st-Numbering functions.
Declaration of Thread class representing threads.
Class for adjacency list elements.
Definition Graph_d.h:79
The parameterized class Array implements dynamic arrays of type E.
Definition Array.h:214
INDEX size() const
Returns the size (number of elements) of the array.
Definition Array.h:297
Dynamic arrays indexed with edges.
Definition EdgeArray.h:125
Class for the representation of edges.
Definition Graph_d.h:300
node opposite(node v) const
Returns the adjacent node different from v.
Definition Graph_d.h:350
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:521
Doubly linked lists (maintaining the length of the list).
Definition List.h:1435
int size() const
Returns the number of elements in the list.
Definition List.h:1472
void clear()
Removes all elements from the list.
Definition List.h:1610
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition List.h:1531
virtual void emptyAllPertinentNodes()
Does a clean up after a reduction.
ReturnType
The return type of a module.
Definition Module.h:50
@ Feasible
The solution is feasible.
@ Optimal
The solution is optimal.
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
Class for the representation of nodes.
Definition Graph_d.h:177
The class template PQLeafKey is a derived class of class template PQBasicKey.
Definition PQLeafKey.h:87
virtual void Cleanup()
Removes the entire PQ-tree.
Definition PQTree.h:1467
ThreadMaster(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int runs)
Array< List< edge > * > m_bestDelEdges
best solution for block
List< edge > * postNewResult(int i, List< edge > *pNewDelEdges)
const Array< BlockType > & m_block
the blocks (graph and edge mapping)
std::mutex m_mutex
thread synchronization
const EdgeArray< TCost > * m_pCost
edge cost (may be 0)
void buildSolution(List< edge > &delEdges)
Array< TCost > m_bestSolution
value of best solution for block
Worker & operator=(const Worker &other)
Worker(const Worker &other)
Computation of a planar subgraph using PQ-trees.
virtual PlanarSubgraphFast * clone() const override
Returns a new instance of fast planar subgraph with the same option settings.
static void doWorkHelper(ThreadMaster &master)
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.
int runs() const
Returns the current number of randomized runs.
static void planarize(const Graph &G, NodeArray< int > &numbering, List< edge > &delEdges)
Performs a planarization on a biconnected component of G.
PlanarSubgraphFast()
Creates an instance of the fast planar subgraph algorithm with default settings (runs = 10).
void seqCall(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int nRuns, bool randomize, List< edge > &delEdges)
Realizes the sequential implementation.
void runs(int nRuns)
Sets the number of randomized runs to nRuns.
void parCall(const Array< BlockType > &block, const EdgeArray< TCost > *pCost, int nRuns, unsigned int nThreads, List< edge > &delEdges)
Realizes the parallel implementation.
std::pair< Graph *, EdgeArray< edge > * > BlockType
int m_nRuns
The number of runs for randomization.
Interface for planar subgraph algorithms.
unsigned int maxThreads() const
Returns the maximal number of used threads.
virtual int Initialize(SListPure< PlanarLeafKey * > &leafKeys)
Initializes a new PQ-tree with a set of leaves.
void ReplaceRoot(SListPure< PlanarLeafKey * > &leafKeys)
Replaces the pertinent subtree by a set of new leaves.
virtual bool Reduction(SListPure< PlanarLeafKey * > &leafKeys, SList< PQLeafKey< edge, whaInfo *, bool > * > &eliminatedKeys)
Reduces a set of leaves.
Singly linked lists (maintaining the length of the list).
Definition SList.h:833
SListIterator< E > pushBack(const E &x)
Adds element x at the end of the list.
Definition SList.h:927
Threads supporting OGDF's memory management.
Definition Thread.h:53
int biconnectedComponents(const Graph &G, EdgeArray< int > &component, int &nonEmptyComponents)
Computes the biconnected components of G.
int computeSTNumbering(const Graph &G, NodeArray< int > &numbering, node s=nullptr, node t=nullptr, bool randomized=false)
Computes an st-Numbering of G.
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
Declaration of simple graph algorithms.