58class EdgeWeightedGraph;
278 m_originalGraph = &G;
279 m_originalTerminals = &terminals;
281 m_upperBound = MAX_WEIGHT;
283 m_mapping.init(m_graph);
284 m_terminals.reset(
new NodeSet(m_graph));
285 int nodeCount = m_originalGraph->numberOfNodes();
286 m_edges =
Array2D<edge>(0, nodeCount, 0, nodeCount,
nullptr);
290 for (
node v : m_originalGraph->nodes) {
291 node copiedNode = m_graph.newNode();
292 copiedNodes[v] = copiedNode;
295 for (
edge e : m_originalGraph->edges) {
296 node source = copiedNodes[e->source()], target = copiedNodes[e->target()];
298 newEdge(source, target, e);
301 for (
node v : *m_originalTerminals) {
302 setTerminal(copiedNodes[v],
true);
306 T result = solve(chosenEdges);
311 for (
edge e : chosenEdges) {
312 node v = e->source();
313 node w = e->target();
321 if (finalSteinerTree->
copy(v) ==
nullptr) {
324 if (finalSteinerTree->
copy(w) ==
nullptr) {
327 finalSteinerTree->
newEdge(e, m_originalGraph->weight(e));
335 T result = MAX_WEIGHT;
340 OGDF_ASSERT(m_mapping[e]->graphOf() == m_originalGraph);
341 result = m_originalGraph->weight(m_mapping[e]);
349 for (
edge e : m_graph.edges) {
351 OGDF_ASSERT(m_mapping[e]->graphOf() == m_originalGraph);
368 edge result = m_mapping[e];
378 edge result = m_graph.newEdge(source, target);
379 m_mapping[result] = e;
380 setEdgeLookup(source, target, result);
389 setEdgeLookup(v, e->
target(), e);
390 m_graph.moveSource(e, v);
397 setEdgeLookup(e->
source(), v, e);
398 m_graph.moveTarget(e, v);
403 return m_terminals->isMember(v);
409 m_terminals->insert(v);
411 m_terminals->remove(v);
417 m_chosenEdges.clear();
419 m_recursionDepth = 0;
421 T result = bnbInternal(0, tmp);
423 for (
edge e : m_chosenEdges) {
432 edge result =
nullptr;
436 T sumOfMinWeights = 0;
437 T sumOfMinTermWeights = 0;
438 T absoluteMinTermWeight = MAX_WEIGHT;
440 sumOfMinWeights < MAX_WEIGHT && it.valid(); ++it) {
442 T minTermWeight = MAX_WEIGHT, minWeight = MAX_WEIGHT, secondMinWeight = MAX_WEIGHT;
443 edge minEdge =
nullptr;
448 edge e = adj->theEdge();
449 if (weightOf(e) < minWeight) {
450 secondMinWeight = minWeight;
451 minWeight = weightOf(e);
454 if (weightOf(e) < secondMinWeight) {
455 secondMinWeight = weightOf(e);
459 if (isTerminal(adj->twinNode()) && weightOf(e) < minTermWeight) {
460 minTermWeight = weightOf(e);
461 if (minTermWeight < absoluteMinTermWeight) {
462 absoluteMinTermWeight = minTermWeight;
467 if (sumOfMinTermWeights < MAX_WEIGHT && minTermWeight < MAX_WEIGHT) {
468 sumOfMinTermWeights += minTermWeight;
470 sumOfMinTermWeights = MAX_WEIGHT;
472 OGDF_ASSERT(absoluteMinTermWeight <= sumOfMinTermWeights);
476 if (minWeight == MAX_WEIGHT || secondMinWeight == MAX_WEIGHT) {
478 if (minWeight == MAX_WEIGHT) {
479 sumOfMinWeights = MAX_WEIGHT;
482 sumOfMinWeights += minWeight;
484 T penalty = secondMinWeight - minWeight;
485 if (penalty > maxPenalty) {
486 maxPenalty = penalty;
493 if (result !=
nullptr) {
494 T maxCost = m_upperBound - prevCost;
495 if (sumOfMinTermWeights < MAX_WEIGHT) {
496 sumOfMinTermWeights -= absoluteMinTermWeight;
498 if (maxCost <= sumOfMinWeights && maxCost <= sumOfMinTermWeights) {
508 T result = MAX_WEIGHT;
511#ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
515 if (prevCost <= m_upperBound) {
516 if (m_terminals->size() < 2) {
518 if (prevCost != m_upperBound || m_chosenEdges.empty()) {
522 m_upperBound = prevCost;
525 edge branchingEdge = determineBranchingEdge(prevCost);
526 T branchingEdgeWeight = weightOf(branchingEdge);
528#ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
529 for (
int i = 0; i < m_recursionDepth; i++) {
532 std::cout <<
"branching on edge: " << branchingEdge << std::endl;
535 if (branchingEdgeWeight < MAX_WEIGHT) {
542 nodeToRemove = branchingEdge->
target();
543 targetNode = branchingEdge->
source();
547 edge origBranchingEdge = deleteEdge(branchingEdge);
558 while (m_graph.searchEdge(targetNode, nodeToRemove) !=
nullptr) {
559 edge e = m_graph.searchEdge(targetNode, nodeToRemove);
565 while (m_graph.searchEdge(nodeToRemove, targetNode) !=
nullptr) {
566 edge e = m_graph.searchEdge(targetNode, nodeToRemove);
573 OGDF_ASSERT(m_graph.searchEdge(targetNode, nodeToRemove) ==
nullptr);
574 OGDF_ASSERT(m_graph.searchEdge(nodeToRemove, targetNode) ==
nullptr);
578 adjNext = adj->
succ();
579 edge e = adj->theEdge();
585 edge f = lookupEdge(targetNode, adj->twinNode());
586 bool deletedEdgeE =
false;
588 if (weightOf(f) < weightOf(e)) {
603 if (e->
target() == nodeToRemove) {
606 moveTarget(e, targetNode);
611 moveSource(e, targetNode);
620 bool targetNodeIsTerminal = isTerminal(targetNode),
621 nodeToRemoveIsTerminal = isTerminal(nodeToRemove);
623 OGDF_ASSERT(targetNodeIsTerminal || nodeToRemoveIsTerminal);
624 setTerminal(nodeToRemove,
false);
625 setTerminal(targetNode,
true);
627#ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
628 for (
int i = 0; i < m_recursionDepth; i++) {
631 std::cout <<
"inclusion branch" << std::endl;
634 currentEdges.
pushFront(origBranchingEdge);
635 result = bnbInternal(branchingEdgeWeight + prevCost, currentEdges);
642 setTerminal(nodeToRemove, nodeToRemoveIsTerminal);
643 setTerminal(targetNode, targetNodeIsTerminal);
646 while (!movedEdges.
empty()) {
649 edge e = lookupEdge(v, targetNode);
654 moveTarget(e, nodeToRemove);
656 moveSource(e, nodeToRemove);
661 while (!delEdges.
empty()) {
667 newEdge(source, target, origDelEdges.
popFrontRet());
671#ifdef OGDF_MINSTEINERTREE_SHORE_LOGGING
672 for (
int i = 0; i < m_recursionDepth; i++) {
675 std::cout <<
"exclusion branch" << std::endl;
678 T exEdgeResult = bnbInternal(prevCost, currentEdges);
681 if (exEdgeResult < result) {
682 result = exEdgeResult;
686 newEdge(nodeToRemove, targetNode, origBranchingEdge);
700 m_graph.allNodes(nodes);
702 for (
node v : nodes) {
704 copiedIsTerminal[v] = isTerminal(v);
707 m_graph.allEdges(edges);
708 for (
edge e : edges) {
709 copiedGraph.
newEdge(e, weightOf(e));
711 std::stringstream filename;
712 filename <<
"bnb_internal_" << m_recursionDepth <<
".svg";
713 this->drawSteinerTreeSVG(copiedGraph, copiedIsTerminal, filename.str().c_str());
Declaration and implementation of class Array2D which implements dynamic two dimensional arrays.
Extends the GraphCopy concept to weighted graphs.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration and implementation of NodeSet, EdgeSet, and AdjEntrySet classes.
Declaration of doubly linked lists and iterators.
Declaration of ogdf::MinSteinerTreeModule.
Basic declarations, included by all source files.
Class for adjacency list elements.
adjEntry succ() const
Returns the successor in the adjacency list.
The parameterized class Array2D implements dynamic two-dimensional arrays.
Class for the representation of edges.
node opposite(node v) const
Returns the adjacent node different from v.
const Graph * graphOf() const
Returns the graph containing this node (debug only).
node target() const
Returns the target node of the edge.
node source() const
Returns the source node of the edge.
edge newEdge(node u, node v, T weight)
void setOriginalGraph(const Graph *wG) override
Re-initializes the copy using G (which might be null), but does not create any nodes or edges.
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
Data type for general directed graphs (adjacency list representation).
Doubly linked lists (maintaining the length of the list).
void popFront()
Removes the first element from the list.
void clear()
Removes all elements from the list.
iterator pushFront(const E &x)
Adds element x at the beginning of the list.
E popFrontRet()
Removes the first element from the list and returns it.
Encapsulates a pointer to a list element.
const_reference front() const
Returns a const reference to the first element.
bool empty() const
Returns true iff the list is empty.
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
Implementation of Shore, Foulds and Gibbons exact branch and bound algorithm for solving Steiner tree...
void moveSource(edge e, node v)
Moves the source of the edge to the specified node.
bool validateMapping() const
Used to validate the current mapping of edges to orignal edges Used solely for debugging.
T solve(List< edge > &chosenEdges)
Solves the current STP instance.
const EdgeWeightedGraph< T > * m_originalGraph
bool isTerminal(const node v) const
Returns whether this node is a terminal or a Steiner node.
void setEdgeLookup(const node u, const node v, const edge e)
Sets the edge incident to both node u and v.
edge lookupEdge(const node u, const node v) const
Retrieves the edge incident to both node u and v.
virtual ~MinSteinerTreeShore()
void setTerminal(const node v, bool makeTerminal)
Updates the status of the given node to either terminal or Steiner node.
edge deleteEdge(edge e)
Removes the specified edge from the graph.
virtual T computeSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree) override
Builds a minimum Steiner tree given a weighted graph and a list of terminals.
T bnbInternal(T prevCost, List< edge > ¤tEdges)
Calculates the optimal Steinter tree recursivly.
List< edge > m_chosenEdges
const List< node > * m_originalTerminals
void moveTarget(edge e, node v)
Moves the target of the edge to the specified node.
edge newEdge(node source, node target, const edge originalEdge)
Creates a new edge.
edge determineBranchingEdge(T prevCost) const
Decides which edge to branch on.
void printSVG()
Prints the current recursion status as a SVG image of the current reduced STP.
T weightOf(edge e) const
Returns the cost of the specified edge.
std::unique_ptr< NodeSet > m_terminals
EdgeArray< edge > m_mapping
Class for the representation of nodes.
int degree() const
Returns the degree of the node (indegree + outdegree).
int index() const
Returns the (unique) node index.
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
const Graph * graphOf() const
Returns the graph containing this node (debug only).
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
RegisteredArray for nodes, edges and adjEntries of a graph.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
The namespace for all OGDF objects.