|
Open Graph Drawing Framework |
v. 2023.09 (Elderberry)
|
|
|
Go to the documentation of this file.
87 #ifdef OGDF_STP_EXACT_LOGGING
123 #ifdef OGDF_STP_EXACT_LOGGING
124 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
234 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);
244 void setMaxFlowModule(MaxFlowModule<double>* module) { m_maxFlowModule = module; }
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
676 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
699 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
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
1140 template<
typename T>
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
1202 template<
typename T>
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) {
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;
1352 template<
typename T>
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
1422 template<
typename T>
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];
1437 template<
typename T>
1439 for (
int i = 0; i < m_pGraph->numberOfEdges(); i++) {
1440 m_bestSolution[i] = 0.0;
1443 m_bestSolution[m_edgeIDs[*it]] = 1.0;
1447 template<
typename T>
1449 :
abacus::
Sub(master, 0, 0, 0), m_alreadySeparated(-1) {
1461 template<
typename T>
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
1481 template<
typename T>
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;
1512 template<
typename T>
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
1581 template<
typename T>
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;
1608 template<
typename T>
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();
1887 template<
typename T>
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
2008 template<
typename T>
2011 double eps = master_->eps();
2015 for (
int i = 0; i < nVar(); i++) {
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;
2052 template<
typename T>
2054 if (m_hashKey != cv->hashKey()) {
2061 for (
node n : m_pGraph->nodes) {
2062 if (m_marked[n] != dirCut->
marked(n)) {
2069 template<
typename T>
2072 if (this->cutedge(edgeVar->
theEdge())) {
2078 template<
typename T>
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);
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
Declaration and implementation of ArrayBuffer class.
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.
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
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.
Definition of exception classes.
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.
abacus::NonDuplPool< abacus::Constraint, abacus::Variable > * m_pCutPool
the non-duplicate cut pool for the directed Steiner cuts
Interface for Max Flow Algorithms.
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 setOriginalGraph(const Graph *wG) override
Associates the graph copy with G, but does not create any nodes or edges.
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
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
Declaration of ogdf::MinSteinerTreeModule.
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).
Declaration and implementation of Goldberg-Tarjan max-flow algorithm with global relabeling and gap r...
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
Decralation of GraphElement and GraphList classes.
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.
Declaration of stopwatch classes.
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.
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
Doubly linked lists (maintaining the length of the list).
RegisteredArray for nodes, edges and adjEntries of a graph.
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
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
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.
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.
Basic declarations, included by all source files.
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
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
node newNode(int index=-1)
Creates a new node and returns it.
int m_maxPoolSize
statistic number of cuts in pool
void setRelaxedSolValue(double val)
solution value of the root
Declaration and implementation of Array class and Array algorithms.
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
Declaration of doubly linked lists and iterators.
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
void init(const Graph *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
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.
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) and returns it.
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)
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.
const Graph & original() const
Returns a reference to the original graph.
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.
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
std::ostream & lout(Level level=Level::Default, bool indent=true) const
stream for logging-output (local)
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.