87#ifdef OGDF_STP_EXACT_LOGGING
123#ifdef OGDF_STP_EXACT_LOGGING
125 void setOutputLevel(
Logger::Level outputLevel) { m_outputLevel = outputLevel; }
179#ifdef OGDF_STP_EXACT_LOGGING
222 delete[] m_bestSolution;
223 delete[] m_terminals;
227 delete m_pWeightedGraphPH;
233#ifdef OGDF_STP_EXACT_LOGGING
235 void setOutputLevel(
Level outputLevel) {
236 this->globalLogLevel(Level::Default);
237 this->localLogMode(LogMode::Log);
238 if (outputLevel >= Level::Minor && outputLevel <= Level::Force) {
239 this->localLogLevel((
Level)outputLevel);
240 this->globalMinimumLogLevel((
Level)outputLevel);
323 return m_isSolutionEdge[m_mapToBidirectedGraph1[e]]
324 || m_isSolutionEdge[m_mapToBidirectedGraph2[e]];
331 int nNodes()
const {
return m_pGraph->numberOfNodes(); }
334 int nEdges()
const {
return m_pGraph->numberOfEdges(); }
406 void updateBestSolution(
double* values);
408 void updateBestSolutionByEdges(
const List<edge>& sol);
448 if (m_poolSizeMax < m_pCutPool->size()) {
449 m_poolSizeMax = m_pCutPool->size();
504 virtual void initializeOptimization()
override;
506 virtual void terminateOptimization()
override;
508 virtual void initializeParameters()
override;
675#ifdef OGDF_STP_EXACT_LOGGING
677 void printCurrentSolution(
bool onlyNonZeros =
true);
682 virtual bool feasible()
override;
686 if (m_alreadySeparated == -1) {
687 m_alreadySeparated = mySeparate();
689 return m_alreadySeparated;
698#ifdef OGDF_STP_EXACT_LOGGING
700 void printMainInfosInFeasible(
bool header =
false)
const;
704#ifdef OGDF_STP_EXACT_LOGGING
741 return new Sub(master_,
this, rule);
753 int id,
edge e,
double coeff,
double lb = 0.0,
double ub = 1.0,
755 :
abacus::
Variable(master, nullptr , false, false, coeff, lb, ub, vartype)
764 int id()
const {
return m_id; }
791 , m_factor(factor) { }
797 if (e != m_e1 && e != m_e2) {
821 , m_coeffOut(coeffOut) { }
827 if (e->
target() == m_node) {
830 if (e->
source() == m_node) {
859 , m_coeffEdge(coeffEdge) { }
870 if (e->
target() != m_edge->source()) {
874 if (e->
source() == m_edge->target()) {
902#ifdef OGDF_STP_EXACT_LOGGING
903 std::cout <<
"Creating new DirectedCutConstraint: " << std::endl;
910#ifdef OGDF_STP_EXACT_LOGGING
913 std::cout <<
" marked node " << n << std::endl;
922 m_hashKey += n->index();
926#ifdef OGDF_STP_EXACT_LOGGING
927 std::cout <<
" front cut edges:" << std::endl;
930 std::cout <<
" " << e << std::endl;
933 std::cout <<
" back cut edges:" << std::endl;
936 std::cout <<
" " << e << std::endl;
957 unsigned hashKey()
const override {
return m_hashKey; };
960 bool equal(
const ConVar* cv)
const override;
963 const char*
name()
const override {
return m_name; }
988 :
abacus::
Master(
"MinSteinerTreeDirectedCut::Master", true, false,
abacus::OptSense::Min, eps)
989 , m_maxFlowModule(nullptr)
990 , m_configfile(nullptr)
992 , m_relaxedSolValue(-1)
995 , m_pCutPool(nullptr)
996 , m_poolSizeInitFactor(5)
1000 , m_addGSEC2Constraints(true)
1001 , m_addDegreeConstraints(true)
1002 , m_addIndegreeEdgeConstraints(true)
1003 , m_addFlowBalanceConstraints(true)
1004 , m_maxNrAddedCuttingPlanes(500)
1005 , m_shuffleTerminals(true)
1006 , m_backCutComputation(true)
1007 , m_nestedCutComputation(true)
1008 , m_separationStrategy(1)
1009 , m_saturationStrategy(1)
1010 , m_minCardinalityCuts(true)
1011 , m_callPrimalHeuristic(1) {
1012#ifdef OGDF_STP_EXACT_LOGGING
1029#ifdef OGDF_STP_EXACT_LOGGING
1038 nodeMapping[nOrig] = n;
1043#ifdef OGDF_STP_EXACT_LOGGING
1050#ifdef OGDF_STP_EXACT_LOGGING
1066 e1 =
m_pGraph->
newEdge(nodeMapping[eOrig->source()], nodeMapping[eOrig->target()]);
1067 e2 =
m_pGraph->
newEdge(nodeMapping[eOrig->target()], nodeMapping[eOrig->source()]);
1079#ifdef OGDF_STP_EXACT_LOGGING
1080 lout(
Level::Minor) <<
" " << eOrig <<
"[" << e1 <<
", " << e2 <<
"]" << std::flush;
1083#ifdef OGDF_STP_EXACT_LOGGING
1100#ifdef OGDF_STP_EXACT_LOGGING
1143 bool objectiveInteger =
false;
1145 this->readParameters(m_configfile);
1147#ifdef OGDF_STP_EXACT_LOGGING
1148 lout(Level::Alarm) <<
"Master::initializeParameters(): Error reading parameters."
1149 <<
"Using default values." << std::endl;
1152#ifdef OGDF_STP_EXACT_LOGGING
1154 getParameter(
"OutputLevel", outputLevel);
1155 setOutputLevel(
static_cast<Level>(outputLevel));
1157 int solver = (
OSISOLVER)findParameter(
"DefaultLpSolver", 12, OSISOLVER_);
1158 this->defaultLpSolver((
OSISOLVER)solver);
1172 getParameter(
"ObjInteger", objectiveInteger);
1173 this->objInteger(objectiveInteger);
1176#ifdef OGDF_STP_EXACT_LOGGING
1178 <<
"Master::initializeParameters(): parameters:" << std::endl
1179 <<
"\tLP-Solver " << OSISOLVER_[this->defaultLpSolver()] << std::endl
1180 <<
"\tOutputLevel " << this->localLogLevel() << std::endl
1196 <<
"\tObjective integer " << this->objInteger() << std::endl
1204#ifdef OGDF_STP_EXACT_LOGGING
1205 lout(Level::High) <<
"Master::initializeOptimization(): Instance properties:" << std::endl
1206 <<
"\t(nNodes,nEdges) : (" << m_pGraph->numberOfNodes() <<
", "
1207 << m_nEdgesU <<
")" << std::endl
1208 <<
"\tNumber of terminals : " << m_nTerminals << std::endl
1209 <<
"\tRoot node : " << m_root << std::endl
1219 m_edgeToVar.init(*m_pGraph,
nullptr);
1226 for (i = 0; i < m_pGraph->numberOfEdges(); i++) {
1227 edge e = m_edges[i];
1228 if (e->
target() != m_root
1230 eVar =
new EdgeVariable(
this, i, e, m_capacities[e], 0.0, 1.0, vartype);
1231#ifdef OGDF_STP_EXACT_LOGGING
1232 lout(Level::Minor) <<
"\tadding variable x_" << i <<
", edge " << e << std::endl;
1237 eVar =
new EdgeVariable(
this, i, e, m_capacities[e], 0.0, 0.0, vartype);
1238#ifdef OGDF_STP_EXACT_LOGGING
1239 lout(Level::Minor) <<
"\tmuting variable x_" << i <<
", edge " << e << std::endl;
1242 variables.
push(eVar);
1243 m_edgeToVar[e] = eVar;
1252 nCons += m_pGraph->numberOfNodes();
1255 nCons += m_pGraph->numberOfEdges();
1258 nCons += m_pGraph->numberOfNodes() - 1;
1266 for (
edge e : m_pGraph->edges) {
1267 if (!marked[e] && !e->isSelfLoop()) {
1270 basicConstraints.
push(newCon);
1272 marked[m_twin[e]] =
true;
1274#ifdef OGDF_STP_EXACT_LOGGING
1276 <<
"\tadding constraint " << i++ <<
" GSEC2: edge " << e << std::endl;
1287 for (
node n : m_pGraph->nodes) {
1293 if (m_isTerminal[n]) {
1301 basicConstraints.
push(newCon);
1303#ifdef OGDF_STP_EXACT_LOGGING
1304 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Degree: node " << n << std::endl;
1310 for (
edge e : m_pGraph->edges) {
1311 if (e->source() != m_root) {
1314 basicConstraints.
push(newCon);
1316#ifdef OGDF_STP_EXACT_LOGGING
1318 <<
"\tadding constraint " << i++ <<
" Indegree: edge " << e << std::endl;
1325 for (
node n : m_pGraph->nodes) {
1326 if (!m_isTerminal[n]) {
1329 basicConstraints.
push(newCon);
1331#ifdef OGDF_STP_EXACT_LOGGING
1332 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Flow-Balance: node " << n
1340 m_poolSizeMax = m_poolSizeInit;
1345 this->initializePools(basicConstraints, variables, 0, nCons,
true);
1347#ifdef OGDF_STP_EXACT_LOGGING
1348 lout(Level::Minor) <<
"Master::initializeOptimization() done." << std::endl;
1354#ifdef OGDF_STP_EXACT_LOGGING
1357 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1358 if (m_bestSolution[i] > 0.5) {
1359 m_isSolutionEdge[m_edges[i]] =
true;
1360#ifdef OGDF_STP_EXACT_LOGGING
1366#ifdef OGDF_STP_EXACT_LOGGING
1367 lout(Level::High) << std::endl;
1368 if (is_lout(Level::Medium)) {
1369 lout(Level::Medium) <<
"\toptimum solution edges:" << std::endl;
1370 for (
edge e : m_pGraph->edges) {
1371 if (m_isSolutionEdge[e]) {
1372 lout(Level::Medium) <<
"\t" << e << std::endl;
1376 lout(Level::Medium) << std::endl;
1379 <<
"Finished optimization. Statistics:" << std::endl
1380 <<
"Solution " << std::endl
1381 <<
" value " << this->primalBound() << std::endl
1382 <<
" rounded sol. value " << ((int)this->primalBound()) << std::endl
1383 <<
" nr edges " << nOnesInSol << std::endl
1384 <<
"Status " << this->STATUS_[this->status()] << std::endl
1385 <<
"Primal/dual bound " << this->primalBound() <<
"/" << this->dualBound()
1387 <<
"Relaxed solution value " << this->m_relaxedSolValue << std::endl
1388 <<
"Nr subproblems " << this->nSub() << std::endl
1389 <<
"Nr solved LPs " << this->nLp() << std::endl
1390 <<
"nr solved LPs in root " << m_nIterRoot << std::endl
1393 <<
"LP Solver " << this->OSISOLVER_[this->defaultLpSolver()] << std::endl
1394 <<
"Enumeration strategy " << this->ENUMSTRAT_[this->enumerationStrategy()] << std::endl
1395 <<
"Branching strategy " << this->BRANCHINGSTRAT_[this->branchingStrategy()]
1397 <<
"Objective integer " << (this->objInteger() ?
"true" :
"false") << std::endl
1400 <<
"Total time (centi sec) " << this->totalTime()->centiSeconds() << std::endl
1401 <<
"Total time " << *this->totalTime() << std::endl
1402 <<
"Total cow-time " << *this->totalCowTime() << std::endl
1403 <<
"LP time " << *this->lpTime() << std::endl
1404 <<
"LP solver time " << *this->lpSolverTime() << std::endl
1405 <<
"Separation time " << this->m_separationTimer << std::endl
1406 <<
"Minimum Cut time " << this->m_timerMinSTCut << std::endl
1407 <<
"Primal heuristic time " << this->m_primalHeuristicTimer << std::endl
1410 <<
"Initial cutpool size " << this->m_poolSizeInit << std::endl
1411 <<
"Maximum cutpool size " << this->m_poolSizeMax << std::endl
1412 <<
"Nr separated cuts " << m_nrCutsTotal << std::endl;
1414 int nDuplicates, nCollisions;
1415 m_pCutPool->statistics(nDuplicates, nCollisions);
1416 lout(Level::High) <<
"Cutpool duplications " << nDuplicates << std::endl
1417 <<
"Cutpool collisions " << nCollisions << std::endl
1424 double eps = this->eps();
1425 double oneMinusEps = 1.0 - eps;
1426 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1427 if (values[i] > oneMinusEps) {
1428 m_bestSolution[i] = 1.0;
1429 }
else if (values[i] < eps) {
1430 m_bestSolution[i] = 0.0;
1432 m_bestSolution[i] = values[i];
1439 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1440 m_bestSolution[i] = 0.0;
1443 m_bestSolution[m_edgeIDs[*it]] = 1.0;
1449 :
abacus::
Sub(master, 0, 0, 0), m_alreadySeparated(-1) {
1464 :
abacus::
Sub(master, father, branchRule), m_alreadySeparated(-1) {
1466#ifdef OGDF_STP_EXACT_LOGGING
1468 <<
" new subproblem, parent=" << father->
id() << std::endl;
1480#ifdef OGDF_STP_EXACT_LOGGING
1487 << std::setw(7) <<
"id" << std::setw(7) <<
"iter" << std::setw(10) <<
"lp value"
1488 << std::setw(10) <<
"gl. LB" << std::setw(10) <<
"gl. UB" << std::setw(10) <<
"nSub"
1489 << std::setw(10) <<
"nOpenSub" << std::endl;
1492 << this->nIter_ << std::setw(10) << lp_->value();
1493 if (this->
id() == 1) {
1498 if (master_->feasibleFound()) {
1504 << master_->openSub()->number() << std::endl;
1514 double eps = master_->eps();
1515 double oneMinusEps = 1.0 - eps;
1517#ifdef OGDF_STP_EXACT_LOGGING
1518 if (this->nIter_ == 1) {
1519 this->printMainInfosInFeasible(
true);
1521 this->printMainInfosInFeasible(
false);
1526 m_alreadySeparated = mySeparate();
1528 if (m_alreadySeparated > 0) {
1535 if (this->
id() == 1) {
1537 m_pMaster->setRelaxedSolValue(lp_->value());
1538 m_pMaster->setNIterRoot(nIter_);
1541 if (!m_pMaster->relaxed()) {
1543 for (
int i = 0; i < m_pMaster->nEdges(); i++) {
1544 if (xVal_[i] > eps && xVal_[i] < oneMinusEps) {
1552#ifdef OGDF_STP_EXACT_LOGGING
1554 <<
"\tsolution is fractional -> Branching." << std::endl;
1561 if (m_pMaster->betterPrimal(lp_->value())) {
1562#ifdef OGDF_STP_EXACT_LOGGING
1564 << std::setw(7) << this->id() << std::setw(7) << this->nIter_
1565 <<
" found better integer solution with value " << lp_->value();
1568 printCurrentSolution();
1573 m_pMaster->primalBound(lp_->value());
1574 m_pMaster->updateBestSolution(xVal_);
1580#ifdef OGDF_STP_EXACT_LOGGING
1584 double eps = master_->eps();
1585 double oneMinusEps = 1.0 - eps;
1586 for (
int i = 0; i < nVar(); i++) {
1587 if (xVal_[i] > -eps && xVal_[i] < eps) {
1588 if (!onlyNonZeros) {
1591 <<
" [edge " << ((
EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1593 }
else if (xVal_[i] > oneMinusEps && xVal_[i] < 1 + eps) {
1596 <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1601 <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1610#ifdef OGDF_STP_EXACT_LOGGING
1612 <<
"Sub::mySeparate(): id=" << this->id() <<
", iter=" << this->nIter_ << std::endl;
1614 m_pMaster->separationTimer()->start();
1615 double eps = master_->eps();
1616 double cardEps = eps / 100;
1617 double oneMinusEps = 1 - eps;
1618 node r = m_pMaster->rootNode();
1619 const Graph& g = m_pMaster->graph();
1620 int nEdgesU = m_pMaster->nEdgesU();
1622 int nTerminals = m_pMaster->nTerminals();
1623 const node* masterTerminals = m_pMaster->terminals();
1626 for (
int i = 0; i < nTerminals; i++) {
1627 terminal[i] = masterTerminals[i];
1634 for (
int i = 0; i < nTerminals - 1; i++) {
1637 terminal[i] = terminal[j];
1642#ifdef OGDF_STP_EXACT_LOGGING
1645 for (
int i = 0; i < nTerminals; i++) {
1653 capacities.
init(g, 0);
1656 capacities[e] = max(xVal_[m_pMaster->edgeID(e)], 0.);
1658 capacities[e] += cardEps;
1662#ifdef OGDF_STP_EXACT_LOGGING
1664 <<
"Sub::mySeparate(): current capacities (>0) for mincut computation:" << std::endl;
1666 if (capacities[e] >= 2 * cardEps) {
1668 <<
"\tcapacity[" << e <<
"]=" << capacities[e] << std::endl;
1679 double cutValue = 2.0;
1681 double cutValueBack = 0.0;
1683 int nOtherNodes = 0;
1685 double uBound = 1 + nEdgesU * cardEps;
1693 int cardinalityCut, cardinalityBackcut;
1694 cardinalityCut = cardinalityBackcut = 0;
1702 while (cutsFound < m_maxNrCuttingPlanes && ti < nTerminals) {
1705#ifdef OGDF_STP_EXACT_LOGGING
1707 <<
"Sub::mySeparate(): computing minimum cut between root " <<
r <<
" and " << t
1717 m_pMaster->timerMinSTCut()->start();
1725#ifdef OGDF_STP_EXACT_LOGGING
1729 <<
" " << flowEdge <<
" : " << flow[flowEdge] <<
" / "
1730 << capacities[flowEdge] << std::endl;
1736 minSTCut.
call(g, capacities, flow,
r, t);
1738 m_pMaster->timerMinSTCut()->stop();
1741#ifdef OGDF_STP_EXACT_LOGGING
1749 cutValue -= cardEps;
1752 cutValueBack += capacities[e] - cardEps;
1755 }
else if (m_computeBackCuts) {
1758 cutValueBack += capacities[e];
1764 cardinalityCut = cardinalityBackcut = 0;
1770 cardinalityBackcut++;
1775#ifdef OGDF_STP_EXACT_LOGGING
1777 if (m_computeBackCuts) {
1784 if (cutValue < oneMinusEps) {
1791 newConstraints.
push(newCut);
1793#ifdef OGDF_STP_EXACT_LOGGING
1795 <<
"Sub::mySeparate(): found violated cut:" << std::endl;
1799 && cutsFound < m_maxNrCuttingPlanes && cutValueBack <= oneMinusEps) {
1805 newConstraints.
push(newBackCut);
1807#ifdef OGDF_STP_EXACT_LOGGING
1809 <<
"Sub::mySeparate(): found violated cut (backcut):" << std::endl;
1815 if (m_computeNestedCuts) {
1819 capacities[e] = 1.0 / (double)cardinalityCut + eps;
1821 capacities[e] = 1.0 + eps;
1828 if (m_computeBackCuts && nOtherNodes > 0 && cutValueBack <= oneMinusEps
1831 capacities[e] = 1.0 / (double)cardinalityBackcut + eps;
1833 capacities[e] = 1.0 + eps;
1846 if (!m_computeNestedCuts) {
1849 if (cutValue > oneMinusEps ||
r == t) {
1852 while (!modified.
empty()) {
1854 capacities[e] = xVal_[m_pMaster->edgeID(e)];
1856 capacities[e] += cardEps;
1864 m_alreadySeparated = cutsFound;
1866 if (cutsFound > 0) {
1868 int nAdded = addCons(newConstraints, m_pMaster->cutPool());
1870 m_pMaster->incNrCutsTotal(nAdded);
1871 m_pMaster->checkSetMaxPoolSize();
1872 if (nAdded != cutsFound) {
1877#ifdef OGDF_STP_EXACT_LOGGING
1879 <<
"Sub::mySeparate(): id=" << this->id() <<
", iter=" << this->nIter_ <<
" separated "
1880 << cutsFound <<
" directed cuts" << std::endl;
1882 m_pMaster->separationTimer()->stop();
1889 m_pMaster->primalHeuristicTimer()->start();
1891#ifdef OGDF_STP_EXACT_LOGGING
1893 <<
"Sub::myImprove(): id=" << this->id() <<
", iter=" << this->nIter_ << std::endl;
1895 double eps = master_->eps();
1896 const Graph& g = m_pMaster->graph();
1899#ifdef OGDF_STP_EXACT_LOGGING
1904 <<
"\tx" << m_pMaster->edgeID(e) <<
"=" << xVal_[m_pMaster->edgeID(e)]
1905 <<
", edge " << e << std::endl;
1912 double currWeight, twinWeight;
1914 edge e2 = m_pMaster->twin(e);
1915 currWeight = 1.0 - xVal_[m_pMaster->edgeID(e)];
1916 twinWeight = 1.0 - xVal_[m_pMaster->edgeID(e2)];
1917 if (twinWeight < currWeight) {
1918 currWeight = twinWeight;
1920 if (currWeight < 0) {
1923 ewg.
setWeight(m_pMaster->edgeGToWgPH(e),
1924 eps + currWeight * variable(m_pMaster->edgeID(e))->obj());
1927#ifdef OGDF_STP_EXACT_LOGGING
1932 <<
"\tweight[" << e <<
"]=" << ewg.
weight(m_pMaster->edgeGToWgPH(e))
1939 auto& primalHeuristic = m_pMaster->getPrimalHeuristic();
1944#ifdef OGDF_STP_EXACT_LOGGING
1946 double tmpHeuristicSolutionValue =
1949 primalHeuristic->call(m_pMaster->weightedGraphPH(), m_pMaster->terminalListPH(),
1950 m_pMaster->isTerminalPH(), heuristicSolutionWg);
1953 bool isSteinerTree = primalHeuristic->isSteinerTree(m_pMaster->weightedGraphPH(),
1954 m_pMaster->terminalListPH(), m_pMaster->isTerminalPH(), *heuristicSolutionWg);
1956#ifdef OGDF_STP_EXACT_LOGGING
1958 <<
"Sub::myImprove(): primal heuristic algorithm returned solution with "
1959 <<
"value " << tmpHeuristicSolutionValue <<
", isSteinerTree=" <<
isSteinerTree
1965 double heuristicSolutionValue = 0.0;
1969 for (
edge e : heuristicSolutionWg->
edges) {
1970 edge e2 = m_pMaster->edgeWgToGPH(heuristicSolutionWg->
original(e));
1972 heuristicSolutionValue += m_pMaster->capacities(e2);
1973#ifdef OGDF_STP_EXACT_LOGGING
1975 <<
"\t" << e <<
" -> " << e2 <<
" c=" << m_pMaster->capacities(e2) << std::endl;
1979#ifdef OGDF_STP_EXACT_LOGGING
1981 <<
"Sub::myImprove(): found integer solution with value " << heuristicSolutionValue
1984 if (m_pMaster->betterPrimal(heuristicSolutionValue)) {
1985#ifdef OGDF_STP_EXACT_LOGGING
1987 << std::setw(7) << this->id() << std::setw(7) << this->nIter_
1988 <<
" primal heuristic founds better integer solution with value "
1989 << heuristicSolutionValue << std::endl;
1991 m_pMaster->primalBound(heuristicSolutionValue);
1992 m_pMaster->updateBestSolutionByEdges(solutionEdges);
1995#ifdef OGDF_STP_EXACT_LOGGING
1998 <<
"Sub::myImprove(): id=" << this->id() <<
", iter=" << this->nIter_
1999 <<
": computed solution is no Steiner tree!" << std::endl;
2003 delete heuristicSolutionWg;
2004 m_pMaster->primalHeuristicTimer()->stop();
2007#ifdef OGDF_STP_EXACT_LOGGING
2011 double eps = master_->eps();
2015 for (
int i = 0; i < nVar(); i++) {
2017 val = constraint->
coeff(var);
2018 if (val > eps || val < -eps) {
2020 if (val > 1 - eps && val < 1 + eps) {
2022 m_pMaster->lout(level) <<
" + ";
2026 m_pMaster->lout(level) <<
" + " << val;
2030 if (val < -1 + eps && val > -1 - eps) {
2032 m_pMaster->lout(level) <<
" - ";
2034 m_pMaster->lout(level) <<
" -";
2038 m_pMaster->lout(level) <<
" - " << (-1) * val;
2040 m_pMaster->lout(level) << val;
2044 m_pMaster->lout(level) <<
"x" << i;
2048 m_pMaster->lout(level) <<
" " << *(constraint->
sense()) <<
" " << constraint->
rhs() << std::endl;
2054 if (m_hashKey != cv->hashKey()) {
2061 for (
node n : m_pGraph->nodes) {
2062 if (m_marked[n] != dirCut->
marked(n)) {
2072 if (this->cutedge(edgeVar->
theEdge())) {
2082 Master stpMaster(G, terminals, isTerminal,
m_eps);
2086#ifdef OGDF_STP_EXACT_LOGGING
2087 stpMaster.setOutputLevel(m_outputLevel);
2115 for (
edge e = G.firstEdge(); e; e = e->succ()) {
2117 const node vO = e->source();
2118 node vC = finalSteinerTree->
copy(vO);
2120 vC = finalSteinerTree->
newNode(vO);
2122 const node wO = e->target();
2123 node wC = finalSteinerTree->
copy(wO);
2125 wC = finalSteinerTree->
newNode(wO);
2127 T edgeCost = G.weight(e);
2128 finalSteinerTree->
newEdge(e, edgeCost);
Declaration and implementation of Array class and Array algorithms.
Declaration and implementation of ArrayBuffer class.
Declaration of class EdgeWeightedGraph.
Extends the GraphCopy concept to weighted graphs.
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration of doubly linked lists and iterators.
Contains logging functionality.
Declaration and implementation of Goldberg-Tarjan max-flow algorithm with global relabeling and gap r...
Interface for Max Flow Algorithms.
Declaration of min-st-cut algorithms parameterized by max-flow alorithm.
Declaration of ogdf::MinSteinerTreeModule.
Implementation of the 2(1-1/l)-approximation algorithm for the minimum Steiner tree problem by Matsuy...
Declaration of stopwatch classes.
Basic declarations, included by all source files.
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.
STATUS optimize()
Performs the optimization by branch-and-bound.
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.
void push(E e)
Puts a new element in the buffer.
The parameterized class Array implements dynamic arrays of type E.
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 u, node v, T weight)
void setOriginalGraph(const Graph *wG) override
Re-initializes the copy using G (which might be null), but does not create any nodes or edges.
T weight(const edge e) const
edge newEdge(node v, node w, T weight)
void setWeight(const edge e, T weight)
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
const Graph & original() const
Returns a reference to the original graph.
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
Data type for general directed graphs (adjacency list representation).
int numberOfNodes() const
Returns the number of nodes in the graph.
int numberOfEdges() const
Returns the number of edges in the graph.
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
node newNode(int index=-1)
Creates a new node and returns it.
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) 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).
iterator pushBack(const E &x)
Adds element x at the end of the list.
E popFrontRet()
Removes the first element from the list and returns it.
Encapsulates a pointer to a list element.
iterator begin()
Returns an iterator to the first element of the list.
bool empty() const
Returns true iff the list is empty.
Centralized global and local logging facility working on streams like std::cout.
std::ostream & lout(Level level=Level::Default, bool indent=true) const
stream for logging-output (local)
Level
supported log-levels from lowest to highest importance
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
virtual void init(const Graph &graph, EdgeArray< T > *flow=nullptr)
Initialize the problem with a graph and optional flow array. If no flow array is given,...
void useEpsilonTest(const double &eps)
Change the used EpsilonTest from StandardEpsilonTest to a user given EpsilonTest.
T computeFlow(EdgeArray< T > &cap, node &s, node &t, EdgeArray< T > &flow)
Only a shortcut for computeValue and computeFlowAfterValue.
Min-st-cut algorithm, that calculates the cut via maxflow.
bool isBackCutEdge(const edge e) const
Returns whether this edge is entering the back cut.
bool isInBackCut(const node v) const
Returns whether this node is part of the back cut.
cutType
The three types of cuts.
bool isFrontCutEdge(const edge e) const
Returns whether this edge is leaving the front cut.
void setEpsilonTest(EpsilonTest *et)
Assigns a new epsilon test.
virtual bool call(const Graph &graph, const EdgeArray< TCost > &weight, node s, node t, List< edge > &edgeList, edge e_st=nullptr) override
The actual algorithm call.
bool frontCutIsComplementOfBackCut() const
Returns whether the front cut is the complement of the backcut.
bool isInFrontCut(const node v) const
Returns whether this node is part of the front cut.
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...
Class for the representation of nodes.
int degree() const
Returns the degree of the node (indegree + outdegree).
void init(const Base *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
Implements a stopwatch measuring wall-clock time.
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition of exception classes.
#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).
The namespace for all OGDF objects.