Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/quadriflow/src/flow.hpp')
-rw-r--r--extern/quadriflow/src/flow.hpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/extern/quadriflow/src/flow.hpp b/extern/quadriflow/src/flow.hpp
new file mode 100644
index 00000000000..ab4a01cb4ed
--- /dev/null
+++ b/extern/quadriflow/src/flow.hpp
@@ -0,0 +1,375 @@
+#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