1 /** \file
2  * \brief Implements class BiconnectedShellingOrder which computes
3  * a shelling order for a biconnected planar graph.
4  *
5  * \author Carsten Gutwenger
6  *
7  * \par License:
8  * This file is part of the Open Graph Drawing Framework (OGDF).
9  *
10  * \par
11  * Copyright (C)<br>
12  * See README.md in the OGDF root directory for details.
13  *
14  * \par
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * Version 2 or 3 as published by the Free Software Foundation;
18  * see the file LICENSE.txt included in the packaging of this file
19  * for details.
20  *
21  * \par
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * \par
28  * You should have received a copy of the GNU General Public
29  * License along with this program; if not, see
30  * http://www.gnu.org/copyleft/gpl.html
31  */
32 
33 
34 #include <ogdf/planarlayout/BiconnectedShellingOrder.h>
35 #include <ogdf/basic/CombinatorialEmbedding.h>
36 #include <ogdf/basic/FaceArray.h>
37 #include <ogdf/basic/SList.h>
38 
39 #include <ogdf/basic/extended_graph_alg.h>
40 #include <ogdf/basic/simple_graph_alg.h>
41 
42 
43 //#define OUTPUT_BSO
44 
45 namespace ogdf {
46 
47 // pair of node v and list itrator it
48 struct PairFaceItem;
49 
50 struct PairNodeItem
51 {
52 	// constructor
PairNodeItemogdf::PairNodeItem53 	PairNodeItem() { }
54 
PairNodeItemogdf::PairNodeItem55 	explicit PairNodeItem(node v, ListIterator<PairFaceItem> it = ListIterator<PairFaceItem>()) : m_v(v), m_it(it) { }
56 
57 	node m_v;
58 	ListIterator<PairFaceItem> m_it;
59 };
60 
61 // pair of face f and list iterator it
62 struct PairFaceItem
63 {
64 	// constructor
PairFaceItemogdf::PairFaceItem65 	PairFaceItem() : m_f(nullptr), m_it(nullptr) { }
66 
PairFaceItemogdf::PairFaceItem67 	explicit PairFaceItem(face f) : m_f(f), m_it(nullptr) { }
68 
PairFaceItemogdf::PairFaceItem69 	PairFaceItem(face f, ListIterator<PairNodeItem> it) : m_f(f), m_it(it) { }
70 
71 	face m_f;
72 	ListIterator<PairNodeItem> m_it;
73 };
74 
75 
76 // defines (as shortcuts)
77 // initialization of a variable
78 #define INIT_VAR(x,var,val) \
79 	var[x] = (val);          \
80 	setUpdate(x);
81 
82 // decrement of a variable
83 #define DEC_VAR(x,var)     \
84 	--var[x];               \
85 	setUpdate(x);
86 
87 // increment of a variable
88 #define INC_VAR(x,var)     \
89 	++var[x];               \
90 	setUpdate(x);
91 
92 
93 class ComputeBicOrder
94 {
95 public:
96 	// types of structures to be removed
97 	enum class CandidateType { Face, Node, Edge };
98 
99 
100 	// constructor
101 	ComputeBicOrder (
102 		const Graph &G,                 // biconnected planar graph
103 		ConstCombinatorialEmbedding &E, // combinatorial embedding of G
104 		face extFace,              // external face
105 		double baseRatio);         // size of base (baseRatio * size(extFace)
106 
107 	// returns external face
externalFace()108 	face externalFace() { return m_extFace; }
109 
110 	// returns face left of adj
left(adjEntry adj)111 	face left(adjEntry adj) { return m_pEmbedding->leftFace(adj); }
112 
113 	// returns face right of adj
right(adjEntry adj)114 	face right(adjEntry adj) { return m_pEmbedding->rightFace(adj); }
115 
116 	// if v = c_i, returns face right of c_i -> c_i+1
right(node v)117 	face right(node v) { return left(m_nextSucc[v]); }
118 
119 	// if v = c_i, returns face left of c_i -> c_i-1
left(node v)120 	face left(node v) { return right(m_prevPred[v]); }
121 
122 	// returns number of virtual edges adjacent to v
123 	int virte (node v);
124 
125 	// returns successor of v on contour (if v=c_i returns c_i+1)
next(node v)126 	node next(node v) { return m_next[v]; }
127 
128 	// returns predecessor of v on contour (if v=c_i returns c_ii1)
prev(node v)129 	node prev(node v) { return m_prev[v]; }
130 
131 	// returns true <=> f contains a virtual edge
cutv(face f)132 	bool cutv(face f) { return m_virtSrc[f] != nullptr; }
133 
134 	// returns true <=> f is a possible next face, i.e
135 	//   outv(f) >= 3 and outv(f) = oute(f)+1
isPossFace(face f)136 	bool isPossFace(face f) {
137 		return f != externalFace()
138 		    && m_outv[f] >= 3
139 		    && m_outv[f] == m_oute[f] + 1;
140 	}
141 
142 	// returns true <=> v is a possible next node, i.e.
143 	//   cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3
isPossNode(node v)144 	bool isPossNode(node v) {  // precond.: v on C_k'
145 		return !m_onBase[v]
146 		    && m_cutf[v] <= 1
147 		    && m_cutf[v] == virte(v)
148 		    && m_numsf[v] == 0
149 		    && m_deg[v] >= 3;
150 	}
151 
152 	// returns true <=> v=c_i and c_i -> c_i+1 is a possible next virtual edge, i.e.
153 	//   c_i -> c_i+1 is a virtual edge and (deg(c_i) = 2 and c_i != vLeft) or
154 	//   deg(c_i+1) = 2 and c_i+1 != vRight)
isPossVirt(node v)155 	bool isPossVirt(node v) {  // precond.: v on C_k'
156 		return m_virtEdge[v] && ((m_deg[v] == 2 && v != m_vLeft) ||
157 			(m_deg[next(v)] == 2 && next(v) != m_vRight));
158 	}
159 
160 	// stores the next candidate in m_nextType and m_nextF, m_nextV or
161 	// m_nextE (depending on type)
162 	// returns true <=> there is a next candidate
163 	bool getPossible();
164 
165 	// returns the type of the next candidate
nextPoss()166 	CandidateType nextPoss() { return m_nextType; }
167 
168 	// puts nodes on base into shelling order set V
169 	void setV1(ShellingOrderSet &V);
170 
171 	// initializes possible nodes and faces
172 	void initPossibles();
173 
174 	// removes next possible face
175 	void removeNextFace(ShellingOrderSet &V);
176 	// removes next possible node
177 	void removeNextNode(ShellingOrderSet &V);
178 	// removes next possible virtual edge
179 	void removeNextVirt(ShellingOrderSet &V);
180 
181 	// updates variables of face and nodes contained in m_updateFaces and
182 	// m_updateNodes; also updates list of possible nodes, faces and virtual edges
183 	void doUpdate();
184 
185 	// outputs contour and some node and face variables
186 	// for debugging only
187 	void print();
188 
189 private:
190 	// if adj = w->v, puts edge (v,w) onto contour
191 	void edgeToContour(adjEntry adj);
192 	// puts virtual edge (v,w) onto contour and sets m_nextSucc[v] and m_prevPred[w]
193 	void virtToContour(node v, node w, adjEntry adjNextSucc, adjEntry adjPrevPred);
194 	// puts virtual edge (v,w) onto contour
195 	void virtToContour(node v, node w);
196 
197 	// returns vertex cl of a face to be removed
198 	node getFaceCl(face f);
199 
200 	void setOutv(node v);
201 	void setSeqp(node cl, node cr);
202 	void delOuterNode(node v);
203 	void decSeqp(node v);
204 	void putOnOuter(node v, face f);
205 	void delOuterRef(face f);
206 
207 	// returns faces adjacent with v in list L
208 	void getAdjFaces(node v, SListPure<face> &L);
209 	// returns nodes adjacent with v in list L; nodes are sorted from left
210 	// to right
211 	void getAdjNodes(node v, SListPure<node> &L);
212 
213 	// marks face f to be updated
214 	void setUpdate(face f);
215 	// marks node v to be updated
216 	void setUpdate(node v);
217 
218 	void initVInFStruct(const ConstCombinatorialEmbedding &E);
219 	bool vInF(node v, face f);
220 	void delVInF(node v, face f);
221 
222 	int getBaseChain(ConstCombinatorialEmbedding &E,
223 		face f,
224 		double baseRatio,
225 		adjEntry &adjLeft,
226 		adjEntry &adjRight);
227 
228 	adjEntry findMaxBaseChain(ConstCombinatorialEmbedding &E,
229 		face f,
230 		int &length);
231 
232 	const Graph                 *m_pGraph;     // the graph
233 	ConstCombinatorialEmbedding *m_pEmbedding; // the embedding of the graph
234 
235 	face m_extFace; // the external face
236 
237 	adjEntry m_adjLeft; // adjacency entry z_1 -> z_2 (if z_1,...,z_p is base)
238 	adjEntry m_adjRight; // adjacency entry z_p-1 -> z_p
239 
240 	node m_vLeft, m_vRight; // left and right node on base
241 	int m_baseLength;       // length of base
242 
243 	// next candidate to be removed
244 	CandidateType m_nextType; // type of next candidate
245 	face m_nextF; // next face (if m_nextType = typeFace)
246 	node m_nextV; // next node (if m_nextType = typeNode)
247 	node m_nextE; // next virtual edge (if m_nextType = typeEdge)
248 
249 	// variables of nodes
250 	NodeArray<int>  m_deg;      // current degree
251 	NodeArray<int>  m_cutf;     // number of adjacent faces f with cutv(f) = true
252 	NodeArray<int>  m_numsf;    // number of adjacent faces f with outv(f) > seqp(f)+1
253 	NodeArray<bool> m_onOuter;  // true <=> v on contour
254 	NodeArray<bool> m_onBase;   // true <=> v on base
255 
256 	// list iterator in m_possNodes containing node (or nil if not contained)
257 	NodeArray<ListIterator<node> > m_vLink;
258 	// list iterator in m_possVirt containing virtual edge at node (or nil if not contained)
259 	NodeArray<ListIterator<node> > m_virtLink;
260 	NodeArray<bool>	m_vUpdate;  // true <=> node marked to be updated
261 	NodeArray<ListPure<PairFaceItem> > m_inOutNodes;
262 
263 	// variables of faces
264 	FaceArray<int>	m_outv,		// number of nodes contained in face on contour
265 					m_oute,		// number of edges contained in face on contour
266 					m_seqp;		// number of sequential pairs c_i,c_i+1 of face
267 	FaceArray<node>	m_virtSrc;	// if face contains virtual edge e then source(e), otherwise nil
268 	// list iterator in m_possFaces containing face (or nil if not contained)
269 	FaceArray<ListIterator<face> >	m_fLink;
270 	FaceArray<bool>	m_fUpdate;  // true <=> face marked to be updated
271 	FaceArray<bool> m_isSf;		// true <=> outv(f) > seqp(f)+1
272 	FaceArray<ListPure<PairNodeItem> > m_outerNodes;	// list of all nodes of face on contour
273 
274 	// represantation of the contour
275 	NodeArray<node>	    m_next, m_prev;
276 	NodeArray<adjEntry>	m_nextSucc, m_prevPred;
277 	NodeArray<bool>	    m_virtEdge;	// virt_edge[c_i] = true <=> (c_i,c_i+1) virtuelle Kante
278 
279 	// lists of possible faces, nodes and edges
280 	ListPure<face> m_possFaces; // faces with outv(f) >= 3 und outv(f) = oute(f)+1
281 	ListPure<node> m_possNodes; // nodes with cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3
282 	ListPure<node> m_possVirt;  // node v denotes virtual edge e = (v,next[v]), that satisfies (deg(v) = 2 and v != vLeft) or (deg(next(v)) = 2 and next(v) != vRight)
283 
284 	ListPure <node> m_updateNodes; // list of nodes to be updated
285 	SListPure<face> m_updateFaces; // list of faces to be updated
286 
287 	// deciding "v in F ?" in constant time
288 	NodeArray<List<PairFaceItem> > m_facesOf;
289 	FaceArray<List<PairNodeItem> > m_nodesOf;
290 };
291 
292 
print()293 void ComputeBicOrder::print()
294 {
295 	std::cout << "contour:\n";
296 	for(node v = m_vLeft; v != nullptr; v = m_next[v])
297 		std::cout << " " << v << "[" << m_prev[v] << "," << m_prevPred[v] <<
298 			" : " << m_next[v] << "," << m_nextSucc[v] <<
299 			"; " << m_virtEdge[v] << "]\n";
300 
301 	std::cout << "node infos:\n";
302 	for(node v : m_pGraph->nodes)
303 		std::cout << v << ": deg = " << m_deg[v] << ", cutf = " << m_cutf[v] <<
304 			", numsf = " << m_numsf[v] << std::endl;
305 
306 	std::cout << "face infos:\n";
307 	for(face f : m_pEmbedding->faces) {
308 		std::cout << f->index() << ": outv = " << m_outv[f] << ", oute = " <<
309 			m_oute[f] << ", seqp = " << m_seqp[f] << ", isSF = " <<
310 			m_isSf[f] << ", virtSrc = " << m_virtSrc[f] << std::endl;
311 	}
312 	std::cout << std::endl;
313 }
314 
315 
ComputeBicOrder(const Graph & G,ConstCombinatorialEmbedding & E,face extFace,double baseRatio)316 ComputeBicOrder::ComputeBicOrder(const Graph &G, // the graph
317 	ConstCombinatorialEmbedding &E,        // embedding of the graph
318 	face extFace,                          // the external face
319 	double baseRatio)                      // length of the base = baseRatio*size(extface)
320 {
321 	m_pGraph = &G;
322 	m_pEmbedding = &E;
323 
324 #ifdef OUTPUT_BSO
325 	std::cout << "faces:" << std::endl;
326 	for(face fh : E.faces) {
327 		std::cout << fh->index() << ":";
328 		for(adjEntry adj : fh->entries)
329 			std::cout << " " << adj;
330 		std::cout << std::endl;
331 	}
332 
333 	std::cout << "adjacency lists:" << std::endl;
334 	for(node vh : G.nodes) {
335 		std::cout << vh << ":";
336 		for(adjEntry adj : vh->adjEntries)
337 			std::cout << " " << adj;
338 		std::cout << std::endl;
339 	}
340 #endif
341 
342 	m_vLink   .init(G, ListIterator<node>());
343 	m_virtLink.init(G, ListIterator<node>());
344 
345 	m_extFace = extFace;
346 
347 #ifdef OUTPUT_BSO
348 	std::cout << "external face = " << extFace->index() << std::endl;
349 #endif
350 
351 	m_baseLength = getBaseChain(E, m_extFace, baseRatio, m_adjLeft, m_adjRight);
352 	m_vLeft      = m_adjLeft->theNode();
353 	m_vRight     = m_adjRight->twinNode();
354 
355 #ifdef OUTPUT_BSO
356 	std::cout << "vLeft = " << m_vLeft << ", " << "vRight = " << m_vRight << std::endl;
357 #endif
358 
359 	// initialization of node and face variables
360 	m_deg      	 .init (G);
361 	m_cutf     	 .init (G, 0);
362 	m_numsf    	 .init (G, 0);
363 	m_onOuter 	 .init (G, false);
364 	m_next       .init (G);
365 	m_prev       .init (G);
366 	m_nextSucc   .init (G);
367 	m_prevPred   .init (G);
368 	m_virtEdge	 .init (G, false);
369 	m_vUpdate    .init (G, false);
370 	m_inOutNodes .init (G);
371 	m_outv       .init (E, 0);
372 	m_oute       .init (E, 0);
373 	m_seqp       .init (E, 0);
374 	m_virtSrc    .init (E, nullptr);
375 	m_fLink      .init (E, ListIterator<face>());
376 	m_fUpdate    .init (E, false);
377 	m_isSf       .init (E, false);
378 	m_outerNodes .init (E);
379 	m_onBase     .init (G, false);
380 
381 	initVInFStruct(E);
382 
383 	// initialization of degree
384 	for(node v : G.nodes)
385 		m_deg[v] = v->degree();
386 
387 	// initialization of m_onBase[v]
388 	adjEntry adj;
389 	for(adj = m_adjRight; adj != m_adjLeft; adj = adj->faceCyclePred())
390 		m_onBase[adj->theNode()] = true;
391 	m_onBase [m_vLeft] = m_onBase [m_vRight] = true;
392 
393 	adj = m_adjLeft;
394 	do {
395 		node v = adj->theNode();
396 		for(adjEntry adj2 : v->adjEntries)
397 		{
398 			face f = E.rightFace(adj2);
399 			if (f != m_extFace) {
400 				m_outv[f] ++;
401 				putOnOuter(v,f);
402 			}
403 		}
404 		adj = adj->faceCyclePred();
405 	} while(adj != m_adjRight);
406 
407 	for(adj = m_adjRight->faceCycleSucc(); adj != m_adjLeft; adj = adj->faceCycleSucc())
408 		m_oute[E.leftFace(adj)]++;
409 
410 	m_onOuter [m_vLeft] = true;
411 	m_prevPred[m_vLeft] = m_nextSucc[m_vRight] = nullptr;
412 	m_prev[m_vLeft] = m_next[m_vRight] = nullptr;
413 	for (adj = m_adjLeft->faceCyclePred(); adj != m_adjRight; adj = adj->faceCyclePred())
414 	{
415 		node v = adj->twinNode();
416 		node w = adj->theNode();
417 		m_onOuter[w] = true;
418 		edgeToContour(adj);
419 
420 		for(adjEntry adj2 : w->adjEntries)
421 		{
422 			face f = left(adj2);
423 			if (vInF(v,f))
424 				++m_seqp[f];
425 		}
426 	}
427 
428 	for (node v = m_vLeft; v != nullptr; v = next(v))
429 	{
430 		for(adjEntry adjV : v->adjEntries) {
431 			face f = left(adjV);
432 			if ((m_isSf[f] = (m_outv[f] > m_seqp[f]+1)))
433 				++m_numsf[v];
434 		}
435 	}
436 }
437 
438 
setV1(ShellingOrderSet & V)439 void ComputeBicOrder::setV1(ShellingOrderSet &V)
440 {
441 	V = ShellingOrderSet(m_baseLength, nullptr, nullptr);
442 
443 	int i;
444 	adjEntry adj;
445 	for (i = 1, adj = m_adjLeft; i <= m_baseLength;
446 		i++, adj = adj->faceCycleSucc())
447 	{
448 		V[i] = adj->theNode();
449 	}
450 }
451 
452 
edgeToContour(adjEntry adj)453 void ComputeBicOrder::edgeToContour(adjEntry adj)
454 {
455 	node v = adj->twinNode(), w = adj->theNode();
456 
457 	m_next     [v] = w;
458 	m_prev     [w] = v;
459 	m_nextSucc [v] = adj->twin()->cyclicSucc();
460 	m_prevPred [w] = adj->cyclicPred();
461 	m_virtEdge [v] = false;
462 }
463 
464 
virtToContour(node v,node w,adjEntry adjNextSucc,adjEntry adjPrevPred)465 void ComputeBicOrder::virtToContour(
466 	node v,
467 	node w,
468 	adjEntry adjNextSucc,
469 	adjEntry adjPrevPred)
470 {
471 	m_next     [v] = w;
472 	m_prev     [w] = v;
473 	m_nextSucc [v] = adjNextSucc;
474 	m_prevPred [w] = adjPrevPred;
475 	m_virtEdge [v] = true;
476 }
477 
478 
virtToContour(node v,node w)479 void ComputeBicOrder::virtToContour(node v, node w)
480 {
481 	m_next     [v] = w;
482 	m_prev     [w] = v;
483 	m_virtEdge [v] = true;
484 }
485 
486 
putOnOuter(node v,face f)487 void ComputeBicOrder::putOnOuter(node v, face f)
488 {
489 	ListIterator<PairNodeItem> it;
490 
491 	it = m_outerNodes[f].pushBack(PairNodeItem(v));
492 	(*it).m_it = m_inOutNodes[v].pushBack(PairFaceItem(f,it));
493 }
494 
495 
delOuterRef(face f)496 void ComputeBicOrder::delOuterRef(face f)
497 {
498 	ListPure<PairNodeItem> &L = m_outerNodes[f];
499 	PairNodeItem x;
500 
501 	while (!L.empty()) {
502 		x = L.popFrontRet();
503 		m_inOutNodes[x.m_v].del(x.m_it);
504 	}
505 }
506 
507 
virte(node v)508 int ComputeBicOrder::virte(node v)
509 {
510 	int num = 0;
511 
512 	if (m_onOuter[v])
513 	{
514 		if (m_virtEdge[v])
515 			num++;
516 		if (v != m_vLeft && m_virtEdge[prev(v)])
517 			num++;
518 	}
519 	return num;
520 }
521 
522 
initVInFStruct(const ConstCombinatorialEmbedding & E)523 void ComputeBicOrder::initVInFStruct(const ConstCombinatorialEmbedding &E)
524 {
525 	const Graph &G = E;
526 
527 	m_facesOf.init(G);
528 	m_nodesOf.init(E);
529 
530 	for (face f : E.faces)
531 	{
532 		for (adjEntry adj : f->entries) {
533 			node v = adj->theNode();
534 
535 			ListIterator<PairFaceItem> it = m_facesOf[v].pushBack(PairFaceItem(f));
536 			(*it).m_it = m_nodesOf[f].pushBack(PairNodeItem(v, it));
537 		}
538 	}
539 
540 	SListPure<node> smallV;
541 	for (node v : G.nodes) {
542 		if (m_facesOf[v].size() <= 5)
543 			smallV.pushBack(v);
544 	}
545 
546 	SListPure<face> smallF;
547 	for (face f : E.faces) {
548 		if (m_nodesOf[f].size() <= 5)
549 			smallF.pushBack(f);
550 	}
551 
552 	for (;;)
553 	{
554 		if (!smallV.empty()) {
555 			node v = smallV.popFrontRet();
556 
557 			for (const PairFaceItem &f_it : m_facesOf[v]) {
558 				m_nodesOf[f_it.m_f].del(f_it.m_it);
559 				if (m_nodesOf[f_it.m_f].size() == 5)
560 					smallF.pushBack(f_it.m_f);
561 			}
562 		}
563 		else if (!smallF.empty()) {
564 			face f = smallF.popFrontRet();
565 			for (const PairNodeItem &v_it : m_nodesOf[f]) {
566 				m_facesOf[v_it.m_v].del(v_it.m_it);
567 				if (m_facesOf[v_it.m_v].size() == 5)
568 					smallV.pushBack(v_it.m_v);
569 			}
570 		}
571 		else
572 			break;
573 	}
574 }
575 
576 
vInF(node v,face f)577 bool ComputeBicOrder::vInF(node v, face f)
578 {
579 	for(const PairNodeItem &ni : m_nodesOf[f])
580 		if (ni.m_v == v) return true;
581 
582 	for(const PairFaceItem &fi : m_facesOf[v])
583 		if (fi.m_f == f) return true;
584 
585 	return false;
586 }
587 
588 
delVInF(node v,face f)589 void ComputeBicOrder::delVInF(node v, face f)
590 {
591 	List<PairNodeItem> &L_f = m_nodesOf[f];
592 	List<PairFaceItem> &L_v = m_facesOf[v];
593 
594 	ListIterator<PairNodeItem> itNI;
595 	for(itNI = L_f.begin(); itNI.valid(); ++itNI) {
596 		if ((*itNI).m_v == v) {
597 			L_f.del(itNI);
598 			return;
599 		}
600 	}
601 
602 	ListIterator<PairFaceItem> itFI;
603 	for(itFI = L_v.begin(); itFI.valid(); ++itFI) {
604 		if ((*itFI).m_f == f) {
605 			L_v.del(itFI);
606 			return;
607 		}
608 	}
609 }
610 
611 
initPossibles()612 void ComputeBicOrder::initPossibles()
613 {
614 	for(face f : m_pEmbedding->faces) {
615 		if (isPossFace(f))
616 			m_fLink[f] = m_possFaces.pushBack(f);
617 	}
618 
619 	for (node v = next(m_vLeft); v != m_vRight; v = next(v))
620 		if (isPossNode(v))
621 			m_vLink[v] = m_possNodes.pushBack(v);
622 }
623 
624 
getPossible()625 bool ComputeBicOrder::getPossible()
626 {
627 	if (!m_possFaces.empty()) {
628 		m_nextType = CandidateType::Face;
629 		m_nextF = m_possFaces.popFrontRet();
630 		m_fLink[m_nextF] = ListIterator<face>();
631 		return true;
632 
633 	} else if (!m_possNodes.empty()) {
634 		m_nextType = CandidateType::Node;
635 		m_nextV = m_possNodes.popFrontRet();
636 		m_vLink[m_nextV] = ListIterator<node>();
637 		return true;
638 
639 	} else if (!m_possVirt.empty()) {
640 		m_nextType = CandidateType::Edge;
641 		m_nextE = m_possVirt.popFrontRet();
642 		m_virtLink[m_nextE] = ListIterator<node>();
643 		return true;
644 
645 	} else
646 		return false;
647 }
648 
649 
getFaceCl(face f)650 node ComputeBicOrder::getFaceCl(face f)
651 {
652 	node v = nullptr;
653 
654 	if (cutv(f)) {
655 		v = m_virtSrc [f];
656 
657 	} else {
658 		for(adjEntry adj : f->entries) {
659 			if (m_onOuter[v = adj->theNode()] && m_deg[v] == 2)
660 				break;
661 		}
662 	}
663 
664 	while (v != m_vLeft && m_deg[v] == 2)
665 		v = prev(v);
666 
667 	return v;
668 }
669 
670 
getAdjFaces(node v,SListPure<face> & L)671 void ComputeBicOrder::getAdjFaces(node v, SListPure<face> &L)
672 {
673 	L.clear();
674 	if (m_deg[v] <= 1) return;
675 
676 	adjEntry adjEnd   = (v != m_vLeft)  ? m_prevPred[v] : m_adjLeft->cyclicPred();
677 	adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc();
678 
679 	if (left(adjStart) != m_extFace)
680 		L.pushBack(left(adjStart));
681 
682 	if (m_deg[v] >= 3) {
683 		adjEntry adj;
684 		for (adj = adjStart; adj != adjEnd; adj = adj->cyclicSucc())
685 			L.pushBack(right(adj));
686 
687 		L.pushBack(right(adjEnd));
688 	}
689 }
690 
691 
getAdjNodes(node v,SListPure<node> & L)692 void ComputeBicOrder::getAdjNodes(node v, SListPure<node> &L)
693 {
694 	adjEntry adjEnd   = (v != m_vLeft)  ? m_prevPred[v] : m_adjLeft->cyclicPred();
695 	adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc();
696 
697 	L.clear();
698 	L.pushBack((v != m_vLeft) ? prev(v) : m_adjLeft->twinNode());
699 
700 	if (m_deg[v] >= 3) {
701 		adjEntry adj;
702 		for (adj = adjEnd; adj != adjStart; adj = adj->cyclicPred())
703 			L.pushBack(adj->twinNode());
704 		L.pushBack(adjStart->twinNode());
705 	}
706 	L.pushBack((v != m_vRight) ? next(v) : m_adjRight->theNode());
707 }
708 
709 
decSeqp(node v)710 void ComputeBicOrder::decSeqp(node v)
711 {
712 	node vNext = next(v);
713 	node vPrev = prev(v);
714 
715 	SListPure<face> L;
716 	getAdjFaces(v, L);
717 
718 	for (face f : L) {
719 		if (vInF(vNext, f))
720 			m_seqp[f]--;
721 		if (vInF(vPrev, f))
722 			m_seqp[f]--;
723 	}
724 }
725 
726 
delOuterNode(node v)727 void ComputeBicOrder::delOuterNode(node v)
728 {
729 	for(const PairFaceItem &fi : m_inOutNodes[v])
730 		m_outerNodes[fi.m_f].del(fi.m_it);
731 }
732 
733 
setOutv(node v)734 void ComputeBicOrder::setOutv(node v)
735 {
736 	SListPure<face> L;
737 	getAdjFaces(v, L);
738 
739 	for (face f : L) {
740 		INC_VAR(f, m_outv)
741 			putOnOuter(v, f);
742 		if (cutv(f)) {
743 			INC_VAR(v, m_cutf)
744 		}
745 		if (m_isSf[f]) {
746 			INC_VAR(v, m_numsf)
747 		}
748 	}
749 }
750 
751 
setSeqp(node cl,node cr)752 void ComputeBicOrder::setSeqp(node cl, node cr)
753 {
754 	SListPure<face> L;
755 
756 	node w;
757 	for (node v = cl; v != cr; v = w)
758 	{
759 		w = next(v);
760 
761 		node wSmall, wBig;
762 		if (m_deg[v] < m_deg[w]) {
763 			wSmall = v;
764 			wBig   = w;
765 		} else {
766 			wSmall = w;
767 			wBig   = v;
768 		}
769 
770 		getAdjFaces(wSmall, L);
771 
772 		for(face f : L) {
773 			if (vInF(wBig,f)) {
774 				INC_VAR (f,m_seqp)
775 			}
776 		}
777 	}
778 }
779 
780 
removeNextFace(ShellingOrderSet & V)781 void ComputeBicOrder::removeNextFace(ShellingOrderSet &V)
782 {
783 #ifdef OUTPUT_BSO
784 	std::cout << "remove next face: " << m_nextF->index() << std::endl;
785 #endif
786 
787 	node cl = getFaceCl(m_nextF), cr, v;
788 
789 	V = ShellingOrderSet(m_outv[m_nextF]-2);
790 	V.left(cl);
791 
792 	int i;
793 	for (i = 1, cr = next(cl); cr != m_vRight && m_deg[cr] == 2; i++, cr = next(cr))
794 		V [i] = cr ;
795 	V.right (cr);
796 	V.leftAdj (m_virtEdge[cl]       ? nullptr : m_nextSucc[cl]->cyclicSucc()->twin());
797 	V.rightAdj(m_virtEdge[prev(cr)] ? nullptr : m_prevPred[cr]->cyclicPred()->twin());
798 
799 	if (cutv(m_nextF) && next(m_virtSrc[m_nextF]) == cr)
800 		setUpdate(cr);
801 
802 	if (cutv(m_nextF)) {
803 		DEC_VAR(cl,m_cutf)
804 		DEC_VAR(cr,m_cutf)
805 		v = m_virtSrc[m_nextF];
806 		if (v != cr) {
807 			m_possVirt.del(m_virtLink[v]);
808 			m_virtLink[v] = ListIterator<node>();
809 		}
810 	}
811 
812 	adjEntry adj = m_nextSucc[cl]->twin();
813 	for( ; ; ) {
814 		edgeToContour(adj);
815 
816 		if (adj->theNode() == cr)
817 			break;
818 		else {
819 			INIT_VAR(adj->theNode(),m_onOuter,true)
820 		}
821 
822 		adj = adj->faceCyclePred();
823 	}
824 	DEC_VAR (cl,m_deg)
825 	DEC_VAR (cr,m_deg)
826 
827 	for (v = cl; v != cr; v = next(v)) {
828 		INC_VAR(right(v),m_oute)
829 		if (v != cl)
830 			setOutv(v);
831 	}
832 
833 	setSeqp(cl, cr);
834 
835 	// possibly remove virtual edge
836 	if (cutv(m_nextF)) {
837 		if (m_virtSrc[m_nextF] == cl) {
838 			setUpdate(cl);
839 			m_virtEdge[cl] = false;
840 		}
841 		m_virtSrc[m_nextF] = nullptr;
842 	}
843 	delOuterRef(m_nextF);
844 }
845 
846 
removeNextNode(ShellingOrderSet & V)847 void ComputeBicOrder::removeNextNode(ShellingOrderSet &V)
848 {
849 #ifdef OUTPUT_BSO
850 	std::cout << "remove next node: " << m_nextV << std::endl;
851 #endif
852 
853 	node cl = prev(m_nextV);
854 	node cr = next(m_nextV);
855 
856 	V = ShellingOrderSet(1);
857 	V[1] = m_nextV;
858 
859 	if (m_virtEdge[prev(m_nextV)]) {
860 		V.left(m_prevPred[m_nextV]->twinNode());
861 		V.leftAdj(m_prevPred[m_nextV]);
862 	} else {
863 		V.left(prev(m_nextV));
864 		V.leftAdj(m_prevPred[m_nextV]->cyclicPred());
865 	}
866 
867 	if (m_virtEdge[m_nextV]) {
868 		V.right(m_nextSucc[m_nextV]->twinNode());
869 		V.rightAdj(m_nextSucc[m_nextV]);
870 	} else {
871 		V.right(next(m_nextV));
872 		V.rightAdj(m_nextSucc[m_nextV]->cyclicSucc());
873 	}
874 
875 	node vVirt = nullptr;
876 	face fVirt = nullptr;
877 	if (m_virtEdge[prev(m_nextV)]) {
878 		INIT_VAR(prev(m_nextV), m_virtEdge, false)
879 		vVirt = cl;
880 		fVirt = left(m_nextV);
881 		m_virtSrc [fVirt] = nullptr;
882 	}
883 
884 	if (m_virtEdge[m_nextV]) {
885 		if (m_virtLink[m_nextV].valid()) {
886 			m_possVirt.del(m_virtLink[m_nextV]);
887 			m_virtLink[m_nextV] = ListIterator<node>();
888 		}
889 		vVirt = cr;
890 		fVirt = right(m_nextV);
891 		m_virtSrc[fVirt] = nullptr;
892 	}
893 
894 	SListPure<face> L;
895 	getAdjFaces(m_nextV, L);
896 	for(face f : L)
897 		--m_outv[f];
898 
899 	SListPure<node> L_v;
900 	getAdjNodes(m_nextV, L_v);
901 
902 	delOuterNode(m_nextV);
903 	--m_oute[left (m_nextV)];
904 	--m_oute[right(m_nextV)];
905 	decSeqp(m_nextV);
906 
907 	for(node w : L_v) {
908 		m_onOuter[w] = true;
909 		DEC_VAR (w, m_deg)
910 	}
911 
912 	face potF = nullptr;
913 	node w1 = L_v.popFrontRet();
914 	bool firstTime = true;
915 	adjEntry adj,adj2;
916 	for(node w : L_v)
917 	{
918 		if (firstTime) {
919 			adj2 = m_nextSucc[prev(m_nextV)];
920 			adj = m_prevPred[m_nextV];
921 			firstTime = false;
922 
923 			if (prev(m_nextV) != m_vLeft) {
924 				face f = left(adj2);
925 				if (vInF(prev(prev(m_nextV)),f))
926 					potF = f;
927 			}
928 
929 		} else {
930 			adj2 = adj->twin()->faceCyclePred()->twin();
931 			adj  = adj->cyclicPred();
932 		}
933 
934 		for( ; ; )
935 		{
936 			node v = adj2->twinNode();
937 
938 			if (v != w && m_onOuter[v])
939 			{
940 				face f = left(adj2);
941 
942 				// possibly remove "v in F" relation
943 				if (adj2->theNode() != w1)
944 				{
945 					adjEntry adj1 = adj2->twin()->faceCycleSucc();
946 					do {
947 						delVInF(adj1->twinNode(),f);
948 						adj1 = adj1->faceCycleSucc();
949 					} while (adj1->theNode() != w1);
950 				}
951 				if (f == potF && adj2->theNode() != prev(m_nextV)) {
952 					DEC_VAR(f,m_seqp)
953 				}
954 
955 				// insert new virtual edge
956 				virtToContour(adj2->theNode(), w, adj2, (w == next(m_nextV)) ?
957 					m_prevPred[w] : adj->twin()->cyclicPred());
958 
959 				setUpdate(f);
960 
961 				INC_VAR(adj2->theNode(),m_deg)
962 				INC_VAR(w,m_deg)
963 
964 				if (f != fVirt) {
965 					for(const PairNodeItem &ni : m_outerNodes[f]) {
966 						INC_VAR(ni.m_v, m_cutf);
967 					}
968 				}
969 				m_virtSrc[f] = adj2->theNode();
970 
971 				break;
972 			}
973 
974 			edgeToContour(adj2->twin());
975 
976 			if (v == w) {
977 				delOuterRef(left(adj2));
978 				break;
979 			}
980 			INIT_VAR(v,m_onOuter,true)
981 			if (adj2->theNode() == cl)
982 			{
983 				ListIterator<PairNodeItem> it, itSucc;
984 				ListPure<PairNodeItem> &listPNI = m_outerNodes[left(adj2)];
985 				for(it = listPNI.begin(); it.valid(); it = itSucc) {
986 					itSucc = it.succ();
987 					if ((*it).m_v == cl) {
988 						m_inOutNodes[cl].del((*it).m_it);
989 						listPNI.del(it);
990 						break;
991 					}
992 				}
993 				m_outv[left(adj2)]--;
994 			}
995 			adj2 = adj2->twin()->faceCyclePred()->twin();
996 		}
997 		w1 = w;
998 	}
999 
1000 	for (node v = cl; v != cr; v = next(v)) {
1001 		INC_VAR(right(v),m_oute)
1002 		if (v != cl)
1003 			setOutv(v);
1004 	}
1005 
1006 	setSeqp(cl,cr);
1007 
1008 	if ((vVirt != nullptr && m_virtSrc[fVirt] == nullptr) ||
1009 		(vVirt ==  cl && m_virtSrc[fVirt] != cl)) {
1010 		DEC_VAR(vVirt,m_cutf)
1011 	}
1012 }
1013 
1014 
removeNextVirt(ShellingOrderSet & V)1015 void ComputeBicOrder::removeNextVirt(ShellingOrderSet &V)
1016 {
1017 #ifdef OUTPUT_BSO
1018 	std::cout << "remove next virt: " << m_nextE << std::endl;
1019 #endif
1020 
1021 	node v, cl = m_nextE, cr = next(m_nextE);
1022 	int i = 0;
1023 
1024 	while (m_deg[cl] == 2 && cl != m_vLeft)
1025 		{ cl = prev(cl); i++; }
1026 	while (m_deg[cr] == 2 && cr != m_vRight)
1027 		{ cr = next(cr); i++; }
1028 
1029 	V = ShellingOrderSet(i,m_virtEdge[cl] ? nullptr : m_prevPred[next(cl)],
1030 		m_virtEdge[prev(cr)] ? nullptr : m_nextSucc[prev(cr)]);
1031 	for (i = 1, v = next(cl); v != cr; v = next(v)) {
1032 		V[i++] = v;
1033 		delOuterNode(v);
1034 	}
1035 	V.left (cl);
1036 	V.right(cr);
1037 
1038 	face f = right(cl);
1039 	m_virtSrc[f] = cl;
1040 
1041 	virtToContour(cl, cr);
1042 
1043 	INIT_VAR(f,m_outv,(m_outv[f] - V.len()))
1044 	INIT_VAR(f,m_oute,(m_oute[f] - V.len()))
1045 	INIT_VAR(f,m_seqp,(m_seqp[f] - V.len()-1))
1046 	setSeqp(cl,cr);
1047 	setUpdate(cl);
1048 	setUpdate(cr);
1049 }
1050 
1051 
setUpdate(node v)1052 void ComputeBicOrder::setUpdate(node v)
1053 {
1054 	if (!m_vUpdate[v]) {
1055 		m_updateNodes.pushBack(v);
1056 		m_vUpdate[v] = true;
1057 	}
1058 }
1059 
1060 
setUpdate(face f)1061 void ComputeBicOrder::setUpdate(face f)
1062 {
1063 	if (!m_fUpdate[f]) {
1064 		m_updateFaces.pushBack(f);
1065 		m_fUpdate[f] = true;
1066 	}
1067 }
1068 
1069 
doUpdate()1070 void ComputeBicOrder::doUpdate()
1071 {
1072 	while (!m_updateFaces.empty())
1073 	{
1074 		face f = m_updateFaces.popFrontRet();
1075 		m_fUpdate[f] = false;
1076 		bool isSeperatingFace = (m_outv[f] > m_seqp[f]+1);
1077 		if (isSeperatingFace != m_isSf[f])
1078 		{
1079 			for(const PairNodeItem &ni : m_outerNodes[f])
1080 			{
1081 				if (isSeperatingFace) {
1082 					INC_VAR(ni.m_v,m_numsf)
1083 				} else {
1084 					DEC_VAR(ni.m_v,m_numsf)
1085 				}
1086 			}
1087 			m_isSf[f] = isSeperatingFace;
1088 		}
1089 		bool possible = isPossFace(f);
1090 		if (possible && !m_fLink[f].valid())
1091 			m_fLink[f] = m_possFaces.pushBack(f);
1092 		else if (!possible && m_fLink[f].valid()) {
1093 			m_possFaces.del(m_fLink[f]);
1094 			m_fLink[f] = ListIterator<face>();
1095 		}
1096 	}
1097 
1098 	for (node v : reverse(m_updateNodes)) {
1099 		if (v != m_vLeft && m_virtEdge[prev(v)])
1100 			setUpdate(prev(v));
1101 	}
1102 
1103 	while (!m_updateNodes.empty())
1104 	{
1105 		node v = m_updateNodes.popFrontRet();
1106 		m_vUpdate[v] = false;
1107 
1108 		bool possible = isPossNode(v);
1109 		if (possible && !m_vLink[v].valid())
1110 			m_vLink[v] = m_possNodes.pushBack(v);
1111 		else if (!possible && m_vLink[v].valid()) {
1112 			m_possNodes.del(m_vLink[v]);
1113 			m_vLink[v] = ListIterator<node>();
1114 		}
1115 		possible = isPossVirt(v);
1116 		if (possible && !m_virtLink[v].valid())
1117 			m_virtLink[v] = m_possVirt.pushBack(v);
1118 		else if (!possible && m_virtLink[v].valid()) {
1119 			m_possVirt.del(m_virtLink[v]);
1120 			m_virtLink[v] = ListIterator<node>();
1121 		}
1122 	}
1123 }
1124 
1125 
getBaseChain(ConstCombinatorialEmbedding & E,face f,double baseRatio,adjEntry & adjLeft,adjEntry & adjRight)1126 int ComputeBicOrder::getBaseChain(ConstCombinatorialEmbedding &E,
1127 	face f,
1128 	double baseRatio,
1129 	adjEntry &adjLeft,
1130 	adjEntry &adjRight)
1131 {
1132 	int len;
1133 	adjLeft = findMaxBaseChain(E, f, len);
1134 	len = max(2, min(len, (int)(baseRatio*f->size()+0.5)));
1135 
1136 	adjRight = adjLeft;
1137 	for (int i = 2; i < len; i++)
1138 		adjRight = adjRight->faceCycleSucc();
1139 
1140 	return len;
1141 }
1142 
1143 
1144 struct QType
1145 {
QTypeogdf::QType1146 	QType (adjEntry adj, int i) {
1147 		m_start = adj;
1148 		m_limit = i;
1149 	}
QTypeogdf::QType1150 	QType () {
1151 		m_start = nullptr;
1152 		m_limit = 0;
1153 	}
1154 
1155 	adjEntry m_start;
1156 	int      m_limit;
1157 };
1158 
1159 
findMaxBaseChain(ConstCombinatorialEmbedding & E,face f,int & length)1160 adjEntry ComputeBicOrder::findMaxBaseChain(ConstCombinatorialEmbedding &E,
1161 	face f,
1162 	int &length)
1163 {
1164 	const Graph &G = (const Graph &) E;
1165 	int p = f->size();
1166 
1167 	NodeArray<int> num(G, -1);
1168 
1169 	int i = 0;
1170 
1171 	for (adjEntry adj : f->entries)
1172 		num[adj->theNode()] = i++;
1173 
1174 	Array<SListPure<int> > diag(0, p - 1);
1175 	for (adjEntry adj : f->entries)
1176 	{
1177 		i = num[adj->theNode()];
1178 		adjEntry adj2;
1179 		for (adj2 = adj->cyclicPred(); adj2 != adj->cyclicSucc();
1180 			adj2 = adj2->cyclicPred())
1181 		{
1182 			int j = num[adj2->twinNode()];
1183 			if (j != -1)
1184 				diag[i].pushBack(j);
1185 		}
1186 	}
1187 
1188 	SListPure<QType> Q;
1189 	Array<SListIterator<QType> > posInQ(0, p - 1, SListIterator<QType>());
1190 
1191 	length = 0;
1192 	bool firstRun = true;
1193 	adjEntry adj = f->firstAdj();
1194 	i = num[adj->theNode()];
1195 
1196 	adjEntry adjStart = nullptr;
1197 	do {
1198 		if (posInQ[i].valid()) {
1199 			adjEntry adj2 = Q.front().m_start;
1200 			int d = (i - num[adj2->theNode()] + p) % p + 1;
1201 			if (d > length || (d == length && adj2->theNode()->index() < adjStart->theNode()->index())) {
1202 				length = d;
1203 				adjStart = adj2;
1204 			}
1205 			SListIterator<QType> it, itLimit = posInQ[i];
1206 			do {
1207 				it = Q.begin();
1208 				posInQ[(*it).m_limit] = SListIterator<QType>();
1209 				Q.popFront();
1210 			} while (it != itLimit);
1211 		}
1212 
1213 		int j = -1;
1214 		if (diag[i].empty())
1215 			j = (i - 2 + p) % p;
1216 		else {
1217 			int m = p;
1218 			for (int k : diag[i]) {
1219 				int d = (k - i + p) % p;
1220 				if (d < m) {
1221 					m = d;
1222 					j = k;
1223 				}
1224 			}
1225 			OGDF_ASSERT(j != -1);
1226 			j = (j - 1 + p) % p;
1227 			if (!firstRun) {
1228 				posInQ[Q.back().m_limit] = nullptr;
1229 				Q.back().m_limit = j;
1230 				posInQ[j] = Q.backIterator();
1231 			}
1232 		}
1233 
1234 		if (firstRun)
1235 			posInQ[j] = Q.pushBack(QType(adj, j));
1236 
1237 		adj = adj->faceCycleSucc();
1238 		i = num[adj->theNode()];
1239 		if (i == 0) firstRun = false;
1240 	} while (!Q.empty());
1241 
1242 	return adjStart;
1243 }
1244 
1245 
doCall(const Graph & G,adjEntry adj,List<ShellingOrderSet> & partition)1246 void BiconnectedShellingOrder::doCall(const Graph &G,
1247 	adjEntry adj,
1248 	List<ShellingOrderSet> &partition)
1249 {
1250 	OGDF_ASSERT(isBiconnected(G));
1251 	OGDF_ASSERT(G.representsCombEmbedding());
1252 
1253 	ConstCombinatorialEmbedding E(G);
1254 
1255 	face extFace = (adj != nullptr) ? E.rightFace(adj) : E.maximalFace();
1256 	ComputeBicOrder cpo(G,E,extFace,m_baseRatio);
1257 
1258 	cpo.initPossibles();
1259 
1260 #ifdef OUTPUT_BSO
1261 	std::cout << "after initialization:\n";
1262 	cpo.print();
1263 #endif
1264 
1265 	while(cpo.getPossible())
1266 	{
1267 		switch(cpo.nextPoss())
1268 		{
1269 		case ComputeBicOrder::CandidateType::Face:
1270 			partition.pushFront(ShellingOrderSet());
1271 			cpo.removeNextFace(partition.front());
1272 			break;
1273 
1274 		case ComputeBicOrder::CandidateType::Node:
1275 			partition.pushFront(ShellingOrderSet());
1276 			cpo.removeNextNode(partition.front());
1277 			break;
1278 
1279 		case ComputeBicOrder::CandidateType::Edge:
1280 			partition.pushFront(ShellingOrderSet());
1281 			cpo.removeNextVirt(partition.front());
1282 			break;
1283 		}
1284 
1285 		cpo.doUpdate();
1286 
1287 #ifdef OUTPUT_BSO
1288 		std::cout << "after update:\n";
1289 		cpo.print();
1290 #endif
1291 	}
1292 
1293 	partition.pushFront(ShellingOrderSet(2));
1294 	cpo.setV1(partition.front());
1295 }
1296 
1297 }
1298