#ifndef FLOW_H_ #define FLOW_H_ #include #include #include #include #include "config.hpp" #include #include #include #include #include #include #include using namespace boost; using namespace Eigen; namespace qflow { class MaxFlowHelper { public: MaxFlowHelper() {} virtual ~MaxFlowHelper(){}; virtual void resize(int n, int m) = 0; virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) = 0; virtual int compute() = 0; virtual void applyTo(std::vector& edge_diff) = 0; }; class BoykovMaxFlowHelper : public MaxFlowHelper { public: typedef int EdgeWeightType; typedef adjacency_list_traits Traits; // clang-format off typedef adjacency_list < vecS, vecS, directedS, property < vertex_name_t, std::string, property < vertex_index_t, long, property < vertex_color_t, boost::default_color_type, property < vertex_distance_t, long, property < vertex_predecessor_t, Traits::edge_descriptor > > > > >, property < edge_capacity_t, EdgeWeightType, property < edge_residual_capacity_t, EdgeWeightType, property < edge_reverse_t, Traits::edge_descriptor > > > > Graph; // clang-format on public: BoykovMaxFlowHelper() { rev = get(edge_reverse, g); } void resize(int n, int m) { vertex_descriptors.resize(n); for (int i = 0; i < n; ++i) vertex_descriptors[i] = add_vertex(g); } int compute() { EdgeWeightType flow = boykov_kolmogorov_max_flow(g, vertex_descriptors.front(), vertex_descriptors.back()); return flow; } void addDirectEdge(Traits::vertex_descriptor& v1, Traits::vertex_descriptor& v2, property_map::type& rev, const int capacity, const int inv_capacity, Graph& g, Traits::edge_descriptor& e1, Traits::edge_descriptor& e2) { e1 = add_edge(v1, v2, g).first; e2 = add_edge(v2, v1, g).first; put(edge_capacity, g, e1, capacity); put(edge_capacity, g, e2, inv_capacity); rev[e1] = e2; rev[e2] = e1; } void addEdge(int x, int y, int c, int rc, int v, int cost = 1) { Traits::edge_descriptor e1, e2; addDirectEdge(vertex_descriptors[x], vertex_descriptors[y], rev, c, rc, g, e1, e2); if (v != -1) { edge_to_variables[e1] = std::make_pair(v, -1); edge_to_variables[e2] = std::make_pair(v, 1); } } void applyTo(std::vector& edge_diff) { property_map::type capacity = get(edge_capacity, g); property_map::type residual_capacity = get(edge_residual_capacity, g); graph_traits::vertex_iterator u_iter, u_end; graph_traits::out_edge_iterator ei, e_end; for (tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) if (capacity[*ei] > 0) { int flow = (capacity[*ei] - residual_capacity[*ei]); if (flow > 0) { auto it = edge_to_variables.find(*ei); if (it != edge_to_variables.end()) { edge_diff[it->second.first / 2][it->second.first % 2] += it->second.second * flow; } } } } private: Graph g; property_map::type rev; std::vector vertex_descriptors; std::map> edge_to_variables; }; class NetworkSimplexFlowHelper : public MaxFlowHelper { public: using Weight = int; using Capacity = int; using Graph = lemon::SmartDigraph; using Node = Graph::Node; using Arc = Graph::Arc; template using ArcMap = lemon::SmartDigraph::ArcMap; using Preflow = lemon::Preflow>; using NetworkSimplex = lemon::NetworkSimplex; public: NetworkSimplexFlowHelper() : cost(graph), capacity(graph), flow(graph), variable(graph) {} ~NetworkSimplexFlowHelper(){}; void resize(int n, int m) { nodes.reserve(n); for (int i = 0; i < n; ++i) nodes.push_back(graph.addNode()); } void addEdge(int x, int y, int c, int rc, int v, int cst = 1) { assert(x >= 0); assert(v >= -1); if (c) { auto e1 = graph.addArc(nodes[x], nodes[y]); cost[e1] = cst; capacity[e1] = c; variable[e1] = std::make_pair(v, 1); } if (rc) { auto e2 = graph.addArc(nodes[y], nodes[x]); cost[e2] = cst; capacity[e2] = rc; variable[e2] = std::make_pair(v, -1); } } int compute() { Preflow pf(graph, capacity, nodes.front(), nodes.back()); NetworkSimplex ns(graph); // Run preflow to find maximum flow lprintf("push-relabel flow... "); pf.runMinCut(); int maxflow = pf.flowValue(); // Run network simplex to find minimum cost maximum flow ns.costMap(cost).upperMap(capacity).stSupply(nodes.front(), nodes.back(), maxflow); auto status = ns.run(); switch (status) { case NetworkSimplex::OPTIMAL: ns.flowMap(flow); break; case NetworkSimplex::INFEASIBLE: lputs("NetworkSimplex::INFEASIBLE"); assert(0); break; default: lputs("Unknown: NetworkSimplex::Default"); assert(0); break; } return maxflow; } void applyTo(std::vector& edge_diff) { for (Graph::ArcIt e(graph); e != lemon::INVALID; ++e) { int var = variable[e].first; if (var == -1) continue; int sgn = variable[e].second; edge_diff[var / 2][var % 2] -= sgn * flow[e]; } } private: Graph graph; ArcMap cost; ArcMap capacity; ArcMap flow; ArcMap> variable; std::vector nodes; std::vector edges; }; #ifdef WITH_GUROBI #include class GurobiFlowHelper : public MaxFlowHelper { public: GurobiFlowHelper() {} virtual ~GurobiFlowHelper(){}; virtual void resize(int n, int m) { nodes.resize(n * 2); edges.resize(m); } virtual void addEdge(int x, int y, int c, int rc, int v, int cost = 1) { nodes[x * 2 + 0].push_back(vars.size()); nodes[y * 2 + 1].push_back(vars.size()); vars.push_back(model.addVar(0, c, 0, GRB_INTEGER)); edges.push_back(std::make_pair(v, 1)); nodes[y * 2 + 0].push_back(vars.size()); nodes[x * 2 + 1].push_back(vars.size()); vars.push_back(model.addVar(0, rc, 0, GRB_INTEGER)); edges.push_back(std::make_pair(v, -1)); } virtual int compute() { std::cerr << "compute" << std::endl; int ns = nodes.size() / 2; int flow; for (int i = 1; i < ns - 1; ++i) { GRBLinExpr cons = 0; for (auto n : nodes[2 * i + 0]) cons += vars[n]; for (auto n : nodes[2 * i + 1]) cons -= vars[n]; model.addConstr(cons == 0); } // first pass, maximum flow GRBLinExpr outbound = 0; { lprintf("first pass\n"); for (auto& n : nodes[0]) outbound += vars[n]; for (auto& n : nodes[1]) outbound -= vars[n]; model.setObjective(outbound, GRB_MAXIMIZE); model.optimize(); flow = (int)model.get(GRB_DoubleAttr_ObjVal); lprintf("Gurobi result: %d\n", flow); } // second pass, minimum cost flow { lprintf("second pass\n"); model.addConstr(outbound == flow); GRBLinExpr cost = 0; for (auto& v : vars) cost += v; model.setObjective(cost, GRB_MINIMIZE); model.optimize(); double optimal_cost = (int)model.get(GRB_DoubleAttr_ObjVal); lprintf("Gurobi result: %.3f\n", optimal_cost); } return flow; } virtual void applyTo(std::vector& edge_diff) { assert(0); }; private: GRBEnv env = GRBEnv(); GRBModel model = GRBModel(env); std::vector vars; std::vector> edges; std::vector> nodes; }; #endif class ECMaxFlowHelper : public MaxFlowHelper { public: struct FlowInfo { int id; int capacity, flow; int v, d; FlowInfo* rev; }; struct SearchInfo { SearchInfo(int _id, int _prev_id, FlowInfo* _info) : id(_id), prev_id(_prev_id), info(_info) {} int id; int prev_id; FlowInfo* info; }; ECMaxFlowHelper() { num = 0; } int num; std::vector variable_to_edge; void resize(int n, int m) { graph.resize(n); variable_to_edge.resize(m, 0); num = n; } void addEdge(int x, int y, int c, int rc, int v, int cost = 0) { FlowInfo flow; flow.id = y; flow.capacity = c; flow.flow = 0; flow.v = v; flow.d = -1; graph[x].push_back(flow); auto& f1 = graph[x].back(); flow.id = x; flow.capacity = rc; flow.flow = 0; flow.v = v; flow.d = 1; graph[y].push_back(flow); auto& f2 = graph[y].back(); f2.rev = &f1; f1.rev = &f2; } int compute() { int total_flow = 0; int count = 0; while (true) { count += 1; std::vector vhash(num, 0); std::vector q; q.push_back(SearchInfo(0, -1, 0)); vhash[0] = 1; int q_front = 0; bool found = false; while (q_front < q.size()) { int vert = q[q_front].id; for (auto& l : graph[vert]) { if (vhash[l.id] || l.capacity <= l.flow) continue; q.push_back(SearchInfo(l.id, q_front, &l)); vhash[l.id] = 1; if (l.id == num - 1) { found = true; break; } } if (found) break; q_front += 1; } if (q_front == q.size()) break; int loc = q.size() - 1; while (q[loc].prev_id != -1) { q[loc].info->flow += 1; q[loc].info->rev->flow -= 1; loc = q[loc].prev_id; // int prev_v = q[loc].id; // applyFlow(prev_v, current_v, 1); // applyFlow(current_v, prev_v, -1); } total_flow += 1; } return total_flow; } void applyTo(std::vector& edge_diff) { for (int i = 0; i < graph.size(); ++i) { for (auto& flow : graph[i]) { if (flow.flow > 0 && flow.v != -1) { if (flow.flow > 0) { edge_diff[flow.v / 2][flow.v % 2] += flow.d * flow.flow; if (abs(edge_diff[flow.v / 2][flow.v % 2]) > 2) { } } } } } } void applyFlow(int v1, int v2, int flow) { for (auto& it : graph[v1]) { if (it.id == v2) { it.flow += flow; break; } } } std::vector> graph; }; } // namespace qflow #endif