Loading [MathJax]/extensions/tex2jax.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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.