|
Open Graph Drawing Framework |
v. 2023.09 (Elderberry)
|
|
|
Go to the documentation of this file.
53 class 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()) {
295 for (
node v : weakComp) {
296 node w = m_steinerGraph.original(v);
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;
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;
void init()
Intializes all relevant variables.
Declaration and implementation of HashArray class.
The namespace for all OGDF objects.
Includes declaration of graph class.
EdgeArray< edge > m_origMapping
maps each directed edge to its undirected original
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
EdgeArray< bool > m_edgeInclusions
stores the resulting Steiner tree
GraphCopy m_steinerGraph
the to-be constructed "almost" Steiner tree
void setOriginalGraph(const Graph *wG) override
Associates the graph copy with G, but does not create any nodes or edges.
E popFrontRet()
Removes the first element from the list and returns it.
Copies of graphs supporting edge splitting.
edge newEdge(node u, node v, T weight)
EdgeArray< T > m_edgeSlacks
slack variables for each directed edge representing the adjusted weight
int findComponent(const node v) const
Returns the component of node v.
Class for adjacency list elements.
Extends the GraphCopy concept to weighted graphs.
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
Declaration of ogdf::MinSteinerTreeModule.
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.
edge theEdge() const
Returns the edge associated with this adjacency entry.
Decralation of GraphElement and GraphList classes.
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Indexed arrays using hashing for element access.
int strongComponents(const Graph &G, NodeArray< int > &component)
Computes the strongly connected components of the digraph G.
const EdgeWeightedGraph< T > * m_pOrigGraph
original graph passed to the module
node source() const
Returns the source node of the edge.
const NodeArray< bool > * m_pIsTerminal
terminal incidence vector passed to the module
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
Declaration of graph copy classes.
Doubly linked lists (maintaining the length of the list).
RegisteredArray for nodes, edges and adjEntries of a graph.
GraphCopy m_diGraph
the directed graph
int findActiveComponent(node *terminal) const
Searches for the next active component.
Dual ascent heuristic for the minimum Steiner tree problem.
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
node m_rootTerminal
root node
const List< node > * m_pTerminals
list of terminals passed to the module
void updateComponents()
Re-establishes all strongly connected components for the Steiner graph.
Basic declarations, included by all source files.
bool isTerminal(const node v, bool rootIsTerminal) const
Returns whether this node is a terminal.
bool isActiveComponent(const node v) const
Determines whether a strongly connected component is active (paper says "is root component").
Class for the representation of edges.
Declaration of doubly linked lists and iterators.
const Graph * graphOf() const
Returns the graph containing this node (debug only).
node target() const
Returns the target node of the edge.
NodeArray< int > m_componentMapping
maps each node to its component
Class for the representation of nodes.
Declaration of simple graph algorithms.
List< edge > * computeCutSet(const node v) const
Returns all incoming cut edges of the component of v.
iterator pushBack(const E &x)
Adds element x at the end of the list.
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
void clear()
Removes all elements from the list.