53class EdgeWeightedGraph;
166 m_pOrigGraph->allNodes(nodes);
168 m_pOrigGraph->allEdges(edges);
172 m_diGraph.setOriginalGraph(*m_pOrigGraph);
174 m_edgeSlacks.init(m_diGraph);
175 m_origMapping.init(m_diGraph);
178 m_steinerGraph.setOriginalGraph(m_diGraph);
179 m_steinerGraph.clear();
180 m_componentMapping.init(m_steinerGraph);
183 m_rootTerminal = m_pTerminals->chooseElement();
185 for (
node v : nodes) {
186 node w = m_diGraph.newNode(v);
187 m_steinerGraph.newNode(w);
190 for (
edge e : edges) {
191 node source = m_diGraph.copy(e->source());
192 node target = m_diGraph.copy(e->target());
193 edge copiedEdgeS = m_diGraph.newEdge(source, target);
194 edge copiedEdgeT = m_diGraph.newEdge(target, source);
195 m_edgeSlacks[copiedEdgeS] = m_edgeSlacks[copiedEdgeT] = m_pOrigGraph->weight(e);
196 m_origMapping[copiedEdgeS] = m_origMapping[copiedEdgeT] = e;
200#ifdef OGDF_DUAL_ASCENT_LOGGING
201 std::cout <<
"directed graph has " << m_diGraph.numberOfNodes() <<
" nodes "
202 <<
"and " << m_diGraph.numberOfEdges() <<
" edges." << std::endl
203 <<
"root terminal is node " << m_rootTerminal <<
"." << std::endl;
211 return m_componentMapping[v];
223 node w = m_diGraph.original(m_steinerGraph.original(v));
224 return (m_rootTerminal != w || rootIsTerminal) && (*m_pIsTerminal)[w];
231#ifdef OGDF_DUAL_ASCENT_LOGGING
232 std::cout <<
" searching for active component.." << std::endl;
236 for (
auto it = m_pTerminals->begin(); it != m_pTerminals->end() && result == -1; it++) {
237 if (*it != m_rootTerminal) {
238 node v = m_steinerGraph.copy(m_diGraph.copy(*it));
239 int candidate = findComponent(v);
240 if (!checked[candidate]) {
241 checked[candidate] =
true;
242 bool isRoot = isActiveComponent(v);
247#ifdef OGDF_DUAL_ASCENT_LOGGING
248 std::cout <<
" active component found: component " << result <<
", terminal "
249 << *terminal << std::endl;
256#ifdef OGDF_DUAL_ASCENT_LOGGING
258 std::cout <<
" could not find an active component" << std::endl;
272 visited[root] =
true;
279 while (!queue.
empty()) {
283 edge e = adj->theEdge();
295 for (
node v : weakComp) {
296 node w = m_steinerGraph.original(v);
298 edge e = adj->theEdge();
299 if (!visited[m_steinerGraph.copy(e->
source())]) {
312 int comp = findComponent(source);
313 bool danglingTerminalFound =
false;
314 bool hasTerminal =
false;
316#ifdef OGDF_DUAL_ASCENT_LOGGING
317 std::cout <<
" checking whether component of node " << source <<
" is active.. " << std::endl;
318 std::cout <<
" component has id " << comp << std::endl;
324 visited[source] =
true;
325#ifdef OGDF_DUAL_ASCENT_LOGGING
326 while (!queue.
empty()) {
328 while (!queue.
empty() && !danglingTerminalFound) {
331 hasTerminal |= isTerminal(v,
false) && findComponent(v) == comp;
333 edge e = adj->theEdge();
336 danglingTerminalFound |= isTerminal(w,
true) && findComponent(w) != comp;
343#ifdef OGDF_DUAL_ASCENT_LOGGING
345 std::cout <<
" component includes a terminal" << std::endl;
347 if (danglingTerminalFound) {
348 std::cout <<
" component has dangling terminal" << std::endl;
350 if (hasTerminal && !danglingTerminalFound) {
351 std::cout <<
" component is active!" << std::endl;
354 return hasTerminal && !danglingTerminalFound;
361#ifdef OGDF_DUAL_ASCENT_LOGGING
362 std::cout <<
"MinSteinerTreeDualAscent called." << std::endl;
363 std::cout <<
"terminals are: ";
365 for (
node v : terminals) {
366 std::cout << v <<
" ";
368 std::cout << std::endl;
371 m_pTerminals = &terminals;
372 m_pIsTerminal = &isTerminal;
382 node terminal =
nullptr;
384#ifdef OGDF_DUAL_ASCENT_LOGGING
385 std::cout <<
"main loop starting.." << std::endl;
387 while ((comp = findActiveComponent(&terminal)) != -1) {
393 List<edge>* cutEdges = computeCutSet(m_steinerGraph.copy(m_diGraph.copy(terminal)));
394 edge minEdge =
nullptr;
395 T minSlack = MAX_VALUE;
396#ifdef OGDF_DUAL_ASCENT_LOGGING
397 std::cout <<
" cut edges:";
399 for (
edge e : *cutEdges) {
400#ifdef OGDF_DUAL_ASCENT_LOGGING
401 std::cout <<
" " << e;
403 if (m_edgeSlacks[e] < MAX_VALUE || minEdge ==
nullptr) {
405 minSlack = m_edgeSlacks[e];
408#ifdef OGDF_DUAL_ASCENT_LOGGING
409 std::cout << std::endl <<
" next edge: " << minEdge << std::endl;
414 for (
edge e : *cutEdges) {
415 m_edgeSlacks[e] -= minSlack;
420 m_steinerGraph.newEdge(minEdge);
424 edge origEdge = m_origMapping[minEdge];
425 T cost = m_pOrigGraph->weight(origEdge);
426 if (finalSteinerTree->
copy(origEdge->
source()) ==
nullptr) {
429 if (finalSteinerTree->
copy(origEdge->
target()) ==
nullptr) {
432 if (finalSteinerTree->
copy(origEdge) ==
nullptr) {
433 finalSteinerTree->
newEdge(origEdge, cost);
438#ifdef OGDF_DUAL_ASCENT_LOGGING
439 std::cout <<
"removing expendable edges" << std::endl;
441 result -= this->pruneAllDanglingSteinerPaths(*finalSteinerTree, *m_pIsTerminal);
442 result -= this->removeCyclesFrom(*finalSteinerTree, *m_pIsTerminal);
444#ifdef OGDF_DUAL_ASCENT_LOGGING
445 std::cout <<
"algorithm terminated." << std::endl;
Extends the GraphCopy concept to weighted graphs.
Includes declaration of graph class.
Declaration of graph copy classes.
Decralation of GraphElement and GraphList classes.
Declaration and implementation of HashArray class.
Declaration of doubly linked lists and iterators.
Declaration of ogdf::MinSteinerTreeModule.
Basic declarations, included by all source files.
Class for adjacency list elements.
Class for the representation of edges.
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.
Copies of graphs supporting edge splitting.
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
Indexed arrays using hashing for element access.
Doubly linked lists (maintaining the length of the list).
void clear()
Removes all elements from the list.
iterator pushBack(const E &x)
Adds element x at the end of the list.
E popFrontRet()
Removes the first element from the list and returns it.
bool empty() const
Returns true iff the list is empty.
Dual ascent heuristic for the minimum Steiner tree problem.
GraphCopy m_steinerGraph
the to-be constructed "almost" Steiner tree
GraphCopy m_diGraph
the directed graph
void init()
Intializes all relevant variables.
NodeArray< int > m_componentMapping
maps each node to its component
List< edge > * computeCutSet(const node v) const
Returns all incoming cut edges of the component of v.
bool isTerminal(const node v, bool rootIsTerminal) const
Returns whether this node is a terminal.
EdgeArray< T > m_edgeSlacks
slack variables for each directed edge representing the adjusted weight
T computeSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree)
Creates a minimum Steiner tree given a weighted graph and a list of terminals.
void updateComponents()
Re-establishes all strongly connected components for the Steiner graph.
const List< node > * m_pTerminals
list of terminals passed to the module
EdgeArray< edge > m_origMapping
maps each directed edge to its undirected original
const EdgeWeightedGraph< T > * m_pOrigGraph
original graph passed to the module
int findActiveComponent(node *terminal) const
Searches for the next active component.
EdgeArray< bool > m_edgeInclusions
stores the resulting Steiner tree
node m_rootTerminal
root node
const NodeArray< bool > * m_pIsTerminal
terminal incidence vector passed to the module
int findComponent(const node v) const
Returns the component of node v.
bool isActiveComponent(const node v) const
Determines whether a strongly connected component is active (paper says "is root component").
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
Class for the representation of nodes.
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
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.
int strongComponents(const Graph &G, NodeArray< int > &component)
Computes the strongly connected components of the digraph G.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
The namespace for all OGDF objects.
Declaration of simple graph algorithms.