 |
Open Graph Drawing Framework |
v. 2022.02 (Dogwood)
|
|
|
Go to the documentation of this file.
76 #ifdef OGDF_STP_EXACT_LOGGING
115 #ifdef OGDF_STP_EXACT_LOGGING
119 m_outputLevel = outputLevel;
202 #ifdef OGDF_STP_EXACT_LOGGING
246 bool relaxed =
false);
251 delete[] m_bestSolution;
252 delete[] m_terminals;
256 delete m_pWeightedGraphPH;
263 m_configfile = filename;
265 #ifdef OGDF_STP_EXACT_LOGGING
266 void setOutputLevel(
Level outputLevel)
269 this->globalLogLevel(Level::Default);
270 this->localLogMode(LogMode::Log);
271 if (outputLevel >= Level::Minor
272 && outputLevel <= Level::Force) {
273 this->localLogLevel((
Level)outputLevel);
274 this->globalMinimumLogLevel((
Level)outputLevel);
280 m_maxFlowModule = module;
286 return m_maxFlowModule;
376 return new Sub(
this);
382 return m_isSolutionEdge[m_mapToBidirectedGraph1[e]]
383 || m_isSolutionEdge[m_mapToBidirectedGraph2[e]];
390 int nNodes()
const {
return m_pGraph->numberOfNodes();}
392 int nEdges()
const {
return m_pGraph->numberOfEdges();}
449 void updateBestSolution(
double *values);
451 void updateBestSolutionByEdges(
const List<edge> &sol);
483 if (m_poolSizeMax < m_pCutPool->size())
484 m_poolSizeMax = m_pCutPool->size();
528 virtual void initializeOptimization()
override;
530 virtual void terminateOptimization()
override;
532 virtual void initializeParameters()
override;
701 #ifdef OGDF_STP_EXACT_LOGGING
702 void printCurrentSolution(
bool onlyNonZeros =
true);
708 virtual bool feasible()
override;
713 if (m_alreadySeparated == -1) {
714 m_alreadySeparated = mySeparate();
716 return m_alreadySeparated;
724 #ifdef OGDF_STP_EXACT_LOGGING
725 void printMainInfosInFeasible(
bool header =
false)
const;
730 #ifdef OGDF_STP_EXACT_LOGGING
767 return new Sub(master_,
this, rule);
787 :
abacus::
Variable(master, nullptr , false, false, coeff, lb, ub, vartype)
796 int id()
const {
return m_id;}
835 if (e != m_e1 && e != m_e2)
864 , m_coeffOut(coeffOut)
873 if (e->
target() == m_node) {
876 if (e->
source() == m_node) {
911 , m_coeffEdge(coeffEdge)
924 if (e->
target() != m_edge->source())
927 if (e->
source() == m_edge->target())
955 #ifdef OGDF_STP_EXACT_LOGGING
956 std::cout <<
"Creating new DirectedCutConstraint: " << std::endl;
963 #ifdef OGDF_STP_EXACT_LOGGING
966 std::cout <<
" marked node " << n << std::endl;
975 m_hashKey += n->index();
979 #ifdef OGDF_STP_EXACT_LOGGING
980 std::cout <<
" front cut edges:" << std::endl;
983 std::cout <<
" " << e << std::endl;
986 std::cout <<
" back cut edges:" << std::endl;
989 std::cout <<
" " << e << std::endl;
1003 return m_marked[e->
source()] && !m_marked[e->
target()];
1010 unsigned hashKey()
const override {
return m_hashKey; };
1012 bool equal(
const ConVar *cv)
const override;
1014 const char *
name()
const override {
return m_name; }
1037 template<
typename T>
1044 :
abacus::
Master(
"MinSteinerTreeDirectedCut::Master", true, false,
abacus::OptSense::Min, eps)
1045 , m_maxFlowModule(nullptr)
1046 , m_configfile(nullptr)
1047 , m_relaxed(relaxed)
1048 , m_relaxedSolValue(-1)
1051 , m_pCutPool(nullptr)
1052 , m_poolSizeInitFactor(5)
1056 , m_addGSEC2Constraints(true)
1057 , m_addDegreeConstraints(true)
1058 , m_addIndegreeEdgeConstraints(true)
1059 , m_addFlowBalanceConstraints(true)
1060 , m_maxNrAddedCuttingPlanes(500)
1061 , m_shuffleTerminals(true)
1062 , m_backCutComputation(true)
1063 , m_nestedCutComputation(true)
1064 , m_separationStrategy(1)
1065 , m_saturationStrategy(1)
1066 , m_minCardinalityCuts(true)
1067 , m_callPrimalHeuristic(1)
1069 #ifdef OGDF_STP_EXACT_LOGGING
1071 <<
"Master::Master(): default LP solver: "
1086 #ifdef OGDF_STP_EXACT_LOGGING
1088 <<
"Master::Master(): nTerminals="
1097 nodeMapping[nOrig] = n;
1102 #ifdef OGDF_STP_EXACT_LOGGING
1109 #ifdef OGDF_STP_EXACT_LOGGING
1126 nodeMapping[eOrig->
target()]);
1139 #ifdef OGDF_STP_EXACT_LOGGING
1140 lout(
Level::Minor) <<
" " << eOrig <<
"[" << e1 <<
", " << e2 <<
"]" << std::flush;
1143 #ifdef OGDF_STP_EXACT_LOGGING
1159 #ifdef OGDF_STP_EXACT_LOGGING
1196 template<
typename T>
1201 bool objectiveInteger =
false;
1203 this->readParameters(m_configfile);
1206 #ifdef OGDF_STP_EXACT_LOGGING
1208 <<
"Master::initializeParameters(): Error reading parameters."
1209 <<
"Using default values." << std::endl;
1212 #ifdef OGDF_STP_EXACT_LOGGING
1214 getParameter(
"OutputLevel", outputLevel);
1215 setOutputLevel(
static_cast<Level>(outputLevel));
1217 int solver = (
OSISOLVER) findParameter(
"DefaultLpSolver", 12, OSISOLVER_);
1218 this->defaultLpSolver((
OSISOLVER)solver);
1232 getParameter(
"ObjInteger", objectiveInteger);
1233 this->objInteger(objectiveInteger);
1236 #ifdef OGDF_STP_EXACT_LOGGING
1238 <<
"Master::initializeParameters(): parameters:" << std::endl
1239 <<
"\tLP-Solver " << OSISOLVER_[this->defaultLpSolver()] << std::endl
1240 <<
"\tOutputLevel " << this->localLogLevel() << std::endl
1258 <<
"\tObjective integer " << this->objInteger() << std::endl
1264 template<
typename T>
1268 #ifdef OGDF_STP_EXACT_LOGGING
1270 <<
"Master::initializeOptimization(): Instance properties:" << std::endl
1271 <<
"\t(nNodes,nEdges) : (" << m_pGraph->numberOfNodes()
1272 <<
", " << m_nEdgesU <<
")" << std::endl
1273 <<
"\tNumber of terminals : " << m_nTerminals << std::endl
1274 <<
"\tRoot node : " << m_root << std::endl
1284 m_edgeToVar.init(*m_pGraph,
nullptr);
1291 for (i = 0; i < m_pGraph->numberOfEdges(); i++) {
1292 edge e = m_edges[i];
1293 if (e->
target() != m_root
1295 eVar =
new EdgeVariable(
this, i, e, m_capacities[e], 0.0, 1.0, vartype);
1296 #ifdef OGDF_STP_EXACT_LOGGING
1297 lout(Level::Minor) <<
"\tadding variable x_" << i <<
", edge " << e << std::endl;
1303 eVar =
new EdgeVariable(
this, i, e, m_capacities[e], 0.0, 0.0, vartype);
1304 #ifdef OGDF_STP_EXACT_LOGGING
1305 lout(Level::Minor) <<
"\tmuting variable x_" << i <<
", edge " << e << std::endl;
1308 variables.
push(eVar);
1309 m_edgeToVar[e] = eVar;
1317 nCons += m_pGraph->numberOfNodes();
1319 nCons += m_pGraph->numberOfEdges();
1321 nCons += m_pGraph->numberOfNodes()-1;
1328 for (
edge e : m_pGraph->edges) {
1333 basicConstraints.
push(newCon);
1335 marked[m_twin[e]] =
true;
1337 #ifdef OGDF_STP_EXACT_LOGGING
1338 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" GSEC2: edge " << e << std::endl;
1350 for (
node n : m_pGraph->nodes) {
1357 if (m_isTerminal[n]) {
1366 basicConstraints.
push(newCon);
1368 #ifdef OGDF_STP_EXACT_LOGGING
1369 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Degree: node " << n << std::endl;
1375 for (
edge e : m_pGraph->edges) {
1376 if (e->
source() != m_root) {
1379 basicConstraints.
push(newCon);
1381 #ifdef OGDF_STP_EXACT_LOGGING
1382 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Indegree: edge " << e << std::endl;
1389 for (
node n : m_pGraph->nodes) {
1390 if (!m_isTerminal[n]) {
1393 basicConstraints.
push(newCon);
1395 #ifdef OGDF_STP_EXACT_LOGGING
1396 lout(Level::Minor) <<
"\tadding constraint " << i++ <<
" Flow-Balance: node " << n << std::endl;
1403 m_poolSizeMax = m_poolSizeInit;
1407 this->initializePools(
1414 #ifdef OGDF_STP_EXACT_LOGGING
1415 lout(Level::Minor) <<
"Master::initializeOptimization() done." << std::endl;
1420 template<
typename T>
1425 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1426 if (m_bestSolution[i] > 0.5) {
1427 m_isSolutionEdge[m_edges[i]] =
true;
1432 #ifdef OGDF_STP_EXACT_LOGGING
1433 lout(Level::High) << std::endl;
1434 if (is_lout(Level::Medium)) {
1435 lout(Level::Medium) <<
"\toptimum solution edges:" << std::endl;
1436 for (
edge e : m_pGraph->edges) {
1437 if (m_isSolutionEdge[e])
1438 lout(Level::Medium) <<
"\t" << e << std::endl;
1441 lout(Level::Medium) << std::endl;
1444 <<
"Finished optimization. Statistics:" << std::endl
1445 <<
"Solution " << std::endl
1446 <<
" value " << this->primalBound() << std::endl
1447 <<
" rounded sol. value " << ((int)this->primalBound()) << std::endl
1448 <<
" nr edges " << nOnesInSol << std::endl
1449 <<
"Status " << this->STATUS_[this->status()] << std::endl
1450 <<
"Primal/dual bound " << this->primalBound() <<
"/" << this->dualBound() << std::endl
1451 <<
"Relaxed solution value " << this->m_relaxedSolValue << std::endl
1452 <<
"Nr subproblems " << this->nSub() << std::endl
1453 <<
"Nr solved LPs " << this->nLp() << std::endl
1454 <<
"nr solved LPs in root " << m_nIterRoot << std::endl
1457 <<
"LP Solver " << this->OSISOLVER_[this->defaultLpSolver()] << std::endl
1458 <<
"Enumeration strategy " << this->ENUMSTRAT_[this->enumerationStrategy()] << std::endl
1459 <<
"Branching strategy " << this->BRANCHINGSTRAT_[this->branchingStrategy()] << std::endl
1460 <<
"Objective integer " << (this->objInteger()?
"true":
"false") << std::endl
1463 <<
"Total time (centi sec) " << this->totalTime()->centiSeconds() << std::endl
1464 <<
"Total time " << *this->totalTime() << std::endl
1465 <<
"Total cow-time " << *this->totalCowTime() << std::endl
1466 <<
"LP time " << *this->lpTime() << std::endl
1467 <<
"LP solver time " << *this->lpSolverTime() << std::endl
1468 <<
"Separation time " << this->m_separationTimer << std::endl
1469 <<
"Minimum Cut time " << this->m_timerMinSTCut << std::endl
1470 <<
"Primal heuristic time " << this->m_primalHeuristicTimer << std::endl
1473 <<
"Initial cutpool size " << this->m_poolSizeInit << std::endl
1474 <<
"Maximum cutpool size " << this->m_poolSizeMax << std::endl
1475 <<
"Nr separated cuts " << m_nrCutsTotal << std::endl;
1477 int nDuplicates, nCollisions;
1478 m_pCutPool->statistics(nDuplicates, nCollisions);
1480 <<
"Cutpool duplications " << nDuplicates << std::endl
1481 <<
"Cutpool collisions " << nCollisions << std::endl
1487 template<
typename T>
1491 double eps = this->eps();
1492 double oneMinusEps = 1.0 - eps;
1493 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1494 if (values[i] > oneMinusEps)
1495 m_bestSolution[i] = 1.0;
1497 if (values[i] < eps)
1498 m_bestSolution[i] = 0.0;
1500 m_bestSolution[i] = values[i];
1504 template<
typename T>
1508 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1509 m_bestSolution[i] = 0.0;
1512 m_bestSolution[m_edgeIDs[*it]] = 1.0;
1517 template<
typename T>
1520 , m_alreadySeparated(-1)
1534 template<
typename T>
1536 :
abacus::
Sub(master, father, branchRule)
1537 , m_alreadySeparated(-1)
1540 #ifdef OGDF_STP_EXACT_LOGGING
1542 << std::setw(7) << this->
id()
1543 << std::setw(7) << this->
nIter_
1544 <<
" new subproblem, parent=" << father->
id() << std::endl;
1556 #ifdef OGDF_STP_EXACT_LOGGING
1557 template<
typename T>
1565 << std::setw(7) <<
"id"
1566 << std::setw(7) <<
"iter"
1567 << std::setw(10) <<
"lp value"
1568 << std::setw(10) <<
"gl. LB"
1569 << std::setw(10) <<
"gl. UB"
1570 << std::setw(10) <<
"nSub"
1571 << std::setw(10) <<
"nOpenSub"
1576 << std::setw(7) << this->id()
1577 << std::setw(7) << this->nIter_
1578 << std::setw(10) << lp_->value();
1579 if (this->
id() == 1)
1583 if (master_->feasibleFound())
1588 << std::setw(10) << master_->nSub()
1589 << std::setw(10) << master_->openSub()->number()
1592 <<
"\tcurrent LP:" << std::endl;
1599 template<
typename T>
1603 double eps = master_->eps();
1604 double oneMinusEps = 1.0 - eps;
1606 #ifdef OGDF_STP_EXACT_LOGGING
1607 if (this->nIter_ == 1) {
1608 this->printMainInfosInFeasible(
true);
1611 this->printMainInfosInFeasible(
false);
1615 m_alreadySeparated = mySeparate();
1617 if (m_alreadySeparated > 0) {
1624 if (this->
id() == 1) {
1626 m_pMaster->setRelaxedSolValue(lp_->value());
1627 m_pMaster->setNIterRoot(nIter_);
1630 if (!m_pMaster->relaxed()) {
1632 for (
int i = 0; i < m_pMaster->nEdges(); i++) {
1633 if (xVal_[i] > eps && xVal_[i] < oneMinusEps) {
1641 #ifdef OGDF_STP_EXACT_LOGGING
1643 <<
"\tsolution is fractional -> Branching." << std::endl;
1650 if (m_pMaster->betterPrimal(lp_->value())) {
1651 #ifdef OGDF_STP_EXACT_LOGGING
1653 << std::setw(7) << this->id()
1654 << std::setw(7) << this->nIter_
1655 <<
" found better integer solution with value " << lp_->value();
1658 printCurrentSolution();
1663 m_pMaster->primalBound(lp_->value());
1664 m_pMaster->updateBestSolution(xVal_);
1670 #ifdef OGDF_STP_EXACT_LOGGING
1671 template<
typename T>
1676 double eps = master_->eps();
1677 double oneMinusEps = 1.0 - eps;
1678 for (
int i = 0; i < nVar(); i++) {
1679 if (xVal_[i] > -eps && xVal_[i] < eps) {
1680 if (!onlyNonZeros) {
1685 else if (xVal_[i] > oneMinusEps && xVal_[i] < 1+eps) {
1687 m_pMaster->lout(
Logger::Level::Minor) <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1692 m_pMaster->lout(
Logger::Level::Minor) <<
" [edge " << ((EdgeVariable*)variable(i))->theEdge() <<
"]" << std::endl;
1699 template<
typename T>
1703 #ifdef OGDF_STP_EXACT_LOGGING
1705 <<
"Sub::mySeparate(): id="
1706 << this->id() <<
", iter=" << this->nIter_ << std::endl;
1708 m_pMaster->separationTimer()->start();
1709 double eps = master_->eps();
1710 double cardEps = eps / 100;
1711 double oneMinusEps = 1 - eps;
1712 node r = m_pMaster->rootNode();
1713 const Graph &g = m_pMaster->graph();
1714 int nEdgesU = m_pMaster->nEdgesU();
1716 int nTerminals = m_pMaster->nTerminals();
1717 const node *masterTerminals = m_pMaster->terminals();
1720 for (
int i = 0; i < nTerminals; i++) {
1721 terminal[i] = masterTerminals[i];
1728 for (
int i = 0; i < nTerminals-1; i++) {
1731 terminal[i] = terminal[j];
1736 #ifdef OGDF_STP_EXACT_LOGGING
1739 <<
"Sub::mySeparate(): considered terminal ordering: ";
1740 for (
int i = 0; i < nTerminals; i++)
1747 capacities.
init(g, 0);
1750 capacities[e] = max(xVal_[m_pMaster->edgeID(e)], 0.);
1752 capacities[e] += cardEps;
1755 #ifdef OGDF_STP_EXACT_LOGGING
1757 <<
"Sub::mySeparate(): current capacities (>0) for mincut computation:" << std::endl;
1759 if (capacities[e] >= 2*cardEps) {
1760 m_pMaster->lout(
Logger::Level::Minor) <<
"\tcapacity[" << e <<
"]=" << capacities[e] << std::endl;
1771 double cutValue = 2.0;
1773 double cutValueBack = 0.0;
1775 int nOtherNodes = 0;
1777 double uBound = 1 + nEdgesU*cardEps;
1785 int cardinalityCut, cardinalityBackcut;
1786 cardinalityCut = cardinalityBackcut = 0;
1794 while (cutsFound < m_maxNrCuttingPlanes && ti < nTerminals) {
1797 #ifdef OGDF_STP_EXACT_LOGGING
1799 <<
"Sub::mySeparate(): computing minimum cut between root " <<
r <<
" and " << t << std::flush;
1808 m_pMaster->timerMinSTCut()->start();
1816 #ifdef OGDF_STP_EXACT_LOGGING
1820 <<
" " << flowEdge <<
" : "
1821 << flow[flowEdge] <<
" / " << capacities[flowEdge] << std::endl;
1827 minSTCut.
call(g, capacities, flow,
r, t);
1829 m_pMaster->timerMinSTCut()->stop();
1832 #ifdef OGDF_STP_EXACT_LOGGING
1840 cutValue -= cardEps;
1843 cutValueBack += capacities[e] - cardEps;
1846 }
else if (m_computeBackCuts) {
1849 cutValueBack += capacities[e];
1855 cardinalityCut = cardinalityBackcut = 0;
1860 cardinalityBackcut++;
1864 #ifdef OGDF_STP_EXACT_LOGGING
1866 <<
", actual cutvalue=" << cutValue;
1867 if (m_computeBackCuts)
1869 <<
", actual cutValueBack=" << cutValueBack;
1874 if (cutValue < oneMinusEps) {
1880 newConstraints.
push(newCut);
1882 #ifdef OGDF_STP_EXACT_LOGGING
1884 <<
"Sub::mySeparate(): found violated cut:" << std::endl;
1887 if (m_computeBackCuts
1889 && cutsFound < m_maxNrCuttingPlanes
1890 && cutValueBack <= oneMinusEps) {
1895 newConstraints.
push(newBackCut);
1897 #ifdef OGDF_STP_EXACT_LOGGING
1899 <<
"Sub::mySeparate(): found violated cut (backcut):" << std::endl;
1905 if (m_computeNestedCuts)
1910 capacities[e] = 1.0/(double)cardinalityCut + eps;
1912 capacities[e] = 1.0 + eps;
1918 if (m_computeBackCuts
1920 && cutValueBack <= oneMinusEps
1923 capacities[e] = 1.0/(double)cardinalityBackcut + eps;
1925 capacities[e] = 1.0 + eps;
1936 if (!m_computeNestedCuts) {
1939 if (cutValue > oneMinusEps ||
r == t) {
1942 while (!modified.empty()) {
1944 capacities[e] = xVal_[m_pMaster->edgeID(e)];
1946 capacities[e] += cardEps;
1953 m_alreadySeparated = cutsFound;
1955 if (cutsFound > 0) {
1957 int nAdded = addCons(newConstraints, m_pMaster->cutPool());
1959 m_pMaster->incNrCutsTotal(nAdded);
1960 m_pMaster->checkSetMaxPoolSize();
1961 if (nAdded != cutsFound) {
1966 #ifdef OGDF_STP_EXACT_LOGGING
1968 <<
"Sub::mySeparate(): id="
1969 << this->id() <<
", iter=" << this->nIter_
1970 <<
" separated " << cutsFound <<
" directed cuts" << std::endl;
1972 m_pMaster->separationTimer()->stop();
1977 template<
typename T>
1981 m_pMaster->primalHeuristicTimer()->start();
1983 #ifdef OGDF_STP_EXACT_LOGGING
1985 <<
"Sub::myImprove(): id="
1986 << this->id() <<
", iter=" << this->nIter_ << std::endl;
1988 double eps = master_->eps();
1989 const Graph &g = m_pMaster->graph();
1992 #ifdef OGDF_STP_EXACT_LOGGING
1995 <<
"Sub::myImprove(): current solution:" << std::endl;
1998 <<
"\tx" << m_pMaster->edgeID(e) <<
"=" << xVal_[m_pMaster->edgeID(e)]
1999 <<
", edge " << e << std::endl;
2006 double currWeight, twinWeight;
2008 edge e2 = m_pMaster->twin(e);
2009 currWeight = 1.0-xVal_[m_pMaster->edgeID(e)];
2010 twinWeight = 1.0-xVal_[m_pMaster->edgeID(e2)];
2011 if (twinWeight < currWeight)
2012 currWeight = twinWeight;
2015 ewg.
setWeight(m_pMaster->edgeGToWgPH(e), eps + currWeight * variable(m_pMaster->edgeID(e))->obj());
2018 #ifdef OGDF_STP_EXACT_LOGGING
2021 <<
"Sub::myImprove(): edge weights:" << std::endl;
2024 <<
"\tweight[" << e <<
"]=" << ewg.
weight(m_pMaster->edgeGToWgPH(e)) << std::endl;
2030 auto &primalHeuristic = m_pMaster->getPrimalHeuristic();
2035 #ifdef OGDF_STP_EXACT_LOGGING
2037 double tmpHeuristicSolutionValue =
2040 primalHeuristic->call(
2041 m_pMaster->weightedGraphPH(),
2042 m_pMaster->terminalListPH(),
2043 m_pMaster->isTerminalPH(),
2044 heuristicSolutionWg);
2048 m_pMaster->weightedGraphPH(),
2049 m_pMaster->terminalListPH(),
2050 m_pMaster->isTerminalPH(),
2051 *heuristicSolutionWg);
2053 #ifdef OGDF_STP_EXACT_LOGGING
2055 <<
"Sub::myImprove(): primal heuristic algorithm returned solution with "
2056 <<
"value " << tmpHeuristicSolutionValue <<
", isSteinerTree=" <<
isSteinerTree << std::endl;
2061 double heuristicSolutionValue = 0.0;
2065 for (
edge e : heuristicSolutionWg->
edges) {
2066 edge e2 = m_pMaster->edgeWgToGPH(heuristicSolutionWg->
original(e));
2068 heuristicSolutionValue += m_pMaster->capacities(e2);
2069 #ifdef OGDF_STP_EXACT_LOGGING
2071 <<
"\t" << e <<
" -> " << e2 <<
" c=" << m_pMaster->capacities(e2) << std::endl;
2075 #ifdef OGDF_STP_EXACT_LOGGING
2077 <<
"Sub::myImprove(): found integer solution with value "
2078 << heuristicSolutionValue << std::endl;
2080 if (m_pMaster->betterPrimal(heuristicSolutionValue)) {
2081 #ifdef OGDF_STP_EXACT_LOGGING
2083 << std::setw(7) << this->id()
2084 << std::setw(7) << this->nIter_
2085 <<
" primal heuristic founds better integer solution with value " << heuristicSolutionValue << std::endl;
2087 m_pMaster->primalBound(heuristicSolutionValue);
2088 m_pMaster->updateBestSolutionByEdges(solutionEdges);
2091 #ifdef OGDF_STP_EXACT_LOGGING
2094 <<
"Sub::myImprove(): id="
2095 << this->id() <<
", iter=" << this->nIter_
2096 <<
": computed solution is no Steiner tree!" << std::endl;
2100 delete heuristicSolutionWg;
2101 m_pMaster->primalHeuristicTimer()->stop();
2104 #ifdef OGDF_STP_EXACT_LOGGING
2105 template<
typename T>
2109 double eps = master_->eps();
2113 for (
int i = 0; i < nVar(); i++) {
2116 if (val > eps || val < -eps) {
2118 if (val > 1-eps && val < 1+eps) {
2120 m_pMaster->lout(level) <<
" + ";
2124 m_pMaster->lout(level) <<
" + " << val;
2128 if (val < -1+eps && val > -1-eps) {
2130 m_pMaster->lout(level) <<
" - ";
2132 m_pMaster->lout(level) <<
" -";
2136 m_pMaster->lout(level) <<
" - " << (-1)*val;
2138 m_pMaster->lout(level) << val;
2141 m_pMaster->lout(level) <<
"x" << i;
2145 m_pMaster->lout(level)
2146 <<
" " << *(constraint->
sense()) <<
" "
2147 << constraint->
rhs() << std::endl;
2151 template<
typename T>
2155 if (m_hashKey != cv->hashKey()) {
2161 for (
node n : m_pGraph->nodes) {
2162 if (m_marked[n] != dirCut->
marked(n)) {
2170 template<
typename T>
2175 if (this->cutedge(edgeVar->
theEdge())) {
2182 template<
typename T>
2185 Master stpMaster(G, terminals, isTerminal,
m_eps);
2189 #ifdef OGDF_STP_EXACT_LOGGING
2190 stpMaster.setOutputLevel(m_outputLevel);
2218 for (
edge e = G.firstEdge(); e; e = e->succ()) {
2220 const node vO = e->source();
2221 node vC = finalSteinerTree->
copy(vO);
2223 vC = finalSteinerTree->
newNode(vO);
2225 const node wO = e->target();
2226 node wC = finalSteinerTree->
copy(wO);
2228 wC = finalSteinerTree->
newNode(wO);
2230 T edgeCost = G.weight(e);
2231 finalSteinerTree->
newEdge(e, edgeCost);
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
double m_coeffIn
coefficient of ingoing edges
The namespace for all OGDF objects.
bool equal(const ConVar *cv) const override
tests if cuts are equal; required method for nonduplpool
int nMarkedNodes() const
the number of marked nodes
int m_poolSizeMax
maximal size of the pool
bool m_addIndegreeEdgeConstraints
add constraints concerning the indegree of a node w.r.t. one outgoing edge: indeg(v) >= outgoing edge...
void incNrCutsTotal(int val)
increases the number of separated directed cuts
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.
void setEpsilonTest(EpsilonTest *et)
Assigns a new epsilon test.
void init()
Reinitializes the array. Associates the array with no graph.
Includes declaration of graph class.
Implementation of the 2(1-1/l)-approximation algorithm for the minimum Steiner tree problem by Matsuy...
StopwatchWallClock m_separationTimer
timer for separation
edge newEdge(node v, node w, T weight)
virtual void initializeParameters() override
read/set parameters from file
bool m_addFlowBalanceConstraints
node rootNode() const
the designated root node (special terminal)
int m_callPrimalHeuristic
bool isFrontCutEdge(const edge e) const
Returns whether this edge is leaving the front cut.
Constraint for relating the indegree and one outgoing edge of a node.
bool m_addGSEC2Constraints
int nEdgesU() const
returns number of undirected edges, i.e., nEdges()/2
Abstract base class for all branching rules.
int m_separationStrategy
parameter: separation strategy, only important if nested cuts are computed
DegreeConstraint(abacus::Master *master, node n, double coeffIn, double coeffOut, abacus::CSense::SENSE sense, double rhs)
MaxFlowModule< double > * getMaxFlowModule()
Get the maximum flow module used by separation algorithm.
node source() const
source node
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
const Graph & original() const
Returns a reference to the original graph.
abacus::NonDuplPool< abacus::Constraint, abacus::Variable > * m_pCutPool
the non-duplicate cut pool for the directed Steiner cuts
edge newEdge(node v, node w)
Creates a new edge (v,w) and returns it.
T weight(const edge e) const
Implements a stopwatch measuring wall-clock time.
bool computeBackCuts() const
parameter: back cut computation
node getNode(int i) const
id -> node
virtual double rhs() const
Returns the right hand side of the constraint.
double solutionValue() const
solution value after solving the problem, i.e., returns final primal bound
Sub(abacus::Master *master)
Constructor for the root problem of the b&b tree.
EdgeArray< edge > m_edgesWgToGPH
edge mapping m_pWeightedGraphPH -> m_pGraph
int m_alreadySeparated
nr of already separated cuts, default is -1
int edgeID(edge e) const
edge -> id of lp variable
double m_relaxedSolValue
statistics: solution value of the relaxed master problem
const List< node > & terminalListPH() const
list of terminals (in m_pWeightedGraphPH)
bool m_addDegreeConstraints
parameter: add constraints concerning the indegree of a node, like: indeg <= 1 for all vertices
DegreeEdgeConstraint(abacus::Master *master, edge e, double coeffIn, double coeffEdge, abacus::CSense::SENSE sense, double rhs)
std::unique_ptr< MinSteinerTreeModule< double > > & getPrimalHeuristic()
the primal heuristic module
void useGSEC2Constraints(bool b)
Switch usage of constraints x_uv + x_vu <= 1 on or off.
void useFlowBalanceConstraints(bool b)
Switch usage of flow balance constraints on or off.
E popFrontRet()
Removes the first element from the list and returns it.
void updateBestSolution(double *values)
updates best found solution
bool frontCutIsComplementOfBackCut() const
Returns whether the front cut is the complement of the backcut.
int m_callPrimalHeuristic
parameter: primal heuristic (PH) call strategy
Master(const EdgeWeightedGraph< T > &wG, const List< node > &terminals, const NodeArray< bool > &isTerminal, double eps, bool relaxed=false)
Constructor of the master problem.
bool isBackCutEdge(const edge e) const
Returns whether this edge is entering the back cut.
edge m_edge
the associated edge
int nrCutsTotal() const
total number of separated directed cuts
double m_coeffEdge
coefficient of the edge
bool isParallelDirected(edge e) const
Returns true iff edge e is parallel to this (directed) edge (or if it is the same edge)
const char * name() const override
return the name of the cut; required method for nonduplpool
virtual bool feasible() override
checks if the current solution is feasible, i.e., calls mySeparate()
bool m_nestedCutComputation
edge theEdge() const
the associated edge
Master * master()
Returns the master of the optimization.
double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
MinSteinerTreeDirectedCut()
MaxFlowModule< double > * m_maxFlowModule
NodeArray< bool > m_marked
defines if a vertex is on the left side of the cut (false) or not
bool m_addDegreeConstraints
edge edgeGToWgPH(edge e) const
edge mapping m_pGraph -> m_pWeightedGraphPH
Level
supported log-levels from lowest to highest importance
node * m_terminals
terminal index -> terminal node
int m_nEdgesU
number of undirected edges
EdgeArray< int > m_edgeIDs
edge -> id
edge newEdge(node u, node v, T weight)
void useFlowBalanceConstraints(bool b)
Switch usage of flow balance constraints on or off.
bool relaxed() const
solve relaxed LP or ILP
void setConfigFile(const char *configfile)
Set a configuration file to use. The contents of the configuration file can override all other used o...
const node * terminals() const
terminals in an array
void useBackCuts(bool b)
Switch computation of back-cuts on or off.
StopwatchWallClock * primalHeuristicTimer()
timer for primal heuristics
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
void checkSetMaxPoolSize()
checks if current pool size is maximum and sets it if necessary
const EdgeWeightedGraph< T > & m_wG
the original weighted graph
int callPrimalHeuristicStrategy() const
strategy for calling primal heuristic (PH)
edge theEdge() const
the associated edge
int nIter_
The number of iterations in the cutting plane phase.
bool m_backCutComputation
parameter: compute back cuts yes/no i.e., outgoing edges of the root-set
edge twin(edge e) const
the twin edge, i.e. twin[(u,v)] = (v,u)
EdgeVariable * getVar(edge e) const
returns the variable assigned to edge e
double m_coeffOut
coefficient of outgoing edges
std::unique_ptr< MaxFlowModule< double > > m_maxFlowModuleOption
void setPrimalHeuristicCallStrategy(int b)
Set primal heuristic call strategy.
int m_nMarkedNodes
number of marked nodes
bool m_minCardinalityCuts
parameter: compute minimum cardinality cuts
EdgeArray< edge > m_mapToOrigGraph
the undirected edge in the original graph for each arc in m_pGraph
EdgeArray< edge > m_edgesGToWgPH
edge mapping m_pGraph -> m_pWeightedGraphPH
bool active(node n) const
returns true iff the node n is separated by this cut
node copy(node v) const
Returns the node in the graph copy corresponding to v.
const NodeArray< int > & nodeIDs() const
lp variable ids of nodes
int m_nIterRoot
statistics: nr of iterations in the root node of the b&b tree
EdgeArray< edge > m_mapToBidirectedGraph2
the second directed arc in m_pGraph for an original edge
edge edgeWgToGPH(edge e) const
edge mapping m_pWeightedGraphPH -> m_pGraph
StopwatchWallClock m_primalHeuristicTimer
timer for primal heuristics
int maxNrAddedCuttingPlanes() const
maximum nr of cutting planes
Contains logging functionality.
Extends the GraphCopy concept to weighted graphs.
void setPrimalHeuristicCallStrategy(int b)
Set primal heuristic call strategy.
int m_maxNrAddedCuttingPlanes
parameter: maximum nr of cutting planes per iteration
OSISOLVER defaultLpSolver() const
returns the Lp Solver.
Exception thrown when an algorithm realizes an internal bug that prevents it from continuing.
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
void setPrimalHeuristic(MinSteinerTreeModule< double > *b)
Set the module option for the primal heuristic (use MinSteinerTreeModule<double> types)....
void incNrCutsTotal()
increases the number of separated directed cuts by 1
const EdgeArray< int > & edgeIDs() const
lp variable ids of edges
NodeArray< bool > m_isTerminal
node is terminal yes/no
double coeff(const abacus::Variable *v) const override
Returns the coefficient of the variable v in the constraint.
EdgeArray< edge > m_mapToBidirectedGraph1
the first directed arc in m_pGraph for an original edge
void useDegreeConstraints(bool b)
Switch usage of degree constraints (like indeg <= 1) on or off.
const Graph & graph() const
the directed graph, i.e., the bidirection of the input graph
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.
Constraint for nodes, e.g., in/outdegree stuff.
T computeFlow(EdgeArray< T > &cap, node &s, node &t, EdgeArray< T > &flow)
Only a shortcut for computeValue and computeFlowAfterValue.
bool computeNestedCuts() const
parameter: nested cut computation
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
bool cutedge(edge e) const
returns true iff the edge is contained in the cut
bool isSelfLoop() const
Returns true iff the edge is a self-loop (source node = target node).
int nTerminals() const
number of terminals
bool shuffleTerminals() const
shuffle ordering of terminals before each separation routine
int numberOfEdges() const
Returns the number of edges in the graph.
void useTerminalShuffle(bool b)
Switch terminal shuffling before separation on or off.
int maxPoolSize() const
the maximum pool size during the algorithm
edge m_e2
twin of m_e1, i.e., if m_e1 = (u,v) it holds m_e2 = (v,u)
const char * m_configfile
problem dependent config file
int degree() const
Returns the degree of the node (indegree + outdegree).
int poolSizeInit() const
initial pool size
bool minCardinalityCuts() const
parameter: compute minimum cardinality cuts
int numberOfNodes() const
Returns the number of nodes in the graph.
static const char * OSISOLVER_[]
Array for the literal values for possible Osi solvers.
virtual T computeSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree) override
Computes the actual Steiner tree.
Constraint for edges, e.g., subtour elimination constraints of size 2 ((G)SEC2)
NodeArray< bool > m_isTerminalPH
is terminal yes/no (in m_pWeightedGraphPH)
int m_saturationStrategy
parameter: saturation strategy, only important if nested cuts are computed
int nNodes() const
number of nodes of the graph
bool m_shuffleTerminals
parameter: shuffle the list of terminals right before separation
Master problem of Steiner tree branch&cut algorithm
bool isTerminal(node n) const
true if n is a terminal
EdgeVariable * getVarTwin(edge e) const
returns the variable assigned to the twin of edge e
void useTerminalShuffle(bool b)
Switch terminal shuffling before separation on or off.
void useEpsilonTest(const double &eps)
Change the used EpsilonTest from StandardEpsilonTest to a user given EpsilonTest.
int m_nrCutsTotal
total number of separated directed cuts
int m_callPrimalHeuristic
Strategy for primal heuristic (PH) calls.
EdgeWeightedGraph< double > * m_pWeightedGraphPH
edge weighted bidirected graph; used and modified for primal heuristics
int saturationStrategy() const
strategy for saturating edges during separation; Only relevant for nested cuts
double capacities(edge e) const
costs for edge e
Graph * m_pGraph
the bidirected graph
void push(E e)
Puts a new element in the buffer.
const NodeArray< bool > isTerminal() const
boolean array of terminal status
bool m_backCutComputation
Master * m_pMaster
the master problem of the b&c algorithm
virtual double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
void useMinCardinalityCuts(bool b)
Switch usage of the cardinality heuristic (minimum-cardinality cuts) on or off.
NodeArray< int > m_nodeIDs
node -> id
int nEdges() const
returns the number of edges
Forms the virtual base class for all possible variables given in pool format.
node source() const
Returns the source node of the edge.
Doubly linked lists (maintaining the length of the list).
int m_poolSizeInitFactor
parameter: factor for the initial size of the cutting pool
Data type for general directed graphs (adjacency list representation).
@ Binary
A variable having value 0 or 1.
void setMaxFlowModule(MaxFlowModule< double > *module)
Set the maximum flow module to be used for separation.
unsigned int m_hashKey
hashkey of the cut; required method for nonduplpool
CSense * sense()
Returns a pointer to the sense of the constraint.
bool marked(node n) const
returns status of node n
int id() const
Returns the identity number of the subproblem.
int m_factor
factor for edge coefficients in the constraint
double m_coeffIn
coefficient of ingoing edges
node rootNodePH() const
root node (in m_pWeightedGraphPH)
int m_maxNrAddedCuttingPlanes
void useMinCardinalityCuts(bool b)
Switch usage of the cardinality heuristic (minimum-cardinality cuts) on or off.
edge getEdge(int i) const
id -> edge
void useIndegreeEdgeConstraints(bool b)
Switch usage of indegree edge constraints (indeg(v) >= outgoing edge(v,x) for all x) on or off.
void myImprove()
primal heuristic procedure
node m_root
the virtual root of our graph. This node is a terminal.
StopwatchWallClock m_timerMinSTCut
timer for minimum st-cut computations. Measures updates + algorithm
double * m_bestSolution
best found solution
void setMaxFlowModule(MaxFlowModule< double > *module)
Set the maximum flow module to be used for separation.
STATUS optimize()
Performs the optimization by branch-and-bound.
bool callPrimalHeuristic() const
parameter: call primal heuristic yes/no
node m_rootPH
root node in m_pWeightedGraphPH
abacus::NonDuplPool< abacus::Constraint, abacus::Variable > * cutPool()
the non-duplicate cutpool for the separated Steiner cuts
int m_poolSizeInit
size of initial pool
bool m_addIndegreeEdgeConstraints
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,...
virtual int separate() override
calls mySeparate() if mySeparate wasn't called in another procedure
Subproblem of Steiner tree algorithm.
EdgeWeightedGraph< double > & weightedGraphPH()
virtual double coeff(const Variable *v) const =0
Returns the coefficient of the variable v in the constraint.
void setMaxNumberAddedCuttingPlanes(int b)
Set maximum number of added cutting planes per iteration.
This class implements the Directed Cut Integer Linear Program for the Steiner tree problem.
bool m_addFlowBalanceConstraints
parameter: add flow balance constraints for Steiner nodes n: outdeg(n) >= indeg(n)
void setSeparationStrategy(int b)
Set separation strategy for nested cuts.
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
StopwatchWallClock * separationTimer()
timer for separation
double coefficient() const
objective function coefficient
unsigned hashKey() const override
retuns an hashkey for the cut; required method for nonduplpool
void setEpsilon(double eps)
Set the epsilon for the LP.
node newNode()
Creates a new node and returns it.
void useBackCuts(bool b)
Switch computation of back-cuts on or off.
This class implements the minimum Steiner tree 2-approximation algorithm by Takahashi and Matsuyama w...
cutType
The three types of cuts.
virtual abacus::Sub * firstSub() override
generates the first subproblem
NodeArray< node > m_nodesGToWgPH
node mapping m_pGraph -> m_pWeightedGraphPH
Declaration of class EdgeWeightedGraph.
node terminal(int i) const
get terminal with index i
void useIndegreeEdgeConstraints(bool b)
Switch usage of indegree edge constraints (indeg(v) >= outgoing edge(v,x) for all x) on or off.
node theNode() const
the associated node
EdgeArray< double > m_capacities
edge costs
void setNIterRoot(int val)
nr of iterations in the root node
EdgeArray< EdgeVariable * > m_edgeToVar
edge -> lp variable
DirectedCutConstraint(abacus::Master *master, const Graph &g, const MinSTCutMaxFlow< double > *minSTCut, MinSTCutMaxFlow< double >::cutType _cutType)
Forms the virtual base class for all possible constraints given in pool format.
virtual void initializeOptimization() override
insert variables and base constraints
std::ostream & lout(Level level=Level::Default) const
stream for logging-output (local)
edge m_e1
base edge and twin of m_e2, i.e., if m_e1 = (u,v) it holds m_e2 = (v,u)
bool m_relaxed
parameter: indicates whether we solve the relaxed problem (LP) or the ILP
int m_maxPoolSize
statistic number of cuts in pool
void setRelaxedSolValue(double val)
solution value of the root
void createEmpty(const Graph &wG)
Declaration of min-st-cut algorithms parameterized by max-flow alorithm.
void setPrimalHeuristic(MinSteinerTreeModule< double > *pMinSteinerTreeModule)
Set the module option for the primal heuristic.
void setPoolSizeInitFactor(int b)
Set factor for the initial size of the cutting pool.
int nodeID(node n) const
npde -> id of lp variable
Class for the representation of edges.
const NodeArray< bool > & isTerminalPH() const
terminal yes/no (in m_pWeightedGraphPH)
void useDegreeConstraints(bool b)
Switch usage of degree constraints (like indeg <= 1) on or off.
virtual Sub * generateSon(abacus::BranchRule *rule) override
generates a b&b node
bool m_nestedCutComputation
parameter: compute nested cuts yes/no i.e., saturate all cut edges and recompute the mincut
void init()
Reinitializes the array. Associates the array with no graph.
virtual ~Master()
destructor
int separationStrategy() const
strategy for separating directed Steiner cuts; Only relevant for nested cuts
void updateBestSolutionByEdges(const List< edge > &sol)
updates best found solution by list of edges
void setSeparationStrategy(int b)
Set separation strategy for nested cuts.
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)
MinSteinerTreeModule< double > * m_primalHeuristic
TYPE
The enumeration with the different variable types.
const char * m_configFile
StopwatchWallClock * timerMinSTCut()
timer for minimum st-cut computations. Measures updates + algorithm
bool m_minCardinalityCuts
double coeff(const abacus::Variable *v) const override
coefficient of variable in constraint
Representation of levels in hierarchies.
List< node > m_terminalListPH
list of terminal nodes (in m_pWeightedGraphPH)
void setSaturationStrategy(int b)
Set saturation strategy for nested cuts.
virtual ~Sub()
The destructor only deletes the sons of the node.
node * nodes() const
nodes of the graph
Encapsulates a pointer to a list element.
int id() const
id of the edge (variable)
void setPoolSizeInitFactor(int b)
Set factor for the initial size of the cutting pool.
bool isInBackCut(const node v) const
Returns whether this node is part of the back cut.
void setSaturationStrategy(int b)
Set saturation strategy for nested cuts.
bool m_addGSEC2Constraints
parameter: add GSEC2 constraints yes/no, i.e. x_uv + x_vu <= 1
Centralized global and local logging facility working on streams like std::cout.
int m_maxNrCuttingPlanes
maximum nr of cutting planes to be added
void setWeight(const edge e, T weight)
void setMaxNumberAddedCuttingPlanes(int b)
Set maximum number of added cutting planes per iteration.
const EdgeArray< edge > & twins() const
std::unique_ptr< MinSteinerTreeModule< double > > m_primalHeuristic
Algorithm used for the primal heuristic.
node target() const
Returns the target node of the edge.
const char * m_name
name of the cut; required method for nonduplpool
Class for directed cuts (i.e., separated Steiner cuts)
int randomNumber(int low, int high)
Returns random integer between low and high (including).
@ Continuous
A continuous variable.
Variable for directed edges.
bool m_minCardinalityCuts
double * bestSolution() const
the best found solution
int mySeparate()
separation procedure
void useNestedCuts(bool b)
Switch computation of nested cuts on or off.
Class for the representation of nodes.
EdgeArray< edge > m_twin
the twin edges (u,v) <-> (v,u)
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
const EdgeArray< double > & capacities() const
edge costs
node m_node
the associated node
void setConfigFile(const char *filename)
Set the config file to use that overrides all other settings.
int m_nTerminals
nr of terminals
OSISOLVER
This enumeration defines which solvers can be used to solve the LP-relaxations.
virtual void terminateOptimization() override
store solution in EdgeArray
void useNestedCuts(bool b)
Switch computation of nested cuts on or off.
EdgeArray< bool > m_isSolutionEdge
node target() const
target node
Min-st-cut algorithm, that calculates the cut via maxflow.
void useGSEC2Constraints(bool b)
Switch usage of constraints x_uv + x_vu <= 1 on or off.
const Graph * m_pGraph
the graph
iterator pushBack(const E &x)
Adds element x at the end of the list.
EdgeConstraint(abacus::Master *master, edge e1, edge e2, int factor=1.0, abacus::CSense::SENSE sense=abacus::CSense::Less, double rhs=1.0)
The master of the optimization.
bool isSolutionEdge(edge e) const
returns true iff original edge is contained in optimum solution
bool isInFrontCut(const node v) const
Returns whether this node is part of the front cut.