74#ifdef OGDF_STP_EXACT_LOGGING
110#ifdef OGDF_STP_EXACT_LOGGING
209 delete[] m_bestSolution;
210 delete[] m_terminals;
214 delete m_pWeightedGraphPH;
220#ifdef OGDF_STP_EXACT_LOGGING
223 this->globalLogLevel(Level::Default);
224 this->localLogMode(LogMode::Log);
310 return m_isSolutionEdge[m_mapToBidirectedGraph1[e]]
311 || m_isSolutionEdge[m_mapToBidirectedGraph2[e]];
318 int nNodes()
const {
return m_pGraph->numberOfNodes(); }
321 int nEdges()
const {
return m_pGraph->numberOfEdges(); }
393 void updateBestSolution(
double*
values);
436 m_poolSizeMax = m_pCutPool->size();
491 virtual void initializeOptimization()
override;
493 virtual void terminateOptimization()
override;
495 virtual void initializeParameters()
override;
662#ifdef OGDF_STP_EXACT_LOGGING
669 virtual bool feasible()
override;
673 if (m_alreadySeparated == -1) {
674 m_alreadySeparated = mySeparate();
676 return m_alreadySeparated;
685#ifdef OGDF_STP_EXACT_LOGGING
691#ifdef OGDF_STP_EXACT_LOGGING
728 return new Sub(master_,
this,
rule);
740 int id,
edge e,
double coeff,
double lb = 0.0,
double ub = 1.0,
751 int id()
const {
return m_id; }
778 , m_factor(factor) { }
784 if (e != m_e1 && e != m_e2) {
814 if (e->
target() == m_node) {
817 if (e->
source() == m_node) {
857 if (e->
target() != m_edge->source()) {
861 if (e->
source() == m_edge->target()) {
889#ifdef OGDF_STP_EXACT_LOGGING
890 std::cout <<
"Creating new DirectedCutConstraint: " << std::endl;
896 m_marked[n] =
minSTCut->isInFrontCut(n);
897#ifdef OGDF_STP_EXACT_LOGGING
900 std::cout <<
" marked node " << n << std::endl;
905 m_marked[n] = !
minSTCut->isInBackCut(n);
909 m_hashKey += n->index();
913#ifdef OGDF_STP_EXACT_LOGGING
914 std::cout <<
" front cut edges:" << std::endl;
917 std::cout <<
" " << e << std::endl;
920 std::cout <<
" back cut edges:" << std::endl;
923 std::cout <<
" " << e << std::endl;
944 unsigned hashKey()
const override {
return m_hashKey; };
947 bool equal(
const ConVar*
cv)
const override;
950 const char*
name()
const override {
return m_name; }
979 , m_relaxedSolValue(-1)
983 , m_poolSizeInitFactor(5)
987 , m_addGSEC2Constraints(
true)
988 , m_addDegreeConstraints(
true)
989 , m_addIndegreeEdgeConstraints(
true)
990 , m_addFlowBalanceConstraints(
true)
991 , m_maxNrAddedCuttingPlanes(500)
992 , m_shuffleTerminals(
true)
993 , m_backCutComputation(
true)
994 , m_nestedCutComputation(
true)
995 , m_separationStrategy(1)
996 , m_saturationStrategy(1)
997 , m_minCardinalityCuts(
true)
998 , m_callPrimalHeuristic(1) {
999#ifdef OGDF_STP_EXACT_LOGGING
1016#ifdef OGDF_STP_EXACT_LOGGING
1030#ifdef OGDF_STP_EXACT_LOGGING
1037#ifdef OGDF_STP_EXACT_LOGGING
1066#ifdef OGDF_STP_EXACT_LOGGING
1070#ifdef OGDF_STP_EXACT_LOGGING
1087#ifdef OGDF_STP_EXACT_LOGGING
1132 this->readParameters(m_configfile);
1134#ifdef OGDF_STP_EXACT_LOGGING
1135 lout(Level::Alarm) <<
"Master::initializeParameters(): Error reading parameters."
1136 <<
"Using default values." << std::endl;
1139#ifdef OGDF_STP_EXACT_LOGGING
1144 int solver = (
OSISOLVER)findParameter(
"DefaultLpSolver", 12, OSISOLVER_);
1163#ifdef OGDF_STP_EXACT_LOGGING
1165 <<
"Master::initializeParameters(): parameters:" << std::endl
1166 <<
"\tLP-Solver " << OSISOLVER_[this->defaultLpSolver()] << std::endl
1167 <<
"\tOutputLevel " << this->localLogLevel() << std::endl
1183 <<
"\tObjective integer " << this->objInteger() << std::endl
1191#ifdef OGDF_STP_EXACT_LOGGING
1192 lout(Level::High) <<
"Master::initializeOptimization(): Instance properties:" << std::endl
1193 <<
"\t(nNodes,nEdges) : (" << m_pGraph->numberOfNodes() <<
", "
1194 << m_nEdgesU <<
")" << std::endl
1195 <<
"\tNumber of terminals : " << m_nTerminals << std::endl
1196 <<
"\tRoot node : " << m_root << std::endl
1206 m_edgeToVar.init(*m_pGraph,
nullptr);
1213 for (i = 0; i < m_pGraph->numberOfEdges(); i++) {
1214 edge e = m_edges[i];
1215 if (e->
target() != m_root
1218#ifdef OGDF_STP_EXACT_LOGGING
1219 lout(Level::Minor) <<
"\tadding variable x_" << i <<
", edge " << e << std::endl;
1225#ifdef OGDF_STP_EXACT_LOGGING
1226 lout(Level::Minor) <<
"\tmuting variable x_" << i <<
", edge " << e << std::endl;
1230 m_edgeToVar[e] =
eVar;
1239 nCons += m_pGraph->numberOfNodes();
1242 nCons += m_pGraph->numberOfEdges();
1245 nCons += m_pGraph->numberOfNodes() - 1;
1253 for (
edge e : m_pGraph->edges) {
1254 if (!marked[e] && !e->isSelfLoop()) {
1259 marked[m_twin[e]] =
true;
1261#ifdef OGDF_STP_EXACT_LOGGING
1263 <<
"\tadding constraint " << i++ <<
" GSEC2: edge " << e << std::endl;
1274 for (
node n : m_pGraph->nodes) {
1280 if (m_isTerminal[n]) {
1290#ifdef OGDF_STP_EXACT_LOGGING
1291 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Degree: node " << n << std::endl;
1297 for (
edge e : m_pGraph->edges) {
1298 if (e->source() != m_root) {
1303#ifdef OGDF_STP_EXACT_LOGGING
1305 <<
"\tadding constraint " << i++ <<
" Indegree: edge " << e << std::endl;
1312 for (
node n : m_pGraph->nodes) {
1313 if (!m_isTerminal[n]) {
1318#ifdef OGDF_STP_EXACT_LOGGING
1319 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Flow-Balance: node " << n
1327 m_poolSizeMax = m_poolSizeInit;
1334#ifdef OGDF_STP_EXACT_LOGGING
1335 lout(Level::Minor) <<
"Master::initializeOptimization() done." << std::endl;
1341#ifdef OGDF_STP_EXACT_LOGGING
1344 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1345 if (m_bestSolution[i] > 0.5) {
1346 m_isSolutionEdge[m_edges[i]] =
true;
1347#ifdef OGDF_STP_EXACT_LOGGING
1353#ifdef OGDF_STP_EXACT_LOGGING
1354 lout(Level::High) << std::endl;
1355 if (is_lout(Level::Medium)) {
1356 lout(Level::Medium) <<
"\toptimum solution edges:" << std::endl;
1357 for (
edge e : m_pGraph->edges) {
1358 if (m_isSolutionEdge[e]) {
1359 lout(Level::Medium) <<
"\t" << e << std::endl;
1363 lout(Level::Medium) << std::endl;
1366 <<
"Finished optimization. Statistics:" << std::endl
1367 <<
"Solution " << std::endl
1368 <<
" value " << this->primalBound() << std::endl
1369 <<
" rounded sol. value " << ((
int)this->primalBound()) << std::endl
1371 <<
"Status " << this->STATUS_[this->status()] << std::endl
1372 <<
"Primal/dual bound " << this->primalBound() <<
"/" << this->dualBound()
1374 <<
"Relaxed solution value " << this->m_relaxedSolValue << std::endl
1375 <<
"Nr subproblems " << this->nSub() << std::endl
1376 <<
"Nr solved LPs " << this->nLp() << std::endl
1377 <<
"nr solved LPs in root " << m_nIterRoot << std::endl
1380 <<
"LP Solver " << this->OSISOLVER_[this->defaultLpSolver()] << std::endl
1381 <<
"Enumeration strategy " << this->ENUMSTRAT_[this->enumerationStrategy()] << std::endl
1382 <<
"Branching strategy " << this->BRANCHINGSTRAT_[this->branchingStrategy()]
1384 <<
"Objective integer " << (this->objInteger() ?
"true" :
"false") << std::endl
1387 <<
"Total time (centi sec) " << this->totalTime()->centiSeconds() << std::endl
1388 <<
"Total time " << *this->totalTime() << std::endl
1389 <<
"Total cow-time " << *this->totalCowTime() << std::endl
1390 <<
"LP time " << *this->lpTime() << std::endl
1391 <<
"LP solver time " << *this->lpSolverTime() << std::endl
1392 <<
"Separation time " << this->m_separationTimer << std::endl
1393 <<
"Minimum Cut time " << this->m_timerMinSTCut << std::endl
1394 <<
"Primal heuristic time " << this->m_primalHeuristicTimer << std::endl
1397 <<
"Initial cutpool size " << this->m_poolSizeInit << std::endl
1398 <<
"Maximum cutpool size " << this->m_poolSizeMax << std::endl
1399 <<
"Nr separated cuts " << m_nrCutsTotal << std::endl;
1403 lout(Level::High) <<
"Cutpool duplications " <<
nDuplicates << std::endl
1404 <<
"Cutpool collisions " << nCollisions << std::endl
1411 double eps = this->eps();
1413 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1415 m_bestSolution[i] = 1.0;
1416 }
else if (
values[i] < eps) {
1417 m_bestSolution[i] = 0.0;
1419 m_bestSolution[i] =
values[i];
1426 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1427 m_bestSolution[i] = 0.0;
1430 m_bestSolution[m_edgeIDs[*it]] = 1.0;
1436 :
abacus::
Sub(master, 0, 0, 0), m_alreadySeparated(-1) {
1451 :
abacus::
Sub(master, father, branchRule), m_alreadySeparated(-1) {
1453#ifdef OGDF_STP_EXACT_LOGGING
1455 <<
" new subproblem, parent=" << father->
id() << std::endl;
1467#ifdef OGDF_STP_EXACT_LOGGING
1474 << std::setw(7) <<
"id" << std::setw(7) <<
"iter" << std::setw(10) <<
"lp value"
1475 << std::setw(10) <<
"gl. LB" << std::setw(10) <<
"gl. UB" << std::setw(10) <<
"nSub"
1476 << std::setw(10) <<
"nOpenSub" << std::endl;
1479 << this->nIter_ << std::setw(10) << lp_->value();
1480 if (this->
id() == 1) {
1485 if (master_->feasibleFound()) {
1491 << master_->openSub()->number() << std::endl;
1501 double eps = master_->eps();
1504#ifdef OGDF_STP_EXACT_LOGGING
1505 if (this->nIter_ == 1) {
1513 m_alreadySeparated = mySeparate();
1515 if (m_alreadySeparated > 0) {
1522 if (this->
id() == 1) {
1524 m_pMaster->setRelaxedSolValue(lp_->value());
1525 m_pMaster->setNIterRoot(nIter_);
1528 if (!m_pMaster->relaxed()) {
1530 for (
int i = 0; i < m_pMaster->nEdges(); i++) {
1539#ifdef OGDF_STP_EXACT_LOGGING
1541 <<
"\tsolution is fractional -> Branching." << std::endl;
1548 if (m_pMaster->betterPrimal(lp_->value())) {
1549#ifdef OGDF_STP_EXACT_LOGGING
1551 << std::setw(7) << this->id() << std::setw(7) << this->nIter_
1552 <<
" found better integer solution with value " << lp_->value();
1560 m_pMaster->primalBound(lp_->value());
1561 m_pMaster->updateBestSolution(xVal_);
1567#ifdef OGDF_STP_EXACT_LOGGING
1571 double eps = master_->eps();
1573 for (
int i = 0; i < nVar(); i++) {
1574 if (xVal_[i] > -eps && xVal_[i] < eps) {
1578 <<
" [edge " << ((
EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1580 }
else if (xVal_[i] >
oneMinusEps && xVal_[i] < 1 + eps) {
1583 <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1588 <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1597#ifdef OGDF_STP_EXACT_LOGGING
1599 <<
"Sub::mySeparate(): id=" << this->id() <<
", iter=" << this->nIter_ << std::endl;
1601 m_pMaster->separationTimer()->start();
1602 double eps = master_->eps();
1605 node r = m_pMaster->rootNode();
1606 const Graph& g = m_pMaster->graph();
1607 int nEdgesU = m_pMaster->nEdgesU();
1609 int nTerminals = m_pMaster->nTerminals();
1613 for (
int i = 0; i < nTerminals; i++) {
1621 for (
int i = 0; i < nTerminals - 1; i++) {
1624 terminal[i] = terminal[
j];
1629#ifdef OGDF_STP_EXACT_LOGGING
1632 for (
int i = 0; i < nTerminals; i++) {
1640 capacities.
init(g, 0);
1643 capacities[e] = max(xVal_[m_pMaster->edgeID(e)], 0.);
1649#ifdef OGDF_STP_EXACT_LOGGING
1651 <<
"Sub::mySeparate(): current capacities (>0) for mincut computation:" << std::endl;
1653 if (capacities[e] >= 2 *
cardEps) {
1655 <<
"\tcapacity[" << e <<
"]=" << capacities[e] << std::endl;
1672 double uBound = 1 + nEdgesU *
cardEps;
1689 while (
cutsFound < m_maxNrCuttingPlanes &&
ti < nTerminals) {
1692#ifdef OGDF_STP_EXACT_LOGGING
1694 <<
"Sub::mySeparate(): computing minimum cut between root " <<
r <<
" and " <<
t
1704 m_pMaster->timerMinSTCut()->start();
1712#ifdef OGDF_STP_EXACT_LOGGING
1717 << capacities[
flowEdge] << std::endl;
1725 m_pMaster->timerMinSTCut()->stop();
1728#ifdef OGDF_STP_EXACT_LOGGING
1738 if (m_computeBackCuts &&
minSTCut.isBackCutEdge(e)) {
1742 }
else if (m_computeBackCuts) {
1756 if (m_computeBackCuts &&
minSTCut.isBackCutEdge(e)) {
1762#ifdef OGDF_STP_EXACT_LOGGING
1764 if (m_computeBackCuts) {
1780#ifdef OGDF_STP_EXACT_LOGGING
1782 <<
"Sub::mySeparate(): found violated cut:" << std::endl;
1785 if (m_computeBackCuts && !
minSTCut.frontCutIsComplementOfBackCut()
1794#ifdef OGDF_STP_EXACT_LOGGING
1796 <<
"Sub::mySeparate(): found violated cut (backcut):" << std::endl;
1802 if (m_computeNestedCuts) {
1808 capacities[e] = 1.0 + eps;
1820 capacities[e] = 1.0 + eps;
1833 if (!m_computeNestedCuts) {
1841 capacities[e] = xVal_[m_pMaster->edgeID(e)];
1857 m_pMaster->incNrCutsTotal(
nAdded);
1858 m_pMaster->checkSetMaxPoolSize();
1864#ifdef OGDF_STP_EXACT_LOGGING
1866 <<
"Sub::mySeparate(): id=" << this->id() <<
", iter=" << this->nIter_ <<
" separated "
1867 <<
cutsFound <<
" directed cuts" << std::endl;
1869 m_pMaster->separationTimer()->stop();
1876 m_pMaster->primalHeuristicTimer()->start();
1878#ifdef OGDF_STP_EXACT_LOGGING
1880 <<
"Sub::myImprove(): id=" << this->id() <<
", iter=" << this->nIter_ << std::endl;
1882 double eps = master_->eps();
1883 const Graph& g = m_pMaster->graph();
1886#ifdef OGDF_STP_EXACT_LOGGING
1891 <<
"\tx" << m_pMaster->edgeID(e) <<
"=" << xVal_[m_pMaster->edgeID(e)]
1892 <<
", edge " << e << std::endl;
1901 edge e2 = m_pMaster->twin(e);
1902 currWeight = 1.0 - xVal_[m_pMaster->edgeID(e)];
1910 ewg.setWeight(m_pMaster->edgeGToWgPH(e),
1911 eps +
currWeight * variable(m_pMaster->edgeID(e))->obj());
1914#ifdef OGDF_STP_EXACT_LOGGING
1919 <<
"\tweight[" << e <<
"]=" <<
ewg.weight(m_pMaster->edgeGToWgPH(e))
1931#ifdef OGDF_STP_EXACT_LOGGING
1936 primalHeuristic->call(m_pMaster->weightedGraphPH(), m_pMaster->terminalListPH(),
1943#ifdef OGDF_STP_EXACT_LOGGING
1945 <<
"Sub::myImprove(): primal heuristic algorithm returned solution with "
1960#ifdef OGDF_STP_EXACT_LOGGING
1962 <<
"\t" << e <<
" -> " <<
e2 <<
" c=" << m_pMaster->capacities(
e2) << std::endl;
1966#ifdef OGDF_STP_EXACT_LOGGING
1972#ifdef OGDF_STP_EXACT_LOGGING
1974 << std::setw(7) << this->id() << std::setw(7) << this->nIter_
1975 <<
" primal heuristic founds better integer solution with value "
1982#ifdef OGDF_STP_EXACT_LOGGING
1985 <<
"Sub::myImprove(): id=" << this->id() <<
", iter=" << this->nIter_
1986 <<
": computed solution is no Steiner tree!" << std::endl;
1991 m_pMaster->primalHeuristicTimer()->stop();
1994#ifdef OGDF_STP_EXACT_LOGGING
1998 double eps = master_->eps();
2002 for (
int i = 0; i < nVar(); i++) {
2005 if (
val > eps ||
val < -eps) {
2007 if (
val > 1 - eps &&
val < 1 + eps) {
2009 m_pMaster->lout(level) <<
" + ";
2013 m_pMaster->lout(level) <<
" + " <<
val;
2019 m_pMaster->lout(level) <<
" - ";
2021 m_pMaster->lout(level) <<
" -";
2025 m_pMaster->lout(level) <<
" - " << (-1) *
val;
2027 m_pMaster->lout(level) <<
val;
2031 m_pMaster->lout(level) <<
"x" << i;
2035 m_pMaster->lout(level) <<
" " << *(constraint->
sense()) <<
" " << constraint->
rhs() << std::endl;
2041 if (m_hashKey !=
cv->hashKey()) {
2045 if (m_nMarkedNodes !=
dirCut->nMarkedNodes()) {
2048 for (
node n : m_pGraph->nodes) {
2049 if (m_marked[n] !=
dirCut->marked(n)) {
2059 if (this->cutedge(
edgeVar->theEdge())) {
2073#ifdef OGDF_STP_EXACT_LOGGING
2102 for (
edge e = G.firstEdge(); e; e = e->succ()) {
2104 const node vO = e->source();
2109 const node wO = e->target();
Declaration of class EdgeWeightedGraph.
Extends the GraphCopy concept to weighted graphs.
Includes declaration of graph class.
Contains logging functionality.
Declaration of min-st-cut algorithms parameterized by max-flow alorithm.
Implementation of the 2(1-1/l)-approximation algorithm for the minimum Steiner tree problem by Matsuy...
Abstract base class for all branching rules.
Forms the virtual base class for all possible constraints given in pool format.
CSense * sense()
Returns a pointer to the sense of the constraint.
virtual double coeff(const Variable *v) const =0
Returns the coefficient of the variable v in the constraint.
virtual double rhs() const
Returns the right hand side of the constraint.
The master of the optimization.
OSISOLVER
This enumeration defines which solvers can be used to solve the LP-relaxations.
static const char * OSISOLVER_[]
Array for the literal values for possible Osi solvers.
OSISOLVER defaultLpSolver() const
returns the Lp Solver.
Standard pools without constraint duplication.
int id() const
Returns the identity number of the subproblem.
int nIter_
The number of iterations in the cutting plane phase.
Master * master()
Returns the master of the optimization.
TYPE
The enumeration with the different variable types.
@ Continuous
A continuous variable.
@ Binary
A variable having value 0 or 1.
Forms the virtual base class for all possible variables given in pool format.
Exception thrown when an algorithm realizes an internal bug that prevents it from continuing.
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
The parameterized class Array implements dynamic arrays of type E.
Dynamic arrays indexed with edges.
void init()
Reinitializes the array. Associates the array with no graph.
Class for the representation of edges.
bool isParallelDirected(edge e) const
Returns true iff edge e is parallel to this (directed) edge (or if it is the same edge)
bool isSelfLoop() const
Returns true iff the edge is a self-loop (source node = target node).
node target() const
Returns the target node of the edge.
node source() const
Returns the source node of the edge.
edge newEdge(node v, node w, T weight)
Data type for general directed graphs (adjacency list representation).
int numberOfNodes() const
Returns the number of nodes in the graph.
edge newEdge(node v, node w)
Creates a new edge (v,w) and returns it.
int numberOfEdges() const
Returns the number of edges in the graph.
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
node newNode()
Creates a new node and returns it.
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Representation of levels in hierarchies.
Doubly linked lists (maintaining the length of the list).
Encapsulates a pointer to a list element.
Centralized global and local logging facility working on streams like std::cout.
Level
supported log-levels from lowest to highest importance
std::ostream & lout(Level level=Level::Default) const
stream for logging-output (local)
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
Min-st-cut algorithm, that calculates the cut via maxflow.
cutType
The three types of cuts.
Constraint for nodes, e.g., in/outdegree stuff.
node theNode() const
the associated node
virtual double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
DegreeConstraint(abacus::Master *master, node n, double coeffIn, double coeffOut, abacus::CSense::SENSE sense, double rhs)
node m_node
the associated node
double m_coeffIn
coefficient of ingoing edges
double m_coeffOut
coefficient of outgoing edges
Constraint for relating the indegree and one outgoing edge of a node.
edge theEdge() const
the associated edge
DegreeEdgeConstraint(abacus::Master *master, edge e, double coeffIn, double coeffEdge, abacus::CSense::SENSE sense, double rhs)
double m_coeffEdge
coefficient of the edge
double m_coeffIn
coefficient of ingoing edges
double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
edge m_edge
the associated edge
Class for directed cuts (i.e., separated Steiner cuts)
NodeArray< bool > m_marked
defines if a vertex is on the left side of the cut (false) or not
bool active(node n) const
returns true iff the node n is separated by this cut
unsigned hashKey() const override
retuns an hashkey for the cut; required method for nonduplpool
bool marked(node n) const
returns status of node n
bool equal(const ConVar *cv) const override
tests if cuts are equal; required method for nonduplpool
unsigned int m_hashKey
hashkey of the cut; required method for nonduplpool
int nMarkedNodes() const
the number of marked nodes
const Graph * m_pGraph
the graph
bool cutedge(edge e) const
returns true iff the edge is contained in the cut
const char * m_name
name of the cut; required method for nonduplpool
DirectedCutConstraint(abacus::Master *master, const Graph &g, const MinSTCutMaxFlow< double > *minSTCut, MinSTCutMaxFlow< double >::cutType _cutType)
int m_nMarkedNodes
number of marked nodes
double coeff(const abacus::Variable *v) const override
Returns the coefficient of the variable v in the constraint.
const char * name() const override
return the name of the cut; required method for nonduplpool
Constraint for edges, e.g., subtour elimination constraints of size 2 ((G)SEC2)
edge m_e2
twin of m_e1, i.e., if m_e1 = (u,v) it holds m_e2 = (v,u)
int m_factor
factor for edge coefficients in the constraint
EdgeConstraint(abacus::Master *master, edge e1, edge e2, int factor=1.0, abacus::CSense::SENSE sense=abacus::CSense::Less, double rhs=1.0)
double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
edge m_e1
base edge and twin of m_e2, i.e., if m_e1 = (u,v) it holds m_e2 = (v,u)
Variable for directed edges.
int id() const
id of the edge (variable)
node source() const
source node
edge theEdge() const
the associated edge
double coefficient() const
objective function coefficient
node target() const
target node
EdgeVariable(abacus::Master *master, int id, edge e, double coeff, double lb=0.0, double ub=1.0, abacus::VarType::TYPE vartype=abacus::VarType::Binary)
Master problem of Steiner tree branch&cut algorithm
StopwatchWallClock * separationTimer()
timer for separation
double m_relaxedSolValue
statistics: solution value of the relaxed master problem
int m_nTerminals
nr of terminals
bool isTerminal(node n) const
true if n is a terminal
const node * terminals() const
terminals in an array
StopwatchWallClock * timerMinSTCut()
timer for minimum st-cut computations. Measures updates + algorithm
StopwatchWallClock * primalHeuristicTimer()
timer for primal heuristics
edge edgeGToWgPH(edge e) const
edge mapping m_pGraph -> m_pWeightedGraphPH
bool m_addIndegreeEdgeConstraints
add constraints concerning the indegree of a node w.r.t. one outgoing edge: indeg(v) >= outgoing edge...
EdgeWeightedGraph< double > * m_pWeightedGraphPH
edge weighted bidirected graph; used and modified for primal heuristics
EdgeArray< bool > m_isSolutionEdge
const NodeArray< bool > & isTerminalPH() const
terminal yes/no (in m_pWeightedGraphPH)
EdgeArray< int > m_edgeIDs
edge -> id
int nTerminals() const
number of terminals
double capacities(edge e) const
costs for edge e
void updateBestSolutionByEdges(const List< edge > &sol)
updates best found solution by list of edges
EdgeArray< edge > m_mapToOrigGraph
the undirected edge in the original graph for each arc in m_pGraph
virtual void terminateOptimization() override
store solution in EdgeArray
node m_root
the virtual root of our graph. This node is a terminal.
void checkSetMaxPoolSize()
checks if current pool size is maximum and sets it if necessary
MaxFlowModule< double > * getMaxFlowModule()
Get the maximum flow module used by separation algorithm.
int m_maxPoolSize
statistic number of cuts in pool
void useFlowBalanceConstraints(bool b)
Switch usage of flow balance constraints on or off.
int nNodes() const
number of nodes of the graph
edge edgeWgToGPH(edge e) const
edge mapping m_pWeightedGraphPH -> m_pGraph
node * m_terminals
terminal index -> terminal node
int maxNrAddedCuttingPlanes() const
maximum nr of cutting planes
const NodeArray< int > & nodeIDs() const
lp variable ids of nodes
EdgeWeightedGraph< double > & weightedGraphPH()
NodeArray< node > m_nodesGToWgPH
node mapping m_pGraph -> m_pWeightedGraphPH
bool relaxed() const
solve relaxed LP or ILP
int m_callPrimalHeuristic
parameter: primal heuristic (PH) call strategy
bool computeNestedCuts() const
parameter: nested cut computation
const EdgeArray< int > & edgeIDs() const
lp variable ids of edges
double * m_bestSolution
best found solution
void useNestedCuts(bool b)
Switch computation of nested cuts on or off.
virtual ~Master()
destructor
node m_rootPH
root node in m_pWeightedGraphPH
int m_separationStrategy
parameter: separation strategy, only important if nested cuts are computed
bool m_backCutComputation
parameter: compute back cuts yes/no i.e., outgoing edges of the root-set
abacus::NonDuplPool< abacus::Constraint, abacus::Variable > * m_pCutPool
the non-duplicate cut pool for the directed Steiner cuts
Graph * m_pGraph
the bidirected graph
EdgeArray< double > m_capacities
edge costs
const char * m_configfile
problem dependent config file
int m_poolSizeInitFactor
parameter: factor for the initial size of the cutting pool
void setSaturationStrategy(int b)
Set saturation strategy for nested cuts.
void useMinCardinalityCuts(bool b)
Switch usage of the cardinality heuristic (minimum-cardinality cuts) on or off.
int nEdges() const
returns the number of edges
bool m_nestedCutComputation
parameter: compute nested cuts yes/no i.e., saturate all cut edges and recompute the mincut
void useIndegreeEdgeConstraints(bool b)
Switch usage of indegree edge constraints (indeg(v) >= outgoing edge(v,x) for all x) on or off.
EdgeArray< edge > m_mapToBidirectedGraph1
the first directed arc in m_pGraph for an original edge
void useTerminalShuffle(bool b)
Switch terminal shuffling before separation on or off.
bool m_minCardinalityCuts
parameter: compute minimum cardinality cuts
void incNrCutsTotal(int val)
increases the number of separated directed cuts
void updateBestSolution(double *values)
updates best found solution
double solutionValue() const
solution value after solving the problem, i.e., returns final primal bound
std::unique_ptr< MinSteinerTreeModule< double > > m_primalHeuristic
Algorithm used for the primal heuristic.
node * nodes() const
nodes of the graph
EdgeVariable * getVar(edge e) const
returns the variable assigned to edge e
int maxPoolSize() const
the maximum pool size during the algorithm
StopwatchWallClock m_timerMinSTCut
timer for minimum st-cut computations. Measures updates + algorithm
EdgeArray< edge > m_mapToBidirectedGraph2
the second directed arc in m_pGraph for an original edge
void incNrCutsTotal()
increases the number of separated directed cuts by 1
EdgeVariable * getVarTwin(edge e) const
returns the variable assigned to the twin of edge e
void setNIterRoot(int val)
nr of iterations in the root node
int m_saturationStrategy
parameter: saturation strategy, only important if nested cuts are computed
const EdgeWeightedGraph< T > & m_wG
the original weighted graph
bool m_addDegreeConstraints
parameter: add constraints concerning the indegree of a node, like: indeg <= 1 for all vertices
int nrCutsTotal() const
total number of separated directed cuts
virtual void initializeOptimization() override
insert variables and base constraints
void setMaxFlowModule(MaxFlowModule< double > *module)
Set the maximum flow module to be used for separation.
const Graph & graph() const
the directed graph, i.e., the bidirection of the input graph
int edgeID(edge e) const
edge -> id of lp variable
StopwatchWallClock m_primalHeuristicTimer
timer for primal heuristics
abacus::NonDuplPool< abacus::Constraint, abacus::Variable > * cutPool()
the non-duplicate cutpool for the separated Steiner cuts
std::unique_ptr< MinSteinerTreeModule< double > > & getPrimalHeuristic()
the primal heuristic module
bool m_relaxed
parameter: indicates whether we solve the relaxed problem (LP) or the ILP
node getNode(int i) const
id -> node
NodeArray< bool > m_isTerminalPH
is terminal yes/no (in m_pWeightedGraphPH)
void setMaxNumberAddedCuttingPlanes(int b)
Set maximum number of added cutting planes per iteration.
int nodeID(node n) const
npde -> id of lp variable
int m_poolSizeMax
maximal size of the pool
virtual abacus::Sub * firstSub() override
generates the first subproblem
const NodeArray< bool > isTerminal() const
boolean array of terminal status
virtual void initializeParameters() override
read/set parameters from file
int poolSizeInit() const
initial pool size
int m_maxNrAddedCuttingPlanes
parameter: maximum nr of cutting planes per iteration
void setSeparationStrategy(int b)
Set separation strategy for nested cuts.
node rootNodePH() const
root node (in m_pWeightedGraphPH)
bool minCardinalityCuts() const
parameter: compute minimum cardinality cuts
const Master & operator=(const Master &rhs)
void useDegreeConstraints(bool b)
Switch usage of degree constraints (like indeg <= 1) on or off.
edge getEdge(int i) const
id -> edge
int m_nEdgesU
number of undirected edges
void setRelaxedSolValue(double val)
solution value of the root
bool m_shuffleTerminals
parameter: shuffle the list of terminals right before separation
void setPoolSizeInitFactor(int b)
Set factor for the initial size of the cutting pool.
NodeArray< bool > m_isTerminal
node is terminal yes/no
edge twin(edge e) const
the twin edge, i.e. twin[(u,v)] = (v,u)
EdgeArray< edge > m_edgesWgToGPH
edge mapping m_pWeightedGraphPH -> m_pGraph
double * bestSolution() const
the best found solution
List< node > m_terminalListPH
list of terminal nodes (in m_pWeightedGraphPH)
EdgeArray< EdgeVariable * > m_edgeToVar
edge -> lp variable
bool computeBackCuts() const
parameter: back cut computation
bool shuffleTerminals() const
shuffle ordering of terminals before each separation routine
void useBackCuts(bool b)
Switch computation of back-cuts on or off.
const EdgeArray< edge > & twins() const
EdgeArray< edge > m_edgesGToWgPH
edge mapping m_pGraph -> m_pWeightedGraphPH
bool isSolutionEdge(edge e) const
returns true iff original edge is contained in optimum solution
void setPrimalHeuristic(MinSteinerTreeModule< double > *pMinSteinerTreeModule)
Set the module option for the primal heuristic.
int m_poolSizeInit
size of initial pool
bool m_addGSEC2Constraints
parameter: add GSEC2 constraints yes/no, i.e. x_uv + x_vu <= 1
Master(const EdgeWeightedGraph< T > &wG, const List< node > &terminals, const NodeArray< bool > &isTerminal, double eps, bool relaxed=false)
Constructor of the master problem.
int callPrimalHeuristicStrategy() const
strategy for calling primal heuristic (PH)
void setConfigFile(const char *filename)
Set the config file to use that overrides all other settings.
int m_nrCutsTotal
total number of separated directed cuts
int saturationStrategy() const
strategy for saturating edges during separation; Only relevant for nested cuts
void setPrimalHeuristicCallStrategy(int b)
Set primal heuristic call strategy.
node terminal(int i) const
get terminal with index i
StopwatchWallClock m_separationTimer
timer for separation
MaxFlowModule< double > * m_maxFlowModule
const List< node > & terminalListPH() const
list of terminals (in m_pWeightedGraphPH)
bool m_addFlowBalanceConstraints
parameter: add flow balance constraints for Steiner nodes n: outdeg(n) >= indeg(n)
bool callPrimalHeuristic() const
parameter: call primal heuristic yes/no
node rootNode() const
the designated root node (special terminal)
void useGSEC2Constraints(bool b)
Switch usage of constraints x_uv + x_vu <= 1 on or off.
Master(const Master &rhs)
int nEdgesU() const
returns number of undirected edges, i.e., nEdges()/2
NodeArray< int > m_nodeIDs
node -> id
EdgeArray< edge > m_twin
the twin edges (u,v) <-> (v,u)
int separationStrategy() const
strategy for separating directed Steiner cuts; Only relevant for nested cuts
const EdgeArray< double > & capacities() const
edge costs
int m_nIterRoot
statistics: nr of iterations in the root node of the b&b tree
Subproblem of Steiner tree algorithm.
void myImprove()
primal heuristic procedure
virtual int separate() override
calls mySeparate() if mySeparate wasn't called in another procedure
virtual bool feasible() override
checks if the current solution is feasible, i.e., calls mySeparate()
int m_callPrimalHeuristic
Strategy for primal heuristic (PH) calls.
virtual ~Sub()
The destructor only deletes the sons of the node.
bool m_minCardinalityCuts
int m_alreadySeparated
nr of already separated cuts, default is -1
Sub(abacus::Master *master)
Constructor for the root problem of the b&b tree.
virtual Sub * generateSon(abacus::BranchRule *rule) override
generates a b&b node
int m_maxNrCuttingPlanes
maximum nr of cutting planes to be added
Master * m_pMaster
the master problem of the b&c algorithm
int mySeparate()
separation procedure
This class implements the Directed Cut Integer Linear Program for the Steiner tree problem.
MinSteinerTreeDirectedCut()
void useIndegreeEdgeConstraints(bool b)
Switch usage of indegree edge constraints (indeg(v) >= outgoing edge(v,x) for all x) on or off.
void useNestedCuts(bool b)
Switch computation of nested cuts on or off.
void setPrimalHeuristicCallStrategy(int b)
Set primal heuristic call strategy.
void setPoolSizeInitFactor(int b)
Set factor for the initial size of the cutting pool.
void setMaxFlowModule(MaxFlowModule< double > *module)
Set the maximum flow module to be used for separation.
bool m_minCardinalityCuts
void setPrimalHeuristic(MinSteinerTreeModule< double > *b)
Set the module option for the primal heuristic (use MinSteinerTreeModule<double> types)....
void setConfigFile(const char *configfile)
Set a configuration file to use. The contents of the configuration file can override all other used o...
std::unique_ptr< MaxFlowModule< double > > m_maxFlowModuleOption
bool m_addIndegreeEdgeConstraints
int m_maxNrAddedCuttingPlanes
bool m_addFlowBalanceConstraints
bool m_backCutComputation
void setSaturationStrategy(int b)
Set saturation strategy for nested cuts.
void useTerminalShuffle(bool b)
Switch terminal shuffling before separation on or off.
int m_callPrimalHeuristic
MinSteinerTreeModule< double > * m_primalHeuristic
bool m_addDegreeConstraints
void useMinCardinalityCuts(bool b)
Switch usage of the cardinality heuristic (minimum-cardinality cuts) on or off.
void setEpsilon(double eps)
Set the epsilon for the LP.
virtual T computeSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree) override
Computes the actual Steiner tree.
bool m_addGSEC2Constraints
void useBackCuts(bool b)
Switch computation of back-cuts on or off.
void useFlowBalanceConstraints(bool b)
Switch usage of flow balance constraints on or off.
bool m_nestedCutComputation
const char * m_configFile
void useGSEC2Constraints(bool b)
Switch usage of constraints x_uv + x_vu <= 1 on or off.
void setMaxNumberAddedCuttingPlanes(int b)
Set maximum number of added cutting planes per iteration.
void setSeparationStrategy(int b)
Set separation strategy for nested cuts.
void useDegreeConstraints(bool b)
Switch usage of degree constraints (like indeg <= 1) on or off.
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
static bool isSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, const EdgeWeightedGraphCopy< T > &steinerTree)
Checks in O(n) time if a given tree is acually a Steiner Tree.
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).
Implements a stopwatch measuring wall-clock time.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
int randomNumber(int low, int high)
Returns random integer between low and high (including).
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.