1 /** \file
2 * \brief Implementation of Block and BlockOrder classes
3 *
4 * \author Paweł Schmidt, Carsten Gutwenger
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32 #include <ogdf/layered/BlockOrder.h>
33
34 namespace ogdf {
35
BlockOrder(Hierarchy & hierarchy,bool longEdgesOnly)36 BlockOrder::BlockOrder(Hierarchy& hierarchy, bool longEdgesOnly)
37 : m_GC(hierarchy.operator const ogdf::GraphCopy &().original())
38 , m_ranks(m_GC,0)
39 , m_storedPerm()
40 , m_currentPerm()
41 , m_bestPerm()
42 , m_currentPermInv()
43 , m_storedCrossings(std::numeric_limits<int>::max())
44 , m_bestCrossings(std::numeric_limits<int>::max())
45 , m_Blocks()
46 , m_NodeBlocks(m_GC,nullptr)
47 , m_EdgeBlocks(m_GC,nullptr)
48 , m_isActiveEdge(m_GC,false)
49 , m_activeBlocksCount(0)
50 , m_hierarchy(hierarchy)
51 , m_levels(0,-1,nullptr)
52 , m_verticalStepsBound(0)
53 {
54 doInit(longEdgesOnly);
55 }
56
57
doInit(bool longEdgesOnly)58 void BlockOrder::doInit(bool longEdgesOnly)
59 {
60 const GraphCopy &GC = m_hierarchy;
61 NodeArray<bool> nodesInCC(m_GC,false);
62
63 unsigned int countBlocks = 0;
64
65 int minLvl = 0;
66 int maxLvl = m_hierarchy.maxRank();
67
68 m_nNodesOnLvls.init(minLvl, maxLvl, 0);
69
70 // one block for every node
71 for(node v : GC.nodes) {
72 //m_GC may contain nodes from another CC
73 if (GC.original(v) != nullptr) {
74 m_ranks[GC.original(v)] = m_hierarchy.rank(v);
75 nodesInCC[GC.original(v)] = true;
76 ++countBlocks;
77 m_nNodesOnLvls[m_hierarchy.rank(v)] += 1;
78 }
79 }
80
81 //one block for every long edge
82 for(edge e : m_GC.edges) {
83 node src = e->source();
84 node tgt = e->target();
85
86 if (nodesInCC[src] && nodesInCC[tgt]) {
87 int top = min(m_ranks[src], m_ranks[tgt]);
88 int bot = max(m_ranks[src], m_ranks[tgt]);
89 if (top + 1 < bot || !longEdgesOnly) {
90 ++countBlocks;
91 }
92 }
93 }
94
95 //m_blocksCount = countBlocks;
96
97 m_Blocks.init(countBlocks);
98 m_storedPerm.init(countBlocks);
99 m_bestPerm.init(countBlocks);
100 m_currentPerm.init(countBlocks);
101 m_currentPermInv.init(countBlocks);
102
103 int i = 0;
104 for(node v : GC.nodes) {
105 node vOrig = GC.original(v);
106 if (vOrig != nullptr) {
107 m_Blocks[i] = m_NodeBlocks[vOrig] = new Block(vOrig);
108 m_Blocks[i]->m_index = i;
109 m_Blocks[i]->m_lower = m_Blocks[i]->m_upper = m_ranks[vOrig];
110 ++i;
111 m_activeBlocksCount += 1;
112 }
113 }
114
115 for(edge e : m_GC.edges) {
116 node src = e->source();
117 node tgt = e->target();
118
119 if (nodesInCC[src] && nodesInCC[tgt]) {
120 int top = min(m_ranks[src], m_ranks[tgt]);
121 int bot = max(m_ranks[src], m_ranks[tgt]);
122
123 if (top + 1 < bot || !longEdgesOnly) {
124 m_Blocks[i] = m_EdgeBlocks[e] = new Block(e);
125 m_Blocks[i]->m_index = i;
126 m_Blocks[i]->m_upper = top + 1;
127 m_Blocks[i]->m_lower = bot - 1;
128 ++i;
129 }
130 if (top + 1 < bot) {
131 m_isActiveEdge[e] = true;
132 m_activeBlocksCount += 1;
133 } else
134 m_isActiveEdge[e] = false;
135 }
136 }
137 }
138
139
Block(edge e)140 Block::Block(edge e)
141 : m_NeighboursIncoming(1)
142 , m_InvertedIncoming(1)
143 , m_NeighboursOutgoing(1)
144 , m_InvertedOutgoing(1)
145 , m_Edge(e)
146 , m_isEdgeBlock(true)
147 , m_isNodeBlock(false)
148 { }
149
150
Block(node v)151 Block::Block(node v)
152 : m_NeighboursIncoming(v->indeg())
153 , m_InvertedIncoming(v->indeg())
154 , m_NeighboursOutgoing(v->outdeg())
155 , m_InvertedOutgoing(v->outdeg())
156 , m_Node(v)
157 , m_isEdgeBlock(false)
158 , m_isNodeBlock(true)
159 { }
160
161
sortAdjacencies()162 void BlockOrder::sortAdjacencies()
163 {
164
165 Block *processedBlock; // A in paper
166
167 EdgeArray<int> p(m_GC, 0); // array P in paper
168 EdgeArray<int> longEdgeP(m_GC, 0); // additional P for long edges
169 // explanation:
170 // Bachmaier et al. in their paper convert long edge u ---> v to three blocks and two edges: u -> [block for edge] -> v.
171 // I decided to use edges and vertices from original graph (thus I am able to use Node- and EdgeArrays).
172 // It implies that (block for a long) edge u ---> v is traversed four times
173 // (i.e. twice when blocks for vertices u and v are processed, and then twice, when block for this edge is processed)
174 // and since that, some information can be overwritten and lost.
175 // To avoid this, for any long edge u--->v , array p stores information about source vertex u, and longEdgeP stores information about target vertex v
176 // Later an attempt to delete this array can be made since long edge block have exactly one neighbour incoming and one outgoing.
177
178 //Array to store number of items inserted to arrays of neighbours in N+
179 // These arrays store next free position in arrays N+ and N-
180 Array<int> NPlusItemsCount(0, m_Blocks.high(), 0);
181 Array<int> NMinusItemsCount(0, m_Blocks.high(), 0);
182
183 // foreach A in B
184 for (int i = 0; i < m_activeBlocksCount; ++i) {
185 processedBlock = m_Blocks[m_currentPermInv[i]];
186
187 if (processedBlock->isVertexBlock()) {
188 node v = processedBlock->m_Node;
189
190 //foreach s in { (u,v) in E' | v=upper(A)}
191 for(adjEntry adj : v->adjEntries) {
192 edge e = adj->theEdge();
193 if (v == e->target()) {
194 // if e is a short edge
195 if (!m_isActiveEdge[e]) {
196
197 node u = e->source();
198 Block *blockOfU = m_NodeBlocks[u];
199
200 // insert v at the next free position j of N+[u]
201 int j = NPlusItemsCount[blockOfU->m_index];
202 NPlusItemsCount [blockOfU->m_index] += 1;
203 blockOfU->m_NeighboursOutgoing[j] = processedBlock->m_index;
204
205
206 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfU->m_index]) {
207 //first traversal of e
208 p[e] = j;
209 } else {
210 //second traversal of e
211 blockOfU->m_InvertedOutgoing[j] = p[e];
212 processedBlock->m_InvertedIncoming[p[e]] = j;
213 }
214 } else {
215 // e is a long edge
216 Block *blockOfU = m_EdgeBlocks[e];
217
218 // insert v at the next free position j of N+[u]
219 int j = NPlusItemsCount[blockOfU->m_index];
220 NPlusItemsCount[blockOfU->m_index] += 1;
221 blockOfU->m_NeighboursOutgoing[j] = processedBlock->m_index;
222
223 // here we count "edges" outgoing from block u
224 // thus we should use longEdgeP
225 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfU ->m_index]) {
226 //first traversal of e
227 longEdgeP[e] = j;
228 } else {
229 //second traversal of e
230 blockOfU->m_InvertedOutgoing[j] = longEdgeP[e];
231 processedBlock->m_InvertedIncoming[longEdgeP[e]] = j;
232 }
233 }
234 }
235 }
236
237 node w = processedBlock->m_Node;
238 // foreach s in { (w,x) in E' | w = lower(A) }
239 for(adjEntry adj : w->adjEntries) {
240 edge e = adj->theEdge();
241 if (w == e->source()) {
242 // if e is a short edge
243 if (!m_isActiveEdge[e]) {
244
245 node x = e->target();
246 Block *blockOfX = m_NodeBlocks[x];
247
248 // insert w at the next free position j of N-[x]
249 int j = NMinusItemsCount[blockOfX->m_index];
250 NMinusItemsCount[blockOfX->m_index] += 1;
251 blockOfX->m_NeighboursIncoming[j] = processedBlock->m_index;
252
253 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfX->m_index]) {
254 // first traversal of e
255 p[e] = j;
256 } else {
257 //second traversal of e
258 blockOfX->m_InvertedIncoming[j] = p[e];
259 processedBlock->m_InvertedOutgoing [p[e]] = j;
260 }
261 } else {
262 // e is a long edge
263 Block *blockOfX = m_EdgeBlocks[e];
264
265 // insert v at the next free position j of N-(x)
266 int j = NMinusItemsCount[blockOfX->m_index];
267 NMinusItemsCount[blockOfX->m_index] += 1;
268 blockOfX->m_NeighboursIncoming[j] = processedBlock->m_index;
269
270 // here we count "edges" incoming to edge block
271 // thus we use p instead of LongEdgeP
272
273 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfX->m_index]) {
274 //first traversal of e
275 p[e] = j;
276 } else {
277 //second traversal of e
278 blockOfX->m_InvertedIncoming[j] = p[e];
279 processedBlock->m_InvertedOutgoing[p[e]] = j;
280 }
281 }
282 }
283 }
284 }
285
286 if (processedBlock->isEdgeBlock()) {
287
288 edge e = processedBlock->m_Edge;
289
290 node u = e->source();
291 node x = e->target();
292
293 Block *blockOfU = m_NodeBlocks[u];
294 Block *blockOfX = m_NodeBlocks[x];
295
296
297 // first foreach loop
298 // edge incoming to block
299 {
300 // insert v at the next free position j of N+[u]
301 int j = NPlusItemsCount[blockOfU->m_index];
302 NPlusItemsCount[blockOfU->m_index] += 1;
303 blockOfU->m_NeighboursOutgoing[j] = processedBlock->m_index;
304
305
306 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfU->m_index]) {
307 // first traversal of e
308 p[e] = j;
309 } else {
310 // second traversal of e
311 blockOfU->m_InvertedOutgoing[j] = p[e];
312 processedBlock->m_InvertedIncoming[p[e]] = j;
313 }
314 }
315
316 // second foreach loop
317 // edge outgoing from block
318 {
319 // insert w at the next free position j of N-[x]
320
321 int j = NMinusItemsCount[blockOfX->m_index];
322 NMinusItemsCount[blockOfX->m_index] += 1;
323 blockOfX->m_NeighboursIncoming[j] = processedBlock->m_index ;
324
325 if (m_currentPerm[processedBlock->m_index] < m_currentPerm[blockOfX->m_index]) {
326 //first traversal of e
327 longEdgeP[e] = j;
328 } else {
329 //second traversal of e
330 blockOfX->m_InvertedIncoming[j] = longEdgeP[e];
331 processedBlock->m_InvertedOutgoing[longEdgeP[e]] = j;
332 }
333 }
334 }
335 }
336 }
337
deconstruct()338 void BlockOrder::deconstruct()
339 {
340 for (auto &elem : m_Blocks) {
341 delete elem;
342 }
343 for (auto &elem : m_levels) {
344 delete elem;
345 }
346 }
347
348
updateAdjacencies(Block * blockOfA,Block * blockOfB,Direction d)349 void BlockOrder::updateAdjacencies(Block *blockOfA, Block *blockOfB, Direction d)
350 {
351 Array<int> &NdA = (d == Direction::Minus) ? blockOfA->m_NeighboursIncoming
352 : blockOfA->m_NeighboursOutgoing;
353 Array<int> &IdA = (d == Direction::Minus) ? blockOfA->m_InvertedIncoming
354 : blockOfA->m_InvertedOutgoing;
355 Array<int> &NdB = (d == Direction::Minus) ? blockOfB->m_NeighboursIncoming
356 : blockOfB->m_NeighboursOutgoing;
357 Array<int> &IdB = (d == Direction::Minus) ? blockOfB->m_InvertedIncoming
358 : blockOfB->m_InvertedOutgoing;
359
360 int i = 0, j = 0;
361
362 int r = NdA.size();
363 int s = NdB.size();
364
365 while (i < r && j < s) {
366 // if pi (block(xi)) < pi(block (yj))
367 if (m_currentPerm[NdA[i]] < m_currentPerm[NdB[j]])
368 ++i;
369 else if (m_currentPerm[NdA[i]] > m_currentPerm[NdB[j]])
370 ++j;
371 else {
372 Block *z = m_Blocks[NdA[i]]; // = yj;
373 if (d == Direction::Plus) {
374
375 z->m_NeighboursIncoming.swap(IdA[i], IdB[j]);
376 z->m_InvertedIncoming.swap(IdA[i], IdB[j]);
377 } else {
378 z->m_NeighboursOutgoing.swap(IdA[i], IdB[j]);
379 z->m_InvertedOutgoing.swap(IdA[i], IdB[j]);
380 }
381 IdA[i] += 1;
382 IdB[j] += -1;
383 ++i; ++j;
384 }
385 }
386 }
387
388
uswap(Block * blockOfA,Block * blockOfB,Direction d,int level)389 int BlockOrder::uswap(Block *blockOfA, Block *blockOfB, Direction d, int level)
390 {
391 Array<int> &NdA = (d == Direction::Minus) ? blockOfA->m_NeighboursIncoming
392 : blockOfA->m_NeighboursOutgoing;
393 Array<int> &NdB = (d == Direction::Minus) ? blockOfB->m_NeighboursIncoming
394 : blockOfB->m_NeighboursOutgoing;
395
396 int nextLevel;
397 if (d == Direction::Minus)
398 for (nextLevel = level - 1; m_nNodesOnLvls[nextLevel] == 0; --nextLevel);
399 else
400 for (nextLevel = level + 1; m_nNodesOnLvls[nextLevel] == 0; ++nextLevel);
401
402
403 int c = 0;
404 int i = 0;
405 int j = 0;
406
407 int r = NdA.size();
408 int s = NdB.size();
409
410 if ((d == Direction::Minus && nextLevel < blockOfA->m_upper && nextLevel < blockOfB->m_upper)
411 || (d == Direction::Plus && nextLevel > blockOfA->m_lower && nextLevel > blockOfB->m_lower)) {
412 while (i < r && j < s) {
413 if (m_currentPerm[NdA[i]] < m_currentPerm[NdB[j]]) {
414 c = c + (s - j);
415 i += 1;
416 } else if (m_currentPerm[NdA[i]] > m_currentPerm[NdB[j]]) {
417 c = c - (r - i);
418 j += 1;
419 } else {
420 c = c + (s - j) - (r - i);
421 i += 1;
422 j += 1;
423 }
424 }
425 } else
426 if ((d == Direction::Minus && nextLevel >= blockOfA->m_upper)
427 || (d == Direction::Plus && nextLevel <= blockOfA->m_lower)) {
428 // edge in block A is an internal edge
429 int pi = m_currentPerm[blockOfA->m_index];
430 for (j = 0; j < s && m_currentPerm[NdB[j]] < pi ;)
431 ++j;
432 // j is the number of blocks on level level that are neighbours of b and are before a in current permutation
433 c = s - 2 * j;
434 } else {
435 // edge in block B is an internal edge
436 int pi = m_currentPerm[blockOfB->m_index];
437 for (i = 0 ; i < r && m_currentPerm[NdA[i]] < pi;)
438 ++i;
439 // j is the number of blocks on level level that are neighbours of a and are before b in current permutation
440 c = 2 * i - s;
441 }
442 return c;
443 }
444
445
siftingSwap(Block * blockOfA,Block * blockOfB)446 int BlockOrder::siftingSwap(Block *blockOfA, Block *blockOfB)
447 {
448 int Delta = 0;
449
450 if (blockOfA->m_upper > blockOfB->m_lower || blockOfA->m_lower < blockOfB->m_upper) {
451 // empty intersection of A.levels and B.levels - no change in number of crossings
452 Delta = 0;
453 } else {
454 // intersection of A.levels and B.levels is nonempty
455 // top = max(upper(A),upper(B))
456 int top = (blockOfA->m_upper > blockOfB->m_upper) ? blockOfA->m_upper
457 : blockOfB->m_upper;
458 // bottom = min(lower(A),lower(B))
459 int bottom = (blockOfA->m_lower < blockOfB->m_lower) ? blockOfA->m_lower
460 : blockOfB->m_lower;
461
462 Delta += uswap(blockOfA, blockOfB, Direction::Minus, top);
463 if (top == blockOfA->m_upper && top == blockOfB->m_upper)
464 updateAdjacencies(blockOfA, blockOfB, Direction::Minus);
465
466 Delta += uswap(blockOfA, blockOfB, Direction::Plus, bottom);
467 if (bottom == blockOfA->m_lower && bottom == blockOfB->m_lower)
468 updateAdjacencies(blockOfA, blockOfB, Direction::Plus);
469 }
470
471 // swap positions of A and B in permutation
472 int c = m_currentPerm[blockOfA->m_index];
473 int d = m_currentPerm[blockOfB->m_index];
474
475 m_currentPermInv[c] = blockOfB->m_index;
476 m_currentPermInv[d] = blockOfA->m_index;
477
478 m_currentPerm[blockOfA->m_index] += 1;
479 m_currentPerm[blockOfB->m_index] += -1;
480
481 return Delta;
482 }
483
484
siftingStep(Block * blockOfA)485 int BlockOrder::siftingStep(Block *blockOfA)
486 {
487
488 // new order with A put to front
489 int positionOfA = m_storedPerm[blockOfA->m_index];
490 for (int i = 0; i < m_storedPerm.size(); ++i) {
491 if (m_storedPerm[i] < positionOfA && m_storedPerm[i] != -1)
492 m_currentPerm[i] = m_storedPerm[i] + 1;
493 else
494 m_currentPerm[i] = m_storedPerm[i];
495 }
496 m_currentPerm[blockOfA->m_index] = 0;
497
498 for (int i = 0; i < m_currentPerm.size(); ++i) {
499 if (m_currentPerm[i] != -1)
500 m_currentPermInv[m_currentPerm[i]] = i;
501 }
502 sortAdjacencies();
503
504 int chi = 0;
505 int bestChi = 0;
506 int bestPos = 0;
507
508 int oldChi = 0;
509
510 for (int p = 1; p < m_activeBlocksCount; ++p) {
511 chi = chi + siftingSwap(blockOfA, m_Blocks[m_currentPermInv[p]]);
512 if (chi < bestChi) {
513 bestChi = chi;
514 bestPos = p;
515 }
516 if (p == positionOfA) {
517 oldChi = chi;
518 }
519 }
520
521 //return B'[1]< ... < B[bestPos] < A < B[bestPos+1] <...
522 for (int i = 0; i < bestPos; ++i) {
523 m_storedPerm[m_currentPermInv[i]] = i;
524 }
525 for (int i = bestPos; i < m_activeBlocksCount; ++i) {
526 m_storedPerm[m_currentPermInv[i]] = i + 1;
527 }
528 m_storedPerm[blockOfA->m_index] = bestPos;
529
530 return bestChi - oldChi;
531 }
532
533
globalSifting(int rho,int nRepeats,int * pNumCrossings)534 void BlockOrder::globalSifting(int rho, int nRepeats, int *pNumCrossings)
535 {
536 Array<int> storedPermInv(m_activeBlocksCount);
537 int p = 0;
538
539 for (auto &elem : m_storedPerm) {
540 elem = -1;
541 }
542
543 for (int i = 0; i < m_Blocks.size(); ++i)
544 if (m_Blocks[i]->isVertexBlock()
545 || (m_Blocks[i]->isEdgeBlock() && m_isActiveEdge[m_Blocks[i]->m_Edge])) {
546 storedPermInv[p] = i;
547 m_storedPerm[i] = p;
548 ++p;
549 }
550 m_bestCrossings = std::numeric_limits<int>().max();
551
552
553
554 while (rho-- > 0) {
555 storedPermInv.permute(0, m_activeBlocksCount - 1);
556
557 for (int i = 0; i < m_activeBlocksCount; ++i)
558 m_storedPerm[storedPermInv[i]] = i;
559
560 int times = nRepeats;
561 while (times-- > 0) {
562 for (auto &block : m_Blocks) {
563 if (block->isVertexBlock()
564 || (block->isEdgeBlock() && m_isActiveEdge[block->m_Edge])) {
565 siftingStep(block);
566 }
567 }
568
569 buildHierarchy();
570 if (m_storedCrossings < m_bestCrossings) {
571 for (int b = 0; b < m_bestPerm.size(); ++b) {
572 m_bestPerm[b] = m_storedPerm[b];
573 }
574 m_bestCrossings = m_storedCrossings;
575 }
576 }
577 }
578
579 //restore the best permutation
580 for (int i = 0; i < m_storedPerm.size(); ++i) {
581 m_storedPerm[i] = m_bestPerm[i];
582 }
583 m_storedCrossings = m_bestCrossings;
584 buildHierarchy();
585 if(pNumCrossings)
586 *pNumCrossings = m_storedCrossings;
587 }
588
589
buildDummyNodesLists()590 void BlockOrder::buildDummyNodesLists()
591 {
592 const GraphCopy &GC = m_hierarchy;
593 NodeArray<bool> mark(GC, false);
594
595 NodeArray<int> ranks(GC);
596
597 for (auto b : m_Blocks) {
598 if (b->isVertexBlock()) {
599 node v = b->m_Node;
600 int rank = m_ranks[v];
601 b->m_nodes.init(rank, rank, nullptr);
602
603 } else if (m_isActiveEdge[b->m_Edge]) {
604 //m_Blocks[i] is EdgeBlock
605 b->m_nodes.init(b->m_upper, b->m_lower, nullptr);
606 }
607 }
608
609 // init m_nodes for vertex blocks
610 for(node v : GC.nodes) {
611 ranks[v] = m_hierarchy.rank(v);
612 node vOrig = GC.original(v);
613 if (vOrig != nullptr) {
614 m_NodeBlocks[vOrig]->m_nodes[m_ranks[vOrig]] = v;
615 mark[v] = true;
616 }
617 }
618
619 //init m_nodes for edge blocks
620 for(node v : GC.nodes) {
621 if (m_hierarchy.isLongEdgeDummy(v)
622 && !mark[v]) {
623 // find the edge from original graph corresponding to this node
624 node low = v;
625 node high = v;
626
627 List<node> nodesInBlock;
628 nodesInBlock.pushBack(v);
629 while (!mark[low]) {
630 for (adjEntry adj : low->adjEntries) {
631 edge e = adj->theEdge();
632 if (low == e->source()) {
633 low = e->target();
634 nodesInBlock.pushBack(low);
635 break;
636 }
637 }
638 }
639 while (!mark[high]) {
640 for (adjEntry adj : high->adjEntries) {
641 edge e = adj->theEdge();
642 if (high == e->target()) {
643 high = e->source();
644 nodesInBlock.pushBack(high);
645 break;
646 }
647 }
648 }
649
650 Block *edgeBlock = m_EdgeBlocks[m_GC.searchEdge(GC.original(high),
651 GC.original(low))];
652 for (node u : nodesInBlock) {
653 if (!mark[u]) {
654 edgeBlock->m_nodes[ranks[u]] = u;
655 mark[u] = true;
656 }
657 }
658 }
659 }
660 }
661
662
buildLevels()663 void BlockOrder::buildLevels()
664 {
665 Array<int> storedPermInv(m_activeBlocksCount);
666
667 for (int i = 0; i < m_storedPerm.size(); ++i) {
668 if (m_storedPerm[i] != -1)
669 storedPermInv[m_storedPerm[i]] = i;
670 }
671
672
673 m_pos = NodeArray<int>(m_hierarchy,0);
674 for (auto &level : m_levels) {
675 delete level;
676 }
677
678 m_levels.init(0);
679
680 // find maximum level index
681 int maxLevel = 0;
682
683 for (int i = 0; i < m_activeBlocksCount; ++i)
684 maxLevel = max<int>(maxLevel, m_Blocks[storedPermInv[i]]->m_lower);
685
686 // number of nodes (on each level)
687 Array<int> levelNodes(0, maxLevel, 0);
688
689 for (int i = 0; i < m_activeBlocksCount; ++i)
690 for (int level = m_Blocks[storedPermInv[i]]->m_upper; level <= m_Blocks[storedPermInv[i]]->m_lower; ++level)
691 levelNodes[level] += 1;
692
693
694 m_levels.init(0, maxLevel);
695 for (int i = 0; i <= maxLevel; ++i)
696 m_levels[i] = new ArrayLevel(levelNodes[i]);
697
698 Array<int> itemsOnLevelCtr(0, maxLevel, 0);
699
700 for (int i = 0; i < m_activeBlocksCount; ++i){
701 Block *b = m_Blocks[storedPermInv[i]];
702 for (int level = b->m_upper; level <= b->m_lower; ++level) {
703 ArrayLevel &lvl = *m_levels[level];
704 lvl[itemsOnLevelCtr[level]] = b->m_nodes[level];
705 m_pos[b->m_nodes[level]] = itemsOnLevelCtr[level];
706 ++itemsOnLevelCtr[level];
707 }
708 }
709 }
710
711 // copied from HierarchyLevels
buildAdjNodes()712 void BlockOrder::buildAdjNodes()
713 {
714 m_nSet = NodeArray<int>(m_hierarchy,0);
715 m_lowerAdjNodes = NodeArray<Array<node> >(m_hierarchy);
716 m_upperAdjNodes = NodeArray<Array<node> >(m_hierarchy);
717
718 const GraphCopy &GC = m_hierarchy;
719 for(node v : GC.nodes) {
720 m_lowerAdjNodes[v].init(v->indeg());
721 m_upperAdjNodes[v].init(v->outdeg());
722 }
723
724
725 for (int i = 0; i<= high(); ++i){
726 if (i > 0) {
727 const ArrayLevel &lowerLevel = *m_levels[i-1];
728
729 for(int j = 0; j <= lowerLevel.high(); ++j)
730 m_nSet[lowerLevel[j]] = 0;
731 }
732
733 if (i < high()) {
734 const ArrayLevel &upperLevel = *m_levels[i+1];
735
736 for(int j = 0; j <= upperLevel.high(); ++j)
737 m_nSet[upperLevel[j]] = 0;
738 }
739
740 const ArrayLevel &level = *m_levels[i];
741 for(int j = 0; j <= level.high(); ++j) {
742 node v = level[j];
743 for(adjEntry adj : v->adjEntries) {
744 edge e = adj->theEdge();
745 if (e->source() == v) {
746 (m_lowerAdjNodes[e->target()])[m_nSet[e->target()]++] = v;
747 } else {
748 (m_upperAdjNodes[e->source()])[m_nSet[e->source()]++] = v;
749 }
750 }
751 }
752 }
753 }
754
755
localCountCrossings(const Array<int> & levels)756 int BlockOrder::localCountCrossings(const Array<int> &levels)
757 {
758
759 if (levels.size() < 2) return 0;
760 // set m_currentPerm
761 for (auto &level : m_levels) {
762 delete level;
763 }
764
765 Graph G;
766
767 Array<int> storedPermInv(m_Blocks.size());
768 m_currentPermInv.init(m_Blocks.size());
769
770 for (int i = 0; i < m_Blocks.size(); ++i) {
771 m_currentPerm[i] = m_storedPerm[i];
772 if (m_storedPerm[i] != -1) {
773 storedPermInv[m_storedPerm[i]] = i;
774 m_currentPermInv[m_storedPerm[i]] = i;
775 }
776 }
777
778
779 sortAdjacencies();
780
781 Array<unsigned int> itemsOnLevelCtr(0, levels.high(), 0);
782
783 // create vertices used to calculate number of crossings
784 for (int i = 0; i < m_Blocks.size(); ++i) {
785 Block *block = m_Blocks[i];
786 if (m_storedPerm[i] != -1) {
787 block->m_nodes.init(levels[0], levels[levels.high()], nullptr);
788
789 for (int j = 0; j < levels.size(); ++j) {
790 int currentLevel = levels[j];
791 if (block->m_upper <= currentLevel && block->m_lower >= currentLevel) {
792 itemsOnLevelCtr[j] += 1;
793 block->m_nodes[currentLevel] = G.newNode();
794 }
795 }
796 } else {
797 edge currentEdge = block->m_Edge;
798 Block *targetBlock = m_NodeBlocks[currentEdge->target()];
799 for (int level = levels.low(); level <= levels.high(); ++level) {
800 if (block->m_upper <= levels[level] && levels[level] <= block->m_lower && targetBlock->m_nodes[levels[level]] == nullptr) {
801 itemsOnLevelCtr[level] += 1;
802 targetBlock->m_nodes[levels[level]] = G.newNode();
803 }
804 }
805 }
806 }
807
808 m_levels.init(levels.size());
809 for (int j = 0; j < levels.size(); ++j)
810 m_levels[j] = new ArrayLevel(itemsOnLevelCtr[j]);
811
812 m_pos.init(G);
813 m_upperAdjNodes.init(G);
814
815 itemsOnLevelCtr.init(0, levels.high(), 0);
816
817 // build m_levels and m_pos
818 for (int i = 0; i < m_activeBlocksCount; ++i) {
819 Block *block = m_Blocks[storedPermInv[i]];
820 for (int j = 0; j < levels.size(); ++j) {
821 if (block->m_nodes[levels[j]] != nullptr) {
822 (*m_levels[j])[itemsOnLevelCtr[j]] = block->m_nodes[levels[j]];
823 m_pos[block->m_nodes[levels[j]]] = itemsOnLevelCtr[j];
824 itemsOnLevelCtr[j] += 1;
825 }
826 }
827 }
828
829 // build m_upperAdjNodes
830 for (int i = 0; i < m_activeBlocksCount; ++i) {
831 Block *block = m_Blocks[storedPermInv[i]];
832 for (int j = 0; j < levels.high(); ++j) {
833 int currentLevel = levels[j];
834
835 int nextLevel = levels[j+1];
836 if (block->m_upper <= currentLevel && block->m_lower >= currentLevel) {
837 if (nextLevel > block->m_lower) {
838 Array<node> &upperAdj = m_upperAdjNodes[block->m_nodes[currentLevel]];
839 upperAdj.init(block->m_NeighboursOutgoing.size());
840 for (int k = 0; k < block->m_NeighboursOutgoing.size(); ++k) {
841 upperAdj[k] = m_Blocks[block->m_NeighboursOutgoing[k]]->m_nodes[nextLevel];
842 }
843 } else {
844 m_upperAdjNodes[block->m_nodes[currentLevel]]
845 .init(0, 0, block->m_nodes[nextLevel]);
846 }
847 }
848 }
849 }
850 return calculateCrossings();
851 }
852
853
verticalSwap(Block * b,int level)854 int BlockOrder::verticalSwap(Block *b, int level)
855 {
856 int Delta = 0;
857
858 int minLvl = level;
859 int maxLvl = level;
860
861 for (int i = m_nNodesOnLvls.low(); i <= m_nNodesOnLvls.high(); ++i) {
862 if (m_nNodesOnLvls[i] > 0) {
863 minLvl = i;
864 break;
865 }
866 }
867 for (int i = m_nNodesOnLvls.high(); i >= m_nNodesOnLvls.low(); --i) {
868 if (m_nNodesOnLvls[i] > 0) {
869 maxLvl = i;
870 break;
871 }
872 }
873
874 Array<int> levels;
875 if (level % 2 == 0) {
876 int ctr = 0;
877 if (minLvl <= level - 2 && level - 2 <= maxLvl) ++ctr;
878 if (minLvl <= level - 1 && level - 1 <= maxLvl) ++ctr;
879 if (minLvl <= level && level <= maxLvl) ++ctr;
880 if (minLvl <= level + 1 && level + 1 <= maxLvl) ++ctr;
881 if (minLvl <= level + 2 && level + 2 <= maxLvl) ++ctr;
882 levels.init(ctr);
883 ctr = 0;
884 if (minLvl <= level - 2 && level - 2 <= maxLvl) levels[ctr++] = level - 2;
885 if (minLvl <= level - 1 && level - 1 <= maxLvl) levels[ctr++] = level - 1;
886 if (minLvl <= level && level <= maxLvl) levels[ctr++] = level;
887 if (minLvl <= level + 1 && level + 1 <= maxLvl) levels[ctr++] = level + 1;
888 if (minLvl <= level + 2 && level + 2 <= maxLvl) levels[ctr++] = level + 2;
889 } else {
890 int ctr = 0;
891 if (minLvl <= level - 3 && level - 3 <= maxLvl) ++ctr;
892 if (minLvl <= level - 1 && level - 1 <= maxLvl) ++ctr;
893 if (minLvl <= level + 1 && level + 1 <= maxLvl) ++ctr;
894
895 levels.init(ctr);
896 ctr = 0;
897 if (minLvl <= level - 3 && level - 3 <= maxLvl) levels[ctr++] = level - 3;
898 if (minLvl <= level - 1 && level - 1 <= maxLvl) levels[ctr++] = level - 1;
899 if (minLvl <= level + 1 && level + 1 <= maxLvl) levels[ctr++] = level + 1;
900 }
901
902 Delta -= localCountCrossings(levels);
903
904 // phi(B) = level
905 m_nNodesOnLvls[b->m_upper] += -1;
906 b->m_upper = b->m_lower = level;
907 m_nNodesOnLvls[level] += 1;
908
909 Array<int> nextExistingLvl(m_nNodesOnLvls.low(), m_nNodesOnLvls.high(), -1);
910 int last = std::numeric_limits<int>::max();
911 for (int i = nextExistingLvl.high(); i >= nextExistingLvl.low(); --i) {
912 nextExistingLvl[i] = last;
913 if (m_nNodesOnLvls[i] > 0)
914 last = i;
915 }
916
917 node v = b->m_Node;
918
919 for(adjEntry adj : v->adjEntries) {
920 edge e = adj->theEdge();
921 Block *BlockOfE = m_EdgeBlocks[e];
922 if (v == e->source()) {
923 BlockOfE->m_upper = level + 1;
924 } else {
925 // v == e->target()
926 BlockOfE->m_lower = level - 1;
927 }
928 }
929
930 for(edge e : m_GC.edges) {
931 if (m_EdgeBlocks[e] != nullptr) {
932 Block *blockOfE = m_EdgeBlocks[e];
933
934 int top = blockOfE->m_upper;
935 int bot = blockOfE->m_lower;
936
937 int lvl = nextExistingLvl[top - 1];
938
939 if (top <= lvl && lvl <= bot) {
940 // block is active
941 if (!m_isActiveEdge[e]) {
942 int sourcePos = m_storedPerm[m_NodeBlocks[e->source()]->m_index];
943 int targetPos = m_storedPerm[m_NodeBlocks[e->target()]->m_index];
944
945 m_storedPerm[blockOfE->m_index] = (sourcePos + targetPos) / 2;
946 m_activeBlocksCount += 1;
947 m_isActiveEdge[e] = true;
948 }
949 } else {
950 //block is inactive
951 if (m_isActiveEdge[e]) {
952 m_storedPerm[blockOfE->m_index] = -1;
953 m_activeBlocksCount -= 1;
954 m_isActiveEdge[e] = false;
955 }
956 }
957 }
958 }
959
960 // bucketsort
961 Array<List<int> > buckets(-1, m_storedPerm.size());
962 for (int i = 0; i < m_storedPerm.size(); ++i) {
963 buckets[m_storedPerm[i]].pushBack(i);
964 m_storedPerm[i] = -1;
965 }
966 int ctr = 0;
967 for (int i = 0; i <= buckets.high(); ++i) {
968 while (!buckets[i].empty()) {
969 int ind = buckets[i].front();
970 buckets[i].popFront();
971 m_storedPerm[ind] = ctr;
972 ctr += 1;
973 }
974 }
975
976 // calculate crossings once again
977 for (int i = m_nNodesOnLvls.low(); i <= m_nNodesOnLvls.high(); ++i) {
978 if (m_nNodesOnLvls[i] > 0) {
979 minLvl = i;
980 break;
981 }
982 }
983 for (int i = m_nNodesOnLvls.high(); i >= m_nNodesOnLvls.low(); --i) {
984 if (m_nNodesOnLvls[i] > 0) {
985 maxLvl = i;
986 break;
987 }
988 }
989
990 if (level % 2 == 0) {
991 ctr = 0;
992 if (minLvl <= level - 2 && level - 2 <= maxLvl) ctr++;
993 if (minLvl <= level && level <= maxLvl) ctr++;
994 if (minLvl <= level + 2 && level + 2 <= maxLvl) ctr++;
995 levels.init(ctr);
996
997 ctr = 0;
998 if (minLvl <= level - 2 && level - 2 <= maxLvl) levels[ctr++] = level - 2;
999 if (minLvl <= level && level <= maxLvl) levels[ctr++] = level;
1000 if (minLvl <= level + 2 && level + 2 <= maxLvl) levels[ctr++] = level + 2;
1001 } else {
1002 ctr = 0;
1003 if (minLvl <= level - 3 && level - 3 <= maxLvl) ctr++;
1004 if (minLvl <= level - 1 && level - 1 <= maxLvl) ctr++;
1005 if (minLvl <= level && level <= maxLvl) ctr++;
1006 if (minLvl <= level + 1 && level + 1 <= maxLvl) ctr++;
1007 levels.init(ctr);
1008
1009 ctr = 0;
1010 if (minLvl <= level - 3 && level - 3 <= maxLvl) levels[ctr++] = level - 3;
1011 if (minLvl <= level - 1 && level - 1 <= maxLvl) levels[ctr++] = level - 1;
1012 if (minLvl <= level && level <= maxLvl) levels[ctr++] = level;
1013 if (minLvl <= level + 1 && level + 1 <= maxLvl) levels[ctr++] = level + 1;
1014 }
1015
1016 Delta += localCountCrossings(levels);
1017
1018 // do horizontal steps
1019 v = b->m_Node;
1020 for(adjEntry adj : v->adjEntries) {
1021 edge e = adj->theEdge();
1022 if (m_isActiveEdge[e]) {
1023 int delta = siftingStep(m_EdgeBlocks[e]);
1024 Delta += delta;
1025 }
1026 }
1027
1028 int delta = siftingStep(b);
1029 Delta += delta;
1030
1031 return Delta;
1032 }
1033
1034
verticalStep(Block * b)1035 void BlockOrder::verticalStep(Block *b)
1036 {
1037 int maxLevel = 0;
1038 //normalize levels to 2,4,6,8,...
1039 for (auto currentBlock : m_Blocks) {
1040 if (currentBlock->isVertexBlock()) {
1041 currentBlock->m_upper = 2 + 2 * (currentBlock->m_upper);
1042 currentBlock->m_lower = 2 + 2 * (currentBlock->m_lower);
1043 } else {
1044 // currentBlock->isEdgeBlock()
1045 edge e = currentBlock->m_Edge;
1046 currentBlock->m_upper = m_NodeBlocks[e->source()]->m_lower + 1;
1047 currentBlock->m_lower = m_NodeBlocks[e->target()]->m_upper - 1;
1048 }
1049
1050 if (currentBlock->m_lower > maxLevel)
1051 maxLevel = currentBlock->m_lower;
1052 }
1053
1054 m_nNodesOnLvls.init(1, maxLevel + 1, 0);
1055
1056 for (auto &block : m_Blocks) {
1057 if (block->isVertexBlock()) {
1058 m_nNodesOnLvls[block->m_upper] += 1;
1059 }
1060 }
1061
1062 int lMin = 1;
1063 int lMax = maxLevel + 1;
1064 node v = b->m_Node;
1065 for(adjEntry adj : v->adjEntries) {
1066 edge e = adj->theEdge();
1067 if (v == e->source()) {
1068 lMax = min<int>(lMax, m_NodeBlocks[e->target()]->m_upper - 1);
1069 } else {
1070 // v == e->target()
1071 lMin = max<int>(lMin, m_NodeBlocks[e->source()]->m_lower + 1);
1072 }
1073 }
1074 if (lMin < b->m_upper - m_verticalStepsBound)
1075 lMin = b->m_upper - m_verticalStepsBound;
1076 if (lMax > b->m_lower + m_verticalStepsBound)
1077 lMax = b->m_lower + m_verticalStepsBound;
1078
1079 Array<int> startingPerm(0, m_storedPerm.high(), -1);
1080
1081 Array<int> startingM_upper(0, m_Blocks.high(), 0);
1082 Array<int> startingM_lower(0, m_Blocks.high(), 0);
1083
1084 int startingActiveBlocksCount;
1085 EdgeArray<bool> startingM_isActiveEdge;
1086
1087 Array<int> bestPerm(m_storedPerm.size());
1088
1089 Array<int> bestM_upper(0, m_Blocks.high(), 0);
1090 Array<int> bestM_lower(0, m_Blocks.high(), 0);
1091
1092 int bestActiveBlocksCount = 0;
1093 EdgeArray<bool> bestM_isActiveEdge;
1094
1095 int bestChi = std::numeric_limits<int>::max();
1096 int currentChi = 0;
1097
1098
1099 // store starting embedding
1100 for (int i = 0; i < m_Blocks.size(); ++i) {
1101 startingPerm[i] = m_storedPerm[i];
1102 startingM_lower[i] = m_Blocks[i]->m_lower;
1103 startingM_upper[i] = m_Blocks[i]->m_upper;
1104 }
1105 startingActiveBlocksCount = m_activeBlocksCount;
1106 startingM_isActiveEdge = m_isActiveEdge;
1107
1108 // for upward
1109 for (int level = b->m_upper + 1; level >= lMin; --level) {
1110 int Delta = verticalSwap(b, level);
1111 currentChi += Delta;
1112 if (currentChi < bestChi) {
1113 // store currentEmbedding as best found
1114 for (int i = 0; i < m_Blocks.size(); ++i) {
1115 bestPerm[i] = m_storedPerm[i];
1116 bestM_lower[i] = m_Blocks[i]->m_lower;
1117 bestM_upper[i] = m_Blocks[i]->m_upper;
1118 }
1119
1120 bestActiveBlocksCount = m_activeBlocksCount;
1121 bestM_isActiveEdge = m_isActiveEdge;
1122 bestChi = currentChi;
1123 }
1124 }
1125
1126 // restore starting embedding
1127 for (int i = 0; i < m_Blocks.size(); ++i) {
1128 m_storedPerm[i] = startingPerm[i];
1129 m_Blocks[i]->m_lower = startingM_lower[i];
1130 m_Blocks[i]->m_upper = startingM_upper[i];
1131 }
1132
1133 currentChi = 0;
1134
1135 m_activeBlocksCount = startingActiveBlocksCount;
1136 m_isActiveEdge = startingM_isActiveEdge;
1137
1138 m_nNodesOnLvls.init(1, maxLevel + 1, 0);
1139
1140 for (auto &block : m_Blocks) {
1141 if (block->isVertexBlock()) {
1142 m_nNodesOnLvls[block->m_upper] += 1;
1143 }
1144 }
1145
1146 // for downward
1147 for (int level = b->m_lower + 1; level <= lMax; ++level) {
1148 int Delta = verticalSwap(b, level);
1149 currentChi += Delta;
1150 if (currentChi < bestChi) {
1151 // store currentEmbedding as best found
1152 for (int i = 0; i < m_Blocks.size(); ++i) {
1153 bestPerm[i] = m_storedPerm[i];
1154 bestM_lower[i] = m_Blocks[i]->m_lower;
1155 bestM_upper[i] = m_Blocks[i]->m_upper;
1156 }
1157
1158 bestActiveBlocksCount = m_activeBlocksCount;
1159 bestM_isActiveEdge = m_isActiveEdge;
1160 bestChi = currentChi;
1161 }
1162 }
1163
1164 // restore best
1165 for (int i = 0; i < m_Blocks.size(); ++i) {
1166 m_storedPerm[i] = bestPerm[i];
1167 m_Blocks[i]->m_lower = bestM_lower[i];
1168 m_Blocks[i]->m_upper = bestM_upper[i];
1169 }
1170 currentChi = bestChi;
1171
1172 m_activeBlocksCount = bestActiveBlocksCount;
1173 m_isActiveEdge = bestM_isActiveEdge;
1174
1175 // delete empty levels
1176 m_nNodesOnLvls.init(1, maxLevel + 1, 0);
1177
1178 for (auto &block : m_Blocks) {
1179 if (block->isVertexBlock()) {
1180 m_nNodesOnLvls[block->m_upper] += 1;
1181 }
1182 }
1183
1184 int p = 0;
1185 Array<int> normalizedLvl(1, maxLevel + 1);
1186 for (int i = 1; i <= maxLevel + 1; ++i) {
1187 if (m_nNodesOnLvls[i] > 0) {
1188 normalizedLvl[i] = p;
1189 ++p;
1190 }
1191 }
1192
1193 for (auto currentBlock : m_Blocks) {
1194 if (currentBlock->isVertexBlock()) {
1195 currentBlock->m_upper = normalizedLvl[currentBlock->m_upper];
1196 currentBlock->m_lower = normalizedLvl[currentBlock->m_lower];
1197 } else { // currentBlock->isEdgeBlock()
1198 edge e = currentBlock->m_Edge;
1199 currentBlock->m_upper = m_NodeBlocks[e->source()]->m_lower + 1;
1200 currentBlock->m_lower = m_NodeBlocks[e->target()]->m_upper - 1;
1201 }
1202 }
1203 }
1204
1205
gridSifting(int nRepeats)1206 void BlockOrder::gridSifting(int nRepeats)
1207 {
1208 #if 0
1209 while (rho-- > 0)
1210 #endif
1211 {
1212 Array<int> storedPermInv(0, m_Blocks.high(), -1);
1213 m_storedPerm.init(0, m_Blocks.high(), -1);
1214 int p = 0;
1215
1216 for (int i = 0; i < m_Blocks.size(); ++i) {
1217 if (m_Blocks[i]->isVertexBlock()
1218 || (m_Blocks[i]->isEdgeBlock() && m_isActiveEdge[m_Blocks[i]->m_Edge])) {
1219 storedPermInv[p] = i;
1220 m_storedPerm[i] = p;
1221 ++p;
1222 }
1223 }
1224
1225 // initialize with random permutation
1226 storedPermInv.permute(0, m_activeBlocksCount - 1);
1227
1228 for (int i = 0; i < m_activeBlocksCount; ++i)
1229 m_storedPerm[storedPermInv[i]] = i;
1230
1231
1232 int times = nRepeats;
1233 while (times-- > 0) {
1234 for(node v : m_GC.nodes) {
1235 Block *currentBlock = m_NodeBlocks[v];
1236 if (currentBlock != nullptr) {
1237 verticalStep(currentBlock);
1238 }
1239 }
1240 }
1241 }
1242
1243 // reassign m_hierarchy!
1244 m_ranks.init(m_GC, 0);
1245 EdgeArray<edge> auxCopy(m_GC);
1246 List<node> nodes;
1247 for(node v : m_GC.nodes) {
1248 if (m_NodeBlocks[v] != nullptr) {
1249 m_ranks[v] = m_NodeBlocks[v]->m_upper;
1250 nodes.pushBack(v);
1251 }
1252 }
1253 m_hierarchy.createEmpty(m_GC);
1254 m_hierarchy.initByNodes(nodes, auxCopy, m_ranks);
1255
1256 // build levels
1257 buildHierarchy();
1258 return;
1259 }
1260
1261 }
1262