44#include <boost/graph/push_relabel_max_flow.hpp>
45#include <boost/rational.hpp>
87 FlowEdge fe = add_edge(u, v, fg).first;
88 FlowEdge fe_r = add_edge(v, u, fg).first;
89 put(edge_capacity, fg, fe, capacity);
90 put(edge_capacity, fg, fe_r, 0);
91 put(edge_reverse, fg, fe, fe_r);
92 put(edge_reverse, fg, fe_r, fe);
108 const long n =
static_cast<long>(num_vertices(g));
109 Vertex u = source(e, g), v = target(e, g);
113 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
114 int idx = get(edge_index, g, *ei);
115 long w = get(edge_weight, g, *ei);
122 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
132 const long unlimited = 2 * q * n + 1;
133 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
135 if (*vi == u || *vi == v) {
136 capacity = unlimited;
139 graph_traits<Graph>::out_edge_iterator oei, oei_end;
140 for (boost::tie(oei, oei_end) = out_edges(*vi, g); oei != oei_end; ++oei) {
141 capacity += get(edge_weight, g, *oei);
148 long flow = push_relabel_max_flow(ctx.
graph, ctx.
src, ctx.
tgt);
149 assert(flow % 2 == 0);
151 long eps = flow / 2 - q;
152 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
153 eps -= get(edge_weight, g, *ei);
159 std::vector<FlowVertex> process{ctx.
src};
160 while (!process.empty()) {
163 C.insert(
static_cast<Vertex>(w));
165 graph_traits<FlowGraph>::out_edge_iterator fei, fei_end;
166 for (boost::tie(fei, fei_end) = out_edges(w, ctx.
graph); fei != fei_end; ++fei) {
167 if (get(edge_residual_capacity, ctx.
graph, *fei) > 0) {
169 if (C.count(
static_cast<Vertex>(w2)) == 0) {
170 process.push_back(w2);
177 std::set<Edge> crit_edges;
179 graph_traits<Graph>::out_edge_iterator oei, oei_end;
180 for (boost::tie(oei, oei_end) = out_edges(a, g); oei != oei_end; ++oei) {
181 if (C.count(target(*oei, g)) > 0) {
182 crit_edges.insert(*oei);
187 return {eps, crit_edges};
201 const long n =
static_cast<long>(num_vertices(g));
208 const std::size_t m = num_edges(g);
211 ctx.
to_target.resize(
static_cast<std::size_t
>(n));
212 ctx.
from_source.resize(
static_cast<std::size_t
>(n));
216 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei, ++i) {
217 put(edge_index, g, *ei,
static_cast<int>(i));
218 Vertex u = source(*ei, g), v = target(*ei, g);
224 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
250 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
251 put(edge_weight, g, *ei, 0);
254 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
255 if (A.count(*ei) > 0) {
261 long w = get(edge_weight, g, *ei);
263 A.insert(crit_edges.begin(), crit_edges.end());
267 put(edge_weight, g, *ei, w + eps);
271 for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
272 total += get(edge_weight, g, *ei);
293 const long m =
static_cast<long>(num_edges(g));
294 const long n =
static_cast<long>(num_vertices(g));
296 std::set<rational<long>> theta_set;
297 for (
long q = 1; q <= m; ++q) {
298 for (
long p = 1; p <= std::min(n - 1, q); ++p) {
299 rational<long> val(p, q);
301 theta_set.insert(val);
305 std::vector<rational<long>> Theta(theta_set.begin(), theta_set.end());
307 std::set<Edge> crit_set;
308 std::size_t lb = 0, ub = Theta.size();
311 std::size_t mid = (ub + lb) / 2;
312 long p = Theta[mid].numerator(), q = Theta[mid].denominator();
316 if (xE >= q * (n - 1)) {
324 return {Theta[lb], crit_set};
344 "spanning_tree_modulus assumes a simple graph (no self-loops, no parallel edges) -- "
345 "see is_simple_graph's docs in graphs.hpp for why a multigraph input isn't just "
346 "unsupported but silently wrong");
348 std::map<Edge, rational<long>> eta_star;
349 long remain =
static_cast<long>(num_edges(g));
354 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
355 put(vertex_name, g, *vi, *vi);
363 std::vector<std::pair<Graph, rational<long>>> process;
365 process.emplace_back(std::move(comp), rational<long>(1, 1));
369 std::cout <<
"| " << std::setw(12) <<
"eta" <<
" | " << std::setw(12) <<
"num edge" <<
" | "
370 << std::setw(12) <<
"edge_remain" <<
" | " << std::setw(12) <<
"comp remain" <<
" |" << std::endl;
373 while (!process.empty()) {
374 Graph h = std::move(process.back().first);
375 rational<long> parent_theta = process.back().second;
378 if (num_edges(h) == 0) {
385 const long m =
static_cast<long>(num_edges(h));
386 long p = theta.numerator(), q = theta.denominator();
387 if (
static_cast<long>(J.size()) == m) {
390 long pp = p * m * m - q;
396 std::set<Edge> crit_set;
398 for (boost::tie(ei, ei_end) = edges(h); ei != ei_end; ++ei) {
399 if (J.count(*ei) == 0) {
400 crit_set.insert(*ei);
405 if (trace !=
nullptr) {
407 for (boost::tie(hvi, hvi_end) = vertices(h); hvi != hvi_end; ++hvi) {
408 trace_round.
vertices.push_back(get(vertex_name, h, *hvi));
410 trace_round.
theta = theta;
413 for (
const Edge& e : crit_set) {
414 Vertex uu = get(vertex_name, h, source(e, h));
415 Vertex vv = get(vertex_name, h, target(e, h));
416 eta_star[edge(uu, vv, g).first] = theta;
417 if (trace !=
nullptr) {
418 trace_round.
crit_set.emplace_back(uu, vv);
422 if (trace !=
nullptr) {
423 trace->rounds.push_back(std::move(trace_round));
431 assert(theta == rational<long>(
static_cast<long>(comps.size()) - 1,
static_cast<long>(crit_set.size())));
433 for (
auto& comp : comps) {
434 process.emplace_back(std::move(comp), theta);
437 remain -=
static_cast<long>(crit_set.size());
439 std::cout <<
"| " << std::setw(12) << theta <<
" | " << std::setw(12) << crit_set.size() <<
" | "
440 << std::setw(12) << remain <<
" | " << std::setw(12) << process.size() <<
" |" << std::endl;
Graph/flow-graph type aliases, subgraph/component helpers, and demo graph generators used by cunningh...
FlowEdge add_capacity_edge(FlowGraph &fg, FlowVertex u, FlowVertex v, long capacity)
Adds a directed capacity edge u -> v to fg, along with its required zero-capacity reverse-residual co...
Definition cunningham.hpp:86
std::pair< long, std::set< Edge > > solve_subproblem(Graph &g, FlowContext &ctx, const Edge &e, long q)
One max-flow step of Cunningham's algorithm: how far can x be increased on edge e without leaving the...
Definition cunningham.hpp:107
Definition cunningham.hpp:50
adjacency_list< vecS, vecS, undirectedS, property< vertex_name_t, Traits::vertex_descriptor >, property< edge_index_t, int, property< edge_weight_t, long > > > Graph
The undirected graph type used throughout this library.
Definition graphs.hpp:43
bool is_simple_graph(const G &g)
Checks whether g is a simple graph: no self-loops, no parallel edges between the same pair of vertice...
Definition graphs.hpp:166
adjacency_list< vecS, vecS, directedS, no_property, property< edge_capacity_t, long, property< edge_residual_capacity_t, long, property< edge_reverse_t, FlowTraits::edge_descriptor > > > > FlowGraph
The directed, capacitated graph type used for the max-flow subproblem in Cunningham's algorithm (see ...
Definition graphs.hpp:69
std::vector< Graph > connected_component_graphs(const G &g)
Splits g into one Graph per connected component.
Definition graphs.hpp:109
std::vector< Graph > induced_components(Graph &g, const std::set< Edge > &A)
Splits g into connected components after removing the critical edge set A.
Definition graphs.hpp:141
std::pair< long, std::set< Edge > > cunningham_min(Graph &g, FlowContext &ctx, long p, long q)
Finds a P(qf)-basis for the constant function p, along with a tight set, using Cunningham's greedy al...
Definition cunningham.hpp:246
std::map< Edge, rational< long > > spanning_tree_modulus(Graph &g, bool verbose=false, SolverTrace *trace=nullptr)
Computes the exact spanning tree modulus of g using Cunningham's algorithm.
Definition cunningham.hpp:341
FlowContext create_flow_graph(Graph &g)
Builds the reusable max-flow network for g.
Definition cunningham.hpp:200
FlowTraits::vertex_descriptor FlowVertex
Definition graphs.hpp:56
graph_traits< Graph >::edge_descriptor Edge
Definition graphs.hpp:46
FlowTraits::edge_descriptor FlowEdge
Definition graphs.hpp:57
graph_traits< Graph >::vertex_iterator VertexIterator
Definition graphs.hpp:47
graph_traits< Graph >::vertex_descriptor Vertex
Definition graphs.hpp:45
graph_traits< Graph >::edge_iterator EdgeIterator
Definition graphs.hpp:48
std::pair< rational< long >, std::set< Edge > > graph_vulnerability(Graph &g, FlowContext &ctx, rational< long > ubound=rational< long >(1, 1))
Finds the vulnerability theta(G) of a graph by binary search, along with an optimal tight set.
Definition cunningham.hpp:291
Opt-in per-round trace recording for spanning_tree_modulus, and a versioned JSON writer for the recor...
The reusable max-flow network for cunningham_min / graph_vulnerability / spanning_tree_modulus,...
Definition cunningham.hpp:64
std::vector< FlowEdge > to_target
indexed by vertex: v -> target
Definition cunningham.hpp:70
FlowVertex src
Definition cunningham.hpp:66
std::vector< FlowEdge > forward
indexed by edge_index: source(e,g) -> target(e,g)
Definition cunningham.hpp:68
FlowGraph graph
Definition cunningham.hpp:65
std::vector< FlowEdge > backward
indexed by edge_index: target(e,g) -> source(e,g)
Definition cunningham.hpp:69
FlowVertex tgt
Definition cunningham.hpp:67
std::vector< FlowEdge > from_source
indexed by vertex: source -> v
Definition cunningham.hpp:71
The full recorded trace of a spanning_tree_modulus run.
Definition solver_trace.hpp:48
One round of spanning_tree_modulus's main loop: the component it was carved from, the edge set dispat...
Definition solver_trace.hpp:41
rational< long > theta
Definition solver_trace.hpp:42
std::vector< std::pair< Vertex, Vertex > > crit_set
the dispatched edges
Definition solver_trace.hpp:44
std::vector< Vertex > vertices
the component's vertex set
Definition solver_trace.hpp:43