52template<
typename T,
typename ExtraDataType>
53class FullComponentWithExtraStore;
62class EdgeWeightedGraph;
64namespace steiner_tree {
113 const edge e = adj->theEdge();
134 for (
int id = 1;
id <= gamma.size(); ++id) {
161 for (
node t : gamma.terminals(
id)) {
169 std::unique_ptr<ArrayBuffer<std::pair<node, int>>> basis(
177#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
178 std::cout <<
"Computing min-cost flow for blowup component " <<
id <<
" of "
179 << gamma.size() << std::endl;
180 std::cout <<
" * terminals of component are " << gamma.terminals(
id) << std::endl;
183 std::cout <<
" * supply node " << v <<
" with supply " << supply[v] << std::endl;
186 std::cout <<
" * demand node " << v <<
" with demand " << -supply[v] << std::endl;
190 std::cout <<
" * edge " << e <<
" with cost " << blowupGraph.
getCost(e)
191 <<
" and flow bounds [" << lB[e] <<
", " << blowupGraph.
getCapacity(e)
204 cost, supply, flow));
207 for (
edge e : sourceCoreEdges) {
209 basis->push(std::make_pair(e->target(), flow[e]));
210 weight -= flow[e] * cost[e];
214#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
215 std::cout <<
"Basis weight is " << weight << std::endl
216 <<
"Checking if " << gamma.cost(
id) <<
"(component cost) * "
217 << blowupGraph.
getLCM() <<
"(lcm) <= " << weight <<
"(basis weight)"
222 if (gamma.cost(
id) * blowupGraph.
getLCM() <= weight +
m_eps) {
223#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
224 std::cout <<
"Using basis because it is feasible." << std::endl;
226 maxBasis.swap(basis);
236 std::unique_ptr<
ArrayBuffer<std::pair<node, int>>>& maxBasis,
241 for (
int id = 1;
id <= gamma.size(); ++id) {
242 if (gamma.cost(
id) > cost) {
243 cost = gamma.cost(
id);
248 maxBasis.reset(
new ArrayBuffer<std::pair<node, int>>());
257 const edge rootEdge) {
261 while (!stack.
empty()) {
268 isNewTerminal[vO] =
true;
271 const node w = adj->theEdge()->target();
282#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
283 std::cout <<
"Remove basis from blowup graph" << std::endl;
289 for (
auto p : basis) {
290 const node v = p.first;
291 const int count = p.second;
294#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
295 std::cout <<
" * node " << v <<
" with count " << count <<
" (of " << origCap <<
")"
298 if (count < origCap) {
300#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
301 std::cout <<
" -> deferred because fractional" << std::endl;
307#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
308 std::cout <<
" -> done" << std::endl;
313#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
314 if (!fractionalCoreEdges.
empty()) {
315 std::cout <<
"Deferred core edges:" << std::endl;
318 for (
auto p : fractionalCoreEdges) {
319 const node v = p.item();
320 const int count = -p.priority();
322#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
323 std::cout <<
" * node " << v <<
" with count " << count <<
" of " << origCap << std::endl;
339 const std::minstd_rand& rng,
double eps = 1e-8)
354#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
355 std::cout <<
"Start solving based on LP solution" << std::endl;
359 BlowupGraph<T> blowupGraph(m_G, m_terminals, m_fullCompStore, cer, m_eps);
361 while (blowupGraph.
terminals().size() > 1) {
362#ifdef OGDF_STEINER_TREE_GOEMANS_APPROXIMATION_LOGGING
363 std::cout <<
"Iteration " << ++iteration <<
" with " << blowupGraph.
terminals().size()
364 <<
" terminals" << std::endl;
371 std::unique_ptr<ArrayBuffer<std::pair<node, int>>> maxBasis;
372 int compId = blowupGraph.
getY() > 0
373 ? findComponentAndMaxBasis(maxBasis, blowupGraph, gamma)
374 : findCheapestComponentAndRemainingBasis(maxBasis, blowupGraph, gamma);
378 addComponent(isNewTerminal, blowupGraph, gamma.rootEdge(compId));
381 removeFractionalBasisAndCleanup(*maxBasis, blowupGraph, gamma);
384 blowupGraph.
contract(gamma.terminals(compId));
386 if (blowupGraph.
terminals().size() > 1) {
Declaration and implementation of ArrayBuffer class.
Definition of the ogdf::steiner_tree::goemans::BlowupComponents class template.
Definition of ogdf::steiner_tree::goemans::BlowupGraph class template.
Definition of ogdf::steiner_tree::goemans::CoreEdgeRandomSpanningTree class template.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration and implementation of Goldberg-Tarjan max-flow algorithm with global relabeling and gap r...
Definition of ogdf::MinCostFlowReinelt class template.
Basic declarations, included by all source files.
Class for adjacency list elements.
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
E popRet()
Removes the newest element from the buffer and returns it.
void push(edge e)
Puts a new element in the buffer.
void quicksort()
Sorts buffer using Quicksort.
bool empty() const
Returns true if the buffer is empty, false otherwise.
int capacity() const
Returns the current capacity of the datastructure. Note that this value is rather irrelevant if the a...
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.
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Doubly linked lists (maintaining the length of the list).
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
TCap computeValue(const EdgeArray< TCap > &cap, const node &s, const node &t)
Compute only the value of the flow.
static bool checkComputedFlow(const Graph &G, const EdgeArray< int > &lowerBound, const EdgeArray< int > &upperBound, const EdgeArray< TCost > &cost, const NodeArray< int > &supply, const EdgeArray< int > &flow, TCost &value)
checks if a computed flow is a feasible solution to the given problem instance.
Computes a min-cost flow using a network simplex method.
virtual bool call(const Graph &G, const EdgeArray< int > &lowerBound, const EdgeArray< int > &upperBound, const EdgeArray< TCost > &cost, const NodeArray< int > &supply, EdgeArray< int > &flow, NodeArray< TCost > &dual) override
Computes a min-cost flow in the directed graph G using a network simplex method.
Class for the representation of nodes.
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Augments any data elements of type X with keys of type Priority. This class is also its own Comparer.
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
RegisteredArray for nodes, edges and adjEntries of a graph.
The actual 1.39-approximation algorithm by Goemans et al. with a set of terminalized nodes as result.
int findCheapestComponentAndRemainingBasis(std::unique_ptr< ArrayBuffer< std::pair< node, int > > > &maxBasis, const BlowupGraph< T > &blowupGraph, const BlowupComponents< T > &gamma)
For the end of the algorithm: find cheapest component and choose all remaining core edges as basis.
void removeFractionalBasisAndCleanup(ArrayBuffer< std::pair< node, int > > &basis, BlowupGraph< T > &blowupGraph, BlowupComponents< T > &gamma)
Remove a given basis and cleanup, the basis may be given fractionally.
const EdgeWeightedGraph< T > & m_G
const FullComponentWithExtraStore< T, double > & m_fullCompStore
all enumerated full components, with solution
int gammoidGetRank(const BlowupGraph< T > &blowupGraph) const
Computes the rank of the gammoid (given by the blowup graph)
Approximation(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, const FullComponentWithExtraStore< T, double > &fullCompStore, const std::minstd_rand &rng, double eps=1e-8)
Initialize everything.
const List< node > & m_terminals
const NodeArray< bool > & m_isTerminal
void addComponent(NodeArray< bool > &isNewTerminal, const BlowupGraph< T > &blowupGraph, const edge rootEdge)
Add a component of the blowup graph to the final solution (by changing nonterminals to terminals)
const double m_eps
epsilon for double operations
int findComponentAndMaxBasis(std::unique_ptr< ArrayBuffer< std::pair< node, int > > > &maxBasis, BlowupGraph< T > &blowupGraph, const BlowupComponents< T > &gamma)
Finds the best component and its maximum-weight basis in the given blowup graph with given core and w...
void solve(NodeArray< bool > &isNewTerminal)
Perform the actual approximation algorithm on the LP solution.
Obtain and provides information about components in a given blowup graph.
A special-purpose blowup graph for gammoid computation: directed, with special source and target,...
T getCost(edge e) const
Returns the cost of e.
void removeBasis(node v)
Removes a basis and cleans up.
const EdgeArray< int > & capacities() const
Returns a reference to the edge array containing all capacities.
void contract(node &v, node t)
Contracts node v and terminal t into v.
int getY() const
Returns the y-value of all terminals.
int getLCM() const
Returns the least common multiple of all denominators.
node getSource() const
Returns the source node.
void delCore(node e)
Remove a core edge.
node getTarget() const
Returns the target node.
void copyComponent(const edge origEdge, const int origCap, const int copyCap)
Copy a component in the blowup graph and set original capacity to origCap and capacity of copy to cop...
double computeCoreWeight(node v) const
Compute the weight of a core edge.
int getCapacity(edge e) const
Returns the capacity of e.
edge findRootEdge(node v)
Finds the root node of a component given by v, an arbitrary inner nonterminal of the component.
const List< node > & terminals() const
Returns a reference to the list containing all terminals in the blowup graph.
const Graph & getGraph() const
void updateSpecialCapacities()
Updates capacities from source to terminals and terminals to pseudotarget.
node getOriginal(node v) const
Returns the original node of v.
bool isTerminal(node v) const
Returns true if and only if v is a terminal.
T getCoreCapacity(node v) const
Get capacity of a core edge.
const List< node > & core() const
Return list of core edges (implemented by nodes)
Computes a random set of core edges.
Declarations for Comparer objects.
bool isLoopFree(const Graph &G)
Returns true iff G contains no self-loop.
#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.
Add edges into a blowup graph and delete them on destruction.
edge add(node v, node w, T cost, int capacity)
Add a temporary edge to the blowup graph.
TemporaryEdges(BlowupGraph< T > &blowupGraph)
Construct object for a specific blowupGraph.
~TemporaryEdges()
Remove the edges again.
BlowupGraph< T > & m_blowupGraph