Files
test2/extern/quadriflow/src/flow.hpp
2019-09-13 10:36:05 +02:00

376 lines
12 KiB
C++

#ifndef FLOW_H_
#define FLOW_H_
#include <Eigen/Core>
#include <list>
#include <map>
#include <vector>
#include "config.hpp"
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/graph/edmonds_karp_max_flow.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <lemon/network_simplex.h>
#include <lemon/preflow.h>
#include <lemon/smart_graph.h>
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<Vector2i>& edge_diff) = 0;
};
class BoykovMaxFlowHelper : public MaxFlowHelper {
public:
typedef int EdgeWeightType;
typedef adjacency_list_traits<vecS, vecS, directedS> 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<Graph, edge_reverse_t>::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<Vector2i>& edge_diff) {
property_map<Graph, edge_capacity_t>::type capacity = get(edge_capacity, g);
property_map<Graph, edge_residual_capacity_t>::type residual_capacity =
get(edge_residual_capacity, g);
graph_traits<Graph>::vertex_iterator u_iter, u_end;
graph_traits<Graph>::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<Graph, edge_reverse_t>::type rev;
std::vector<Traits::vertex_descriptor> vertex_descriptors;
std::map<Traits::edge_descriptor, std::pair<int, int>> 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 <typename ValueType>
using ArcMap = lemon::SmartDigraph::ArcMap<ValueType>;
using Preflow = lemon::Preflow<lemon::SmartDigraph, ArcMap<Capacity>>;
using NetworkSimplex = lemon::NetworkSimplex<lemon::SmartDigraph, Capacity, Weight>;
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<Vector2i>& 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<Weight> cost;
ArcMap<Capacity> capacity;
ArcMap<Capacity> flow;
ArcMap<std::pair<int, int>> variable;
std::vector<Node> nodes;
std::vector<Arc> edges;
};
#ifdef WITH_GUROBI
#include <gurobi_c++.h>
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<Vector2i>& edge_diff) { assert(0); };
private:
GRBEnv env = GRBEnv();
GRBModel model = GRBModel(env);
std::vector<GRBVar> vars;
std::vector<std::pair<int, int>> edges;
std::vector<std::vector<int>> 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<FlowInfo*> 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<int> vhash(num, 0);
std::vector<SearchInfo> 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<Vector2i>& 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<std::list<FlowInfo>> graph;
};
} // namespace qflow
#endif