41#include <forward_list>
44#include <unordered_map>
49namespace steiner_tree {
497 template<
typename TWhat,
typename TWhatArray>
595 template<
typename LAMBDA>
610 : m_origGraph(
wg), m_origTerminals(terminals), m_origIsTerminal(isTerminal), m_eps(1e-6) {
653template<
typename TWhat,
typename TWhatArray>
734 std::forward_list<NewEdgeData>
newEdges;
746 if (
f && m_copyGraph.
weight(
f) <= edgeWeight) {
760 for (
const auto& newEdge :
newEdges) {
763 if (newEdge.already) {
765 m_copyGraph.
setWeight(newEdge.already, newEdge.weight);
779 m_copyTerminals.
clear();
781 if (m_copyIsTerminal[v]) {
814 auto deleteAll = [
this]() {
828 if (m_copyTerminals.
size() == 1) {
835 if (v->degree() == 1) {
851 if (m_copyIsTerminal[v]) {
854 if (!m_copyIsTerminal[w]) {
855 m_copyIsTerminal[w] =
true;
858 m_copyTerminals.
del(m_copyTerminals.
search(v));
859 m_costAlreadyInserted += m_copyGraph.
weight(e);
860 int cur = m_nodeSonsListIndex[w];
862 m_sonsList.emplace_back(
863 std::vector<int> {
cur, m_nodeSonsListIndex[v], m_edgeSonsListIndex[e]});
864 m_nodeSonsListIndex[w] = (
int)m_sonsList.
size() - 1;
866 m_sonsList[
cur].push_back(m_nodeSonsListIndex[v]);
867 m_sonsList[
cur].push_back(m_edgeSonsListIndex[e]);
875 if (m_copyTerminals.
size() == 1) {
891 edge e = adj->theEdge();
914 for (
adjEntry adj : v->adjEntries) {
925 node v2 = adj->twinNode();
951 shortestPath[v].init(m_copyGraph, std::numeric_limits<T>::max());
968 edge e = adj->theEdge();
986 if (m_copyIsTerminal[v] || v->degree() != 2) {
1014 for (
node v : m_copyTerminals) {
1016 std::cerr <<
"terminals in different connected components!\n";
1064 distance[source] = 0;
1065 queue.push(source, distance[source]);
1067 while (!
queue.empty()) {
1074 edge e = adj->theEdge();
1104 yDistance(m_copyGraph, std::numeric_limits<T>::max());
1114 if (
yDistance[commonNode] == std::numeric_limits<T>::max()) {
1141 std::unordered_map<
NodePair,
typename NodePairQueue::Handle,
1146 for (
node v : m_copyTerminals) {
1157 return static_cast<T
>(-1);
1189 while (!
queue.empty()) {
1201 edge e = adj->theEdge();
1263 if (m_copyTerminals.
size() <= 2) {
1283 if (m_copyIsTerminal[v]) {
1292 for (
adjEntry adj : v->adjEntries) {
1355 edge e = adj->theEdge();
1374 edge e = adj->theEdge();
1375 if (first ==
nullptr
1396 node x = e->source(), y = e->target();
1397 m_sonsList.emplace_back(std::vector<int> {
1398 m_nodeSonsListIndex[x], m_nodeSonsListIndex[y], m_edgeSonsListIndex[e]});
1399 m_costAlreadyInserted += m_copyGraph.
weight(e);
1401 m_nodeSonsListIndex[newNode] = (
int)m_sonsList.
size() - 1;
1402 m_copyIsTerminal[newNode] =
true;
1405 recomputeTerminalsList();
1421 for (
node terminal : m_copyTerminals) {
1422 if (terminal->degree() >= 2) {
1430 for (
node terminal : m_copyTerminals) {
1431 if (terminal->degree() >= 2) {
1443 node x = e->source(), y = e->target();
1462 for (
node terminal : m_copyTerminals) {
1463 if (terminal->degree() >= 2) {
1503 const node x = e->source(), y = e->target();
1514 for (
node terminal : m_copyTerminals) {
1521 const node x =
e1->source(), y =
e1->target();
1546 for (
adjEntry adj : v->adjEntries) {
1547 edge e = adj->theEdge();
1559 const T upperBound) {
1575 if (m_copyTerminals.
size() <= 1) {
1590 if (m_copyIsTerminal[v]) {
1611 node x = e->source(), y = e->target();
1623 Graph auxiliaryGraph;
1625 for (
node terminal : m_copyTerminals) {
1639 EdgeArray<T> edgeWeight(auxiliaryGraph, std::numeric_limits<T>::max());
1641 node x = e->source(), y = e->target();
1689 if (m_copyTerminals.
size() > 1) {
1704 const T upperBound) {
1725 for (
node terminal : m_copyTerminals) {
1791 for (
node terminal : m_copyTerminals) {
1809 == std::numeric_limits<T>::max()
1832template<
typename LAMBDA>
1838 distance.
init(m_copyGraph);
1842 for (
node terminal : m_copyTerminals) {
1843 if (predecessor[terminal] ==
nullptr) {
1866 if (m_copyTerminals.
size() <= 2) {
1882 for (
node terminal : m_copyTerminals) {
1883 for (
adjEntry adj : terminal->adjEntries) {
1893 std::set<edge> delEdges;
1914 node w = adj->twinNode();
1915 if (m_copyIsTerminal[w]) {
1937 + m_copyGraph.
weight(adj->theEdge()),
1939 delEdges.insert(adj->theEdge());
1946 for (
edge e : delEdges) {
Declaration and implementation of bounded queue class.
Definition of the ogdf::steiner_tree:HeavyPathDecomposition class template.
Implementation of Mehlhorn's minimum Steiner tree 2(1-1/l)-approximation algorithm.
Implementation of the 2(1-1/l)-approximation algorithm for the minimum Steiner tree problem by Matsuy...
Definition of the ogdf::SteinerTreeLowerBoundDualAscent class template.
A class that allows to enumerate k-subsets.
Class for adjacency list elements.
edge theEdge() const
Returns the edge associated with this adjacency entry.
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
The parameterized class Array implements dynamic arrays of type E.
INDEX size() const
Returns the size (number of elements) of the array.
The parameterized class BoundedQueue implements queues with bounded size.
Dijkstra's single source shortest path algorithm.
Dynamic arrays indexed with edges.
void init()
Reinitializes the array. Associates the array with no graph.
Class for the representation of edges.
int index() const
Returns the index of the edge.
node opposite(node v) const
Returns the adjacent node different from v.
void createEmpty(const Graph &wG)
T weight(const edge e) const
edge newEdge(node v, node w, T weight)
const EdgeArray< T > & edgeWeights() const
void setWeight(const edge e, T weight)
std::enable_if< std::is_integral< T >::value, bool >::type leq(const T &x, const T &y) const
Compare if x is LEQ than y for integral types.
std::enable_if< std::is_integral< T >::value, bool >::type geq(const T &x, const T &y) const
Compare if x is GEQ to y for integral types.
std::enable_if< std::is_integral< T >::value, bool >::type less(const T &x, const T &y) const
Compare if x is LESS than y for integral types.
std::enable_if< std::is_integral< T >::value, bool >::type equal(const T &x, const T &y) const
Compare if x is EQUAL to y for integral types.
std::enable_if< std::is_integral< T >::value, bool >::type greater(const T &x, const T &y) const
Compare if x is GREATER than y for integral types.
Data type for general directed graphs (adjacency list representation).
node contract(edge e, bool keepSelfLoops=false)
Contracts edge e while preserving the order of adjacency entries.
int numberOfNodes() const
Returns the number of nodes in the graph.
edge firstEdge() const
Returns the first edge in the list of all edges.
edge newEdge(node v, node w)
Creates a new edge (v,w) and returns it.
virtual void delNode(node v)
Removes node v and all incident edges from the graph.
int numberOfEdges() const
Returns the number of edges in the graph.
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
virtual void delEdge(edge e)
Removes edge e from the graph.
node firstNode() const
Returns the first node in the list of all nodes.
bool empty() const
Returns true iff the graph is empty, i.e., contains no nodes.
node newNode()
Creates a new node and returns it.
edge searchEdge(node v, node w, bool directed=false) const
Searches and returns an edge connecting nodes v and w in time O( min(deg(v ), deg(w ))).
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Doubly linked lists (maintaining the length of the list).
int size() const
Returns the number of elements in the list.
void clear()
Removes all elements from the list.
iterator pushBack(const E &x)
Adds element x at the end of the list.
void del(iterator it)
Removes it from the list.
Encapsulates a pointer to a list element.
ListIteratorBase< E, isConst, isReverse > succ() const
Returns successor iterator.
const_reference front() const
Returns a const reference to the first element.
ListConstIterator< E > search(const E &e) const
Scans the list for the specified element and returns an iterator to the first occurrence in the list,...
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
This class implements the minimum Steiner tree 2-approximation algorithm by Takahashi and Matsuyama w...
Dynamic arrays indexed with nodes.
void init()
Reinitializes the array. Associates the array with no graph.
Class for the representation of nodes.
int degree() const
Returns the degree of the node (indegree + outdegree).
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
int index() const
Returns the (unique) node index.
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Prioritized queue interface wrapper for heaps.
Implementation of a dual-ascent-based lower bound heuristic for Steiner tree problems.
This class implements preprocessing strategies for the Steiner tree problem.
T computeMinSteinerTreeUpperBound(EdgeWeightedGraphCopy< T > *&finalSteinerTree) const
bool degree2Test()
deletes degree-2 nodes and replaces them with one edge with the adjacent edges' sum
bool deleteLeaves()
Deletes the leaves of the graph.
bool reduceFastAndDualAscent()
Apply fast reductions and the dual-ascent-based tests iteratively.
void computeOriginalSolution(const EdgeWeightedGraphCopy< T > &reducedGraphSolution, EdgeWeightedGraphCopy< T > &correspondingOriginalSolution)
Computes the solution for the original graph, given a solution on the reduction.
bool deleteEdgesAboveUpperBound(const EdgeArray< T > &lowerBoundWithEdge, const T upperBound)
Deletes the edges whose lowerBoundWithEdge exceeds upperBound.
bool cutReachabilityTest()
Performs a cut reachability test [DV89].
void computeShortestPathMatrix(NodeArray< NodeArray< T > > &shortestPath) const
Computes the shortest path matrix corresponding to the m_copyGraph.
const EdgeWeightedGraph< T > & getReducedGraph() const
Returns the reduced form of the graph.
bool dualAscentBasedTest(int repetitions=1)
Like dualAscentBasedTest(int repetitions, T upperBound) but the upper bound is computed by computeMin...
bool longEdgesTest()
Long-Edges test from [DV89].
T computeRadiusSum() const
Compute the sum of all radii except the two largest.
bool deleteNodesAboveUpperBound(const NodeArray< T > &lowerBoundWithNode, const T upperBound)
Deletes the nodes whose lowerBoundWithNode exceeds upperBound.
void computeOptimalTerminals(node v, LAMBDA dist, node &optimalTerminal1, node &optimalTerminal2, NodeArray< T > &distance) const
Compute first and second best terminals according to function dist.
bool reduceTrivial()
Apply trivial (hence amazingly fast) reductions iteratively, that is degree2Test(),...
T costEdgesAlreadyInserted() const
Returns the cost of the edges already inserted in solution during the reductions.
void addNew(TWhat x, const std::vector< node > &replacedNodes, const std::vector< edge > &replacedEdges, bool deleteReplacedElements, TWhatArray &whatSonsListIndex)
Update internal data structures to let a (new) node or edge represent replaced nodes and/or edges.
void findTwoMinimumCostEdges(node v, edge &first, edge &second) const
Finds the first and second smallest edges incident to v.
EdgeArray< int > m_edgeSonsListIndex
See m_nodeSonsListIndex but for edges.
bool terminalDistanceTest()
Simple terminal distance test [PV01].
static bool repeat(std::function< bool()> f)
Auxiliary function: Repeats a function until it returns false (used for iteratively applying reductio...
std::vector< std::vector< int > > m_sonsList
List with lists (corresponding to nodes and containing the indexes of their sons)
void markSuccessors(node currentNode, const Voronoi< T > &voronoiRegions, NodeArray< bool > &isSuccessorOfMinCostEdge) const
Mark successors of currentNode in its shortest-path tree in voronoiRegions.
bool lowerBoundBasedTest()
Like lowerBoundBasedTest(T upperBound) but the upper bound is computed by computeMinSteinerTreeUpperB...
T computeMinSteinerTreeUpperBound() const
void setCostUpperBoundAlgorithm(MinSteinerTreeModule< T > *pMinSteinerTreeModule)
Set the module option for the algorithm used for computing the MinSteinerTree cost upper bound.
void floydWarshall(NodeArray< NodeArray< T > > &shortestPath) const
Applies the Floyd-Warshall algorithm on the m_copyGraph. The shortestPath matrix has to be already in...
T m_costAlreadyInserted
The cost of the already inserted in solution edges.
T solve(MinSteinerTreeModule< T > &mst, EdgeWeightedGraphCopy< T > *&finalSteinerTree)
A shortcut to get the solution of a reduced instance.
List< node > m_copyTerminals
The reduced form of terminals.
T computeBottleneckDistance(node x, node y, const EdgeWeightedGraphCopy< T > &tprime, const steiner_tree::HeavyPathDecomposition< T > &tprimeHPD, const NodeArray< List< std::pair< node, T > > > &closestTerminals) const
Heuristic computation [PV01] of the bottleneck Steiner distance between two nodes in a graph.
void computeRadiusOfTerminals(NodeArray< T > &terminalRadius) const
Compute radius of terminals.
SteinerTreePreprocessing(const EdgeWeightedGraph< T > &wg, const List< node > &terminals, const NodeArray< bool > &isTerminal)
void deleteSteinerDegreeTwoNode(node v, const EdgeWeightedGraphCopy< T > &tprime, const steiner_tree::HeavyPathDecomposition< T > &tprimeHPD, const NodeArray< List< std::pair< node, T > > > &closestTerminals)
Deletes a node that is known to have degree 2 in at least one minimum Steiner tree.
const List< node > & getReducedTerminals() const
Returns the list of the terminals corresponding to the reduced graph.
void recomputeTerminalsList()
Used by reductions to recompute the m_copyTerminals list, according to m_copyIsTerminal; useful when ...
const NodeArray< bool > & m_origIsTerminal
Const reference to the original isTerminal.
NodeArray< int > m_nodeSonsListIndex
It contains for each node an index i.
void shuffleReducedTerminals()
Shuffles the list of reduced terminals. This can have an effect on some tests.
void findClosestNonTerminals(node source, List< node > &reachedNodes, NodeArray< T > &distance, T maxDistance, int expandedEdges) const
Heuristic approach to computing the closest non-terminals for one node, such that there is no termina...
void addNewNode(node v, const std::vector< node > &replacedNodes, const std::vector< edge > &replacedEdges, bool deleteReplacedElements)
Calls addNew() for a node.
void computeClosestKTerminals(const int k, NodeArray< List< std::pair< node, T > > > &closestTerminals) const
Computes for every non-terminal the closest k terminals such that there is no other terminal on the p...
std::unique_ptr< MinSteinerTreeModule< T > > m_costUpperBoundAlgorithm
Algorithm used for computing the upper bound for the cost of a minimum Steiner tree.
bool reduceFast()
Apply fast reductions iteratively (includes trivial reductions).
const EdgeWeightedGraph< T > & m_origGraph
Const reference to the original graph.
bool reachabilityTest(int maxDegreeTest=0, const int k=3)
Performs a reachability test [DV89].
EdgeWeightedGraph< T > m_copyGraph
Copy of the original graph; this copy will actually be reduced.
void addNewEdge(edge e, const std::vector< node > &replacedNodes, const std::vector< edge > &replacedEdges, bool deleteReplacedElements)
The function is called after a new edge is added to the copy graph during the reductions.
NodeArray< bool > m_copyIsTerminal
The reduced form of isTerminal.
bool PTmTest(const int k=3)
"Paths with many terminals" test, efficient on paths with many terminals.
bool makeSimple()
Deletes parallel edges keeping only the minimum cost one, and deletes self-loops.
const List< node > & m_origTerminals
Const reference to the original list of terminals.
bool shortLinksTest()
Short links test using Voronoi regions [PV01].
const NodeArray< bool > & getReducedIsTerminal() const
Returns the NodeArray<bool> isTerminal corresponding to the reduced graph.
void addToSolution(const int listIndex, Array< bool, int > &isInSolution) const
Helper method for computeOriginalSolution.
bool leastCostTest()
Performs a least cost test [DV89] computing the whole shortest path matrix.
bool nearestVertexTest()
Nearest vertex test using Voronoi regions [DV89, PV01].
bool addEdgesToSolution(const List< edge > &edgesToBeAddedInSolution)
The function adds a set of edges in the solution.
bool deleteComponentsWithoutTerminals()
Deletes connected components with no terminals.
bool NTDkTest(const int maxTestedDegree=5, const int k=3)
Non-terminals of degree k test [DV89, PV01].
bool dualAscentBasedTest(int repetitions, T upperBound)
Like lowerBoundBasedTest(T upperBound) but uses ogdf::SteinerTreeLowerBoundDualAscent to compute lowe...
Enumerator for k-subsets of a given type.
Computes Voronoi regions in an edge-weighted graph.
Defines a queue for handling prioritized elements.
An implementation of the heavy path decomposition on trees.
A class used by the unordered_maps inside the reductions.
bool operator()(const NodePair &pair1, const NodePair &pair2) const
A class used by the unordered_maps inside the reductions.
int operator()(const NodePair &v) const
bool isConnected(const Graph &G)
Returns true iff G is connected.
int connectedComponents(const Graph &G, NodeArray< int > &component, List< node > *isolated=nullptr)
Computes the connected components of G and optionally generates a list of isolated nodes.
T computeMinST(const Graph &G, const EdgeArray< T > &weight, EdgeArray< bool > &isInTree)
Computes a minimum spanning tree using Prim's algorithm.
bool isLoopFree(const Graph &G)
Returns true iff G contains no self-loop.
bool isSimpleUndirected(const Graph &G)
Returns true iff G contains neither self-loops nor undirected parallel edges.
EdgeElement * edge
The type of edges.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
void updateMin(T &min, const T &newValue)
Stores the minimum of min and newValue in min.
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
T constructTerminalSpanningTreeUsingVoronoiRegions(EdgeWeightedGraphCopy< T > &terminalSpanningTree, const EdgeWeightedGraph< T > &graph, const List< node > &terminals)
The namespace for all OGDF objects.