|
|
|
|
|
#ifndef DLIB_MIN_CuT_Hh_ |
|
#define DLIB_MIN_CuT_Hh_ |
|
|
|
#include "min_cut_abstract.h" |
|
#include "../matrix.h" |
|
#include "general_flow_graph.h" |
|
#include "../is_kind.h" |
|
|
|
#include <iostream> |
|
#include <fstream> |
|
#include <deque> |
|
|
|
|
|
|
|
|
|
|
|
namespace dlib |
|
{ |
|
|
|
typedef unsigned char node_label; |
|
|
|
|
|
|
|
const node_label SOURCE_CUT = 0; |
|
const node_label SINK_CUT = 254; |
|
const node_label FREE_NODE = 255; |
|
|
|
|
|
|
|
template <typename flow_graph> |
|
typename disable_if<is_directed_graph<flow_graph>,typename flow_graph::edge_type>::type |
|
graph_cut_score ( |
|
const flow_graph& g |
|
) |
|
{ |
|
typedef typename flow_graph::edge_type edge_weight_type; |
|
edge_weight_type score = 0; |
|
typedef typename flow_graph::out_edge_iterator out_edge_iterator; |
|
for (unsigned long i = 0; i < g.number_of_nodes(); ++i) |
|
{ |
|
if (g.get_label(i) != SOURCE_CUT) |
|
continue; |
|
|
|
for (out_edge_iterator n = g.out_begin(i); n != g.out_end(i); ++n) |
|
{ |
|
if (g.get_label(g.node_id(n)) != SOURCE_CUT) |
|
{ |
|
score += g.get_flow(n); |
|
} |
|
} |
|
} |
|
|
|
return score; |
|
} |
|
|
|
template <typename directed_graph> |
|
typename enable_if<is_directed_graph<directed_graph>,typename directed_graph::edge_type>::type |
|
graph_cut_score ( |
|
const directed_graph& g |
|
) |
|
{ |
|
return graph_cut_score(dlib::impl::general_flow_graph<const directed_graph>(g)); |
|
} |
|
|
|
|
|
|
|
class min_cut |
|
{ |
|
|
|
public: |
|
|
|
min_cut() |
|
{ |
|
} |
|
|
|
min_cut( const min_cut& ) |
|
{ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
template < |
|
typename directed_graph |
|
> |
|
typename enable_if<is_directed_graph<directed_graph> >::type operator() ( |
|
directed_graph& g, |
|
const unsigned long source_node, |
|
const unsigned long sink_node |
|
) const |
|
{ |
|
DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, |
|
"\t void min_cut::operator()" |
|
<< "\n\t Invalid arguments were given to this function." |
|
); |
|
DLIB_ASSERT(graph_has_symmetric_edges(g) == true, |
|
"\t void min_cut::operator()" |
|
<< "\n\t Invalid arguments were given to this function." |
|
); |
|
|
|
dlib::impl::general_flow_graph<directed_graph> temp(g); |
|
(*this)(temp, source_node, sink_node); |
|
} |
|
|
|
template < |
|
typename flow_graph |
|
> |
|
typename disable_if<is_directed_graph<flow_graph> >::type operator() ( |
|
flow_graph& g, |
|
const unsigned long source_node, |
|
const unsigned long sink_node |
|
) const |
|
{ |
|
#ifdef ENABLE_ASSERTS |
|
DLIB_ASSERT(source_node != sink_node && |
|
source_node < g.number_of_nodes() && |
|
sink_node < g.number_of_nodes(), |
|
"\t void min_cut::operator()" |
|
<< "\n\t Invalid arguments were given to this function." |
|
<< "\n\t g.number_of_nodes(): " << g.number_of_nodes() |
|
<< "\n\t source_node: " << source_node |
|
<< "\n\t sink_node: " << sink_node |
|
<< "\n\t this: " << this |
|
); |
|
|
|
for (unsigned long i = 0; i < g.number_of_nodes(); ++i) |
|
{ |
|
typename flow_graph::out_edge_iterator j, end = g.out_end(i); |
|
for (j = g.out_begin(i); j != end; ++j) |
|
{ |
|
const unsigned long jj = g.node_id(j); |
|
DLIB_ASSERT(g.get_flow(i,jj) >= 0, |
|
"\t void min_cut::operator()" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t i: "<< i |
|
<< "\n\t jj: "<< jj |
|
<< "\n\t g.get_flow(i,jj): "<< g.get_flow(i,jj) |
|
<< "\n\t this: "<< this |
|
); |
|
|
|
} |
|
} |
|
#endif |
|
parent.clear(); |
|
active.clear(); |
|
orphans.clear(); |
|
|
|
typedef typename flow_graph::edge_type edge_type; |
|
COMPILE_TIME_ASSERT(is_signed_type<edge_type>::value); |
|
|
|
typedef typename flow_graph::out_edge_iterator out_edge_iterator; |
|
typedef typename flow_graph::in_edge_iterator in_edge_iterator; |
|
|
|
|
|
for (unsigned long i = 0; i < g.number_of_nodes(); ++i) |
|
g.set_label(i, FREE_NODE); |
|
|
|
g.set_label(source_node, SOURCE_CUT); |
|
g.set_label(sink_node, SINK_CUT); |
|
|
|
|
|
const unsigned long no_parent = g.number_of_nodes(); |
|
|
|
parent.assign(g.number_of_nodes(), no_parent); |
|
|
|
time = 1; |
|
dist.assign(g.number_of_nodes(), 0); |
|
ts.assign(g.number_of_nodes(), time); |
|
|
|
active.push_back(source_node); |
|
active.push_back(sink_node); |
|
|
|
|
|
in_edge_iterator in_begin = g.in_begin(active[0]); |
|
out_edge_iterator out_begin = g.out_begin(active[0]); |
|
|
|
unsigned long source_side, sink_side; |
|
while (grow(g,source_side,sink_side, in_begin, out_begin)) |
|
{ |
|
++time; |
|
ts[source_node] = time; |
|
ts[sink_node] = time; |
|
|
|
augment(g, source_node, sink_node, source_side, sink_side); |
|
adopt(g, source_node, sink_node); |
|
} |
|
|
|
} |
|
|
|
|
|
private: |
|
|
|
unsigned long distance_to_origin ( |
|
const unsigned long no_parent, |
|
unsigned long p, |
|
unsigned long |
|
) const |
|
{ |
|
unsigned long start = p; |
|
unsigned long count = 0; |
|
while (p != no_parent) |
|
{ |
|
if (ts[p] == time) |
|
{ |
|
count += dist[p]; |
|
|
|
unsigned long count_down = count; |
|
|
|
while (start != p) |
|
{ |
|
ts[start] = time; |
|
dist[start] = count_down; |
|
--count_down; |
|
start = parent[start]; |
|
} |
|
|
|
return count; |
|
} |
|
p = parent[p]; |
|
++count; |
|
} |
|
|
|
return std::numeric_limits<unsigned long>::max(); |
|
} |
|
|
|
template <typename flow_graph> |
|
void adopt ( |
|
flow_graph& g, |
|
const unsigned long source, |
|
const unsigned long sink |
|
) const |
|
{ |
|
typedef typename flow_graph::out_edge_iterator out_edge_iterator; |
|
typedef typename flow_graph::in_edge_iterator in_edge_iterator; |
|
|
|
|
|
const unsigned long no_parent = g.number_of_nodes(); |
|
|
|
while (orphans.size() > 0) |
|
{ |
|
const unsigned long p = orphans.back(); |
|
orphans.pop_back(); |
|
|
|
const unsigned char label_p = g.get_label(p); |
|
|
|
|
|
if (label_p == SOURCE_CUT) |
|
{ |
|
const in_edge_iterator begin(g.in_begin(p)); |
|
const in_edge_iterator end(g.in_end(p)); |
|
unsigned long best_dist = std::numeric_limits<unsigned long>::max(); |
|
unsigned long best_node = 0; |
|
for(in_edge_iterator q = begin; q != end; ++q) |
|
{ |
|
const unsigned long id = g.node_id(q); |
|
|
|
if (g.get_label(id) != label_p || g.get_flow(q) <= 0 ) |
|
continue; |
|
|
|
unsigned long temp = distance_to_origin(no_parent, id,source); |
|
if (temp < best_dist) |
|
{ |
|
best_dist = temp; |
|
best_node = id; |
|
} |
|
|
|
} |
|
if (best_dist != std::numeric_limits<unsigned long>::max()) |
|
{ |
|
parent[p] = best_node; |
|
dist[p] = dist[best_node] + 1; |
|
ts[p] = time; |
|
} |
|
|
|
|
|
if (parent[p] == no_parent) |
|
{ |
|
for(in_edge_iterator q = begin; q != end; ++q) |
|
{ |
|
const unsigned long id = g.node_id(q); |
|
|
|
if (g.get_label(id) != SOURCE_CUT) |
|
continue; |
|
|
|
if (g.get_flow(q) > 0) |
|
active.push_back(id); |
|
|
|
if (parent[id] == p) |
|
{ |
|
parent[id] = no_parent; |
|
orphans.push_back(id); |
|
} |
|
} |
|
g.set_label(p, FREE_NODE); |
|
} |
|
} |
|
else |
|
{ |
|
unsigned long best_node = 0; |
|
unsigned long best_dist = std::numeric_limits<unsigned long>::max(); |
|
const out_edge_iterator begin(g.out_begin(p)); |
|
const out_edge_iterator end(g.out_end(p)); |
|
for(out_edge_iterator q = begin; q != end; ++q) |
|
{ |
|
const unsigned long id = g.node_id(q); |
|
if (g.get_label(id) != label_p || g.get_flow(q) <= 0) |
|
continue; |
|
|
|
unsigned long temp = distance_to_origin(no_parent, id,sink); |
|
|
|
if (temp < best_dist) |
|
{ |
|
best_dist = temp; |
|
best_node = id; |
|
} |
|
} |
|
|
|
if (best_dist != std::numeric_limits<unsigned long>::max()) |
|
{ |
|
parent[p] = best_node; |
|
dist[p] = dist[best_node] + 1; |
|
ts[p] = time; |
|
} |
|
|
|
|
|
if (parent[p] == no_parent) |
|
{ |
|
for(out_edge_iterator q = begin; q != end; ++q) |
|
{ |
|
const unsigned long id = g.node_id(q); |
|
|
|
if (g.get_label(id) != SINK_CUT) |
|
continue; |
|
|
|
if (g.get_flow(q) > 0) |
|
active.push_back(id); |
|
|
|
if (parent[id] == p) |
|
{ |
|
parent[id] = no_parent; |
|
orphans.push_back(id); |
|
} |
|
} |
|
|
|
g.set_label(p, FREE_NODE); |
|
} |
|
} |
|
|
|
|
|
} |
|
|
|
} |
|
|
|
template <typename flow_graph> |
|
void augment ( |
|
flow_graph& g, |
|
const unsigned long& source, |
|
const unsigned long& sink, |
|
const unsigned long& source_side, |
|
const unsigned long& sink_side |
|
) const |
|
{ |
|
typedef typename flow_graph::edge_type edge_type; |
|
|
|
|
|
const unsigned long no_parent = g.number_of_nodes(); |
|
|
|
unsigned long s = source_side; |
|
unsigned long t = sink_side; |
|
edge_type min_cap = g.get_flow(s,t); |
|
|
|
|
|
|
|
|
|
t = s; |
|
while (t != source) |
|
{ |
|
s = parent[t]; |
|
const edge_type temp = g.get_flow(s, t); |
|
if (temp < min_cap) |
|
{ |
|
min_cap = temp; |
|
} |
|
t = s; |
|
} |
|
|
|
|
|
s = sink_side; |
|
while (s != sink) |
|
{ |
|
t = parent[s]; |
|
const edge_type temp = g.get_flow(s, t); |
|
if (temp < min_cap) |
|
{ |
|
min_cap = temp; |
|
} |
|
s = t; |
|
} |
|
|
|
|
|
|
|
s = source_side; |
|
t = sink_side; |
|
g.adjust_flow(t,s, min_cap); |
|
|
|
|
|
t = s; |
|
while (t != source) |
|
{ |
|
s = parent[t]; |
|
g.adjust_flow(t,s, min_cap); |
|
if (g.get_flow(s,t) <= 0) |
|
{ |
|
parent[t] = no_parent; |
|
orphans.push_back(t); |
|
} |
|
|
|
t = s; |
|
} |
|
|
|
|
|
s = sink_side; |
|
while (s != sink) |
|
{ |
|
t = parent[s]; |
|
g.adjust_flow(t,s, min_cap); |
|
if (g.get_flow(s,t) <= 0) |
|
{ |
|
parent[s] = no_parent; |
|
orphans.push_back(s); |
|
} |
|
s = t; |
|
} |
|
} |
|
|
|
template <typename flow_graph> |
|
bool grow ( |
|
flow_graph& g, |
|
unsigned long& source_side, |
|
unsigned long& sink_side, |
|
typename flow_graph::in_edge_iterator& in_begin, |
|
typename flow_graph::out_edge_iterator& out_begin |
|
) const |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
typedef typename flow_graph::out_edge_iterator out_edge_iterator; |
|
typedef typename flow_graph::in_edge_iterator in_edge_iterator; |
|
|
|
|
|
while (active.size() != 0) |
|
{ |
|
|
|
const unsigned long A = active[0]; |
|
|
|
const unsigned char label_A = g.get_label(A); |
|
|
|
|
|
if (label_A == SOURCE_CUT) |
|
{ |
|
const out_edge_iterator out_end = g.out_end(A); |
|
for(out_edge_iterator& i = out_begin; i != out_end; ++i) |
|
{ |
|
if (g.get_flow(i) > 0) |
|
{ |
|
const unsigned long id = g.node_id(i); |
|
const unsigned char label_i = g.get_label(id); |
|
if (label_i == FREE_NODE) |
|
{ |
|
active.push_back(id); |
|
g.set_label(id,SOURCE_CUT); |
|
parent[id] = A; |
|
ts[id] = ts[A]; |
|
dist[id] = dist[A] + 1; |
|
} |
|
else if (label_A != label_i) |
|
{ |
|
source_side = A; |
|
sink_side = id; |
|
return true; |
|
} |
|
else if (is_closer(A, id)) |
|
{ |
|
parent[id] = A; |
|
ts[id] = ts[A]; |
|
dist[id] = dist[A] + 1; |
|
} |
|
} |
|
} |
|
} |
|
else if (label_A == SINK_CUT) |
|
{ |
|
const in_edge_iterator in_end = g.in_end(A); |
|
for(in_edge_iterator& i = in_begin; i != in_end; ++i) |
|
{ |
|
if (g.get_flow(i) > 0) |
|
{ |
|
const unsigned long id = g.node_id(i); |
|
const unsigned char label_i = g.get_label(id); |
|
if (label_i == FREE_NODE) |
|
{ |
|
active.push_back(id); |
|
g.set_label(id,SINK_CUT); |
|
parent[id] = A; |
|
ts[id] = ts[A]; |
|
dist[id] = dist[A] + 1; |
|
} |
|
else if (label_A != label_i) |
|
{ |
|
sink_side = A; |
|
source_side = id; |
|
return true; |
|
} |
|
else if (is_closer(A, id)) |
|
{ |
|
parent[id] = A; |
|
ts[id] = ts[A]; |
|
dist[id] = dist[A] + 1; |
|
} |
|
} |
|
} |
|
} |
|
|
|
active.pop_front(); |
|
if (active.size() != 0) |
|
{ |
|
in_begin = g.in_begin(active[0]); |
|
out_begin = g.out_begin(active[0]); |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
inline bool is_closer ( |
|
unsigned long p, |
|
unsigned long q |
|
) const |
|
{ |
|
|
|
return ts[q] <= ts[p] && dist[q] > dist[p]; |
|
} |
|
|
|
mutable std::vector<uint32> dist; |
|
mutable std::vector<uint32> ts; |
|
mutable uint32 time; |
|
mutable std::vector<unsigned long> parent; |
|
|
|
mutable std::deque<unsigned long> active; |
|
mutable std::vector<unsigned long> orphans; |
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|