From 1a6577f26eb861dbabed9672b3164a250dad8665 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Fri, 25 Mar 2016 19:27:06 +0100 Subject: [PATCH 01/15] implemented LP for LMC --- src/command-line-tools/solve-lmp.hxx | 102 +++++++++++++++++---------- src/command-line-tools/solve-mp.hxx | 2 +- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx index 99320d2..7036497 100644 --- a/src/command-line-tools/solve-lmp.hxx +++ b/src/command-line-tools/solve-lmp.hxx @@ -1,10 +1,11 @@ #include #include -// #include #include #include +#include +#include #include #include @@ -18,6 +19,7 @@ enum class Method { Ones, GAEC, Kernighan_Lin, + LP }; enum class Initialization { @@ -28,12 +30,12 @@ enum class Initialization { }; struct Parameters { - std::string inputHDF5FileName_; - std::string outputHDF5FileName_; - std::string labelingHDF5FileName_; - Method optimizationMethod_ { Method::Kernighan_Lin }; - Initialization initialization_ { Initialization::Zeros }; - bool probabilistic_ { true }; + std::string inputHDF5FileName; + std::string outputHDF5FileName; + std::string labelingHDF5FileName; + Method optimizationMethod { Method::Kernighan_Lin }; + Initialization initialization { Initialization::Zeros }; + bool probabilistic { true }; }; inline void @@ -45,31 +47,33 @@ parseCommandLine( try { TCLAP::CmdLine tclap("solve-lifted-multicut-problem-grid-graph", ' ', "1.0"); - TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName_, "INPUT_HDF5_FILE", tclap); - TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", true, parameters.outputHDF5FileName_, "OUTPUT_HDF5_FILE", tclap); - TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName_, "LABELING_HDF5_FILE", tclap); - TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); + TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); + TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", false, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); + TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); + TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, LP, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC}", false, "zeros", "INITIALIZATION_METHOD", tclap); TCLAP::SwitchArg argNonProbabilistic("p", "non-probabilistic", "Assume inputs are not probabilities. By default, all inputs are assumed to be Logistic Probabilities. (Default: disabled).",tclap); tclap.parse(argc, argv); - parameters.inputHDF5FileName_ = argInputHDF5FileName.getValue(); - parameters.outputHDF5FileName_ = argOutputHDF5FileName.getValue(); - parameters.probabilistic_ = !argNonProbabilistic.getValue(); + parameters.inputHDF5FileName = argInputHDF5FileName.getValue(); + parameters.outputHDF5FileName = argOutputHDF5FileName.getValue(); + parameters.probabilistic = !argNonProbabilistic.getValue(); if (!argOptimizationMethod.isSet()) throw std::runtime_error("No optimization method specified"); if (argOptimizationMethod.getValue() == "GAEC") - parameters.optimizationMethod_ = Method::GAEC; + parameters.optimizationMethod = Method::GAEC; else if (argOptimizationMethod.getValue() == "zeros") - parameters.optimizationMethod_ = Method::Zeros; + parameters.optimizationMethod = Method::Zeros; else if (argOptimizationMethod.getValue() == "ones") - parameters.optimizationMethod_ = Method::Ones; + parameters.optimizationMethod = Method::Ones; + else if (argOptimizationMethod.getValue() == "LP") + parameters.optimizationMethod = Method::LP; else if(argOptimizationMethod.getValue() == "KL") { - parameters.optimizationMethod_ = Method::Kernighan_Lin; + parameters.optimizationMethod = Method::Kernighan_Lin; if (!argInitializationMethod.isSet() && !argLabelingHDF5FileName.isSet()) throw std::runtime_error("Either initialization method (zeros, ones) or initial labeling must be specified for Kernighan-Lin."); @@ -79,17 +83,17 @@ try if(argInitializationMethod.isSet()) throw std::runtime_error("Either initialization method or initial labeling must be specified."); - parameters.labelingHDF5FileName_ = argLabelingHDF5FileName.getValue(); - parameters.initialization_ = Initialization::Input_Labeling; + parameters.labelingHDF5FileName = argLabelingHDF5FileName.getValue(); + parameters.initialization = Initialization::Input_Labeling; } else if (argInitializationMethod.isSet()) { if(argInitializationMethod.getValue() == "ones") - parameters.initialization_ = Initialization::Ones; + parameters.initialization = Initialization::Ones; else if(argInitializationMethod.getValue() == "zeros") - parameters.initialization_ = Initialization::Zeros; + parameters.initialization = Initialization::Zeros; else if(argInitializationMethod.getValue() == "GAEC") - parameters.initialization_ = Initialization::GAEC; + parameters.initialization = Initialization::GAEC; else throw std::runtime_error("Invalid initialization method specified"); } @@ -114,7 +118,7 @@ void solveLiftedMulticutProblem( // Load Lifted Multicut Problem { - auto fileHandle = andres::graph::hdf5::openFile(parameters.inputHDF5FileName_); + auto fileHandle = andres::graph::hdf5::openFile(parameters.inputHDF5FileName); andres::graph::hdf5::load(fileHandle, "graph", original_graph); andres::graph::hdf5::load(fileHandle, "graph-lifted", lifted_graph); @@ -124,7 +128,7 @@ void solveLiftedMulticutProblem( andres::graph::hdf5::closeFile(fileHandle); } - if (parameters.probabilistic_) + if (parameters.probabilistic) std::transform( edge_values.begin(), edge_values.end(), @@ -138,13 +142,13 @@ void solveLiftedMulticutProblem( Timer t; t.start(); - if (parameters.initialization_ == Initialization::Zeros) + if (parameters.initialization == Initialization::Zeros) std::fill(edge_labels.begin(), edge_labels.end(), 0); - else if (parameters.initialization_ == Initialization::Ones) + else if (parameters.initialization == Initialization::Ones) std::fill(edge_labels.begin(), edge_labels.end(), 1); - else if (parameters.initialization_ == Initialization::Input_Labeling) + else if (parameters.initialization == Initialization::Input_Labeling) { - auto fileHandle = andres::graph::hdf5::openFile(parameters.labelingHDF5FileName_); + auto fileHandle = andres::graph::hdf5::openFile(parameters.labelingHDF5FileName); std::vector shape; std::vector vertex_labels; @@ -159,25 +163,51 @@ void solveLiftedMulticutProblem( vertexToEdgeLabels(original_graph, lifted_graph, vertex_labels, edge_labels); } - else if (parameters.initialization_ == Initialization::GAEC) + else if (parameters.initialization == Initialization::GAEC) andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, edge_values, edge_labels); - if (parameters.optimizationMethod_ == Method::Ones) + if (parameters.optimizationMethod == Method::Ones) std::fill(edge_labels.begin(), edge_labels.end(), 1); - else if (parameters.optimizationMethod_ == Method::Zeros) + else if (parameters.optimizationMethod == Method::Zeros) std::fill(edge_labels.begin(), edge_labels.end(), 0); - else if (parameters.optimizationMethod_ == Method::GAEC) + else if (parameters.optimizationMethod == Method::GAEC) andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, edge_values, edge_labels); - else if (parameters.optimizationMethod_ == Method::Kernighan_Lin) + else if (parameters.optimizationMethod == Method::Kernighan_Lin) andres::graph::multicut_lifted::kernighanLin(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + else if (parameters.optimizationMethod == Method::LP) + { + auto values = andres::graph::multicut_lifted::lp>(original_graph, lifted_graph, edge_values); + + t.stop(); + + auto energy_value = inner_product(edge_values.begin(), edge_values.end(), values.begin(), .0); + + if (!parameters.outputHDF5FileName.empty()) + { + auto file = andres::graph::hdf5::createFile(parameters.outputHDF5FileName); + + andres::graph::hdf5::save(file, "graph", original_graph); + andres::graph::hdf5::save(file, "energy-value", energy_value); + andres::graph::hdf5::save(file, "running-time", t.get_elapsed_seconds()); + andres::graph::hdf5::save(file, "labels", { values.size() }, values.data()); // we save directly edge values as given by the LP solution, since the latter is not guaranteed to be integer + + andres::graph::hdf5::closeFile(file); + } + + std::cout << "Number of clusters: N/A\n"; + std::cout << "Energy value: " << energy_value << std::endl; + std::cout << "Running time: " << t.to_string() << std::endl; + + return; + } else throw std::runtime_error("Unsupported algorithm"); t.stop(); - stream << "saving decomposition into file: " << parameters.outputHDF5FileName_ << std::endl; + stream << "saving decomposition into file: " << parameters.outputHDF5FileName << std::endl; { - auto file = andres::graph::hdf5::createFile(parameters.outputHDF5FileName_); + auto file = andres::graph::hdf5::createFile(parameters.outputHDF5FileName); andres::graph::hdf5::save(file, "graph", original_graph); diff --git a/src/command-line-tools/solve-mp.hxx b/src/command-line-tools/solve-mp.hxx index ac1da1e..0e380c9 100644 --- a/src/command-line-tools/solve-mp.hxx +++ b/src/command-line-tools/solve-mp.hxx @@ -56,7 +56,7 @@ parseCommandLine( try { TCLAP::CmdLine tclap("solve-multicut-problem", ' ', "1.0"); - TCLAP::ValueArg argInputHDF5FileName("i", "hdf5-input", "File to load multicut problem from", false, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); + TCLAP::ValueArg argInputHDF5FileName("i", "hdf5-input", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", true, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); From b6b6dc998a8d6530409af81fa32aaf98d522e94a Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Fri, 25 Mar 2016 19:46:38 +0100 Subject: [PATCH 02/15] implemeted ILP for LMC --- include/andres/graph/multicut-lifted/ilp.hxx | 271 ++++++++++++++++ include/andres/graph/multicut-lifted/lp.hxx | 324 +++++++++++++++++++ src/command-line-tools/solve-lmp.hxx | 11 +- 3 files changed, 604 insertions(+), 2 deletions(-) create mode 100644 include/andres/graph/multicut-lifted/ilp.hxx create mode 100644 include/andres/graph/multicut-lifted/lp.hxx diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx new file mode 100644 index 0000000..bcf3c8b --- /dev/null +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -0,0 +1,271 @@ +#pragma once +#ifndef ANDRES_GRAPH_MULTICUT_LIFTED_ILP_HXX +#define ANDRES_GRAPH_MULTICUT_LIFTED_ILP_HXX + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace andres { +namespace graph { +namespace multicut_lifted +{ + +template +inline +void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, size_t numberOfIterations = std::numeric_limits::max()) +{ + struct Visitor + { + bool operator()(ELA const& edge_labels) const + { + return true; + } + } visitor; + + ilp(original_graph, lifted_graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations); +} + +template +inline +void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, VIS& visitor, size_t numberOfIterations = std::numeric_limits::max()) +{ + struct SubgraphWithCut + { + SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) + : ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) + {} + + bool vertex(size_t v) const + { + return true; + } + + bool edge(size_t e) const + { + return ilp_.label(edge_in_lifted_graph_[e]) < .5; + } + + ILP const& ilp_; + std::vector const& edge_in_lifted_graph_; + }; + + ILP ilp; + levinkov::Timer t; + + std::vector coefficients(lifted_graph.numberOfEdges()); + ComponentsBySearch components; + std::vector buffer; + std::vector edge_in_lifted_graph(original_graph.numberOfEdges()); + std::deque path; + std::vector variables(lifted_graph.numberOfEdges()); + std::vector visited(original_graph.numberOfVertices()); + + auto addCycleInequalities = [&] () + { + t.stop(); + + levinkov::Timer t_separation; + t_separation.start(); + + components.build(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph)); + + // search for violated non-chordal cycles and add corresp. inequalities + size_t nCycle = 0; + size_t nPath = 0; + size_t nCut = 0; + + for (ptrdiff_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + { + auto lv0 = lifted_graph.vertexOfEdge(edge, 0); + auto lv1 = lifted_graph.vertexOfEdge(edge, 1); + + if (ilp.label(edge) == 1 && components.areConnected(lv0, lv1)) + { + // if cycle/path inequality is violated + + // search for shortest path + spsp(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph), lv0, lv1, path, buffer); + + // check for chords only if the edge is from the original graph + if (original_graph.findEdge(lv0, lv1).first && findChord(original_graph, path.begin(), path.end(), true).first) + continue; + + // add inequality + for (size_t j = 0; j < path.size() - 1; ++j) + { + variables[j] = lifted_graph.findEdge(path[j], path[j + 1]).second; + coefficients[j] = 1.0; + } + + variables[path.size() - 1] = edge; + coefficients[path.size() - 1] = -1.0; + + ilp.addConstraint(variables.begin(), variables.begin() + path.size(), coefficients.begin(), 0, std::numeric_limits::infinity()); + + if (original_graph.findEdge(lv0, lv1).first) + ++nCycle; + else + ++nPath; + } + else if (ilp.label(edge) == 0 && !components.areConnected(lv0, lv1)) + { + // if cut inequality is violated + + // do a simple DFS to find all the edges, that leave the partition, which is essentially a cut + auto label = components.labels_[lv0]; + + std::fill(visited.begin(), visited.end(), 0); + std::stack S; + S.push(lv0); + visited[lv0] = 1; + + size_t sz = 0; + + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) + if (components.labels_[it->vertex()] == label) + { + if (!visited[it->vertex()]) + { + S.push(it->vertex()); + visited[it->vertex()] = 1; + } + } + else + { + variables[sz] = edge_in_lifted_graph[it->edge()]; + coefficients[sz++] = -1; + } + } + + // variables[sz] = static_cast(edge); + // coefficients[sz] = 1; + + // #pragma omp critical + // ilp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + // #pragma omp atomic + // ++counter; + + + label = components.labels_[lv1]; + + S.push(lv1); + visited[lv1] = 1; + + // sz = 0; + + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) + if (components.labels_[it->vertex()] == label) + { + if (!visited[it->vertex()]) + { + S.push(it->vertex()); + visited[it->vertex()] = 1; + } + } + else + { + variables[sz] = edge_in_lifted_graph[it->edge()]; + coefficients[sz++] = -1; + } + } + + coefficients[sz] = 1; + variables[sz] = edge; + + ilp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + } + } + + t_separation.stop(); + + double objValue = .0; + for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) + objValue += ilp.label(i)*edgeCosts[i]; + + std::cerr << t.get_elapsed_seconds() << " " << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + + t.start(); + + return nCycle + nPath + nCut; + }; + + auto repairSolution = [&] () + { + for(size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + { + auto v0 = lifted_graph.vertexOfEdge(edge, 0); + auto v1 = lifted_graph.vertexOfEdge(edge, 1); + + outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; + } + + ilp.setStart(outputLabels.begin()); + }; + + t.start(); + + for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) + { + auto v0 = original_graph.vertexOfEdge(i, 0); + auto v1 = original_graph.vertexOfEdge(i, 1); + + edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; + } + + ilp.initModel(lifted_graph.numberOfEdges(), edgeCosts.data()); + ilp.setStart(inputLabels.begin()); + + for(size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) + { + if (i != 0) + { + repairSolution(); + + auto energy_value = inner_product(edgeCosts.begin(), edgeCosts.end(), inputLabels.begin(), .0); + printf("Energy: %f\n", energy_value); + energy_value = .0; + for(ptrdiff_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + if (ilp.label(edge) > 0.5) + energy_value += edgeCosts[edge]; + + printf("ILP Energy: %f\n", energy_value); + + if (!visitor(outputLabels)) + break; + } + + ilp.optimize(); + + if (addCycleInequalities() == 0) + break; + } + + repairSolution(); +} + +} +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_ILP_HXX diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx new file mode 100644 index 0000000..8be28f1 --- /dev/null +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -0,0 +1,324 @@ +#pragma once +#ifndef ANDRES_GRAPH_MULTICUT_LIFTED_LP_HXX +#define ANDRES_GRAPH_MULTICUT_LIFTED_LP_HXX + +#include +#include +#include +#include + +#include +#include + + +namespace andres { +namespace graph { +namespace multicut_lifted { + +template +inline +std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, size_t numberOfIterations = std::numeric_limits::max()) +{ + struct Visitor + { + bool operator()() const + { + return true; + } + } visitor; + + return lp(original_graph, lifted_graph, edgeCosts, visitor, numberOfIterations); +} + +template +inline +std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, VIS& visitor, size_t numberOfIterations = std::numeric_limits::max()) +{ + const double tolerance = std::numeric_limits::epsilon(); + + // Dinic's Max FLow algorithm for undirected graph + class DinicFlow + { + public: + DinicFlow(int n) : + dist_(n), q_(n), work_(n), g_(n) + {} + + // Adds bidirectional edge + void addEdge(int s, int t, int cap) + { + Edge a = { t, static_cast(g_[t].size()), 0, cap }; + Edge b = { s, static_cast(g_[s].size()), 0, cap }; + + g_[s].push_back(a); + g_[t].push_back(b); + } + + void clear() + { + for (auto& v : g_) + v.clear(); + } + + int maxFlow(int src, int dest) + { + src_ = src; + dest_ = dest; + + int result = 0; + + while (bfs()) + { + std::fill(work_.begin(), work_.end(), 0); + + while (auto delta = dfs(src_, std::numeric_limits::max())) + result += delta; + } + + return result; + } + + // return edges (as pairs of vertices) of the Min Cut + std::set> getMinCut() + { + std::fill(work_.begin(), work_.end(), 0); + + std::stack S; + + work_[src_] = 1; + S.push(src_); + + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto& e : g_[v]) + if (e.f < e.cap && work_[e.to] == 0) + { + work_[e.to] = 1; + S.push(e.to); + } + } + + std::set> ret; + + for (int i = 0; i < g_.size(); ++i) + for (auto& e : g_[i]) + if (work_[i] != work_[e.to]) + ret.insert(std::make_pair(std::min(i, e.to), std::max(i, e.to))); + + return ret; + } + + private: + struct Edge + { + int to, rev; + int f, cap; + }; + + bool bfs() + { + std::fill(dist_.begin(), dist_.end(), -1); + + dist_[src_] = 0; + + int qt = 0; + q_[qt++] = src_; + + for (int qh = 0; qh < qt; qh++) + { + auto u = q_[qh]; + + for (int j = 0; j < g_[u].size(); j++) + { + Edge &e = g_[u][j]; + auto v = e.to; + + if (dist_[v] < 0 && e.f < e.cap) + { + dist_[v] = dist_[u] + 1; + q_[qt++] = v; + } + } + } + + return dist_[dest_] >= 0; + } + + int dfs(int u, int f) + { + if (u == dest_) + return f; + + for (int &i = work_[u]; i < (int) g_[u].size(); i++) + { + Edge &e = g_[u][i]; + + if (e.cap <= e.f) + continue; + + int v = e.to; + + if (dist_[v] == dist_[u] + 1) + { + auto df = dfs(v, std::min(f, e.cap - e.f)); + + if (df > 0) + { + e.f += df; + g_[v][e.rev].f -= df; + + return df; + } + } + } + + return 0; + } + + int src_, dest_; + std::vector dist_, q_, work_; + std::vector> g_; + }; + + LP lp; + levinkov::Timer t; + + std::vector coefficients(lifted_graph.numberOfEdges()); + std::vector distances(lifted_graph.numberOfVertices()); + std::vector edge_in_lifted_graph(original_graph.numberOfEdges()); + std::vector parents(lifted_graph.numberOfVertices()); + std::deque path; + std::vector vars(original_graph.numberOfEdges()); + std::vector variables(lifted_graph.numberOfEdges()); + + auto separateAndAddInequalities = [&] () + { + t.stop(); + + levinkov::Timer t_separation; + t_separation.start(); + + DinicFlow flow(original_graph.numberOfVertices()); + + for (size_t i = 0; i < vars.size(); ++i) + { + vars[i] = std::min(std::max(.0, lp.variableValue(edge_in_lifted_graph[i])), 1.0); + + auto v0 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 0); + auto v1 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 1); + + flow.addEdge(v0, v1, 100000.0*(1.0 - vars[i])); + } + + // search for violated non-chordal cycles and add corresp. inequalities + size_t nCycle = 0; + size_t nPath = 0; + size_t nCut = 0; + + for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + { + auto lv0 = lifted_graph.vertexOfEdge(edge, 0); + auto lv1 = lifted_graph.vertexOfEdge(edge, 1); + + // search for shortest path + double distance; + spsp(original_graph, DefaultSubgraphMask<>(), lv0, lv1, vars.begin(), path, distance, distances.begin(), parents.begin()); + + if (lp.variableValue(edge) > distance + tolerance) + { + // add inequality + for (size_t j = 0; j < path.size() - 1; ++j) + { + coefficients[j] = 1.0; + variables[j] = lifted_graph.findEdge(path[j], path[j + 1]).second; + } + + coefficients[path.size() - 1] = -1.0; + variables[path.size() - 1] = edge; + + lp.addConstraint(variables.begin(), variables.begin() + path.size(), coefficients.begin(), .0, std::numeric_limits::infinity()); + + if (original_graph.findEdge(lv0, lv1).first) + ++nCycle; + else + ++nPath; + } + + flow.maxFlow(lv0, lv1); + + double S_cut = .0; + + ptrdiff_t sz = 0; + for (auto& p : flow.getMinCut()) + { + coefficients[sz] = -1.0; + variables[sz] = lifted_graph.findEdge(p.first, p.second).second; + + S_cut += 1.0 - vars[variables[sz]]; + + ++sz; + } + + if (1.0 - lp.variableValue(edge) > S_cut + tolerance) + { + coefficients[sz] = 1.0; + variables[sz] = edge; + + lp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + } + } + + t_separation.stop(); + + double objValue = .0; + for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) + objValue += lp.variableValue(i)*edgeCosts[i]; + + std::cerr << t.get_elapsed_seconds() << " " << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + + t.start(); + + return nCycle + nPath + nCut; + }; + + t.start(); + + for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) + { + auto v0 = original_graph.vertexOfEdge(i, 0); + auto v1 = original_graph.vertexOfEdge(i, 1); + + edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; + } + + lp.initModel(lifted_graph.numberOfEdges(), edgeCosts.data()); + + for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) + { + if (!visitor()) + break; + + lp.optimize(); + + if (separateAndAddInequalities() == 0) + break; + } + + std::vector edge_values(lifted_graph.numberOfEdges()); + + for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) + edge_values[i] = lp.variableValue(i); + + return edge_values; +} + +} +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_LP_HXX diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx index 7036497..dc58393 100644 --- a/src/command-line-tools/solve-lmp.hxx +++ b/src/command-line-tools/solve-lmp.hxx @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -19,7 +21,8 @@ enum class Method { Ones, GAEC, Kernighan_Lin, - LP + LP, + ILP }; enum class Initialization { @@ -50,7 +53,7 @@ try TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", false, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); - TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, LP, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); + TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, ILP, LP, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC}", false, "zeros", "INITIALIZATION_METHOD", tclap); TCLAP::SwitchArg argNonProbabilistic("p", "non-probabilistic", "Assume inputs are not probabilities. By default, all inputs are assumed to be Logistic Probabilities. (Default: disabled).",tclap); @@ -71,6 +74,8 @@ try parameters.optimizationMethod = Method::Ones; else if (argOptimizationMethod.getValue() == "LP") parameters.optimizationMethod = Method::LP; + else if (argOptimizationMethod.getValue() == "ILP") + parameters.optimizationMethod = Method::ILP; else if(argOptimizationMethod.getValue() == "KL") { parameters.optimizationMethod = Method::Kernighan_Lin; @@ -170,6 +175,8 @@ void solveLiftedMulticutProblem( std::fill(edge_labels.begin(), edge_labels.end(), 1); else if (parameters.optimizationMethod == Method::Zeros) std::fill(edge_labels.begin(), edge_labels.end(), 0); + else if (parameters.optimizationMethod == Method::ILP) + andres::graph::multicut_lifted::ilp>(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod == Method::GAEC) andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, edge_values, edge_labels); else if (parameters.optimizationMethod == Method::Kernighan_Lin) From 207068d7b8717d5b17b13598209433da8d439539 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Fri, 25 Mar 2016 20:05:45 +0100 Subject: [PATCH 03/15] working --- include/andres/graph/multicut-lifted/ilp.hxx | 66 +++----------------- 1 file changed, 10 insertions(+), 56 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index bcf3c8b..59a5298 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -123,11 +123,13 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con auto label = components.labels_[lv0]; std::fill(visited.begin(), visited.end(), 0); + std::stack S; S.push(lv0); + visited[lv0] = 1; - size_t sz = 0; + ptrdiff_t sz = 0; while (!S.empty()) { @@ -135,56 +137,17 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con S.pop(); for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) - if (components.labels_[it->vertex()] == label) - { - if (!visited[it->vertex()]) - { - S.push(it->vertex()); - visited[it->vertex()] = 1; - } - } - else + if (components.labels_[it->vertex()] != label) { + coefficients[sz] = -1; variables[sz] = edge_in_lifted_graph[it->edge()]; - coefficients[sz++] = -1; + + ++sz; } - } - - // variables[sz] = static_cast(edge); - // coefficients[sz] = 1; - - // #pragma omp critical - // ilp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); - - // #pragma omp atomic - // ++counter; - - - label = components.labels_[lv1]; - - S.push(lv1); - visited[lv1] = 1; - - // sz = 0; - - while (!S.empty()) - { - auto v = S.top(); - S.pop(); - - for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) - if (components.labels_[it->vertex()] == label) + else if (!visited[it->vertex()]) { - if (!visited[it->vertex()]) - { - S.push(it->vertex()); - visited[it->vertex()] = 1; - } - } - else - { - variables[sz] = edge_in_lifted_graph[it->edge()]; - coefficients[sz++] = -1; + S.push(it->vertex()); + visited[it->vertex()] = 1; } } @@ -242,15 +205,6 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con { repairSolution(); - auto energy_value = inner_product(edgeCosts.begin(), edgeCosts.end(), inputLabels.begin(), .0); - printf("Energy: %f\n", energy_value); - energy_value = .0; - for(ptrdiff_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) - if (ilp.label(edge) > 0.5) - energy_value += edgeCosts[edge]; - - printf("ILP Energy: %f\n", energy_value); - if (!visitor(outputLabels)) break; } From d00eb9b6ed16c6ec44e40386a63074238e10687e Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Mon, 28 Mar 2016 19:22:16 +0200 Subject: [PATCH 04/15] fixed max flow --- include/andres/graph/multicut-lifted/ilp.hxx | 3 +- include/andres/graph/multicut-lifted/lp.hxx | 40 ++++++++++---------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index 59a5298..a668439 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -70,8 +70,6 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con auto addCycleInequalities = [&] () { - t.stop(); - levinkov::Timer t_separation; t_separation.start(); @@ -161,6 +159,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con } t_separation.stop(); + t.stop(); double objValue = .0; for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index 8be28f1..f9545e4 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -64,6 +64,10 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ { src_ = src; dest_ = dest; + + for (auto& adj : g_) + for (auto& e : adj) + e.f = 0; int result = 0; @@ -196,8 +200,6 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ auto separateAndAddInequalities = [&] () { - t.stop(); - levinkov::Timer t_separation; t_separation.start(); @@ -247,33 +249,33 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ ++nPath; } - flow.maxFlow(lv0, lv1); - - double S_cut = .0; - - ptrdiff_t sz = 0; - for (auto& p : flow.getMinCut()) + if (!original_graph.findEdge(lv0, lv1).first) { - coefficients[sz] = -1.0; - variables[sz] = lifted_graph.findEdge(p.first, p.second).second; + auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 100000.0; - S_cut += 1.0 - vars[variables[sz]]; + if (1.0 - std::min(std::max(.0, lp.variableValue(edge)), 1.0) > flow_value + tolerance) + { + ptrdiff_t sz = 0; + for (auto& p : flow.getMinCut()) + { + coefficients[sz] = -1.0; + variables[sz] = lifted_graph.findEdge(p.first, p.second).second; - ++sz; - } + ++sz; + } - if (1.0 - lp.variableValue(edge) > S_cut + tolerance) - { - coefficients[sz] = 1.0; - variables[sz] = edge; + coefficients[sz] = 1.0; + variables[sz] = edge; - lp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + lp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); - ++nCut; + ++nCut; + } } } t_separation.stop(); + t.stop(); double objValue = .0; for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) From 426d4f269bb1625bb7aee1c2c59c7f702425263a Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Tue, 29 Mar 2016 14:54:16 +0200 Subject: [PATCH 05/15] added chordality check --- include/andres/graph/multicut-lifted/ilp.hxx | 20 +++++++++++++++--- include/andres/graph/multicut-lifted/lp.hxx | 22 +++++++++++++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index a668439..2a1d323 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -89,11 +89,25 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con { // if cycle/path inequality is violated - // search for shortest path + // search for shortest path that contains only non-lifted edges spsp(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph), lv0, lv1, path, buffer); - // check for chords only if the edge is from the original graph - if (original_graph.findEdge(lv0, lv1).first && findChord(original_graph, path.begin(), path.end(), true).first) + bool chordless = true; + for (auto it1 = path.begin(); it1 != path.end() - 2 && chordless; ++it1) + for (auto it2 = it1 + 2; it2 != path.end(); ++it2) + { + if (it1 == path.begin() && it2 == path.end() - 1) + continue; + + auto e = lifted_graph.findEdge(*it1, *it2); + if (e.first && ilp.label(e.second) > .5) + { + chordless = false; + break; + } + } + + if (!chordless) continue; // add inequality diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index f9545e4..3d09584 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -228,8 +228,26 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ // search for shortest path double distance; spsp(original_graph, DefaultSubgraphMask<>(), lv0, lv1, vars.begin(), path, distance, distances.begin(), parents.begin()); + + bool chordless = true; + for (auto it1 = path.begin(); it1 != path.end() - 2 && chordless; ++it1) + for (auto it2 = it1 + 2; it2 != path.end(); ++it2) + { + if (it1 == path.begin() && it2 == path.end() - 1) + continue; + + auto e = lifted_graph.findEdge(*it1, *it2); + if (e.first && std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) + { + chordless = false; + break; + } + } + + if (!chordless) + continue; - if (lp.variableValue(edge) > distance + tolerance) + if (std::min(std::max(.0, lp.variableValue(edge)), 1.0) > distance + tolerance) { // add inequality for (size_t j = 0; j < path.size() - 1; ++j) @@ -251,6 +269,8 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ if (!original_graph.findEdge(lv0, lv1).first) { + // find min cut only for lifted edges + auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 100000.0; if (1.0 - std::min(std::max(.0, lp.variableValue(edge)), 1.0) > flow_value + tolerance) From 32448751cc384a1f8cc9da05e4ce099a932025cb Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Fri, 1 Apr 2016 14:30:14 +0200 Subject: [PATCH 06/15] added unit-test for ILP LMP --- CMakeLists.txt | 8 ++++ include/andres/graph/multicut-lifted/lp.hxx | 49 +++++++++++---------- src/command-line-tools/solve-lmp.hxx | 19 ++++++-- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23bd295..6688f88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,14 @@ if(GUROBI_FOUND) add_executable(test-graph-multicut-ilp-callback src/andres/graph/unit-test/multicut/ilp-callback.cxx ${headers}) target_link_libraries(test-graph-multicut-ilp-callback ${CMAKE_THREAD_LIBS_INIT} ${GUROBI_CPP_LIBRARY} ${GUROBI_LIBRARY}) add_test(test-graph-multicut-ilp-callback test-graph-multicut-ilp-callback) + + add_executable(test-graph-multicut-lifted-ilp src/andres/graph/unit-test/multicut-lifted/ilp.cxx ${headers}) + target_link_libraries(test-graph-multicut-lifted-ilp ${CMAKE_THREAD_LIBS_INIT} ${GUROBI_CPP_LIBRARY} ${GUROBI_LIBRARY}) + add_test(test-graph-multicut-lifted-ilp test-graph-multicut-lifted-ilp) + + add_executable(test-graph-multicut-lifted-ilp-callback src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx ${headers}) + target_link_libraries(test-graph-multicut-lifted-ilp-callback ${CMAKE_THREAD_LIBS_INIT} ${GUROBI_CPP_LIBRARY} ${GUROBI_LIBRARY}) + add_test(test-graph-multicut-lifted-ilp-callback test-graph-multicut-lifted-ilp-callback) endif() if(DOXYGEN_FOUND) diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index 3d09584..7335a80 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -40,15 +40,15 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ class DinicFlow { public: - DinicFlow(int n) : + DinicFlow(size_t n) : dist_(n), q_(n), work_(n), g_(n) {} // Adds bidirectional edge - void addEdge(int s, int t, int cap) + void addEdge(size_t s, size_t t, ptrdiff_t cap) { - Edge a = { t, static_cast(g_[t].size()), 0, cap }; - Edge b = { s, static_cast(g_[s].size()), 0, cap }; + Edge a = { t, g_[t].size(), 0, cap }; + Edge b = { s, g_[s].size(), 0, cap }; g_[s].push_back(a); g_[t].push_back(b); @@ -60,7 +60,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ v.clear(); } - int maxFlow(int src, int dest) + size_t maxFlow(size_t src, size_t dest) { src_ = src; dest_ = dest; @@ -69,13 +69,13 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (auto& e : adj) e.f = 0; - int result = 0; + size_t result = 0; while (bfs()) { std::fill(work_.begin(), work_.end(), 0); - while (auto delta = dfs(src_, std::numeric_limits::max())) + while (auto delta = dfs(src_, std::numeric_limits::max())) result += delta; } @@ -83,11 +83,11 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ } // return edges (as pairs of vertices) of the Min Cut - std::set> getMinCut() + std::set> getMinCut() { std::fill(work_.begin(), work_.end(), 0); - std::stack S; + std::stack S; work_[src_] = 1; S.push(src_); @@ -105,9 +105,9 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ } } - std::set> ret; + std::set> ret; - for (int i = 0; i < g_.size(); ++i) + for (size_t i = 0; i < g_.size(); ++i) for (auto& e : g_[i]) if (work_[i] != work_[e.to]) ret.insert(std::make_pair(std::min(i, e.to), std::max(i, e.to))); @@ -118,8 +118,8 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ private: struct Edge { - int to, rev; - int f, cap; + size_t to, rev; + ptrdiff_t f, cap; }; bool bfs() @@ -128,17 +128,17 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ dist_[src_] = 0; - int qt = 0; + size_t qt = 0; q_[qt++] = src_; - for (int qh = 0; qh < qt; qh++) + for (size_t qh = 0; qh < qt; qh++) { auto u = q_[qh]; - for (int j = 0; j < g_[u].size(); j++) + for (size_t j = 0; j < g_[u].size(); j++) { - Edge &e = g_[u][j]; - auto v = e.to; + auto& e = g_[u][j]; + auto v = e.to; if (dist_[v] < 0 && e.f < e.cap) { @@ -151,19 +151,19 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ return dist_[dest_] >= 0; } - int dfs(int u, int f) + size_t dfs(size_t u, ptrdiff_t f) { if (u == dest_) return f; - for (int &i = work_[u]; i < (int) g_[u].size(); i++) + for (auto& i = work_[u]; i < g_[u].size(); i++) { - Edge &e = g_[u][i]; + auto& e = g_[u][i]; if (e.cap <= e.f) continue; - int v = e.to; + auto v = e.to; if (dist_[v] == dist_[u] + 1) { @@ -182,8 +182,9 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ return 0; } - int src_, dest_; - std::vector dist_, q_, work_; + size_t src_, dest_; + std::vector dist_; + std::vector q_, work_; std::vector> g_; }; diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx index dc58393..d8f0fdd 100644 --- a/src/command-line-tools/solve-lmp.hxx +++ b/src/command-line-tools/solve-lmp.hxx @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -22,7 +24,8 @@ enum class Method { GAEC, Kernighan_Lin, LP, - ILP + ILP, + ILPC }; enum class Initialization { @@ -53,7 +56,7 @@ try TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", false, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); - TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, ILP, LP, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); + TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {zeros, ones, ILP, ILPC, LP, GAEC, KL}", false, "KL", "OPTIMIZATION_METHOD", tclap); TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC}", false, "zeros", "INITIALIZATION_METHOD", tclap); TCLAP::SwitchArg argNonProbabilistic("p", "non-probabilistic", "Assume inputs are not probabilities. By default, all inputs are assumed to be Logistic Probabilities. (Default: disabled).",tclap); @@ -76,6 +79,8 @@ try parameters.optimizationMethod = Method::LP; else if (argOptimizationMethod.getValue() == "ILP") parameters.optimizationMethod = Method::ILP; + else if (argOptimizationMethod.getValue() == "ILPC") + parameters.optimizationMethod = Method::ILPC; else if(argOptimizationMethod.getValue() == "KL") { parameters.optimizationMethod = Method::Kernighan_Lin; @@ -133,6 +138,10 @@ void solveLiftedMulticutProblem( andres::graph::hdf5::closeFile(fileHandle); } + std::cout << "Number of vertices: " << original_graph.numberOfVertices() << std::endl; + std::cout << "Number of non-lifted edges: " << original_graph.numberOfEdges() << std::endl; + std::cout << "Number of edges: " << lifted_graph.numberOfEdges() << std::endl; + if (parameters.probabilistic) std::transform( edge_values.begin(), @@ -176,14 +185,16 @@ void solveLiftedMulticutProblem( else if (parameters.optimizationMethod == Method::Zeros) std::fill(edge_labels.begin(), edge_labels.end(), 0); else if (parameters.optimizationMethod == Method::ILP) - andres::graph::multicut_lifted::ilp>(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + else if (parameters.optimizationMethod == Method::ILPC) + andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod == Method::GAEC) andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, edge_values, edge_labels); else if (parameters.optimizationMethod == Method::Kernighan_Lin) andres::graph::multicut_lifted::kernighanLin(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod == Method::LP) { - auto values = andres::graph::multicut_lifted::lp>(original_graph, lifted_graph, edge_values); + auto values = andres::graph::multicut_lifted::lp(original_graph, lifted_graph, edge_values); t.stop(); From 6a1f942d6a6191667100793fcd74eb455d8c3198 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Fri, 1 Apr 2016 14:30:56 +0200 Subject: [PATCH 07/15] adding files --- .../multicut-lifted/ilp-callback.cxx | 147 ++++++++++++++++++ .../graph/unit-test/multicut-lifted/ilp.cxx | 147 ++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx create mode 100644 src/andres/graph/unit-test/multicut-lifted/ilp.cxx diff --git a/src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx b/src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx new file mode 100644 index 0000000..6248137 --- /dev/null +++ b/src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx @@ -0,0 +1,147 @@ +#include +#include +#include + +#include +#include +#include + +inline void test(bool pred) +{ + if(!pred) + throw std::runtime_error("Test failed."); +} + +void test_3() +{ + andres::graph::Graph<> original_graph(3); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(1, 2); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(0, 2); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -10; + edge_values[1] = -10; + edge_values[2] = 10; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); +} + +void test_4() +{ + andres::graph::Graph<> original_graph(4); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(0, 3); + original_graph.insertEdge(1, 2); + original_graph.insertEdge(2, 3); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(0, 3); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(2, 3); + lifted_graph.insertEdge(0, 2); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -10; + edge_values[1] = -2; + edge_values[2] = -10; + edge_values[3] = -4; + edge_values[4] = 1; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); + test(edge_labels[3] == 1); + test(edge_labels[4] == 1); +} + +void test_8() +{ + andres::graph::Graph<> original_graph(8); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(1, 2); + original_graph.insertEdge(2, 3); + original_graph.insertEdge(4, 5); + original_graph.insertEdge(5, 6); + original_graph.insertEdge(6, 7); + original_graph.insertEdge(0, 4); + original_graph.insertEdge(1, 5); + original_graph.insertEdge(2, 6); + original_graph.insertEdge(3, 7); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(2, 3); + lifted_graph.insertEdge(4, 5); + lifted_graph.insertEdge(5, 6); + lifted_graph.insertEdge(6, 7); + lifted_graph.insertEdge(0, 4); + lifted_graph.insertEdge(1, 5); + lifted_graph.insertEdge(2, 6); + lifted_graph.insertEdge(3, 7); + + lifted_graph.insertEdge(0, 7); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -5; + edge_values[1] = -5; + edge_values[2] = -5; + edge_values[3] = 5; + edge_values[4] = .5; + edge_values[5] = 5; + edge_values[6] = 1; + edge_values[7] = -1; + edge_values[8] = 1; + edge_values[9] = .5; + + edge_values[10] = -4; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); + test(edge_labels[3] == 0); + test(edge_labels[4] == 1); + test(edge_labels[5] == 0); + test(edge_labels[6] == 0); + test(edge_labels[7] == 1); + test(edge_labels[8] == 0); + test(edge_labels[9] == 1); + test(edge_labels[10] == 1); +} + +int main() +{ + test_3(); + + test_4(); + + test_8(); + + return 0; +} \ No newline at end of file diff --git a/src/andres/graph/unit-test/multicut-lifted/ilp.cxx b/src/andres/graph/unit-test/multicut-lifted/ilp.cxx new file mode 100644 index 0000000..4b44449 --- /dev/null +++ b/src/andres/graph/unit-test/multicut-lifted/ilp.cxx @@ -0,0 +1,147 @@ +#include +#include +#include + +#include +#include +#include + +inline void test(bool pred) +{ + if(!pred) + throw std::runtime_error("Test failed."); +} + +void test_3() +{ + andres::graph::Graph<> original_graph(3); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(1, 2); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(0, 2); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -10; + edge_values[1] = -10; + edge_values[2] = 10; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); +} + +void test_4() +{ + andres::graph::Graph<> original_graph(4); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(0, 3); + original_graph.insertEdge(1, 2); + original_graph.insertEdge(2, 3); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(0, 3); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(2, 3); + lifted_graph.insertEdge(0, 2); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -10; + edge_values[1] = -2; + edge_values[2] = -10; + edge_values[3] = -4; + edge_values[4] = 1; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); + test(edge_labels[3] == 1); + test(edge_labels[4] == 1); +} + +void test_8() +{ + andres::graph::Graph<> original_graph(8); + + original_graph.insertEdge(0, 1); + original_graph.insertEdge(1, 2); + original_graph.insertEdge(2, 3); + original_graph.insertEdge(4, 5); + original_graph.insertEdge(5, 6); + original_graph.insertEdge(6, 7); + original_graph.insertEdge(0, 4); + original_graph.insertEdge(1, 5); + original_graph.insertEdge(2, 6); + original_graph.insertEdge(3, 7); + + andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); + + lifted_graph.insertEdge(0, 1); + lifted_graph.insertEdge(1, 2); + lifted_graph.insertEdge(2, 3); + lifted_graph.insertEdge(4, 5); + lifted_graph.insertEdge(5, 6); + lifted_graph.insertEdge(6, 7); + lifted_graph.insertEdge(0, 4); + lifted_graph.insertEdge(1, 5); + lifted_graph.insertEdge(2, 6); + lifted_graph.insertEdge(3, 7); + + lifted_graph.insertEdge(0, 7); + + vector edge_values(lifted_graph.numberOfEdges()); + + edge_values[0] = -5; + edge_values[1] = -5; + edge_values[2] = -5; + edge_values[3] = 5; + edge_values[4] = .5; + edge_values[5] = 5; + edge_values[6] = 1; + edge_values[7] = -1; + edge_values[8] = 1; + edge_values[9] = .5; + + edge_values[10] = -4; + + vector edge_labels(lifted_graph.numberOfEdges()); + andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + + test(edge_labels[0] == 1); + test(edge_labels[1] == 1); + test(edge_labels[2] == 1); + test(edge_labels[3] == 0); + test(edge_labels[4] == 1); + test(edge_labels[5] == 0); + test(edge_labels[6] == 0); + test(edge_labels[7] == 1); + test(edge_labels[8] == 0); + test(edge_labels[9] == 1); + test(edge_labels[10] == 1); +} + +int main() +{ + test_3(); + + test_4(); + + test_8(); + + return 0; +} \ No newline at end of file From 0f1b9a5a9a92210b8910a22f4418e418c7ceef69 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Thu, 19 May 2016 11:01:53 +0200 Subject: [PATCH 08/15] added ILP callback for LMC --- .../graph/multicut-lifted/ilp-callback.hxx | 271 ++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 include/andres/graph/multicut-lifted/ilp-callback.hxx diff --git a/include/andres/graph/multicut-lifted/ilp-callback.hxx b/include/andres/graph/multicut-lifted/ilp-callback.hxx new file mode 100644 index 0000000..43726dc --- /dev/null +++ b/include/andres/graph/multicut-lifted/ilp-callback.hxx @@ -0,0 +1,271 @@ +#pragma once +#ifndef ANDRES_GRAPH_MULTICUT_LIFTED_ILP_CALLBACK_HXX +#define ANDRES_GRAPH_MULTICUT_LIFTED_ILP_CALLBACK_HXX + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace andres { +namespace graph { +namespace multicut_lifted +{ + +template +inline +void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, size_t timeLimitSeconds = 86400) +{ + struct Visitor + { + bool operator()(ELA const& edge_labels) const + { + return true; + } + } visitor; + + ilp_callback(original_graph, lifted_graph, edgeCosts, inputLabels, outputLabels, visitor, timeLimitSeconds); +} + +template +inline +void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, VIS& visitor, size_t timeLimitSeconds = 86400) +{ + struct SubgraphWithCut + { + SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) + : ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) + {} + + bool vertex(size_t v) const + { + return true; + } + + bool edge(size_t e) const + { + return ilp_.label(edge_in_lifted_graph_[e]) < .5; + } + + ILP const& ilp_; + std::vector const& edge_in_lifted_graph_; + }; + + + levinkov::Timer t; + + class Callback: public ILP::Callback + { + public: + Callback(ILP& solver, ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, levinkov::Timer& t) : + ILP::Callback(solver), + original_graph_(original_graph), + lifted_graph_(lifted_graph), + coefficients_(lifted_graph.numberOfEdges()), + variables_(lifted_graph.numberOfEdges()), + visited_(original_graph.numberOfVertices()), + edge_in_lifted_graph_(original_graph.numberOfEdges()), + t_(t) + { + for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) + { + auto v0 = original_graph.vertexOfEdge(i, 0); + auto v1 = original_graph.vertexOfEdge(i, 1); + + edge_in_lifted_graph_[i] = lifted_graph.findEdge(v0, v1).second; + } + } + + void separateAndAddLazyConstraints() override + { + levinkov::Timer t_separation; + t_separation.start(); + + components_.build(original_graph_, SubgraphWithCut(*this, edge_in_lifted_graph_)); + + // search for violated non-chordal cycles and add corresp. inequalities + size_t nCycle = 0; + size_t nPath = 0; + size_t nCut = 0; + + for (ptrdiff_t edge = 0; edge < lifted_graph_.numberOfEdges(); ++edge) + { + auto lv0 = lifted_graph_.vertexOfEdge(edge, 0); + auto lv1 = lifted_graph_.vertexOfEdge(edge, 1); + + if (this->label(edge) == 1 && components_.areConnected(lv0, lv1)) + { + // if cycle/path inequality is violated + + // search for shortest path that contains only non-lifted edges + spsp(original_graph_, SubgraphWithCut(*this, edge_in_lifted_graph_), lv0, lv1, path_, buffer_); + + bool chordless = true; + for (auto it1 = path_.begin(); it1 != path_.end() - 2 && chordless; ++it1) + for (auto it2 = it1 + 2; it2 != path_.end(); ++it2) + { + if (it1 == path_.begin() && it2 == path_.end() - 1) + continue; + + auto e = lifted_graph_.findEdge(*it1, *it2); + if (e.first && this->label(e.second) > .5) + { + chordless = false; + break; + } + } + + if (!chordless) + continue; + + // add inequality + for (size_t j = 0; j < path_.size() - 1; ++j) + { + variables_[j] = lifted_graph_.findEdge(path_[j], path_[j + 1]).second; + coefficients_[j] = 1.0; + } + + variables_[path_.size() - 1] = edge; + coefficients_[path_.size() - 1] = -1.0; + + this->addLazyConstraint(variables_.begin(), variables_.begin() + path_.size(), coefficients_.begin(), 0, std::numeric_limits::infinity()); + + if (original_graph_.findEdge(lv0, lv1).first) + ++nCycle; + else + ++nPath; + } + else if (this->label(edge) == 0 && !components_.areConnected(lv0, lv1)) + { + // if cut inequality is violated + + // do a simple DFS to find all the edges, that leave the partition, which is essentially a cut + auto label = components_.labels_[lv0]; + + std::fill(visited_.begin(), visited_.end(), 0); + + std::stack S; + S.push(lv0); + + visited_[lv0] = 1; + + ptrdiff_t sz = 0; + + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto it = original_graph_.adjacenciesFromVertexBegin(v); it != original_graph_.adjacenciesFromVertexEnd(v); ++it) + if (components_.labels_[it->vertex()] != label) + { + coefficients_[sz] = -1; + variables_[sz] = edge_in_lifted_graph_[it->edge()]; + + ++sz; + } + else if (!visited_[it->vertex()]) + { + S.push(it->vertex()); + visited_[it->vertex()] = 1; + } + } + + coefficients_[sz] = 1; + variables_[sz] = edge; + + this->addLazyConstraint(variables_.begin(), variables_.begin() + sz + 1, coefficients_.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + } + } + + t_separation.stop(); + t_.stop(); + + std::cerr << t_.get_elapsed_seconds() << " " << this->objectiveBound_ << " " << this->objectiveBest_ << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + + t_.start(); + } + + private: + struct SubgraphWithCut + { + SubgraphWithCut(Callback& callback, std::vector const& edge_in_lifted_graph) + : callback_(callback), edge_in_lifted_graph_(edge_in_lifted_graph) + {} + + bool vertex(size_t v) const + { + return true; + } + + bool edge(size_t e) const + { + return callback_.label(edge_in_lifted_graph_[e]) < .5; + } + + Callback& callback_; + std::vector const& edge_in_lifted_graph_; + }; + + ORIGGRAPH const& original_graph_; + LIFTGRAPH const& lifted_graph_; + + levinkov::Timer& t_; + + std::vector coefficients_; + ComponentsBySearch components_; + std::vector buffer_; + std::vector edge_in_lifted_graph_; + std::deque path_; + std::vector variables_; + std::vector visited_; + }; + + t.start(); + + ILP ilp; + + ilp.setRelativeGap(0.0); + ilp.setAbsoluteGap(0.0); + ilp.setTimeLimit(timeLimitSeconds); + ilp.addVariables(edgeCosts.size(), edgeCosts.data()); + + Callback callback(ilp, original_graph, lifted_graph, t); + ilp.setCallback(callback); + + ilp.optimize(); + + std::vector edge_in_lifted_graph(original_graph.numberOfEdges()); + for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) + { + auto v0 = original_graph.vertexOfEdge(i, 0); + auto v1 = original_graph.vertexOfEdge(i, 1); + + edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; + } + + ComponentsBySearch components; + components.build(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph)); + + for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + { + auto v0 = lifted_graph.vertexOfEdge(edge, 0); + auto v1 = lifted_graph.vertexOfEdge(edge, 1); + + outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; + } +} + +} +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_MULTICUT_LIFTED_ILP_CALLBACK_HXX From afa2d9d62ba54a40d9fce602b2deb1a173f5f6ca Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Thu, 14 Jul 2016 12:20:48 +0200 Subject: [PATCH 09/15] working --- include/andres/graph/multicut-lifted/lp.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index 7335a80..53d71d3 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -68,7 +68,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (auto& adj : g_) for (auto& e : adj) e.f = 0; - + size_t result = 0; while (bfs()) @@ -213,7 +213,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ auto v0 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 0); auto v1 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 1); - flow.addEdge(v0, v1, 100000.0*(1.0 - vars[i])); + flow.addEdge(v0, v1, 10000000.0*(1.0 - vars[i])); } // search for violated non-chordal cycles and add corresp. inequalities @@ -272,7 +272,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ { // find min cut only for lifted edges - auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 100000.0; + auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 10000000.0; if (1.0 - std::min(std::max(.0, lp.variableValue(edge)), 1.0) > flow_value + tolerance) { From da79689901419392b81eb81ee9398b1fe9f9f61d Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Mon, 18 Jul 2016 14:36:39 +0200 Subject: [PATCH 10/15] fixed numerics of LP. Cuts are found for both vertices of an edge --- .../graph/multicut-lifted/ilp-callback.hxx | 38 +++++++++++++++++-- include/andres/graph/multicut-lifted/ilp.hxx | 36 +++++++++++++++++- include/andres/graph/multicut-lifted/lp.hxx | 30 +++++++++++++-- 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp-callback.hxx b/include/andres/graph/multicut-lifted/ilp-callback.hxx index 43726dc..6fe0162 100644 --- a/include/andres/graph/multicut-lifted/ilp-callback.hxx +++ b/include/andres/graph/multicut-lifted/ilp-callback.hxx @@ -114,7 +114,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph continue; auto e = lifted_graph_.findEdge(*it1, *it2); - if (e.first && this->label(e.second) > .5) + if (this->label(e.second) > .5) { chordless = false; break; @@ -145,18 +145,50 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph { // if cut inequality is violated - // do a simple DFS to find all the edges, that leave the partition, which is essentially a cut + // do a DFS to find all the edges, that leave the partition, which is essentially a cut auto label = components_.labels_[lv0]; std::fill(visited_.begin(), visited_.end(), 0); std::stack S; S.push(lv0); - visited_[lv0] = 1; ptrdiff_t sz = 0; + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto it = original_graph_.adjacenciesFromVertexBegin(v); it != original_graph_.adjacenciesFromVertexEnd(v); ++it) + if (components_.labels_[it->vertex()] != label) + { + coefficients_[sz] = -1; + variables_[sz] = edge_in_lifted_graph_[it->edge()]; + + ++sz; + } + else if (!visited_[it->vertex()]) + { + S.push(it->vertex()); + visited_[it->vertex()] = 1; + } + } + + coefficients_[sz] = 1; + variables_[sz] = edge; + + this->addLazyConstraint(variables_.begin(), variables_.begin() + sz + 1, coefficients_.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + + + label = components_.labels_[lv1]; + + S.push(lv1); + visited_[lv1] = 1; + sz = 0; while (!S.empty()) { auto v = S.top(); diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index 2a1d323..2b5f989 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -100,7 +100,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con continue; auto e = lifted_graph.findEdge(*it1, *it2); - if (e.first && ilp.label(e.second) > .5) + if (/*e.first && */ilp.label(e.second) > .5) { chordless = false; break; @@ -138,11 +138,43 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con std::stack S; S.push(lv0); - visited[lv0] = 1; ptrdiff_t sz = 0; + while (!S.empty()) + { + auto v = S.top(); + S.pop(); + + for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) + if (components.labels_[it->vertex()] != label) + { + coefficients[sz] = -1; + variables[sz] = edge_in_lifted_graph[it->edge()]; + + ++sz; + } + else if (!visited[it->vertex()]) + { + S.push(it->vertex()); + visited[it->vertex()] = 1; + } + } + + coefficients[sz] = 1; + variables[sz] = edge; + + ilp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + + + label = components.labels_[lv1]; + + S.push(lv1); + visited[lv1] = 1; + sz = 0; while (!S.empty()) { auto v = S.top(); diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index 53d71d3..747eb92 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -213,7 +213,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ auto v0 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 0); auto v1 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 1); - flow.addEdge(v0, v1, 10000000.0*(1.0 - vars[i])); + flow.addEdge(v0, v1, 100000000000.0*(1.0 - vars[i])); } // search for violated non-chordal cycles and add corresp. inequalities @@ -238,7 +238,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ continue; auto e = lifted_graph.findEdge(*it1, *it2); - if (e.first && std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) + if (std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) { chordless = false; break; @@ -271,8 +271,30 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ if (!original_graph.findEdge(lv0, lv1).first) { // find min cut only for lifted edges + // find cut(s) for both vertices of an edge - considerably improves convergence - auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 10000000.0; + auto flow_value = static_cast(flow.maxFlow(lv0, lv1)) / 100000000000.0; + + if (1.0 - std::min(std::max(.0, lp.variableValue(edge)), 1.0) > flow_value + tolerance) + { + ptrdiff_t sz = 0; + for (auto& p : flow.getMinCut()) + { + coefficients[sz] = -1.0; + variables[sz] = lifted_graph.findEdge(p.first, p.second).second; + + ++sz; + } + + coefficients[sz] = 1.0; + variables[sz] = edge; + + lp.addConstraint(variables.begin(), variables.begin() + sz + 1, coefficients.begin(), 1.0 - sz, std::numeric_limits::infinity()); + + ++nCut; + } + + flow_value = static_cast(flow.maxFlow(lv1, lv0)) / 100000000000.0; if (1.0 - std::min(std::max(.0, lp.variableValue(edge)), 1.0) > flow_value + tolerance) { @@ -302,7 +324,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) objValue += lp.variableValue(i)*edgeCosts[i]; - std::cerr << t.get_elapsed_seconds() << " " << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + std::cerr << t.get_elapsed_seconds() << " " << std::setprecision(5) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; t.start(); From 6fd630e9aa02bbb7e268419cc2602ee22f828c08 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Mon, 1 Aug 2016 16:27:00 +0200 Subject: [PATCH 11/15] fixed a bug in all exact solvers --- .../graph/multicut-lifted/ilp-callback.hxx | 5 ++- include/andres/graph/multicut-lifted/ilp.hxx | 42 +++++++------------ include/andres/graph/multicut-lifted/lp.hxx | 4 +- src/command-line-tools/solve-lmp.hxx | 2 +- 4 files changed, 21 insertions(+), 32 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp-callback.hxx b/include/andres/graph/multicut-lifted/ilp-callback.hxx index 6fe0162..821e022 100644 --- a/include/andres/graph/multicut-lifted/ilp-callback.hxx +++ b/include/andres/graph/multicut-lifted/ilp-callback.hxx @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -114,7 +115,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph continue; auto e = lifted_graph_.findEdge(*it1, *it2); - if (this->label(e.second) > .5) + if (e.first && this->label(e.second) > .5) { chordless = false; break; @@ -221,7 +222,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph t_separation.stop(); t_.stop(); - std::cerr << t_.get_elapsed_seconds() << " " << this->objectiveBound_ << " " << this->objectiveBest_ << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + std::cerr <objectiveBound_ << " " << std::setprecision(10) << this->objectiveBest_ << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; t_.start(); } diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index 2b5f989..fb8aa09 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con auto lv0 = lifted_graph.vertexOfEdge(edge, 0); auto lv1 = lifted_graph.vertexOfEdge(edge, 1); - if (ilp.label(edge) == 1 && components.areConnected(lv0, lv1)) + if (ilp.label(edge) > .5 && components.areConnected(lv0, lv1)) { // if cycle/path inequality is violated @@ -100,7 +101,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con continue; auto e = lifted_graph.findEdge(*it1, *it2); - if (/*e.first && */ilp.label(e.second) > .5) + if (e.first && ilp.label(e.second) > .5) { chordless = false; break; @@ -127,7 +128,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con else ++nPath; } - else if (ilp.label(edge) == 0 && !components.areConnected(lv0, lv1)) + else if (ilp.label(edge) < .5 && !components.areConnected(lv0, lv1)) { // if cut inequality is violated @@ -211,26 +212,13 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) objValue += ilp.label(i)*edgeCosts[i]; - std::cerr << t.get_elapsed_seconds() << " " << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + std::cerr << std::fixed << t.get_elapsed_seconds() << " " << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; t.start(); return nCycle + nPath + nCut; }; - auto repairSolution = [&] () - { - for(size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) - { - auto v0 = lifted_graph.vertexOfEdge(edge, 0); - auto v1 = lifted_graph.vertexOfEdge(edge, 1); - - outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; - } - - ilp.setStart(outputLabels.begin()); - }; - t.start(); for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) @@ -244,23 +232,23 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con ilp.initModel(lifted_graph.numberOfEdges(), edgeCosts.data()); ilp.setStart(inputLabels.begin()); - for(size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) + for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) { - if (i != 0) - { - repairSolution(); - - if (!visitor(outputLabels)) - break; - } - ilp.optimize(); if (addCycleInequalities() == 0) break; } - repairSolution(); + components.build(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph)); + + for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) + { + auto v0 = lifted_graph.vertexOfEdge(edge, 0); + auto v1 = lifted_graph.vertexOfEdge(edge, 1); + + outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; + } } } diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index 747eb92..deb1703 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -238,7 +238,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ continue; auto e = lifted_graph.findEdge(*it1, *it2); - if (std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) + if (e.first && std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) { chordless = false; break; @@ -324,7 +324,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) objValue += lp.variableValue(i)*edgeCosts[i]; - std::cerr << t.get_elapsed_seconds() << " " << std::setprecision(5) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; + std::cerr << std::fixed << t.get_elapsed_seconds() << " " << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; t.start(); diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx index d8f0fdd..58b75f9 100644 --- a/src/command-line-tools/solve-lmp.hxx +++ b/src/command-line-tools/solve-lmp.hxx @@ -213,7 +213,7 @@ void solveLiftedMulticutProblem( } std::cout << "Number of clusters: N/A\n"; - std::cout << "Energy value: " << energy_value << std::endl; + std::cout << "Energy value: " << std::fixed << std::setprecision(10) << energy_value << std::endl; std::cout << "Running time: " << t.to_string() << std::endl; return; From 39c8c8c4d8a00fb24e650b19bd7d508a6e8845d3 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Mon, 1 Aug 2016 17:28:32 +0200 Subject: [PATCH 12/15] small changes --- src/command-line-tools/solve-mp.hxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/command-line-tools/solve-mp.hxx b/src/command-line-tools/solve-mp.hxx index b4173ae..f333b4b 100644 --- a/src/command-line-tools/solve-mp.hxx +++ b/src/command-line-tools/solve-mp.hxx @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ enum class Method { GF, KL, ILP, + ILPC, LP }; @@ -60,7 +62,7 @@ parseCommandLine( TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", true, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); - TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {LP, ILP, GAEC, GF, LGAEC, KL, LKL, OKL, CGC, zeros, ones}", false, "KL", "OPTIMIZATION_METHOD", tclap); + TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {LP, ILP, ILPC, GAEC, GF, KL, zeros, ones}", false, "KL", "OPTIMIZATION_METHOD", tclap); TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC, GF}", false, "zeros", "INITIALIZATION_METHOD", tclap); tclap.parse(argc, argv); @@ -93,6 +95,8 @@ parseCommandLine( parameters.optimizationMethod_ = Method::KL; else if (argOptimizationMethod.getValue() == "ILP") parameters.optimizationMethod_ = Method::ILP; + else if (argOptimizationMethod.getValue() == "ILPC") + parameters.optimizationMethod_ = Method::ILPC; else if (argOptimizationMethod.getValue() == "LP") parameters.optimizationMethod_ = Method::LP; else if(argInitializationMethod.getValue() == "ones") @@ -110,8 +114,7 @@ parseCommandLine( template void solveMulticutProblem( - const Parameters& parameters, - ostream& stream = std::cout + const Parameters& parameters ) { GraphType graph; @@ -173,6 +176,8 @@ void solveMulticutProblem( andres::graph::multicut::kernighanLin(graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod_ == Method::ILP) andres::graph::multicut::ilp(graph, edge_values, edge_labels, edge_labels); + else if (parameters.optimizationMethod_ == Method::ILPC) + andres::graph::multicut::ilp(graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod_ == Method::LP) { auto values = andres::graph::multicut::lp(graph, edge_values); From 82ce0e25f2cbcff8294b54a03b32c90d0507175c Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Wed, 3 Aug 2016 11:38:03 +0200 Subject: [PATCH 13/15] small changes --- .gitignore | 0 CMakeLists.txt | 0 README.md | 0 cmake/modules/FindGUROBI.cmake | 0 doxygen/doxyfile-graph.in | 0 include/andres/functional.hxx | 0 include/andres/graph/adjacency.hxx | 0 include/andres/graph/bfs.hxx | 0 include/andres/graph/bridges.hxx | 0 include/andres/graph/complete-graph.hxx | 0 include/andres/graph/components.hxx | 0 include/andres/graph/cut-vertices.hxx | 0 include/andres/graph/detail/graph.hxx | 0 include/andres/graph/dfs.hxx | 0 include/andres/graph/digraph.hxx | 0 include/andres/graph/doxygen.hxx | 0 include/andres/graph/edge-value.hxx | 0 include/andres/graph/graph.hxx | 0 include/andres/graph/grid-graph.hxx | 0 include/andres/graph/hdf5/complete-graph.hxx | 0 include/andres/graph/hdf5/digraph.hxx | 0 include/andres/graph/hdf5/graph.hxx | 0 include/andres/graph/hdf5/grid-graph.hxx | 0 include/andres/graph/hdf5/hdf5.hxx | 0 include/andres/graph/lifting.hxx | 0 include/andres/graph/max-flow.hxx | 0 include/andres/graph/minimum-spanning-tree.hxx | 0 include/andres/graph/multicut-lifted/greedy-additive.hxx | 0 include/andres/graph/multicut-lifted/kernighan-lin.hxx | 0 include/andres/graph/multicut/greedy-additive.hxx | 0 include/andres/graph/multicut/greedy-fixation.hxx | 0 include/andres/graph/multicut/ilp-callback.hxx | 0 include/andres/graph/multicut/ilp.hxx | 0 include/andres/graph/multicut/kernighan-lin.hxx | 0 include/andres/graph/multicut/lp.hxx | 0 include/andres/graph/paths.hxx | 0 include/andres/graph/shortest-paths.hxx | 0 include/andres/graph/subgraph.hxx | 0 include/andres/graph/twocut-lifted/kernighan-lin.hxx | 0 include/andres/graph/twocut/kernighan-lin.hxx | 0 include/andres/graph/visitor.hxx | 0 include/andres/ilp/gurobi-callback.hxx | 0 include/andres/ilp/gurobi.hxx | 0 include/andres/lp/gurobi.hxx | 0 include/andres/partition.hxx | 0 include/andres/random-access-set.hxx | 0 src/andres/graph/unit-test/bfs.cxx | 0 src/andres/graph/unit-test/bridges.cxx | 0 src/andres/graph/unit-test/components.cxx | 0 src/andres/graph/unit-test/cut-vertices.cxx | 0 src/andres/graph/unit-test/dfs.cxx | 0 src/andres/graph/unit-test/digraph.cxx | 0 src/andres/graph/unit-test/graph-complete.cxx | 0 src/andres/graph/unit-test/graph-grid.cxx | 0 src/andres/graph/unit-test/graph.cxx | 0 src/andres/graph/unit-test/hdf5.cxx | 0 src/andres/graph/unit-test/lifting.cxx | 0 src/andres/graph/unit-test/max-flow.cxx | 0 src/andres/graph/unit-test/minimum-spanning-tree.cxx | 0 src/andres/graph/unit-test/multicut-lifted/greedy-additive.cxx | 0 src/andres/graph/unit-test/multicut-lifted/kernighan-lin.cxx | 0 src/andres/graph/unit-test/multicut/greedy-additive.cxx | 0 src/andres/graph/unit-test/multicut/ilp-callback.cxx | 0 src/andres/graph/unit-test/multicut/ilp.cxx | 0 src/andres/graph/unit-test/multicut/kernighan-lin.cxx | 0 src/andres/graph/unit-test/paths.cxx | 0 src/andres/graph/unit-test/shortest-paths.cxx | 0 src/command-line-tools/fast-marching.hxx | 0 src/command-line-tools/lift-mp-grid-graph.cxx | 0 src/command-line-tools/lift-mp.cxx | 0 src/command-line-tools/probabilistic-lifting.hxx | 0 src/command-line-tools/solve-lmp-grid-graph.cxx | 0 src/command-line-tools/solve-lmp.cxx | 0 src/command-line-tools/solve-lmp.hxx | 0 src/command-line-tools/solve-mp-complete-graph.cxx | 0 src/command-line-tools/solve-mp-grid-graph.cxx | 0 src/command-line-tools/solve-mp.cxx | 0 src/command-line-tools/solve-mp.hxx | 0 src/command-line-tools/test-probabilistic-lifting.cxx | 0 src/command-line-tools/utils.hxx | 0 src/tclap/Arg.h | 0 src/tclap/ArgException.h | 0 src/tclap/ArgTraits.h | 0 src/tclap/CmdLine.h | 0 src/tclap/CmdLineInterface.h | 0 src/tclap/CmdLineOutput.h | 0 src/tclap/Constraint.h | 0 src/tclap/DocBookOutput.h | 0 src/tclap/HelpVisitor.h | 0 src/tclap/IgnoreRestVisitor.h | 0 src/tclap/MultiArg.h | 0 src/tclap/MultiSwitchArg.h | 0 src/tclap/OptionalUnlabeledTracker.h | 0 src/tclap/StandardTraits.h | 0 src/tclap/StdOutput.h | 0 src/tclap/SwitchArg.h | 0 src/tclap/UnlabeledMultiArg.h | 0 src/tclap/UnlabeledValueArg.h | 0 src/tclap/ValueArg.h | 0 src/tclap/ValuesConstraint.h | 0 src/tclap/VersionVisitor.h | 0 src/tclap/Visitor.h | 0 src/tclap/XorHandler.h | 0 src/tclap/ZshCompletionOutput.h | 0 104 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 CMakeLists.txt mode change 100644 => 100755 README.md mode change 100644 => 100755 cmake/modules/FindGUROBI.cmake mode change 100644 => 100755 doxygen/doxyfile-graph.in mode change 100644 => 100755 include/andres/functional.hxx mode change 100644 => 100755 include/andres/graph/adjacency.hxx mode change 100644 => 100755 include/andres/graph/bfs.hxx mode change 100644 => 100755 include/andres/graph/bridges.hxx mode change 100644 => 100755 include/andres/graph/complete-graph.hxx mode change 100644 => 100755 include/andres/graph/components.hxx mode change 100644 => 100755 include/andres/graph/cut-vertices.hxx mode change 100644 => 100755 include/andres/graph/detail/graph.hxx mode change 100644 => 100755 include/andres/graph/dfs.hxx mode change 100644 => 100755 include/andres/graph/digraph.hxx mode change 100644 => 100755 include/andres/graph/doxygen.hxx mode change 100644 => 100755 include/andres/graph/edge-value.hxx mode change 100644 => 100755 include/andres/graph/graph.hxx mode change 100644 => 100755 include/andres/graph/grid-graph.hxx mode change 100644 => 100755 include/andres/graph/hdf5/complete-graph.hxx mode change 100644 => 100755 include/andres/graph/hdf5/digraph.hxx mode change 100644 => 100755 include/andres/graph/hdf5/graph.hxx mode change 100644 => 100755 include/andres/graph/hdf5/grid-graph.hxx mode change 100644 => 100755 include/andres/graph/hdf5/hdf5.hxx mode change 100644 => 100755 include/andres/graph/lifting.hxx mode change 100644 => 100755 include/andres/graph/max-flow.hxx mode change 100644 => 100755 include/andres/graph/minimum-spanning-tree.hxx mode change 100644 => 100755 include/andres/graph/multicut-lifted/greedy-additive.hxx mode change 100644 => 100755 include/andres/graph/multicut-lifted/kernighan-lin.hxx mode change 100644 => 100755 include/andres/graph/multicut/greedy-additive.hxx mode change 100644 => 100755 include/andres/graph/multicut/greedy-fixation.hxx mode change 100644 => 100755 include/andres/graph/multicut/ilp-callback.hxx mode change 100644 => 100755 include/andres/graph/multicut/ilp.hxx mode change 100644 => 100755 include/andres/graph/multicut/kernighan-lin.hxx mode change 100644 => 100755 include/andres/graph/multicut/lp.hxx mode change 100644 => 100755 include/andres/graph/paths.hxx mode change 100644 => 100755 include/andres/graph/shortest-paths.hxx mode change 100644 => 100755 include/andres/graph/subgraph.hxx mode change 100644 => 100755 include/andres/graph/twocut-lifted/kernighan-lin.hxx mode change 100644 => 100755 include/andres/graph/twocut/kernighan-lin.hxx mode change 100644 => 100755 include/andres/graph/visitor.hxx mode change 100644 => 100755 include/andres/ilp/gurobi-callback.hxx mode change 100644 => 100755 include/andres/ilp/gurobi.hxx mode change 100644 => 100755 include/andres/lp/gurobi.hxx mode change 100644 => 100755 include/andres/partition.hxx mode change 100644 => 100755 include/andres/random-access-set.hxx mode change 100644 => 100755 src/andres/graph/unit-test/bfs.cxx mode change 100644 => 100755 src/andres/graph/unit-test/bridges.cxx mode change 100644 => 100755 src/andres/graph/unit-test/components.cxx mode change 100644 => 100755 src/andres/graph/unit-test/cut-vertices.cxx mode change 100644 => 100755 src/andres/graph/unit-test/dfs.cxx mode change 100644 => 100755 src/andres/graph/unit-test/digraph.cxx mode change 100644 => 100755 src/andres/graph/unit-test/graph-complete.cxx mode change 100644 => 100755 src/andres/graph/unit-test/graph-grid.cxx mode change 100644 => 100755 src/andres/graph/unit-test/graph.cxx mode change 100644 => 100755 src/andres/graph/unit-test/hdf5.cxx mode change 100644 => 100755 src/andres/graph/unit-test/lifting.cxx mode change 100644 => 100755 src/andres/graph/unit-test/max-flow.cxx mode change 100644 => 100755 src/andres/graph/unit-test/minimum-spanning-tree.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut-lifted/greedy-additive.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut-lifted/kernighan-lin.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut/greedy-additive.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut/ilp-callback.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut/ilp.cxx mode change 100644 => 100755 src/andres/graph/unit-test/multicut/kernighan-lin.cxx mode change 100644 => 100755 src/andres/graph/unit-test/paths.cxx mode change 100644 => 100755 src/andres/graph/unit-test/shortest-paths.cxx mode change 100644 => 100755 src/command-line-tools/fast-marching.hxx mode change 100644 => 100755 src/command-line-tools/lift-mp-grid-graph.cxx mode change 100644 => 100755 src/command-line-tools/lift-mp.cxx mode change 100644 => 100755 src/command-line-tools/probabilistic-lifting.hxx mode change 100644 => 100755 src/command-line-tools/solve-lmp-grid-graph.cxx mode change 100644 => 100755 src/command-line-tools/solve-lmp.cxx mode change 100644 => 100755 src/command-line-tools/solve-lmp.hxx mode change 100644 => 100755 src/command-line-tools/solve-mp-complete-graph.cxx mode change 100644 => 100755 src/command-line-tools/solve-mp-grid-graph.cxx mode change 100644 => 100755 src/command-line-tools/solve-mp.cxx mode change 100644 => 100755 src/command-line-tools/solve-mp.hxx mode change 100644 => 100755 src/command-line-tools/test-probabilistic-lifting.cxx mode change 100644 => 100755 src/command-line-tools/utils.hxx mode change 100644 => 100755 src/tclap/Arg.h mode change 100644 => 100755 src/tclap/ArgException.h mode change 100644 => 100755 src/tclap/ArgTraits.h mode change 100644 => 100755 src/tclap/CmdLine.h mode change 100644 => 100755 src/tclap/CmdLineInterface.h mode change 100644 => 100755 src/tclap/CmdLineOutput.h mode change 100644 => 100755 src/tclap/Constraint.h mode change 100644 => 100755 src/tclap/DocBookOutput.h mode change 100644 => 100755 src/tclap/HelpVisitor.h mode change 100644 => 100755 src/tclap/IgnoreRestVisitor.h mode change 100644 => 100755 src/tclap/MultiArg.h mode change 100644 => 100755 src/tclap/MultiSwitchArg.h mode change 100644 => 100755 src/tclap/OptionalUnlabeledTracker.h mode change 100644 => 100755 src/tclap/StandardTraits.h mode change 100644 => 100755 src/tclap/StdOutput.h mode change 100644 => 100755 src/tclap/SwitchArg.h mode change 100644 => 100755 src/tclap/UnlabeledMultiArg.h mode change 100644 => 100755 src/tclap/UnlabeledValueArg.h mode change 100644 => 100755 src/tclap/ValueArg.h mode change 100644 => 100755 src/tclap/ValuesConstraint.h mode change 100644 => 100755 src/tclap/VersionVisitor.h mode change 100644 => 100755 src/tclap/Visitor.h mode change 100644 => 100755 src/tclap/XorHandler.h mode change 100644 => 100755 src/tclap/ZshCompletionOutput.h diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/cmake/modules/FindGUROBI.cmake b/cmake/modules/FindGUROBI.cmake old mode 100644 new mode 100755 diff --git a/doxygen/doxyfile-graph.in b/doxygen/doxyfile-graph.in old mode 100644 new mode 100755 diff --git a/include/andres/functional.hxx b/include/andres/functional.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/adjacency.hxx b/include/andres/graph/adjacency.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/bfs.hxx b/include/andres/graph/bfs.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/bridges.hxx b/include/andres/graph/bridges.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/complete-graph.hxx b/include/andres/graph/complete-graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/components.hxx b/include/andres/graph/components.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/cut-vertices.hxx b/include/andres/graph/cut-vertices.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/detail/graph.hxx b/include/andres/graph/detail/graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/dfs.hxx b/include/andres/graph/dfs.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/digraph.hxx b/include/andres/graph/digraph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/doxygen.hxx b/include/andres/graph/doxygen.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/edge-value.hxx b/include/andres/graph/edge-value.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/graph.hxx b/include/andres/graph/graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/grid-graph.hxx b/include/andres/graph/grid-graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/hdf5/complete-graph.hxx b/include/andres/graph/hdf5/complete-graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/hdf5/digraph.hxx b/include/andres/graph/hdf5/digraph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/hdf5/graph.hxx b/include/andres/graph/hdf5/graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/hdf5/grid-graph.hxx b/include/andres/graph/hdf5/grid-graph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/hdf5/hdf5.hxx b/include/andres/graph/hdf5/hdf5.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/lifting.hxx b/include/andres/graph/lifting.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/max-flow.hxx b/include/andres/graph/max-flow.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/minimum-spanning-tree.hxx b/include/andres/graph/minimum-spanning-tree.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut-lifted/greedy-additive.hxx b/include/andres/graph/multicut-lifted/greedy-additive.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut-lifted/kernighan-lin.hxx b/include/andres/graph/multicut-lifted/kernighan-lin.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/greedy-additive.hxx b/include/andres/graph/multicut/greedy-additive.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/greedy-fixation.hxx b/include/andres/graph/multicut/greedy-fixation.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/ilp-callback.hxx b/include/andres/graph/multicut/ilp-callback.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/ilp.hxx b/include/andres/graph/multicut/ilp.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/kernighan-lin.hxx b/include/andres/graph/multicut/kernighan-lin.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/multicut/lp.hxx b/include/andres/graph/multicut/lp.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/paths.hxx b/include/andres/graph/paths.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/shortest-paths.hxx b/include/andres/graph/shortest-paths.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/subgraph.hxx b/include/andres/graph/subgraph.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/twocut-lifted/kernighan-lin.hxx b/include/andres/graph/twocut-lifted/kernighan-lin.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/twocut/kernighan-lin.hxx b/include/andres/graph/twocut/kernighan-lin.hxx old mode 100644 new mode 100755 diff --git a/include/andres/graph/visitor.hxx b/include/andres/graph/visitor.hxx old mode 100644 new mode 100755 diff --git a/include/andres/ilp/gurobi-callback.hxx b/include/andres/ilp/gurobi-callback.hxx old mode 100644 new mode 100755 diff --git a/include/andres/ilp/gurobi.hxx b/include/andres/ilp/gurobi.hxx old mode 100644 new mode 100755 diff --git a/include/andres/lp/gurobi.hxx b/include/andres/lp/gurobi.hxx old mode 100644 new mode 100755 diff --git a/include/andres/partition.hxx b/include/andres/partition.hxx old mode 100644 new mode 100755 diff --git a/include/andres/random-access-set.hxx b/include/andres/random-access-set.hxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/bfs.cxx b/src/andres/graph/unit-test/bfs.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/bridges.cxx b/src/andres/graph/unit-test/bridges.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/components.cxx b/src/andres/graph/unit-test/components.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/cut-vertices.cxx b/src/andres/graph/unit-test/cut-vertices.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/dfs.cxx b/src/andres/graph/unit-test/dfs.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/digraph.cxx b/src/andres/graph/unit-test/digraph.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/graph-complete.cxx b/src/andres/graph/unit-test/graph-complete.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/graph-grid.cxx b/src/andres/graph/unit-test/graph-grid.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/graph.cxx b/src/andres/graph/unit-test/graph.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/hdf5.cxx b/src/andres/graph/unit-test/hdf5.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/lifting.cxx b/src/andres/graph/unit-test/lifting.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/max-flow.cxx b/src/andres/graph/unit-test/max-flow.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/minimum-spanning-tree.cxx b/src/andres/graph/unit-test/minimum-spanning-tree.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut-lifted/greedy-additive.cxx b/src/andres/graph/unit-test/multicut-lifted/greedy-additive.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut-lifted/kernighan-lin.cxx b/src/andres/graph/unit-test/multicut-lifted/kernighan-lin.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut/greedy-additive.cxx b/src/andres/graph/unit-test/multicut/greedy-additive.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut/ilp-callback.cxx b/src/andres/graph/unit-test/multicut/ilp-callback.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut/ilp.cxx b/src/andres/graph/unit-test/multicut/ilp.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/multicut/kernighan-lin.cxx b/src/andres/graph/unit-test/multicut/kernighan-lin.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/paths.cxx b/src/andres/graph/unit-test/paths.cxx old mode 100644 new mode 100755 diff --git a/src/andres/graph/unit-test/shortest-paths.cxx b/src/andres/graph/unit-test/shortest-paths.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/fast-marching.hxx b/src/command-line-tools/fast-marching.hxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/lift-mp-grid-graph.cxx b/src/command-line-tools/lift-mp-grid-graph.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/lift-mp.cxx b/src/command-line-tools/lift-mp.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/probabilistic-lifting.hxx b/src/command-line-tools/probabilistic-lifting.hxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-lmp-grid-graph.cxx b/src/command-line-tools/solve-lmp-grid-graph.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-lmp.cxx b/src/command-line-tools/solve-lmp.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-mp-complete-graph.cxx b/src/command-line-tools/solve-mp-complete-graph.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-mp-grid-graph.cxx b/src/command-line-tools/solve-mp-grid-graph.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-mp.cxx b/src/command-line-tools/solve-mp.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/solve-mp.hxx b/src/command-line-tools/solve-mp.hxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/test-probabilistic-lifting.cxx b/src/command-line-tools/test-probabilistic-lifting.cxx old mode 100644 new mode 100755 diff --git a/src/command-line-tools/utils.hxx b/src/command-line-tools/utils.hxx old mode 100644 new mode 100755 diff --git a/src/tclap/Arg.h b/src/tclap/Arg.h old mode 100644 new mode 100755 diff --git a/src/tclap/ArgException.h b/src/tclap/ArgException.h old mode 100644 new mode 100755 diff --git a/src/tclap/ArgTraits.h b/src/tclap/ArgTraits.h old mode 100644 new mode 100755 diff --git a/src/tclap/CmdLine.h b/src/tclap/CmdLine.h old mode 100644 new mode 100755 diff --git a/src/tclap/CmdLineInterface.h b/src/tclap/CmdLineInterface.h old mode 100644 new mode 100755 diff --git a/src/tclap/CmdLineOutput.h b/src/tclap/CmdLineOutput.h old mode 100644 new mode 100755 diff --git a/src/tclap/Constraint.h b/src/tclap/Constraint.h old mode 100644 new mode 100755 diff --git a/src/tclap/DocBookOutput.h b/src/tclap/DocBookOutput.h old mode 100644 new mode 100755 diff --git a/src/tclap/HelpVisitor.h b/src/tclap/HelpVisitor.h old mode 100644 new mode 100755 diff --git a/src/tclap/IgnoreRestVisitor.h b/src/tclap/IgnoreRestVisitor.h old mode 100644 new mode 100755 diff --git a/src/tclap/MultiArg.h b/src/tclap/MultiArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/MultiSwitchArg.h b/src/tclap/MultiSwitchArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/OptionalUnlabeledTracker.h b/src/tclap/OptionalUnlabeledTracker.h old mode 100644 new mode 100755 diff --git a/src/tclap/StandardTraits.h b/src/tclap/StandardTraits.h old mode 100644 new mode 100755 diff --git a/src/tclap/StdOutput.h b/src/tclap/StdOutput.h old mode 100644 new mode 100755 diff --git a/src/tclap/SwitchArg.h b/src/tclap/SwitchArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/UnlabeledMultiArg.h b/src/tclap/UnlabeledMultiArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/UnlabeledValueArg.h b/src/tclap/UnlabeledValueArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/ValueArg.h b/src/tclap/ValueArg.h old mode 100644 new mode 100755 diff --git a/src/tclap/ValuesConstraint.h b/src/tclap/ValuesConstraint.h old mode 100644 new mode 100755 diff --git a/src/tclap/VersionVisitor.h b/src/tclap/VersionVisitor.h old mode 100644 new mode 100755 diff --git a/src/tclap/Visitor.h b/src/tclap/Visitor.h old mode 100644 new mode 100755 diff --git a/src/tclap/XorHandler.h b/src/tclap/XorHandler.h old mode 100644 new mode 100755 diff --git a/src/tclap/ZshCompletionOutput.h b/src/tclap/ZshCompletionOutput.h old mode 100644 new mode 100755 From 31378821976b99dc2ea42d5a826caa5e5e678742 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Wed, 3 Aug 2016 12:47:05 +0200 Subject: [PATCH 14/15] minor refactoring --- .../graph/multicut-lifted/ilp-callback.hxx | 65 +++++++------------ include/andres/graph/multicut-lifted/ilp.hxx | 44 ++++--------- include/andres/graph/multicut-lifted/lp.hxx | 41 ++++-------- 3 files changed, 48 insertions(+), 102 deletions(-) diff --git a/include/andres/graph/multicut-lifted/ilp-callback.hxx b/include/andres/graph/multicut-lifted/ilp-callback.hxx index 821e022..fcd8c84 100644 --- a/include/andres/graph/multicut-lifted/ilp-callback.hxx +++ b/include/andres/graph/multicut-lifted/ilp-callback.hxx @@ -11,7 +11,6 @@ #include #include #include -#include namespace andres { @@ -23,12 +22,8 @@ template(original_graph, lifted_graph, edgeCosts, inputLabels, outputLabels, visitor, timeLimitSeconds); @@ -40,9 +35,9 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph { struct SubgraphWithCut { - SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) - : ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) - {} + SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) : + ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) + {} bool vertex(size_t v) const { @@ -57,27 +52,23 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph ILP const& ilp_; std::vector const& edge_in_lifted_graph_; }; - - levinkov::Timer t; - class Callback: public ILP::Callback { public: - Callback(ILP& solver, ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, levinkov::Timer& t) : + Callback(ILP& solver, ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph) : ILP::Callback(solver), original_graph_(original_graph), lifted_graph_(lifted_graph), coefficients_(lifted_graph.numberOfEdges()), variables_(lifted_graph.numberOfEdges()), visited_(original_graph.numberOfVertices()), - edge_in_lifted_graph_(original_graph.numberOfEdges()), - t_(t) + edge_in_lifted_graph_(original_graph.numberOfEdges()) { for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) { - auto v0 = original_graph.vertexOfEdge(i, 0); - auto v1 = original_graph.vertexOfEdge(i, 1); + auto const v0 = original_graph.vertexOfEdge(i, 0); + auto const v1 = original_graph.vertexOfEdge(i, 1); edge_in_lifted_graph_[i] = lifted_graph.findEdge(v0, v1).second; } @@ -85,9 +76,6 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph void separateAndAddLazyConstraints() override { - levinkov::Timer t_separation; - t_separation.start(); - components_.build(original_graph_, SubgraphWithCut(*this, edge_in_lifted_graph_)); // search for violated non-chordal cycles and add corresp. inequalities @@ -97,8 +85,8 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph for (ptrdiff_t edge = 0; edge < lifted_graph_.numberOfEdges(); ++edge) { - auto lv0 = lifted_graph_.vertexOfEdge(edge, 0); - auto lv1 = lifted_graph_.vertexOfEdge(edge, 1); + auto const lv0 = lifted_graph_.vertexOfEdge(edge, 0); + auto const lv1 = lifted_graph_.vertexOfEdge(edge, 1); if (this->label(edge) == 1 && components_.areConnected(lv0, lv1)) { @@ -114,7 +102,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph if (it1 == path_.begin() && it2 == path_.end() - 1) continue; - auto e = lifted_graph_.findEdge(*it1, *it2); + auto const e = lifted_graph_.findEdge(*it1, *it2); if (e.first && this->label(e.second) > .5) { chordless = false; @@ -158,7 +146,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph ptrdiff_t sz = 0; while (!S.empty()) { - auto v = S.top(); + auto const v = S.top(); S.pop(); for (auto it = original_graph_.adjacenciesFromVertexBegin(v); it != original_graph_.adjacenciesFromVertexEnd(v); ++it) @@ -192,7 +180,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph sz = 0; while (!S.empty()) { - auto v = S.top(); + auto const v = S.top(); S.pop(); for (auto it = original_graph_.adjacenciesFromVertexBegin(v); it != original_graph_.adjacenciesFromVertexEnd(v); ++it) @@ -219,20 +207,15 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph } } - t_separation.stop(); - t_.stop(); - - std::cerr <objectiveBound_ << " " << std::setprecision(10) << this->objectiveBest_ << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; - - t_.start(); + std::cerr << std::fixed << std::setprecision(10) << this->objectiveBound_ << " " << std::setprecision(10) << this->objectiveBest_ << " " << nCycle << " " << nPath << " " << nCut << std::endl; } private: struct SubgraphWithCut { - SubgraphWithCut(Callback& callback, std::vector const& edge_in_lifted_graph) - : callback_(callback), edge_in_lifted_graph_(edge_in_lifted_graph) - {} + SubgraphWithCut(Callback& callback, std::vector const& edge_in_lifted_graph) : + callback_(callback), edge_in_lifted_graph_(edge_in_lifted_graph) + {} bool vertex(size_t v) const { @@ -251,8 +234,6 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph ORIGGRAPH const& original_graph_; LIFTGRAPH const& lifted_graph_; - levinkov::Timer& t_; - std::vector coefficients_; ComponentsBySearch components_; std::vector buffer_; @@ -262,8 +243,6 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph std::vector visited_; }; - t.start(); - ILP ilp; ilp.setRelativeGap(0.0); @@ -271,7 +250,7 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph ilp.setTimeLimit(timeLimitSeconds); ilp.addVariables(edgeCosts.size(), edgeCosts.data()); - Callback callback(ilp, original_graph, lifted_graph, t); + Callback callback(ilp, original_graph, lifted_graph); ilp.setCallback(callback); ilp.optimize(); @@ -279,8 +258,8 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph std::vector edge_in_lifted_graph(original_graph.numberOfEdges()); for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) { - auto v0 = original_graph.vertexOfEdge(i, 0); - auto v1 = original_graph.vertexOfEdge(i, 1); + auto const v0 = original_graph.vertexOfEdge(i, 0); + auto const v1 = original_graph.vertexOfEdge(i, 1); edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; } @@ -290,8 +269,8 @@ void ilp_callback(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) { - auto v0 = lifted_graph.vertexOfEdge(edge, 0); - auto v1 = lifted_graph.vertexOfEdge(edge, 1); + auto const v0 = lifted_graph.vertexOfEdge(edge, 0); + auto const v1 = lifted_graph.vertexOfEdge(edge, 1); outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; } diff --git a/include/andres/graph/multicut-lifted/ilp.hxx b/include/andres/graph/multicut-lifted/ilp.hxx index fb8aa09..8473e97 100644 --- a/include/andres/graph/multicut-lifted/ilp.hxx +++ b/include/andres/graph/multicut-lifted/ilp.hxx @@ -11,7 +11,6 @@ #include #include #include -#include namespace andres { @@ -23,12 +22,8 @@ template::max()) { - struct Visitor + struct EmptyVisitor { - bool operator()(ELA const& edge_labels) const - { - return true; - } } visitor; ilp(original_graph, lifted_graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations); @@ -40,9 +35,9 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con { struct SubgraphWithCut { - SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) - : ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) - {} + SubgraphWithCut(ILP const& ilp, std::vector const& edge_in_lifted_graph) : + ilp_(ilp), edge_in_lifted_graph_(edge_in_lifted_graph) + {} bool vertex(size_t v) const { @@ -59,7 +54,6 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con }; ILP ilp; - levinkov::Timer t; std::vector coefficients(lifted_graph.numberOfEdges()); ComponentsBySearch components; @@ -71,9 +65,6 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con auto addCycleInequalities = [&] () { - levinkov::Timer t_separation; - t_separation.start(); - components.build(original_graph, SubgraphWithCut(ilp, edge_in_lifted_graph)); // search for violated non-chordal cycles and add corresp. inequalities @@ -83,8 +74,8 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con for (ptrdiff_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) { - auto lv0 = lifted_graph.vertexOfEdge(edge, 0); - auto lv1 = lifted_graph.vertexOfEdge(edge, 1); + auto const lv0 = lifted_graph.vertexOfEdge(edge, 0); + auto const lv1 = lifted_graph.vertexOfEdge(edge, 1); if (ilp.label(edge) > .5 && components.areConnected(lv0, lv1)) { @@ -100,7 +91,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con if (it1 == path.begin() && it2 == path.end() - 1) continue; - auto e = lifted_graph.findEdge(*it1, *it2); + auto const e = lifted_graph.findEdge(*it1, *it2); if (e.first && ilp.label(e.second) > .5) { chordless = false; @@ -144,7 +135,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con ptrdiff_t sz = 0; while (!S.empty()) { - auto v = S.top(); + auto const v = S.top(); S.pop(); for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) @@ -178,7 +169,7 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con sz = 0; while (!S.empty()) { - auto v = S.top(); + auto const v = S.top(); S.pop(); for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) @@ -205,26 +196,19 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con } } - t_separation.stop(); - t.stop(); - double objValue = .0; for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) objValue += ilp.label(i)*edgeCosts[i]; - std::cerr << std::fixed << t.get_elapsed_seconds() << " " << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; - - t.start(); + std::cerr << std::fixed << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << std::endl; return nCycle + nPath + nCut; }; - t.start(); - for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) { - auto v0 = original_graph.vertexOfEdge(i, 0); - auto v1 = original_graph.vertexOfEdge(i, 1); + auto const v0 = original_graph.vertexOfEdge(i, 0); + auto const v1 = original_graph.vertexOfEdge(i, 1); edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; } @@ -244,8 +228,8 @@ void ilp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA con for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) { - auto v0 = lifted_graph.vertexOfEdge(edge, 0); - auto v1 = lifted_graph.vertexOfEdge(edge, 1); + auto const v0 = lifted_graph.vertexOfEdge(edge, 0); + auto const v1 = lifted_graph.vertexOfEdge(edge, 1); outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; } diff --git a/include/andres/graph/multicut-lifted/lp.hxx b/include/andres/graph/multicut-lifted/lp.hxx index deb1703..1d32a3c 100644 --- a/include/andres/graph/multicut-lifted/lp.hxx +++ b/include/andres/graph/multicut-lifted/lp.hxx @@ -8,7 +8,6 @@ #include #include -#include namespace andres { @@ -19,12 +18,8 @@ template inline std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_graph, ECA const& edgeCosts, size_t numberOfIterations = std::numeric_limits::max()) { - struct Visitor + struct EmptyVisitor { - bool operator()() const - { - return true; - } } visitor; return lp(original_graph, lifted_graph, edgeCosts, visitor, numberOfIterations); @@ -189,7 +184,6 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ }; LP lp; - levinkov::Timer t; std::vector coefficients(lifted_graph.numberOfEdges()); std::vector distances(lifted_graph.numberOfVertices()); @@ -201,18 +195,18 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ auto separateAndAddInequalities = [&] () { - levinkov::Timer t_separation; - t_separation.start(); - DinicFlow flow(original_graph.numberOfVertices()); for (size_t i = 0; i < vars.size(); ++i) { vars[i] = std::min(std::max(.0, lp.variableValue(edge_in_lifted_graph[i])), 1.0); - auto v0 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 0); - auto v1 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 1); + auto const v0 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 0); + auto const v1 = lifted_graph.vertexOfEdge(edge_in_lifted_graph[i], 1); + // as MaxLow can be computed only for intergral edge weights, we lose a bit of precision doing the following + // if your weights are very small, you might want to increase the constant (everywhere in this file), + // in order not to run into precision problems flow.addEdge(v0, v1, 100000000000.0*(1.0 - vars[i])); } @@ -223,8 +217,8 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge) { - auto lv0 = lifted_graph.vertexOfEdge(edge, 0); - auto lv1 = lifted_graph.vertexOfEdge(edge, 1); + auto const lv0 = lifted_graph.vertexOfEdge(edge, 0); + auto const lv1 = lifted_graph.vertexOfEdge(edge, 1); // search for shortest path double distance; @@ -237,7 +231,7 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ if (it1 == path.begin() && it2 == path.end() - 1) continue; - auto e = lifted_graph.findEdge(*it1, *it2); + auto const e = lifted_graph.findEdge(*it1, *it2); if (e.first && std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) { chordless = false; @@ -317,26 +311,19 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ } } - t_separation.stop(); - t.stop(); - double objValue = .0; for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) objValue += lp.variableValue(i)*edgeCosts[i]; - std::cerr << std::fixed << t.get_elapsed_seconds() << " " << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << " " << t_separation.get_elapsed_seconds() << std::endl; - - t.start(); + std::cerr << std::fixed << std::setprecision(10) << objValue << " " << nCycle << " " << nPath << " " << nCut << std::endl; return nCycle + nPath + nCut; }; - t.start(); - for (size_t i = 0; i < original_graph.numberOfEdges(); ++i) { - auto v0 = original_graph.vertexOfEdge(i, 0); - auto v1 = original_graph.vertexOfEdge(i, 1); + auto const v0 = original_graph.vertexOfEdge(i, 0); + auto const v1 = original_graph.vertexOfEdge(i, 1); edge_in_lifted_graph[i] = lifted_graph.findEdge(v0, v1).second; } @@ -345,9 +332,6 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) { - if (!visitor()) - break; - lp.optimize(); if (separateAndAddInequalities() == 0) @@ -355,7 +339,6 @@ std::vector lp(ORIGGRAPH const& original_graph, LIFTGRAPH const& lifted_ } std::vector edge_values(lifted_graph.numberOfEdges()); - for (size_t i = 0; i < lifted_graph.numberOfEdges(); ++i) edge_values[i] = lp.variableValue(i); From 807e11846a2cd7b275ae9578c98de298dcd796e1 Mon Sep 17 00:00:00 2001 From: Evgeny Levinkov Date: Wed, 3 Aug 2016 13:06:59 +0200 Subject: [PATCH 15/15] major refactoring. Introduced conditional compilation for Gurobi --- CMakeLists.txt | 23 ++-- .../andres/graph/multicut/ilp-callback.hxx | 50 ++++----- include/andres/graph/multicut/ilp.hxx | 104 ++++++++---------- include/andres/graph/multicut/lp.hxx | 17 +-- src/command-line-tools/solve-lmp.hxx | 33 ++++-- src/command-line-tools/solve-mp.hxx | 46 +++++--- 6 files changed, 133 insertions(+), 140 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6688f88..81bdd6b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ include_directories(${HDF5_INCLUDE_DIR}) find_package(GUROBI) if(GUROBI_FOUND) include_directories(${GUROBI_INCLUDE_DIR}) + add_definitions("-DWITH_GUROBI") endif() ############################################################################## @@ -149,19 +150,6 @@ if(DOXYGEN_FOUND) add_custom_target(doc-graph ALL COMMAND ${DOXYGEN} "${graph_BINARY_DIR}/doxyfile-graph") endif() -if((COMPILER_SUPPORTS_CXX0X OR COMPILER_SUPPORTS_CXX11) AND GUROBI_FOUND AND HDF5_FOUND) - include_directories(src) - - add_executable(solve-mp src/command-line-tools/solve-mp.cxx ${headers}) - target_link_libraries(solve-mp ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) - - add_executable(solve-mp-complete-graph src/command-line-tools/solve-mp-complete-graph.cxx ${headers}) - target_link_libraries(solve-mp-complete-graph ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) - - add_executable(solve-mp-grid-graph src/command-line-tools/solve-mp-grid-graph.cxx ${headers}) - target_link_libraries(solve-mp-grid-graph ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) -endif() - if((COMPILER_SUPPORTS_CXX0X OR COMPILER_SUPPORTS_CXX11) AND HDF5_FOUND) include_directories(src) @@ -174,6 +162,15 @@ if((COMPILER_SUPPORTS_CXX0X OR COMPILER_SUPPORTS_CXX11) AND HDF5_FOUND) add_executable(lift-mp-grid-graph src/command-line-tools/lift-mp-grid-graph.cxx ${headers}) target_link_libraries(lift-mp-grid-graph ${HDF5_LIBRARIES}) + add_executable(solve-mp src/command-line-tools/solve-mp.cxx ${headers}) + target_link_libraries(solve-mp ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) + + add_executable(solve-mp-complete-graph src/command-line-tools/solve-mp-complete-graph.cxx ${headers}) + target_link_libraries(solve-mp-complete-graph ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) + + add_executable(solve-mp-grid-graph src/command-line-tools/solve-mp-grid-graph.cxx ${headers}) + target_link_libraries(solve-mp-grid-graph ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) + add_executable(solve-lmp src/command-line-tools/solve-lmp.cxx ${headers}) target_link_libraries(solve-lmp ${HDF5_LIBRARIES} ${GUROBI_LIBRARIES}) diff --git a/include/andres/graph/multicut/ilp-callback.hxx b/include/andres/graph/multicut/ilp-callback.hxx index 649acc8..a71f1ee 100755 --- a/include/andres/graph/multicut/ilp-callback.hxx +++ b/include/andres/graph/multicut/ilp-callback.hxx @@ -36,12 +36,8 @@ template inline void ilp_callback(GRAPH const& graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, size_t timeLimitSeconds = 86400) { - struct Visitor + struct EmptyVisitor { - bool operator()(ELA const& edge_labels) const - { - return true; - } } visitor; ilp_callback(graph, edgeCosts, inputLabels, outputLabels, visitor, timeLimitSeconds); @@ -53,9 +49,9 @@ void ilp_callback(GRAPH const& graph, ECA const& edgeCosts, ELA const& inputLabe { struct SubgraphWithCut { - SubgraphWithCut(ILP const& ilp) - : ilp_(ilp) - {} + SubgraphWithCut(ILP const& ilp) : + ilp_(ilp) + {} bool vertex(size_t v) const { @@ -91,8 +87,8 @@ void ilp_callback(GRAPH const& graph, ECA const& edgeCosts, ELA const& inputLabe for (size_t edge = 0; edge < graph_.numberOfEdges(); ++edge) if (this->label(edge) > .5) { - auto v0 = graph_.vertexOfEdge(edge, 0); - auto v1 = graph_.vertexOfEdge(edge, 1); + auto const v0 = graph_.vertexOfEdge(edge, 0); + auto const v1 = graph_.vertexOfEdge(edge, 1); if (components.areConnected(v0, v1)) { @@ -104,27 +100,25 @@ void ilp_callback(GRAPH const& graph, ECA const& edgeCosts, ELA const& inputLabe continue; // add inequality - auto sz = path.size(); - - for (size_t j = 0; j < sz - 1; ++j) + for (size_t j = 0; j < path.size() - 1; ++j) { variables[j] = static_cast(graph_.findEdge(path[j], path[j + 1]).second); coefficients[j] = 1.0; } - variables[sz-1] = static_cast(edge); - coefficients[sz-1] = -1.0; + variables[path.size() - 1] = static_cast(edge); + coefficients[path.size() - 1] = -1.0; - this->addLazyConstraint(variables.begin(), variables.begin() + sz, coefficients.begin(), 0, std::numeric_limits::infinity()); + this->addLazyConstraint(variables.begin(), variables.begin() + path.size(), coefficients.begin(), 0, std::numeric_limits::infinity()); } } } private: struct SubgraphWithCut { - SubgraphWithCut(Callback& callback) - : callback_(callback) - {} + SubgraphWithCut(Callback& callback) : + callback_(callback) + {} bool vertex(size_t v) const { @@ -159,8 +153,8 @@ void ilp_callback(GRAPH const& graph, ECA const& edgeCosts, ELA const& inputLabe for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; } @@ -173,12 +167,8 @@ template inline void ilp_callback(CompleteGraph const& graph, ECA const& edgeCosts, ELA const& inputLabels, ELA& outputLabels, size_t timeLimitSeconds = 86400) { - struct Visitor + struct EmptyVisitor { - bool operator()(ELA const& edge_labels) const - { - return true; - } } visitor; ilp_callback(graph, edgeCosts, inputLabels, outputLabels, visitor); @@ -224,8 +214,8 @@ void ilp_callback(CompleteGraph const& graph, ECA const& edgeCost { variables[2] = edge; - auto v0 = graph_.vertexOfEdge(edge, 0); - auto v1 = graph_.vertexOfEdge(edge, 1); + auto const v0 = graph_.vertexOfEdge(edge, 0); + auto const v1 = graph_.vertexOfEdge(edge, 1); for (size_t i = 0; i < graph_.numberOfVertices(); ++i) { @@ -267,8 +257,8 @@ void ilp_callback(CompleteGraph const& graph, ECA const& edgeCost for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; } diff --git a/include/andres/graph/multicut/ilp.hxx b/include/andres/graph/multicut/ilp.hxx index 23898cf..2f5e555 100755 --- a/include/andres/graph/multicut/ilp.hxx +++ b/include/andres/graph/multicut/ilp.hxx @@ -33,10 +33,8 @@ ilp( ELA& outputLabels, size_t numberOfIterations = std::numeric_limits::max() ) { - struct Visitor { - bool operator()(ELA const& edge_labels) const { - return true; - } + struct EmptyVisitor + { } visitor; ilp(graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations); @@ -52,15 +50,23 @@ ilp( VIS& visitor, size_t numberOfIterations = std::numeric_limits::max() ) { - struct SubgraphWithCut { - SubgraphWithCut(const ILP& ilp) - : ilp_(ilp) - {} + struct SubgraphWithCut + { + SubgraphWithCut(const ILP& ilp) : + ilp_(ilp) + {} + bool vertex(const size_t v) const - { return true; } + { + return true; + } + bool edge(const size_t e) const - { return ilp_.label(e) < .5; } - const ILP& ilp_; + { + return ilp_.label(e) < .5; + } + + ILP const& ilp_; }; ComponentsBySearch components; @@ -80,8 +86,8 @@ ilp( for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) if (ilp.label(edge) > .5) { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); if (components.areConnected(v0, v1)) { @@ -93,8 +99,6 @@ ilp( continue; // add inequality - auto sz = path.size(); - for (size_t j = 0; j < path.size() - 1; ++j) { variables[j] = graph.findEdge(path[j], path[j + 1]).second; @@ -113,39 +117,26 @@ ilp( return nCycle; }; - auto repairSolution = [&] () - { - for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) - { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); - - outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; - } - - ilp.setStart(outputLabels.begin()); - }; - ilp.initModel(graph.numberOfEdges(), edgeCosts.data()); ilp.setStart(inputLabels.begin()); for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) { - if (i != 0) - { - repairSolution(); - - if (!visitor(outputLabels)) - break; - } - ilp.optimize(); if (addCycleInequalities() == 0) break; } - repairSolution(); + components.build(graph, SubgraphWithCut(ilp)); + + for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) + { + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); + + outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; + } } /// Algorithm for the Set Partition Problem. @@ -162,12 +153,8 @@ ilp( ELA& outputLabels, size_t numberOfIterations = std::numeric_limits::max() ) { - struct Visitor + struct EmptyVisitor { - bool operator()() const - { - return true; - } } visitor; ilp(graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations); @@ -183,15 +170,23 @@ ilp( VIS& visitor, size_t numberOfIterations = std::numeric_limits::max() ) { - struct SubgraphWithCut { - SubgraphWithCut(const ILP& ilp) - : ilp_(ilp) - {} + struct SubgraphWithCut + { + SubgraphWithCut(const ILP& ilp) : + ilp_(ilp) + {} + bool vertex(const size_t v) const - { return true; } + { + return true; + } + bool edge(const size_t e) const - { return ilp_.label(e) < .5; } - const ILP& ilp_; + { + return ilp_.label(e) < .5; + } + + ILP const& ilp_; }; ILP ilp; @@ -207,8 +202,8 @@ ilp( { variables[2] = edge; - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); for (size_t i = 0; i < graph.numberOfVertices(); ++i) { @@ -239,9 +234,6 @@ ilp( for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) { - if (!visitor()) - break; - ilp.optimize(); if (addCycleInequalities() == 0) @@ -253,8 +245,8 @@ ilp( for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1; } diff --git a/include/andres/graph/multicut/lp.hxx b/include/andres/graph/multicut/lp.hxx index 83ff00b..9e4c557 100755 --- a/include/andres/graph/multicut/lp.hxx +++ b/include/andres/graph/multicut/lp.hxx @@ -6,7 +6,6 @@ #include #include -#include #include @@ -18,12 +17,8 @@ template inline std::vector lp(GRAPH const& graph, ECA const& edgeCosts, size_t numberOfIterations = std::numeric_limits::max()) { - struct Visitor + struct EmptyVisitor { - bool operator()() const - { - return true; - } } visitor; return lp(graph, edgeCosts, visitor, numberOfIterations); @@ -55,8 +50,8 @@ std::vector lp(GRAPH const& graph, ECA const& edgeCosts, VIS& visitor, s size_t nCycle = 0; for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge) { - auto v0 = graph.vertexOfEdge(edge, 0); - auto v1 = graph.vertexOfEdge(edge, 1); + auto const v0 = graph.vertexOfEdge(edge, 0); + auto const v1 = graph.vertexOfEdge(edge, 1); // search for shortest path double distance; @@ -69,7 +64,7 @@ std::vector lp(GRAPH const& graph, ECA const& edgeCosts, VIS& visitor, s if (it1 == path.begin() && it2 == path.end() - 1) continue; - auto e = graph.findEdge(*it1, *it2); + auto const e = graph.findEdge(*it1, *it2); if (e.first && std::min(std::max(.0, lp.variableValue(e.second)), 1.0) > distances[*it2] - distances[*it1] + tolerance) { chordless = false; @@ -105,9 +100,6 @@ std::vector lp(GRAPH const& graph, ECA const& edgeCosts, VIS& visitor, s for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i) { - if (!visitor()) - break; - lp.optimize(); if (addCycleInequalities() == 0) @@ -115,7 +107,6 @@ std::vector lp(GRAPH const& graph, ECA const& edgeCosts, VIS& visitor, s } std::vector edge_values(graph.numberOfEdges()); - for (size_t i = 0; i < graph.numberOfEdges(); ++i) edge_values[i] = lp.variableValue(i); diff --git a/src/command-line-tools/solve-lmp.hxx b/src/command-line-tools/solve-lmp.hxx index 58b75f9..aa0f693 100755 --- a/src/command-line-tools/solve-lmp.hxx +++ b/src/command-line-tools/solve-lmp.hxx @@ -4,12 +4,16 @@ #include #include -#include -#include -#include -#include -#include -#include + +#ifdef WITH_GUROBI + #include + #include + #include + #include + #include + #include +#endif + #include #include @@ -22,10 +26,13 @@ enum class Method { Zeros, Ones, GAEC, - Kernighan_Lin, + Kernighan_Lin +#ifdef WITH_GUROBI + , LP, ILP, ILPC +#endif }; enum class Initialization { @@ -75,12 +82,14 @@ try parameters.optimizationMethod = Method::Zeros; else if (argOptimizationMethod.getValue() == "ones") parameters.optimizationMethod = Method::Ones; +#ifdef WITH_GUROBI else if (argOptimizationMethod.getValue() == "LP") parameters.optimizationMethod = Method::LP; else if (argOptimizationMethod.getValue() == "ILP") parameters.optimizationMethod = Method::ILP; else if (argOptimizationMethod.getValue() == "ILPC") parameters.optimizationMethod = Method::ILPC; +#endif else if(argOptimizationMethod.getValue() == "KL") { parameters.optimizationMethod = Method::Kernighan_Lin; @@ -184,14 +193,15 @@ void solveLiftedMulticutProblem( std::fill(edge_labels.begin(), edge_labels.end(), 1); else if (parameters.optimizationMethod == Method::Zeros) std::fill(edge_labels.begin(), edge_labels.end(), 0); - else if (parameters.optimizationMethod == Method::ILP) - andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); - else if (parameters.optimizationMethod == Method::ILPC) - andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod == Method::GAEC) andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, edge_values, edge_labels); else if (parameters.optimizationMethod == Method::Kernighan_Lin) andres::graph::multicut_lifted::kernighanLin(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); +#ifdef WITH_GUROBI + else if (parameters.optimizationMethod == Method::ILP) + andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); + else if (parameters.optimizationMethod == Method::ILPC) + andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod == Method::LP) { auto values = andres::graph::multicut_lifted::lp(original_graph, lifted_graph, edge_values); @@ -218,6 +228,7 @@ void solveLiftedMulticutProblem( return; } +#endif else throw std::runtime_error("Unsupported algorithm"); diff --git a/src/command-line-tools/solve-mp.hxx b/src/command-line-tools/solve-mp.hxx index 1474b37..c81a674 100755 --- a/src/command-line-tools/solve-mp.hxx +++ b/src/command-line-tools/solve-mp.hxx @@ -3,15 +3,20 @@ #include #include #include +#include #include -#include -#include +#ifdef WITH_GUROBI + #include + #include + #include + + #include + #include + #include +#endif -#include -#include -#include #include #include #include @@ -26,10 +31,13 @@ enum class Method { Ones, GAEC, GF, - KL, + KL +#ifdef WITH_GUROBI + , ILP, ILPC, LP +#endif }; enum class Initialization { @@ -41,9 +49,9 @@ enum class Initialization { }; struct Parameters { - string inputHDF5FileName; - string outputHDF5FileName; - string labelingHDF5FileName; + std::string inputHDF5FileName; + std::string outputHDF5FileName; + std::string labelingHDF5FileName; Method optimizationMethod_; Initialization initialization; }; @@ -58,12 +66,12 @@ parseCommandLine( try { TCLAP::CmdLine tclap("solve-multicut-problem", ' ', "1.0"); - TCLAP::ValueArg argInputHDF5FileName("i", "hdf5-input", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); - TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", true, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); - TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); + TCLAP::ValueArg argInputHDF5FileName("i", "hdf5-input", "File to load multicut problem from", true, parameters.inputHDF5FileName, "INPUT_HDF5_FILE", tclap); + TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf-file", "hdf file (output)", true, parameters.outputHDF5FileName, "OUTPUT_HDF5_FILE", tclap); + TCLAP::ValueArg argLabelingHDF5FileName("l", "labeling-hdf-file", "hdf file specifying initial node labelings (input)", false, parameters.labelingHDF5FileName, "LABELING_HDF5_FILE", tclap); - TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {LP, ILP, ILPC, GAEC, GF, KL, zeros, ones}", false, "KL", "OPTIMIZATION_METHOD", tclap); - TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC, GF}", false, "zeros", "INITIALIZATION_METHOD", tclap); + TCLAP::ValueArg argOptimizationMethod("m", "optimization-method", "optimization method to use {LP, ILP, ILPC, GAEC, GF, KL, zeros, ones}", false, "KL", "OPTIMIZATION_METHOD", tclap); + TCLAP::ValueArg argInitializationMethod("I", "initialization-method", "initialization method to use {zeros, ones, GAEC, GF}", false, "zeros", "INITIALIZATION_METHOD", tclap); tclap.parse(argc, argv); @@ -93,15 +101,17 @@ parseCommandLine( parameters.optimizationMethod_ = Method::GF; else if(argOptimizationMethod.getValue() == "KL") parameters.optimizationMethod_ = Method::KL; +#ifdef WITH_GUROBI else if (argOptimizationMethod.getValue() == "ILP") parameters.optimizationMethod_ = Method::ILP; else if (argOptimizationMethod.getValue() == "ILPC") parameters.optimizationMethod_ = Method::ILPC; else if (argOptimizationMethod.getValue() == "LP") parameters.optimizationMethod_ = Method::LP; - else if(argInitializationMethod.getValue() == "ones") +#endif + else if(argOptimizationMethod.getValue() == "ones") parameters.optimizationMethod_ = Method::Ones; - else if(argInitializationMethod.getValue() == "zeros") + else if(argOptimizationMethod.getValue() == "zeros") parameters.optimizationMethod_ = Method::Zeros; else throw std::runtime_error("Invalid optimization method specified"); @@ -174,10 +184,11 @@ void solveMulticutProblem( andres::graph::multicut::greedyFixation(graph, edge_values, edge_labels); else if (parameters.optimizationMethod_ == Method::KL) andres::graph::multicut::kernighanLin(graph, edge_values, edge_labels, edge_labels); +#ifdef WITH_GUROBI else if (parameters.optimizationMethod_ == Method::ILP) andres::graph::multicut::ilp(graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod_ == Method::ILPC) - andres::graph::multicut::ilp(graph, edge_values, edge_labels, edge_labels); + andres::graph::multicut::ilp_callback(graph, edge_values, edge_labels, edge_labels); else if (parameters.optimizationMethod_ == Method::LP) { auto values = andres::graph::multicut::lp(graph, edge_values); @@ -204,6 +215,7 @@ void solveMulticutProblem( return; } +#endif else throw std::runtime_error("Unsupported algorithm");