34#include <coin/CoinPackedMatrix.hpp>
43#define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
44#define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
47namespace steiner_tree {
66#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
103 source = G.newNode();
107 target = G.newNode();
116 capacity[G.newEdge(source,
rC)] = cap;
117 if (terminals.
size() > 2) {
118 const node v = G.newNode();
119 capacity[G.newEdge(
rC, v)] = cap;
120 for (
auto it =
it0 + 1; it != terminals.
end(); ++it) {
121 const node w = G.copy(*it);
122 capacity[G.newEdge(v, w)] = cap;
125 capacity[G.newEdge(
rC, G.copy(*terminals.
rbegin()))] = cap;
132 const node v = G.copy(
t);
137 if (adj->twinNode() != source) {
138 y_v += capacity[adj->theEdge()];
142#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
149 capacity[G.newEdge(v, target)] =
y_v;
155 for (
edge e : G.edges) {
156 if (G.original(e->source())) {
157 std::cout <<
" T:" << G.original(e->source());
159 std::cout <<
" " << e->source();
162 if (G.original(e->target())) {
163 std::cout <<
"T:" << G.original(e->target());
165 std::cout << e->target();
167 std::cout <<
" " << capacity[e] <<
"\n";
187 T upperBound = 0,
int cliqueSize = 0,
double eps = 1e-8)
206#ifndef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
228 const int n = m_fullCompStore.size();
230 m_matrix->setDimensions(0, n);
231 for (
int i = 0; i < n; ++i) {
232 m_lowerBounds[i] = 0;
233 m_upperBounds[i] = 1;
235 for (
int i = 0; i < n; ++i) {
236 m_objective[i] = m_fullCompStore.cost(i);
238 m_osiSolver->loadProblem(*m_matrix, m_lowerBounds, m_upperBounds, m_objective,
nullptr,
nullptr);
240 if (m_upperBound > 0) {
242 row.setFull(m_fullCompStore.size(), m_objective);
243 m_osiSolver->addRow(row, 0, m_upperBound);
251 for (
int i = 0; i < m_fullCompStore.size(); ++i) {
252 if (m_fullCompStore.isTerminal(i,
t)) {
257 m_osiSolver->addRow(row, 1, m_osiSolver->getInfinity());
266 for (
int i = 0; i < m_fullCompStore.size(); ++i) {
269 auto terminals = m_fullCompStore.terminals(i);
273 if ((*it1)->index() < (*it2)->index()) {
275 }
else if ((*it1)->index() > (*it2)->index()) {
290 m_osiSolver->addRow(row, 0,
subset.size() - 1);
302 for (
int i = 0; i < m_fullCompStore.size(); ++i) {
303 row.insert(i, m_fullCompStore.terminals(i).size() - 1);
306 int value = m_terminals.size() - 1;
307 m_osiSolver->addRow(row, value, value);
316 m_osiSolver->initialSolve();
317#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_LOGGING
318 std::cout <<
"Objective value " << m_osiSolver->getObjValue() <<
" of initial solution."
323 m_osiSolver->resolve();
324#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_LOGGING
325 std::cout <<
"Objective value " << m_osiSolver->getObjValue() <<
" after resolve."
330 if (!m_osiSolver->isProvenOptimal()) {
331 if (m_upperBound > 0) {
334 std::cerr <<
"Failed to optimize LP!" << std::endl;
338 }
while (separate());
340 const double*
constSol = m_osiSolver->getColSolution();
344 m_fullCompStore.extra(i) =
constSol[i];
347#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_OUTPUT_LP
348 m_osiSolver->writeLp(
stderr);
356 const double*
constSol = m_osiSolver->getColSolution();
359 for (
int i = 0; i < m_fullCompStore.size(); ++i) {
360 m_fullCompStore.extra(i) =
constSol[i];
361 if (m_fullCompStore.extra(i) > m_eps) {
366#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
367 if (!m_separationStage) {
371 m_separationStage = 1;
384 for (
node t : m_terminals) {
391 auto it = terminals.begin();
392 const int s1 =
setID[*it];
393 for (++it; it != terminals.end(); ++it) {
398 if (
uf.getNumberOfSets() == 1) {
404 for (
node t : m_terminals) {
428#ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
440 for (
node t : m_terminals) {
444 capacity[
v_to_target] = std::numeric_limits<double>::max();
448 const double cutVal =
maxFlow.computeValue(capacity, source, target);
478 const int i1 =
id[
u1];
481 const int i2 =
id[
u2];
488 if ((*it1)->index() < (*it2)->index()) {
490 }
else if ((*it1)->index() > (*it2)->index()) {
505 if (G.numberOfEdges() == 0) {
511 for (
node v : G.nodes) {
512 int idx = v->degree();
516 if (idx >= m_separateCliqueSize) {
517 idx = m_separateCliqueSize - 1;
523 for (
int k =
degrees.size(); k >= 2; --k) {
525 if (
degrees[k - 2].size() >= k) {
532 for (
edge e : G.edges) {
533 if (
test[e->source()] &&
test[e->target()]) {
545 val += m_fullCompStore.extra(i);
548 if (
val >= 1 + m_eps) {
549 m_osiSolver->addRow(row, 0, 1);
Definition of the FullComponentStore class template.
#define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
Declaration of min-st-cut algorithms parameterized by max-flow alorithm.
A class that allows to enumerate k-subsets.
Class for adjacency list elements.
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
void push(E e)
Puts a new element in the buffer.
The parameterized class Array implements dynamic arrays of type E.
iterator begin()
Returns an iterator to the first element.
reverse_iterator rbegin()
Returns an reverse iterator to the last element.
iterator end()
Returns an iterator to one past the last element.
INDEX size() const
Returns the size (number of elements) of the array.
If you use COIN-OR, you should use this class.
A Union/Find data structure for maintaining disjoint sets.
Dynamic arrays indexed with edges.
void init()
Reinitializes the array. Associates the array with no graph.
Class for the representation of edges.
Copies of graphs supporting edge splitting.
Data type for general directed graphs (adjacency list representation).
Doubly linked lists (maintaining the length of the list).
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
Min-st-cut algorithm, that calculates the cut via maxflow.
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.
node succ() const
Returns the successor in the list of all nodes.
Enumerator for k-subsets of a given type.
const Array< node > & terminals(int id) const
Returns the list of terminals in the full component with given id.
Class managing the component-based subtour elimination LP relaxation for the Steiner tree problem and...
bool separate()
Perform all available separation algorithms.
bool separateConnected(const ArrayBuffer< int > &activeComponents)
Separate to ensure that the solution is connected.
LPRelaxationSER(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, FullComponentWithExtraStore< T, double > &fullCompStore, T upperBound=0, int cliqueSize=0, double eps=1e-8)
Initialize the LP.
CoinPackedMatrix * m_matrix
bool solve()
Solve the LP. The solution will be written to the extra data of the full component store.
double generateMinCutSeparationGraph(const ArrayBuffer< int > &activeComponents, node &source, node &target, GraphCopy &G, EdgeArray< double > &capacity, int &cutsFound)
Generates an auxiliary multi-graph for separation (during LP solving): directed, with special source ...
bool separateCycles(const ArrayBuffer< int > &activeComponents)
Perform the separation algorithm for cycle constraints (to obtain stronger LP solution)
const double m_eps
epsilon for double operations
void generateProblem()
Generate the basic LP model.
bool addSubsetCoverConstraint(const ArrayBuffer< node > &subset)
Add subset cover constraints to the LP for a given subset of terminals.
const int m_separateCliqueSize
const EdgeWeightedGraph< T > & m_G
const NodeArray< bool > & m_isTerminal
bool separateMinCut(const ArrayBuffer< int > &activeComponents)
Perform the general cut-based separation algorithm.
OsiSolverInterface * m_osiSolver
void addYConstraint(const node t)
Add constraint that the sum of x_C over all components C spanning terminal t is at least 1 to ensure ...
const List< node > & m_terminals
List of terminals.
FullComponentWithExtraStore< T, double > & m_fullCompStore
all enumerated full components, with solution
void addTerminalCoverConstraint()
Add terminal cover constraints to the LP.
Definition of ogdf::CoinManager.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.