Skip to content

Commit

Permalink
Merge pull request #26 from levinkov/master
Browse files Browse the repository at this point in the history
fixing bugs in complete graph 
fixing bugs in the Kernighan-Lin Algorithm. 
adding algorithm to solve an LP relaxation of the minimum cost multicut problem.
  • Loading branch information
bjoern-andres committed Feb 10, 2016
2 parents 13466f4 + f456bcb commit 26ec62c
Show file tree
Hide file tree
Showing 39 changed files with 6,811 additions and 65 deletions.
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,17 @@ if(DOXYGEN_FOUND)
configure_file("${graph_SOURCE_DIR}/doxygen/doxyfile-graph.in" "${graph_BINARY_DIR}/doxyfile-graph" @ONLY IMMEDIATE)
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)
include_directories(src/command-line-tools)

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()
6 changes: 3 additions & 3 deletions include/andres/graph/complete-graph.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,9 @@ CompleteGraph<VISITOR>::vertexOfEdge(
) const {
assert(edge < numberOfEdges());
assert(j < 2);
const float p = static_cast<float>(numberOfVertices() * 2 - 1) / 2;
const float q = static_cast<float>(edge) * 2;
const std::size_t vertex0 = static_cast<std::size_t>(p - std::sqrt(p * p - q));
double p = static_cast<double>(numberOfVertices() * 2 - 1) / 2;
double q = static_cast<double>(edge) * 2;
std::size_t vertex0 = static_cast<std::size_t>(p - std::sqrt(p * p - q));
if(j == 0) {
return vertex0;
}
Expand Down
8 changes: 2 additions & 6 deletions include/andres/graph/multicut-lifted/kernighan-lin.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void kernighanLin(
const ELA& inputLabels,
ELA& outputLabels,
VIS& visitor,
const KernighanLinSettings settings)
const KernighanLinSettings settings = KernighanLinSettings())
{
struct SubgraphWithCut { // a subgraph with cut mask
SubgraphWithCut(const ELA& labels, std::vector<std::size_t> const& edge_in_lifted_graph)
Expand Down Expand Up @@ -61,26 +61,22 @@ void kernighanLin(

double current_energy_value = .0;

// find out how many connected components there are
// check if the input multicut labeling is valid
std::size_t numberOfComponents = 0;
for(std::size_t edge = 0; edge < lifted_graph.numberOfEdges(); ++edge)
{
outputLabels[edge] = inputLabels[edge];

auto v0 = lifted_graph.vertexOfEdge(edge, 0);
auto v1 = lifted_graph.vertexOfEdge(edge, 1);

numberOfComponents = std::max(numberOfComponents, std::max(components.labels_[v0], components.labels_[v1]));

if (inputLabels[edge])
current_energy_value += edgeCosts[edge];

if (static_cast<bool>(inputLabels[edge]) != !components.areConnected(v0, v1))
throw std::runtime_error("the input multicut labeling is invalid.");
}

++numberOfComponents;
auto numberOfComponents = *std::max_element(components.labels_.begin(), components.labels_.end()) + 1;

std::vector<std::vector<std::size_t>> partitions(numberOfComponents);

Expand Down
179 changes: 179 additions & 0 deletions include/andres/graph/multicut/greedy-fixation.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#pragma once

#include <cstddef>
#include <iterator>
#include <vector>
#include <algorithm>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <queue>

#include "andres/partition.hxx"

namespace andres {
namespace graph {
namespace multicut {

/// Greedy agglomerative decomposition of a graph.
///
template<typename GRAPH, typename EVA, typename ELA>
void greedyFixation(
const GRAPH& graph,
EVA const& edge_values,
ELA& edge_labels
)
{
class DynamicGraph
{
public:
DynamicGraph(size_t n) :
vertices_(n), cut_edges_(n)
{}

bool edgeExists(size_t a, size_t b) const
{
return !vertices_[a].empty() && vertices_[a].find(b) != vertices_[a].end();
}

std::unordered_map<size_t, typename EVA::value_type> const& getAdjacentVertices(size_t v) const
{
return vertices_[v];
}

typename EVA::value_type getEdgeWeight(size_t a, size_t b) const
{
return vertices_[a].at(b);
}

bool isCutEdge(size_t a, size_t b) const
{
return !cut_edges_[a].empty() && cut_edges_[a].find(b) != cut_edges_[a].end();
}

void markEdgeCut(size_t a, size_t b)
{
cut_edges_[a].insert(b);
cut_edges_[b].insert(a);
}

void removeVertex(size_t v)
{
for (auto& p : vertices_[v])
{
vertices_[p.first].erase(v);
cut_edges_[p.first].erase(v);
}

vertices_[v].clear();
cut_edges_[v].clear();
}

void setEdgeWeight(size_t a, size_t b, typename EVA::value_type w)
{
vertices_[a][b] = w;
vertices_[b][a] = w;
}

private:
std::vector<std::unordered_set<size_t>> cut_edges_;
std::vector<std::unordered_map<size_t, typename EVA::value_type>> vertices_;
};

struct Edge
{
Edge(size_t _a, size_t _b, typename EVA::value_type _w)
{
if (_a > _b)
std::swap(_a, _b);

a = _a;
b = _b;

w = _w;
}

size_t a;
size_t b;
size_t edition;
typename EVA::value_type w;

bool operator <(Edge const& other) const
{
return fabs(w) < fabs(other.w);
}
};

std::vector<std::unordered_map<size_t, size_t>> edge_editions(graph.numberOfVertices());
(graph.numberOfVertices());

DynamicGraph original_graph_cp(graph.numberOfVertices());
std::priority_queue<Edge> Q;

for (size_t i = 0; i < graph.numberOfEdges(); ++i)
{
auto a = graph.vertexOfEdge(i, 0);
auto b = graph.vertexOfEdge(i, 1);

original_graph_cp.setEdgeWeight(a, b, edge_values[i]);

auto e = Edge(a, b, edge_values[i]);
e.edition = ++edge_editions[e.a][e.b];

Q.push(e);
}

andres::Partition<size_t> partition(graph.numberOfVertices());

while (!Q.empty())
{
auto edge = Q.top();
Q.pop();

if (!original_graph_cp.edgeExists(edge.a, edge.b) || edge.edition < edge_editions[edge.a][edge.b])
continue;

if (edge.w > typename EVA::value_type() && !original_graph_cp.isCutEdge(edge.a, edge.b))
{
auto stable_vertex = edge.a;
auto merge_vertex = edge.b;

if (original_graph_cp.getAdjacentVertices(stable_vertex).size() < original_graph_cp.getAdjacentVertices(merge_vertex).size())
std::swap(stable_vertex, merge_vertex);

partition.merge(stable_vertex, merge_vertex);

for (auto& p : original_graph_cp.getAdjacentVertices(merge_vertex))
{
if (p.first == stable_vertex)
continue;

typename EVA::value_type t = typename EVA::value_type();

if (original_graph_cp.edgeExists(stable_vertex, p.first))
t = original_graph_cp.getEdgeWeight(stable_vertex, p.first);

if (original_graph_cp.isCutEdge(merge_vertex, p.first))
original_graph_cp.markEdgeCut(stable_vertex, p.first);

original_graph_cp.setEdgeWeight(stable_vertex, p.first, p.second + t);

auto e = Edge(stable_vertex, p.first, p.second + t);
e.edition = ++edge_editions[e.a][e.b];

Q.push(e);
}

original_graph_cp.removeVertex(merge_vertex);
}
else if (edge.w < typename EVA::value_type())
original_graph_cp.markEdgeCut(edge.a, edge.b);
}

for (size_t i = 0; i < graph.numberOfEdges(); ++i)
edge_labels[i] = partition.find(graph.vertexOfEdge(i, 0)) == partition.find(graph.vertexOfEdge(i, 1)) ? 0 : 1;
}

} // namespace multicut
} // namespace graph
} // namespace andres
Loading

0 comments on commit 26ec62c

Please sign in to comment.