Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
BlowupGraph.h
Go to the documentation of this file.
1
32#pragma once
33
35#include <ogdf/basic/Graph.h>
38#include <ogdf/basic/Hashing.h>
39#include <ogdf/basic/List.h>
40#include <ogdf/basic/Math.h>
41#include <ogdf/basic/basic.h>
42
43#include <iostream>
44#include <utility>
45
47template<typename T>
48class CoreEdgeModule;
49} // namespace ogdf::steiner_tree::goemans
50
51namespace ogdf::steiner_tree {
52template<typename T, typename ExtraDataType>
53class FullComponentWithExtraStore;
54} // namespace ogdf::steiner_tree
55
56//#define OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
57
58namespace ogdf {
59template<typename T>
60class EdgeWeightedGraph;
61
62namespace steiner_tree {
63namespace goemans {
64
69template<typename T>
71private:
74 const double m_eps;
75
78
85
88
89 int m_lcm;
90 int m_y;
94
96
98
99 /* witness set (for some component and specified K (core edge set))
100 *
101 * W(e) = { e } if e is a core edge
102 * W(e) =
103 * take the path P of loss edges from u to e in the component
104 * add every incident core edge of u
105 * that is: if we root the loss connected component at the terminal,
106 * W(e) = all core edges incident to the subtree below e
107 *
108 * Need fast lookups for:
109 * (1) |W(f)|
110 * (2) all loss edges f such that given core edge e is in W(f)
111 * (3) all loss edges f such that W(f) is a subset of a given basis -> for each e \in B: do (2)
112 *
113 * Data Structures:
114 * - witnessCard[e] = |W(e)|
115 * - witness[v_e] = { f | e \in W(f) }
116 * (Note that core edges are given as nodes.)
117 * Also note that we can save it all much sparser.
118 */
121
122protected:
124 void computeLCM() {
125 ArrayBuffer<int> denominators;
126
127 for (int i = 0; i < m_fullCompStore.size(); ++i) {
130 int num, denom;
132 OGDF_ASSERT(Math::gcd(num, denom) == 1);
133 denominators.push(denom);
134 }
135
136 m_lcm = 1;
137 for (int denom : denominators) {
138 m_lcm = Math::lcm(m_lcm, denom);
139 }
140#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
141 std::cout << "Normalizing factor is " << m_lcm << std::endl;
142#endif
143 }
144
147 const node v = m_graph.newNode();
148 m_isTerminal[v] = true;
149 m_terminals.pushBack(v);
150 m_original[v] = t;
151#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
152 std::cout << "Add terminal " << v << " representing original terminal " << t << std::endl;
153#endif
154 return v;
155 }
156
158 const node vCopy = m_graph.newNode();
159 m_original[vCopy] = v;
160 return vCopy;
161 }
162
166 node v = m_fullCompStore.original(start->theNode());
167 List<adjEntry> queueT;
168 List<node> queueC;
169 queueT.pushBack(start);
170 queueC.pushBack(copy[v]);
171 while (!queueT.empty()) {
172 const adjEntry inAdj = queueT.popFrontRet();
173 const node wT = inAdj->twinNode();
174 const node vC = queueC.popFrontRet();
175
176 const node wO = m_fullCompStore.original(wT);
177 if (m_fullCompStore.isTerminal(wT)) {
178 newEdge(vC, copy[wO], m_fullCompStore.graph().weight(inAdj->theEdge()), cap);
179 } else { // not a terminal
180 const node wC = initNode(wO);
181 newEdge(vC, wC, m_fullCompStore.graph().weight(inAdj->theEdge()), cap);
182 const adjEntry back = inAdj->twin();
183 for (adjEntry adj = back->cyclicSucc(); adj != back; adj = adj->cyclicSucc()) {
184 queueT.pushBack(adj);
185 queueC.pushBack(wC);
186 }
187 }
188 }
189 return copy[v];
190 }
191
193 void initSource(ArrayBuffer<std::pair<node, int>>& roots) {
194 OGDF_ASSERT(m_source == nullptr);
196#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
197 std::cout << "Add source node " << getSource() << " with edges to:" << std::endl;
198#endif
199 for (auto root : roots) {
200#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
201 std::cout << " * node " << root.first << " with cost 0 and capacity " << root.second
202 << std::endl;
203#endif
204 newEdge(getSource(), root.first, 0, root.second);
205 }
206 }
207
210 const List<node>& terminals) {
211 ArrayBuffer<std::pair<node, int>> roots; // roots (in the blowupGraph) and their capacities
212
213 NodeArray<node> copy(originalGraph, nullptr);
214 for (node t : terminals) { // generate all terminals
215 copy[t] = initTerminal(t);
216 }
217 for (int i = 0; i < m_fullCompStore.size(); ++i) {
218 int cap = int(getLCM() * m_fullCompStore.extra(i) + m_eps);
220 roots.push(std::make_pair(root, cap));
221 }
222
223 removeIsolatedTerminals(); // can exist by preprocessing
224
225#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
226 for (edge e : m_graph.edges) {
227 std::cout << "Edge from " << e << " of cost " << m_cost[e] << " and capacity "
228 << m_capacity[e] << std::endl;
229 }
230#endif
231
232 // compute core edges (and replace these edges by nodes)
233 // and witness sets
235
236 initSource(roots);
237 }
238
241 OGDF_ASSERT(m_pseudotarget == nullptr);
243
244#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
245 std::cout << "Add pseudo-target " << getPseudotarget()
246 << " with edges coming from:" << std::endl;
247#endif
248 for (node v : terminals()) {
249 OGDF_ASSERT(v);
250 int y_v = -getLCM();
251 // compute y_v, the number of components containing v in the blow up graph - N
252 // NOTE: for the non-blowup variant this is simply the sum of all x_C where C contains v ... - 1
253 for (adjEntry adj : v->adjEntries) {
254 if (adj->twinNode() != getSource()) {
255 y_v += getCapacity(adj->theEdge());
256 }
257 }
258 OGDF_ASSERT(y_v >= 0);
259
260 if (y_v > 0) {
261 newEdge(v, getPseudotarget(), 0, y_v);
262#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
263 std::cout << " * terminal " << v << " with zero cost and capacity " << y_v
264 << std::endl;
265#endif
266 m_y += y_v;
267 }
268 }
269 }
270
272 void initTarget() {
273 OGDF_ASSERT(m_target == nullptr);
275
277#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
278 std::cout << "Add edge from pseudo-target " << getPseudotarget() << " to target "
279 << getTarget() << " with zero cost and capacity " << m_y << std::endl;
280#endif
281 }
282
285#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
286 std::cout << " * updating for terminal " << v << std::endl;
287#endif
288 int delta = 0;
289 int capSource = 0;
290 int capTarget = -getLCM();
291#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
292 std::cout << " * target capacity initialized to " << capTarget
293 << ", source capacity and delta to 0" << std::endl;
294#endif
295 adjEntry adj2;
296 for (adjEntry adj = v->firstAdj(); adj; adj = adj2) {
297 adj2 = adj->succ();
298 if (adj->twinNode() == getSource()) {
299#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
300 std::cout << " * remove edge with capacity " << getCapacity(adj->theEdge())
301 << " from source " << getSource() << std::endl;
302#endif
303 OGDF_ASSERT(adj->theEdge()->source() == getSource());
304
305 // remove arcs from the source
306 m_graph.delEdge(adj->theEdge());
307 } else if (adj->twinNode() == getPseudotarget()) {
308#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
309 std::cout << " * remove edge to pseudotarget " << getPseudotarget()
310 << " with capacity " << getCapacity(adj->theEdge())
311 << " participating in delta" << std::endl;
312#endif
313 OGDF_ASSERT(adj->theEdge()->target() == getPseudotarget());
314
315 // remove arcs to the pseudotarget
316 delta -= getCapacity(adj->theEdge());
317 m_graph.delEdge(adj->theEdge());
318 } else {
319#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
320 std::cout << " * update target capacity for edge " << adj->theEdge()
321 << " by adding " << getCapacity(adj->theEdge()) << std::endl;
322#endif
323 // compute y_v for the contraction node
324 capTarget += getCapacity(adj->theEdge());
325 // compute s->v capacity
326 if (v != adj->theEdge()->target()) { // outgoing edge
327#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
328 std::cout << " and change source capacity by the same amount" << std::endl;
329#endif
330 capSource += getCapacity(adj->theEdge());
331 }
332 }
333 }
334#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
335 std::cout << " * new target capacity is " << capTarget << " and delta = " << delta
336 << std::endl;
337#endif
338 OGDF_ASSERT(capTarget >= 0);
339 if (capTarget > 0) {
340 newEdge(v, getPseudotarget(), 0, capTarget);
341#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
342 std::cout << " * new edge from pseudotarget to target with zero cost and capacity "
343 << capTarget << std::endl;
344#endif
345 }
346 if (capSource > 0) {
347#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
348 std::cout << " * new edge from source to " << v << " with zero cost and capacity "
349 << capSource << std::endl;
350#endif
351 newEdge(getSource(), v, 0, capSource);
352 }
353
354 return delta + capTarget;
355 }
356
357 void setCapacity(edge e, int capacity) { m_capacity[e] = capacity; }
358
361
364 void addCore(node e) { m_coreEdges.pushBack(e); }
365
367 void addWitness(node e, edge f) {
368 ++m_witnessCard[f];
369 m_witness[e].push(f);
370 }
371
378 m_witnessCard.init(m_graph, 0);
379 m_witness.init(m_graph);
380
381 // compute set of core edges
382 EdgeArray<bool> isLossEdge;
383 m_ceModule.call(m_graph, terminals(), isLossEdge);
384
385 // add nodes for core edges and be able to map them
386 EdgeArray<node> splitMap(m_graph, nullptr);
387 ArrayBuffer<edge> coreEdges;
388 for (edge e : m_graph.edges) {
389 if (!isLossEdge[e]) {
390 splitMap[e] = m_graph.newNode();
391 coreEdges.push(e);
392 }
393 }
394
395 // traverse losses from all terminals to find witness sets
396 NodeArray<adjEntry> pred(m_graph, nullptr);
397 for (node t : terminals()) {
398 ArrayBuffer<node> stack;
399 stack.push(t);
400 while (!stack.empty()) {
401 // for each node v "below" an edge e in the traversal:
402 // add all incident core edges vw to W(e)
403 const node v = stack.popRet();
404 for (adjEntry adj : v->adjEntries) {
405 const edge e = adj->theEdge();
406 const node w = adj->twinNode();
407 if (!pred[v] || w != pred[v]->theNode()) { // do not look at backward arcs in the tree
408 if (isLossEdge[e]) {
409 stack.push(w);
410 pred[w] = adj;
411 } else {
412 for (node x = v; pred[x]; x = pred[x]->theNode()) {
413 addWitness(splitMap[e], pred[x]->theEdge());
414 }
415 }
416 }
417 }
418 }
419 }
420
421 // finally replace core edges by nodes
422 for (edge e : coreEdges) {
423 const T w = getCost(e);
424 const node x = splitMap[e];
425 const int cap = getCapacity(e);
426 OGDF_ASSERT(x);
427 newEdge(e->source(), x, w, cap);
428 newEdge(x, e->target(), 0, cap);
429 // the cost of a core edge node is hence the weight of one incident edge;
430 // also keep capacity.
431 // Note that we cannot guarantee throughout the algorithm that the edge
432 // with the non-zero cost is the first one nor that it is the incoming one
433 // because both directions and adjacency orders can be changed.
434 m_graph.delEdge(e);
435 addCore(x);
436 }
437 }
438
440 void makeCWCopy(const HashArray<edge, edge>& edgeMap) {
441 for (HashConstIterator<edge, edge> pair = edgeMap.begin(); pair.valid(); ++pair) {
442 const edge eO = pair.key();
443 const edge eC = pair.info();
444 const node vO = eO->target();
445 const node vC = eC->target();
446 m_witnessCard[eC] = m_witnessCard[eO]; // copy witness cardinality
447 if (vC == vO) { // target is a terminal, so it cannot be a core edge
448 continue;
449 }
450 for (ListIterator<node> it = m_coreEdges.begin(); it.valid(); ++it) {
451 if (*it == vO) { // vO is a core edge
452 m_coreEdges.insertAfter(vC, it); // make vC a core edge
453
454 // copy witness sets
455 // XXX: do we need this or are witness sets computed after the loop again?!
456 for (edge e : m_witness[vO]) {
457 m_witness[vC].push(edgeMap[e]);
458 }
459 break;
460 }
461 }
462 }
463 }
464
466
467public:
470 const FullComponentWithExtraStore<T, double>& fullCompStore,
471 const CoreEdgeModule<T>& ceModule, double eps = 1e-8)
472 : m_fullCompStore(fullCompStore)
473 , m_eps(eps)
474 , m_terminals()
475 , m_isTerminal(m_graph, false)
476 , m_original(m_graph, nullptr)
477 , m_cost(m_graph)
479 , m_y(0)
480 , m_source(nullptr)
481 , m_pseudotarget(nullptr)
482 , m_target(nullptr)
483 , m_ceModule(ceModule) {
484 computeLCM();
485
486#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
487 std::cout << "Full components to use in blowup graph:\n";
488 for (int k = 0; k < m_fullCompStore.size(); ++k) {
489 std::cout << " * " << m_fullCompStore.terminals(k) << " cost "
490 << m_fullCompStore.cost(k) << " support " << m_fullCompStore.extra(k)
491 << " (normalized to " << m_fullCompStore.extra(k) * m_lcm << ")" << std::endl;
492 }
493#endif
494
497 initTarget();
498 }
499
502
503 const Graph& getGraph() const { return m_graph; }
504
506 node getSource() const { return m_source; }
507
510
512 node getTarget() const { return m_target; }
513
515 int getCapacity(edge e) const { return m_capacity[e]; }
516
518 const EdgeArray<int>& capacities() const { return m_capacity; }
519
521 T getCost(edge e) const { return m_cost[e]; }
522
524 node getOriginal(node v) const { return m_original[v]; }
525
527 int getLCM() const { return m_lcm; }
528
530 int getY() const { return m_y; }
531
533 const List<node>& terminals() const { return m_terminals; }
534
536 bool isTerminal(node v) const { return m_isTerminal[v]; }
537
541
544 OGDF_ASSERT(v->degree() == 2);
545 return getCapacity(v->firstAdj()->theEdge());
546 }
547
549 T getCoreCost(node v) const {
550 OGDF_ASSERT(v->degree() == 2);
551 T val = getCost(v->firstAdj()->theEdge());
552 if (val == 0) {
553 val = getCost(v->lastAdj()->theEdge());
554 }
555 return val;
556 }
557
559 double computeCoreWeight(node v) const {
560 double weight = (double)getCoreCost(v);
561 for (edge e : witnessList(v)) {
563 weight += (double)getCost(e) / numberOfWitnesses(e);
564 }
565 return weight;
566 }
567
569
572#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
573 std::cout << "Updating capacities (y = " << m_y << ")" << std::endl;
574#endif
575 for (node t : terminals()) {
577#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
578 std::cout << " * new y = " << m_y << std::endl;
579#endif
580 }
581 // XXX: doing it for v and all terminals we have met during cleanup would be sufficient
582 OGDF_ASSERT(getTarget()->degree() == 1);
583 setCapacity(getTarget()->firstAdj()->theEdge(), m_y);
584 }
585
587 edge newEdge(node v, node w, T cost, int capacity) {
588 edge e = m_graph.newEdge(v, w);
589 m_cost[e] = cost;
590 m_capacity[e] = capacity;
591 return e;
592 }
593
596 for (edge e : edges) {
597 m_graph.delEdge(e);
598 }
599 }
600
602 void contract(node& v, node t) {
603 if (v->degree() == 0) {
604 std::swap(v, t);
605 }
606
608 m_terminals.removeFirst(t);
609 m_isTerminal[t] = false;
610
611 if (t->degree() > 0) {
612 v = m_graph.contract(m_graph.newEdge(v, t));
613 // the contract method ensures that capacities, weights, and everything is kept
614 } else {
615 m_graph.delNode(t);
616 }
617 }
618
620 template<typename NODELIST>
621 void contract(NODELIST& nodes) {
622 auto it = nodes.begin();
623 node v = *it;
624 for (++it; it != nodes.end(); ++it) {
625 contract(v, *it);
626 }
627 }
628
635 ArrayBuffer<node> cleanup;
636 cleanup.push(v->firstAdj()->twinNode());
637 cleanup.push(v->lastAdj()->twinNode());
638 OGDF_ASSERT(v->degree() == 2);
639 OGDF_ASSERT(v->firstAdj()->twinNode() != v->lastAdj()->twinNode());
640 m_graph.delNode(v);
641
642 while (!cleanup.empty()) {
643 v = cleanup.popRet();
644 if (!isTerminal(v)) {
645 OGDF_ASSERT(v->degree() >= 1);
646 if (v->degree() == 1) { // v is a pendant node, delete
647#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
648 std::cout << " * remove pendant node " << v << " for cleanup" << std::endl;
649#endif
650 cleanup.push(v->firstAdj()->twinNode());
651 m_graph.delNode(v);
652 } else if (v->indeg() == 0) { // v has no incoming edge, fix
653#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
654 std::cout << " * " << v << " has no incoming edge -> fix directions"
655 << std::endl;
656#endif
657 const node w = v->firstAdj()->twinNode();
658 const edge e = v->firstAdj()->theEdge();
659#ifdef OGDF_STEINER_TREE_GOEMANS_BLOWUP_GRAPH_LOGGING
660 std::cout << " * make " << w << " parent of " << v << " (reverse edge "
661 << e << ")" << std::endl;
662#endif
664 OGDF_ASSERT(e->source() == w);
665 if (!isTerminal(w)) {
666 cleanup.push(w);
667 // when w is cleaned up, it must not go back to v
668 if (w->firstAdj()->theEdge() == e) {
669 // move first adjacency entries of w away (w->v is not first anymore)
671 }
672 }
673 }
674 }
675 }
676 }
677
680 for (ListIterator<node> it = m_terminals.begin(), itNext; it.valid(); it = itNext) {
681 itNext = it.succ();
682 if ((*it)->degree() == 0) {
683 m_graph.delNode(*it);
684 m_terminals.del(it);
685 }
686 }
687 }
688
691 edge rootEdge = nullptr;
693 for (auto it = v->adjEntries.begin(); it != v->adjEntries.end();) {
694 edge e = (*it)->theEdge();
695 if (e->source() != v) { // incoming edge
696 rootEdge = e;
697 if (isTerminal(e->source())) {
698 break;
699 }
700 v = e->source();
701 it = v->adjEntries.begin();
702 } else {
703 ++it;
704 }
705 }
706 OGDF_ASSERT(rootEdge != nullptr);
707 OGDF_ASSERT(isTerminal(rootEdge->source()));
708 return rootEdge;
709 }
710
712 void copyComponent(const edge origEdge, const int origCap, const int copyCap) {
713 if (copyCap == 0) {
714 return;
715 }
716 List<edge> todo;
717 List<node> origin;
718 HashArray<edge, edge> edgeMap;
719 todo.pushBack(origEdge);
720 origin.pushBack(origEdge->source());
721 while (!todo.empty()) {
722 edge eO = todo.popFrontRet();
723 node vC = origin.popFrontRet();
724 node wO = eO->target();
725 node wC = wO;
726 if (!isTerminal(wO)) {
727 wC = initNode(getOriginal(wO));
728 }
729 edge eC = newEdge(vC, wC, getCost(eO), copyCap);
730 setCapacity(eO, origCap);
731 edgeMap[eO] = eC;
732 if (!isTerminal(wO)) {
733 for (adjEntry adj = eO->adjTarget()->cyclicSucc(); adj != eO->adjTarget();
734 adj = adj->cyclicSucc()) {
735 OGDF_ASSERT(adj->theEdge()->target() != eO->target()); // outgoing edges
736 origin.pushBack(wC);
737 todo.pushBack(adj->theEdge());
738 }
739 }
740 }
741 makeCWCopy(edgeMap);
742 }
743
746
748 const List<node>& core() const { return m_coreEdges; }
749
752 void delCore(node e) {
753 /* What happens when we remove a core edge?
754 * - loss edges are not affected
755 * - we have to remove a core edge e from W(f) for all f, which means:
756 * for all elements f of witness[v_e], decrease witnessCard[f], then remove witness[v_e]
757 */
758 for (edge f : m_witness[e]) {
759 --m_witnessCard[f];
760 }
761 // witness[e] is removed by removing the node from the graph
762 m_coreEdges.removeFirst(e);
763 }
764
766 int numberOfWitnesses(edge e) const { return m_witnessCard[e]; }
767
769 const ArrayBuffer<edge>& witnessList(node e) const { return m_witness[e]; }
770
772};
773
774}
775}
776}
Declaration and implementation of ArrayBuffer class.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration and implementation of HashArray class.
Declaration of classes used for hashing.
Declaration of doubly linked lists and iterators.
Mathematical Helpers.
Basic declarations, included by all source files.
Class for adjacency list elements.
Definition Graph_d.h:143
adjEntry twin() const
Returns the corresponding adjacency element associated with the same edge.
Definition Graph_d.h:173
adjEntry cyclicSucc() const
Returns the cyclic successor in the adjacency list.
Definition Graph_d.h:355
adjEntry succ() const
Returns the successor in the adjacency list.
Definition Graph_d.h:219
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition Graph_d.h:161
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition Graph_d.h:176
node theNode() const
Returns the node whose adjacency list contains this element.
Definition Graph_d.h:167
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
Definition ArrayBuffer.h:64
E popRet()
Removes the newest element from the buffer and returns it.
void push(E e)
Puts a new element in the buffer.
bool empty() const
Returns true if the buffer is empty, false otherwise.
Class for the representation of edges.
Definition Graph_d.h:364
adjEntry adjTarget() const
Returns the corresponding adjacancy entry at target node.
Definition Graph_d.h:411
node target() const
Returns the target node of the edge.
Definition Graph_d.h:402
node source() const
Returns the source node of the edge.
Definition Graph_d.h:399
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:866
node contract(edge e, bool keepSelfLoops=false)
Contracts edge e while preserving the order of adjacency entries.
virtual void delNode(node v)
Removes node v and all incident edges from the graph.
void reverseEdge(edge e)
Reverses the edge e, i.e., exchanges source and target node.
virtual void delEdge(edge e)
Removes edge e from the graph.
node newNode(int index=-1)
Creates a new node and returns it.
Definition Graph_d.h:1061
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) and returns it.
Definition Graph_d.h:1080
void moveAdjAfter(adjEntry adjMove, adjEntry adjAfter)
Moves adjacency entry adjMove after adjAfter.
Definition Graph_d.h:1544
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:932
Indexed arrays using hashing for element access.
Definition HashArray.h:93
HashConstIterator< I, E, H > begin() const
Returns an iterator to the first element in the list of all elements.
Definition HashArray.h:112
Iterators for hash tables.
Definition Hashing.h:432
Doubly linked lists (maintaining the length of the list).
Definition List.h:1451
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition List.h:1547
E popFrontRet()
Removes the first element from the list and returns it.
Definition List.h:1591
Encapsulates a pointer to a list element.
Definition List.h:113
bool valid() const
Returns true iff the iterator points to an element.
Definition List.h:153
bool empty() const
Returns true iff the list is empty.
Definition List.h:286
Class for the representation of nodes.
Definition Graph_d.h:241
int indeg() const
Returns the indegree of the node.
Definition Graph_d.h:278
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition Graph_d.h:284
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition Graph_d.h:272
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition Graph_d.h:287
adjEntry lastAdj() const
Returns the last entry in the adjacency list.
Definition Graph_d.h:290
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition Graph_d.h:717
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
bool isTerminal(int id, node t) const
checks if a given node t is a terminal in the full component with given id
T cost(int i) const
Returns the sum of edge costs of this full component.
const EdgeWeightedGraph< T > & graph() const
const Array< node > & terminals(int id) const
Returns the list of terminals in the full component with given id.
int size() const
Returns the number of full components in the store.
A data structure to store full components with extra data for each component.
ExtraDataType & extra(int i)
Returns a reference to the extra data of this full component.
A special-purpose blowup graph for gammoid computation: directed, with special source and target,...
Definition BlowupGraph.h:70
T getCost(edge e) const
Returns the cost of e.
void removeBasis(node v)
Removes a basis and cleans up.
List< node > m_terminals
The terminals in the blowup graph.
Definition BlowupGraph.h:76
const EdgeArray< int > & capacities() const
Returns a reference to the edge array containing all capacities.
void contract(node &v, node t)
Contracts node v and terminal t into v.
void setCapacity(edge e, int capacity)
void initBlowupGraphComponents(const EdgeWeightedGraph< T > &originalGraph, const List< node > &terminals)
Initializes all components in the blowup graph as well as core edges and witness sets.
int numberOfWitnesses(edge e) const
Return the number of witnesses of an edge.
void delEdges(ArrayBuffer< edge > edges)
Removes edges in edges.
void removeIsolatedTerminals()
Removes isolated terminals.
int getY() const
Returns the y-value of all terminals.
int getLCM() const
Returns the least common multiple of all denominators.
node getSource() const
Returns the source node.
void initSource(ArrayBuffer< std::pair< node, int > > &roots)
Connects source to component roots.
void initCoreWitness()
Finds a "random" set of core edges and "replace" found edges by nodes, also find the witness sets for...
void delCore(node e)
Remove a core edge.
edge newEdge(node v, node w, T cost, int capacity)
Adds and returns a new edge between v and w of specified cost and capacity.
void addWitness(node e, edge f)
Adds e to W(f)
node getTarget() const
Returns the target node.
List< node > m_coreEdges
the core edges as nodes
Definition BlowupGraph.h:97
void copyComponent(const edge origEdge, const int origCap, const int copyCap)
Copy a component in the blowup graph and set original capacity to origCap and capacity of copy to cop...
void addCore(node e)
Adds a core edge.
double computeCoreWeight(node v) const
Compute the weight of a core edge.
const FullComponentWithExtraStore< T, double > & m_fullCompStore
all enumerated full components, with solution
Definition BlowupGraph.h:73
int getCapacity(edge e) const
Returns the capacity of e.
edge findRootEdge(node v)
Finds the root node of a component given by v, an arbitrary inner nonterminal of the component.
NodeArray< ArrayBuffer< edge > > m_witness
const List< node > & terminals() const
Returns a reference to the list containing all terminals in the blowup graph.
node getPseudotarget() const
Returns the pseudotarget node.
T getCoreCost(node v) const
Get cost of a core edge.
const double m_eps
epsilon for double operations
Definition BlowupGraph.h:74
node initBlowupGraphComponent(const NodeArray< node > &copy, adjEntry start, int cap)
Does a bfs of the component tree to add directed components with the first terminal as root.
void updateSpecialCapacities()
Updates capacities from source to terminals and terminals to pseudotarget.
node initTerminal(node t)
Inserts a terminal.
void contract(NODELIST &nodes)
Contracts nodes.
void makeCWCopy(const HashArray< edge, edge > &edgeMap)
Copies witness sets and core edges for a given copy map.
node getOriginal(node v) const
Returns the original node of v.
void initPseudotarget()
Connects pseudotarget.
NodeArray< bool > m_isTerminal
Incidence vector for the blowup graph terminals.
Definition BlowupGraph.h:77
void computeLCM()
Computes the least common multiple of the values assigned to the full components.
bool isTerminal(node v) const
Returns true if and only if v is a terminal.
const CoreEdgeModule< T > & m_ceModule
Definition BlowupGraph.h:95
NodeArray< node > m_original
Mapping of blowup graph nodes to original nodes. If a node in a blowup graph represents more than one...
Definition BlowupGraph.h:84
int updateSourceAndTargetArcCapacities(const node v)
Updates arc capacities s->v and v->t.
T getCoreCapacity(node v) const
Get capacity of a core edge.
BlowupGraph(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const FullComponentWithExtraStore< T, double > &fullCompStore, const CoreEdgeModule< T > &ceModule, double eps=1e-8)
Initializes a blowup graph including core edges and witness sets.
const ArrayBuffer< edge > & witnessList(node e) const
Return list of loss edges f in W(e)
const List< node > & core() const
Return list of core edges (implemented by nodes)
Interface for core edge finder algorithms.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
T lcm(T a, T b)
Returns the least common multipler of two numbers.
Definition Math.h:197
T gcd(T a, T b)
Returns the greatest common divisor of two numbers.
Definition Math.h:175
void getFraction(double d, int &num, int &denom, const double epsilon=5e-10, const int count=10)
Converts a double to a fraction.
Definition Math.h:204
The namespace for all OGDF objects.