154 m_pOrigGraph->allNodes(nodes);
156 m_pOrigGraph->allEdges(edges);
160 m_diGraph.createEmpty(*m_pOrigGraph);
162 m_edgeSlacks.init(m_diGraph);
163 m_origMapping.init(m_diGraph);
166 m_steinerGraph.createEmpty(m_diGraph);
167 m_steinerGraph.clear();
168 m_componentMapping.init(m_steinerGraph);
171 m_rootTerminal = m_pTerminals->chooseElement();
173 for (
node v : nodes) {
174 node w = m_diGraph.newNode(v);
175 m_steinerGraph.newNode(w);
178 for (
edge e : edges) {
179 node source = m_diGraph.copy(e->source());
180 node target = m_diGraph.copy(e->target());
188#ifdef OGDF_DUAL_ASCENT_LOGGING
189 std::cout <<
"directed graph has " << m_diGraph.numberOfNodes() <<
" nodes "
190 <<
"and " << m_diGraph.numberOfEdges() <<
" edges." << std::endl
191 <<
"root terminal is node " << m_rootTerminal <<
"." << std::endl;
199 return m_componentMapping[v];
211 node w = m_diGraph.original(m_steinerGraph.original(v));
212 return (m_rootTerminal != w ||
rootIsTerminal) && (*m_pIsTerminal)[w];
219#ifdef OGDF_DUAL_ASCENT_LOGGING
220 std::cout <<
" searching for active component.." << std::endl;
224 for (
auto it = m_pTerminals->begin(); it != m_pTerminals->end() && result == -1; it++) {
225 if (*it != m_rootTerminal) {
226 node v = m_steinerGraph.copy(m_diGraph.copy(*it));
230 bool isRoot = isActiveComponent(v);
235#ifdef OGDF_DUAL_ASCENT_LOGGING
236 std::cout <<
" active component found: component " << result <<
", terminal "
237 << *terminal << std::endl;
244#ifdef OGDF_DUAL_ASCENT_LOGGING
246 std::cout <<
" could not find an active component" << std::endl;
260 visited[root] =
true;
263 queue.pushBack(root);
267 while (!
queue.empty()) {
271 edge e = adj->theEdge();
284 node w = m_steinerGraph.original(v);
286 edge e = adj->theEdge();
287 if (!visited[m_steinerGraph.copy(e->
source())]) {
300 int comp = findComponent(source);
304#ifdef OGDF_DUAL_ASCENT_LOGGING
305 std::cout <<
" checking whether component of node " << source <<
" is active.. " << std::endl;
306 std::cout <<
" component has id " <<
comp << std::endl;
311 queue.pushBack(source);
312 visited[source] =
true;
313#ifdef OGDF_DUAL_ASCENT_LOGGING
314 while (!
queue.empty()) {
321 edge e = adj->theEdge();
331#ifdef OGDF_DUAL_ASCENT_LOGGING
333 std::cout <<
" component includes a terminal" << std::endl;
336 std::cout <<
" component has dangling terminal" << std::endl;
339 std::cout <<
" component is active!" << std::endl;
349#ifdef OGDF_DUAL_ASCENT_LOGGING
350 std::cout <<
"MinSteinerTreeDualAscent called." << std::endl;
351 std::cout <<
"terminals are: ";
353 for (
node v : terminals) {
354 std::cout << v <<
" ";
356 std::cout << std::endl;
359 m_pTerminals = &terminals;
360 m_pIsTerminal = &isTerminal;
370 node terminal =
nullptr;
372#ifdef OGDF_DUAL_ASCENT_LOGGING
373 std::cout <<
"main loop starting.." << std::endl;
375 while ((
comp = findActiveComponent(&terminal)) != -1) {
384#ifdef OGDF_DUAL_ASCENT_LOGGING
385 std::cout <<
" cut edges:";
388#ifdef OGDF_DUAL_ASCENT_LOGGING
389 std::cout <<
" " << e;
391 if (m_edgeSlacks[e] < MAX_VALUE ||
minEdge ==
nullptr) {
396#ifdef OGDF_DUAL_ASCENT_LOGGING
397 std::cout << std::endl <<
" next edge: " <<
minEdge << std::endl;
408 m_steinerGraph.newEdge(
minEdge);
413 T cost = m_pOrigGraph->weight(origEdge);
426#ifdef OGDF_DUAL_ASCENT_LOGGING
427 std::cout <<
"removing expendable edges" << std::endl;
429 result -= this->pruneAllDanglingSteinerPaths(*
finalSteinerTree, *m_pIsTerminal);
432#ifdef OGDF_DUAL_ASCENT_LOGGING
433 std::cout <<
"algorithm terminated." << std::endl;
Extends the GraphCopy concept to weighted graphs.
Declaration of ogdf::MinSteinerTreeModule.
Class for adjacency list elements.
Dynamic arrays indexed with edges.
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.
Copies of graphs supporting edge splitting.
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.
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...
Dynamic arrays indexed with nodes.
Class for the representation of nodes.
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
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.
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.