Add Chromium-only Blender WebEngine parity work
This commit is contained in:
558
blender-5.2.0/extern/quadriflow/patches/blender.patch
vendored
Normal file
558
blender-5.2.0/extern/quadriflow/patches/blender.patch
vendored
Normal file
@@ -0,0 +1,558 @@
|
||||
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
|
||||
index 35a73d9f308..0eeba8ab6c2 100644
|
||||
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
|
||||
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
|
||||
@@ -221,9 +221,8 @@ namespace lemon {
|
||||
const std::string &opt)
|
||||
{
|
||||
Opts::iterator o = _opts.find(opt);
|
||||
- Opts::iterator s = _opts.find(syn);
|
||||
LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
|
||||
- LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
|
||||
+ LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'");
|
||||
ParData p;
|
||||
p.help=opt;
|
||||
p.mandatory=false;
|
||||
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h
|
||||
index 355ee008246..a770bbee60c 100644
|
||||
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h
|
||||
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/bits/array_map.h
|
||||
@@ -88,7 +88,7 @@ namespace lemon {
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
- allocator.construct(&(values[id]), Value());
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,15 +218,15 @@ namespace lemon {
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int jd = nf->id(it);;
|
||||
if (id != jd) {
|
||||
- allocator.construct(&(new_values[jd]), values[jd]);
|
||||
- allocator.destroy(&(values[jd]));
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(new_values[jd]), values[jd]);
|
||||
+ std::allocator_traits<Allocator>::destroy(allocator, &(values[jd]));
|
||||
}
|
||||
}
|
||||
if (capacity != 0) allocator.deallocate(values, capacity);
|
||||
values = new_values;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
- allocator.construct(&(values[id]), Value());
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(values[id]), Value());
|
||||
}
|
||||
|
||||
// \brief Adds more new keys to the map.
|
||||
@@ -260,8 +260,8 @@ namespace lemon {
|
||||
}
|
||||
}
|
||||
if (found) continue;
|
||||
- allocator.construct(&(new_values[id]), values[id]);
|
||||
- allocator.destroy(&(values[id]));
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(new_values[id]), values[id]);
|
||||
+ std::allocator_traits<Allocator>::destroy(allocator, &(values[id]));
|
||||
}
|
||||
if (capacity != 0) allocator.deallocate(values, capacity);
|
||||
values = new_values;
|
||||
@@ -269,7 +269,7 @@ namespace lemon {
|
||||
}
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = nf->id(keys[i]);
|
||||
- allocator.construct(&(values[id]), Value());
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace lemon {
|
||||
// and it overrides the erase() member function of the observer base.
|
||||
virtual void erase(const Key& key) {
|
||||
int id = Parent::notifier()->id(key);
|
||||
- allocator.destroy(&(values[id]));
|
||||
+ std::allocator_traits<Allocator>::destroy(allocator, &(values[id]));
|
||||
}
|
||||
|
||||
// \brief Erase more keys from the map.
|
||||
@@ -289,7 +289,7 @@ namespace lemon {
|
||||
virtual void erase(const std::vector<Key>& keys) {
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = Parent::notifier()->id(keys[i]);
|
||||
- allocator.destroy(&(values[id]));
|
||||
+ std::allocator_traits<Allocator>::destroy(allocator, &(values[id]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ namespace lemon {
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
- allocator.construct(&(values[id]), Value());
|
||||
+ std::allocator_traits<Allocator>::construct(allocator, &(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ namespace lemon {
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);
|
||||
- allocator.destroy(&(values[id]));
|
||||
+ std::allocator_traits<Allocator>::destroy(allocator, &(values[id]));
|
||||
}
|
||||
allocator.deallocate(values, capacity);
|
||||
capacity = 0;
|
||||
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
|
||||
index 6ccad33e68e..388e990ec3b 100644
|
||||
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
|
||||
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
|
||||
@@ -234,7 +234,7 @@ namespace lemon {
|
||||
int in_arc, join, u_in, v_in, u_out, v_out;
|
||||
Value delta;
|
||||
|
||||
- const Value MAX;
|
||||
+ const Value MAX_VALUE;
|
||||
|
||||
public:
|
||||
|
||||
@@ -649,9 +649,9 @@ namespace lemon {
|
||||
NetworkSimplex(const GR& graph, bool arc_mixing = true) :
|
||||
_graph(graph), _node_id(graph), _arc_id(graph),
|
||||
_arc_mixing(arc_mixing),
|
||||
- MAX(std::numeric_limits<Value>::max()),
|
||||
+ MAX_VALUE(std::numeric_limits<Value>::max()),
|
||||
INF(std::numeric_limits<Value>::has_infinity ?
|
||||
- std::numeric_limits<Value>::infinity() : MAX)
|
||||
+ std::numeric_limits<Value>::infinity() : MAX_VALUE)
|
||||
{
|
||||
// Check the number types
|
||||
LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
|
||||
@@ -1076,9 +1076,9 @@ namespace lemon {
|
||||
for (int i = 0; i != _arc_num; ++i) {
|
||||
Value c = _lower[i];
|
||||
if (c >= 0) {
|
||||
- _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF;
|
||||
+ _cap[i] = _upper[i] < MAX_VALUE ? _upper[i] - c : INF;
|
||||
} else {
|
||||
- _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF;
|
||||
+ _cap[i] = _upper[i] < MAX_VALUE + c ? _upper[i] - c : INF;
|
||||
}
|
||||
_supply[_source[i]] -= c;
|
||||
_supply[_target[i]] += c;
|
||||
@@ -1282,7 +1282,7 @@ namespace lemon {
|
||||
d = _flow[e];
|
||||
if (_pred_dir[u] == DIR_DOWN) {
|
||||
c = _cap[e];
|
||||
- d = c >= MAX ? INF : c - d;
|
||||
+ d = c >= MAX_VALUE ? INF : c - d;
|
||||
}
|
||||
if (d < delta) {
|
||||
delta = d;
|
||||
@@ -1297,7 +1297,7 @@ namespace lemon {
|
||||
d = _flow[e];
|
||||
if (_pred_dir[u] == DIR_UP) {
|
||||
c = _cap[e];
|
||||
- d = c >= MAX ? INF : c - d;
|
||||
+ d = c >= MAX_VALUE ? INF : c - d;
|
||||
}
|
||||
if (d <= delta) {
|
||||
delta = d;
|
||||
@@ -1559,7 +1559,7 @@ namespace lemon {
|
||||
_pi[_target[in_arc]]) >= 0) continue;
|
||||
findJoinNode();
|
||||
bool change = findLeavingArc();
|
||||
- if (delta >= MAX) return false;
|
||||
+ if (delta >= MAX_VALUE) return false;
|
||||
changeFlow(change);
|
||||
if (change) {
|
||||
updateTreeStructure();
|
||||
@@ -1598,7 +1598,7 @@ namespace lemon {
|
||||
while (pivot.findEnteringArc()) {
|
||||
findJoinNode();
|
||||
bool change = findLeavingArc();
|
||||
- if (delta >= MAX) return UNBOUNDED;
|
||||
+ if (delta >= MAX_VALUE) return UNBOUNDED;
|
||||
changeFlow(change);
|
||||
if (change) {
|
||||
updateTreeStructure();
|
||||
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h
|
||||
index 8de74ede8a9..f9861f39169 100644
|
||||
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h
|
||||
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/random.h
|
||||
@@ -249,8 +249,8 @@ namespace lemon {
|
||||
|
||||
current = state + length;
|
||||
|
||||
- register Word *curr = state + length - 1;
|
||||
- register long num;
|
||||
+ Word *curr = state + length - 1;
|
||||
+ long num;
|
||||
|
||||
num = length - shift;
|
||||
while (num--) {
|
||||
diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
|
||||
index c333256a139..70a9628320f 100644
|
||||
--- a/extern/quadriflow/src/hierarchy.cpp
|
||||
+++ b/extern/quadriflow/src/hierarchy.cpp
|
||||
@@ -269,7 +269,13 @@ void Hierarchy::DownsampleGraph(const AdjacentMatrix adj, const MatrixXd& V, con
|
||||
for (auto it = ad.begin(); it != ad.end(); ++it, ++entry_it) {
|
||||
int k = it->id;
|
||||
double dp = N.col(i).dot(N.col(k));
|
||||
- double ratio = A[i] > A[k] ? (A[i] / A[k]) : (A[k] / A[i]);
|
||||
+ double ratio;
|
||||
+ if (A[i] > A[k]) {
|
||||
+ ratio = (A[k] == 0.0f) ? 1.0f : A[i] / A[k];
|
||||
+ }
|
||||
+ else {
|
||||
+ ratio = (A[i] == 0.0f) ? 1.0f : A[k] / A[i];
|
||||
+ }
|
||||
*entry_it = Entry(i, k, dp * ratio);
|
||||
}
|
||||
}
|
||||
@@ -1133,7 +1139,8 @@ void Hierarchy::propagateConstraints() {
|
||||
auto& COw = mCOw[l];
|
||||
auto& COw_next = mCOw[l + 1];
|
||||
auto& toUpper = mToUpper[l];
|
||||
- MatrixXd& S = mS[l];
|
||||
+ // FIXME
|
||||
+ // MatrixXd& S = mS[l];
|
||||
|
||||
for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
|
||||
Vector2i upper = toUpper.col(i);
|
||||
diff --git a/extern/quadriflow/src/loader.cpp b/extern/quadriflow/src/loader.cpp
|
||||
index aa27066e6e4..5b9d717db71 100644
|
||||
--- a/extern/quadriflow/src/loader.cpp
|
||||
+++ b/extern/quadriflow/src/loader.cpp
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "loader.hpp"
|
||||
|
||||
+#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -69,7 +70,7 @@ void load(const char* filename, MatrixXd& V, MatrixXi& F)
|
||||
};
|
||||
|
||||
/// Hash function for obj_vertex
|
||||
- struct obj_vertexHash : std::unary_function<obj_vertex, size_t> {
|
||||
+ struct obj_vertexHash {
|
||||
std::size_t operator()(const obj_vertex &v) const {
|
||||
size_t hash = std::hash<uint32_t>()(v.p);
|
||||
hash = hash * 37 + std::hash<uint32_t>()(v.uv);
|
||||
diff --git a/extern/quadriflow/src/flow.hpp b/extern/quadriflow/src/flow.hpp
|
||||
index ab4a01c..a77f7ae 100644
|
||||
--- a/extern/quadriflow/src/flow.hpp
|
||||
+++ b/extern/quadriflow/src/flow.hpp
|
||||
@@ -7,17 +7,12 @@
|
||||
#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 "../patches/boykov_kolmogorov_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 {
|
||||
@@ -34,78 +29,52 @@ class MaxFlowHelper {
|
||||
|
||||
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;
|
||||
+ BoykovMaxFlowHelper() = default;
|
||||
+ void resize(int n, int m) override {
|
||||
+ num_verts = n;
|
||||
+ num_edges = 0;
|
||||
+ flow.resize(num_verts, m * 2);
|
||||
}
|
||||
- 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;
|
||||
+ int compute() override {
|
||||
+ return flow.max_flow(0, num_verts - 1);
|
||||
}
|
||||
- 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);
|
||||
+ void addEdge(int x, int y, int c, int rc, int v, int cost = 1) override {
|
||||
+ const int e1 = num_edges++;
|
||||
+ const int e2 = num_edges++;
|
||||
+ flow.set_edge(e1, e2, x, y, c);
|
||||
+ flow.set_edge(e2, e1, y, x, rc);
|
||||
if (v != -1) {
|
||||
- edge_to_variables[e1] = std::make_pair(v, -1);
|
||||
- edge_to_variables[e2] = std::make_pair(v, 1);
|
||||
+ edge_to_variables.emplace_back(v, -1);
|
||||
+ edge_to_variables.emplace_back(v, 1);
|
||||
+ }
|
||||
+ else {
|
||||
+ edge_to_variables.emplace_back(-1, -1);
|
||||
+ edge_to_variables.emplace_back(-1, -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]);
|
||||
+ void applyTo(std::vector<Vector2i>& edge_diff) override {
|
||||
+ for (int vert = 0; vert < num_verts; vert++) {
|
||||
+ for (int edge : flow.vertex_out_edges(vert)) {
|
||||
+ const int capacity = flow.edge_capacity(edge);
|
||||
+ const int residual_capacity = flow.edge_residual_capacity(edge);
|
||||
+ if (capacity > 0) {
|
||||
+ int flow = (capacity - residual_capacity);
|
||||
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;
|
||||
+ std::pair<int, int> e2v = edge_to_variables[edge];
|
||||
+ if (e2v.first != -1) {
|
||||
+ edge_diff[e2v.first / 2][e2v.first % 2] += e2v.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;
|
||||
+ BoykovKolmogorovMaxFlow flow;
|
||||
+ std::vector<std::pair<int, int>> edge_to_variables;
|
||||
+ int num_verts = 0;
|
||||
+ int num_edges = 0;
|
||||
};
|
||||
|
||||
class NetworkSimplexFlowHelper : public MaxFlowHelper {
|
||||
diff --git a/extern/quadriflow/src/main.cpp b/extern/quadriflow/src/main.cpp
|
||||
index 18bc4063c42..63c9e61b8c9 100644
|
||||
--- a/extern/quadriflow/src/main.cpp
|
||||
+++ b/extern/quadriflow/src/main.cpp
|
||||
@@ -110,7 +110,10 @@ int main(int argc, char** argv) {
|
||||
printf("Use %lf seconds\n", (t2 - t1) * 1e-3);
|
||||
t1 = GetCurrentTime64();
|
||||
printf("Solve index map...\n");
|
||||
- field.ComputeIndexMap();
|
||||
+ if (!field.ComputeIndexMap()) {
|
||||
+ fprintf(stderr, "Failed to solve result, exiting!\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
t2 = GetCurrentTime64();
|
||||
printf("Indexmap Use %lf seconds\n", (t2 - t1) * 1e-3);
|
||||
printf("Writing the file...\n");
|
||||
diff --git a/extern/quadriflow/src/parametrizer.cpp b/extern/quadriflow/src/parametrizer.cpp
|
||||
index b85383566c9..3dbdc386eca 100644
|
||||
--- a/extern/quadriflow/src/parametrizer.cpp
|
||||
+++ b/extern/quadriflow/src/parametrizer.cpp
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
namespace qflow {
|
||||
|
||||
-void Parametrizer::ComputeIndexMap(int with_scale) {
|
||||
+bool Parametrizer::ComputeIndexMap(int with_scale) {
|
||||
// build edge info
|
||||
auto& V = hierarchy.mV[0];
|
||||
auto& F = hierarchy.mF;
|
||||
@@ -80,9 +80,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) {
|
||||
#ifdef LOG_OUTPUT
|
||||
printf("subdivide...\n");
|
||||
#endif
|
||||
- subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
|
||||
- edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges,
|
||||
- singularities, 1);
|
||||
+ if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
|
||||
+ edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges,
|
||||
+ singularities, 1))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
allow_changes.clear();
|
||||
allow_changes.resize(edge_diff.size() * 2, 1);
|
||||
@@ -99,9 +102,12 @@ void Parametrizer::ComputeIndexMap(int with_scale) {
|
||||
int t1 = GetCurrentTime64();
|
||||
#endif
|
||||
FixFlipHierarchy();
|
||||
- subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
|
||||
+ if (!subdivide_edgeDiff(F, V, N, Q, O, &hierarchy.mS[0], V2E, hierarchy.mE2E, boundary, nonManifold,
|
||||
edge_diff, edge_values, face_edgeOrients, face_edgeIds, sharp_edges,
|
||||
- singularities, 1);
|
||||
+ singularities, 1))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
FixFlipSat();
|
||||
|
||||
#ifdef LOG_OUTPUT
|
||||
@@ -242,6 +248,7 @@ void Parametrizer::ComputeIndexMap(int with_scale) {
|
||||
// E2E_compact,
|
||||
// V, N, Q, O, F, V2E, hierarchy.mE2E, disajoint_tree,
|
||||
// hierarchy.mScale, false);
|
||||
+ return true;
|
||||
}
|
||||
|
||||
} // namespace qflow
|
||||
diff --git a/extern/quadriflow/src/parametrizer.hpp b/extern/quadriflow/src/parametrizer.hpp
|
||||
index 1f4a02be6c2..9703ebbfff6 100644
|
||||
--- a/extern/quadriflow/src/parametrizer.hpp
|
||||
+++ b/extern/quadriflow/src/parametrizer.hpp
|
||||
@@ -54,7 +54,8 @@ class Parametrizer {
|
||||
void ComputePositionSingularities();
|
||||
|
||||
// Integer Grid Map Pipeline
|
||||
- void ComputeIndexMap(int with_scale = 0);
|
||||
+ // Return false when the solver fails.
|
||||
+ bool ComputeIndexMap(int with_scale = 0);
|
||||
void BuildEdgeInfo();
|
||||
void ComputeMaxFlow();
|
||||
void MarkInteger();
|
||||
diff --git a/extern/quadriflow/src/post-solver.cpp b/extern/quadriflow/src/post-solver.cpp
|
||||
index 6027ddd..ccefd15 100644
|
||||
--- a/extern/quadriflow/src/post-solver.cpp
|
||||
+++ b/extern/quadriflow/src/post-solver.cpp
|
||||
@@ -5,7 +5,9 @@
|
||||
// Created by Jingwei on 2/5/18.
|
||||
//
|
||||
#include <algorithm>
|
||||
+#ifdef POST_SOLVER
|
||||
#include <boost/program_options.hpp>
|
||||
+#endif
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
diff --git a/extern/quadriflow/src/subdivide.cpp b/extern/quadriflow/src/subdivide.cpp
|
||||
index c408bbc6394..babff96ccb4 100644
|
||||
--- a/extern/quadriflow/src/subdivide.cpp
|
||||
+++ b/extern/quadriflow/src/subdivide.cpp
|
||||
@@ -145,7 +145,7 @@ void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi
|
||||
E2E.conservativeResize(nF * 3);
|
||||
}
|
||||
|
||||
-void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
|
||||
+bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
|
||||
VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold,
|
||||
std::vector<Vector2i> &edge_diff, std::vector<DEdge> &edge_values,
|
||||
std::vector<Vector3i> &face_edgeOrients, std::vector<Vector3i> &face_edgeIds,
|
||||
@@ -500,17 +500,18 @@ void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, Matr
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
auto diff = edge_diff[face_edgeIds[i][j]];
|
||||
if (abs(diff[0]) > 1 || abs(diff[1]) > 1) {
|
||||
- printf("wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j);
|
||||
- exit(0);
|
||||
+ fprintf(stderr, "wrong init %d %d!\n", face_edgeIds[i][j], i * 3 + j);
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < edge_diff.size(); ++i) {
|
||||
if (abs(edge_diff[i][0]) > 1 || abs(edge_diff[i][1]) > 1) {
|
||||
- printf("wrong...\n");
|
||||
- exit(0);
|
||||
+ fprintf(stderr, "wrong...\n");
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
+ return true;
|
||||
}
|
||||
|
||||
} // namespace qflow
|
||||
diff --git a/extern/quadriflow/src/subdivide.hpp b/extern/quadriflow/src/subdivide.hpp
|
||||
index a93c58ac2a7..8c682b6d9f2 100644
|
||||
--- a/extern/quadriflow/src/subdivide.hpp
|
||||
+++ b/extern/quadriflow/src/subdivide.hpp
|
||||
@@ -9,7 +9,8 @@ namespace qflow {
|
||||
void subdivide(MatrixXi &F, MatrixXd &V, VectorXd& rho, VectorXi &V2E, VectorXi &E2E, VectorXi &boundary,
|
||||
VectorXi &nonmanifold, double maxLength);
|
||||
|
||||
-void subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
|
||||
+// Return false when solving fails.
|
||||
+bool subdivide_edgeDiff(MatrixXi &F, MatrixXd &V, MatrixXd &N, MatrixXd &Q, MatrixXd &O, MatrixXd* S,
|
||||
VectorXi &V2E, VectorXi &E2E, VectorXi &boundary, VectorXi &nonmanifold,
|
||||
std::vector<Vector2i> &edge_diff, std::vector<DEdge> &edge_values,
|
||||
std::vector<Vector3i> &face_edgeOrients, std::vector<Vector3i> &face_edgeIds,
|
||||
diff --git a/extern/quadriflow/src/optimizer.cpp b/extern/quadriflow/src/optimizer.cpp
|
||||
index 1c59ad0f70c..f8836ed0d0e 100644
|
||||
--- a/extern/quadriflow/src/optimizer.cpp
|
||||
+++ b/extern/quadriflow/src/optimizer.cpp
|
||||
@@ -1296,7 +1296,9 @@ void Optimizer::optimize_integer_constraints(Hierarchy& mRes, std::map<int, int>
|
||||
solver = std::make_unique<GurobiFlowHelper>();
|
||||
}
|
||||
#endif
|
||||
- solver->resize(initial.size() + 2, arc_ids.size());
|
||||
+ /* This used to be arc_ids.size() which is wrong, the loop below adds
|
||||
+ * exactly arcs.size() edges. */
|
||||
+ solver->resize(initial.size() + 2, arcs.size());
|
||||
|
||||
std::set<int> ids;
|
||||
for (int i = 0; i < arcs.size(); ++i) {
|
||||
diff --git a/extern/quadriflow/src/field-math.hpp b/extern/quadriflow/src/field-math.hpp
|
||||
index 86ed4b2b1f4..3f4fe3fa097 100644
|
||||
--- a/extern/quadriflow/src/field-math.hpp
|
||||
+++ b/extern/quadriflow/src/field-math.hpp
|
||||
@@ -292,7 +292,6 @@ inline Vector3d Travel(Vector3d p, const Vector3d &dir, double &len, int &f, Vec
|
||||
double max_len = 1e30;
|
||||
bool found = false;
|
||||
int next_id, next_f;
|
||||
- Vector3d next_q;
|
||||
Matrix3d m, n;
|
||||
m.col(0) = t1;
|
||||
m.col(1) = t2;
|
||||
@@ -399,7 +398,6 @@ inline Vector3d TravelField(Vector3d p, Vector3d &pt, double &len, int &f, Vecto
|
||||
double max_len = 1e30;
|
||||
bool found = false;
|
||||
int next_id = -1, next_f = -1;
|
||||
- Vector3d next_q;
|
||||
Matrix3d m, n;
|
||||
m.col(0) = t1;
|
||||
m.col(1) = t2;
|
||||
693
blender-5.2.0/extern/quadriflow/patches/boykov_kolmogorov_max_flow.hpp
vendored
Normal file
693
blender-5.2.0/extern/quadriflow/patches/boykov_kolmogorov_max_flow.hpp
vendored
Normal file
@@ -0,0 +1,693 @@
|
||||
// SPDX-FileCopyrightText: 2006 Stephan Diederich
|
||||
// SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Adapted from boost::graph
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace qflow {
|
||||
|
||||
class BoykovKolmogorovMaxFlow {
|
||||
// Types
|
||||
enum class Color { white, black, gray };
|
||||
|
||||
struct Edge {
|
||||
int source;
|
||||
int target;
|
||||
};
|
||||
|
||||
const int NULL_VERTEX = -1;
|
||||
const int NULL_EDGE = -1;
|
||||
|
||||
public:
|
||||
BoykovKolmogorovMaxFlow() = default;
|
||||
|
||||
void resize(int num_verts, int num_edges)
|
||||
{
|
||||
m_graph_edges.resize(num_edges);
|
||||
m_graph_out_edges.resize(num_verts);
|
||||
m_cap_map.resize(num_edges);
|
||||
m_res_cap_map.resize(num_edges);
|
||||
m_rev_edge_map.resize(num_edges);
|
||||
m_pre_map.resize(num_verts, 0);
|
||||
m_tree_map.resize(num_verts, Color::gray);
|
||||
m_dist_map.resize(num_verts, 0);
|
||||
m_in_active_list_map.resize(num_verts, false);
|
||||
m_has_parent_map.resize(num_verts, false);
|
||||
m_time_map.resize(num_verts, 0);
|
||||
}
|
||||
|
||||
void set_edge(const int edge,
|
||||
const int reverse_edge,
|
||||
const int source,
|
||||
const int target,
|
||||
const int capacity)
|
||||
{
|
||||
assert(edge < m_graph_edges.size());
|
||||
|
||||
m_graph_edges[edge] = Edge{source, target};
|
||||
m_graph_out_edges[source].push_back(edge);
|
||||
m_rev_edge_map[edge] = reverse_edge;
|
||||
|
||||
// Initialize flow to zero which means initializing
|
||||
// the residual capacity equal to the capacity
|
||||
m_cap_map[edge] = capacity;
|
||||
m_res_cap_map[edge] = capacity;
|
||||
}
|
||||
|
||||
int edge_capacity(const int edge)
|
||||
{
|
||||
return m_cap_map[edge];
|
||||
}
|
||||
|
||||
int edge_residual_capacity(const int edge)
|
||||
{
|
||||
return m_res_cap_map[edge];
|
||||
}
|
||||
|
||||
const std::vector<int> &vertex_out_edges(const int vertex)
|
||||
{
|
||||
return m_graph_out_edges[vertex];
|
||||
}
|
||||
|
||||
int max_flow(int src, int sink)
|
||||
{
|
||||
m_source = src;
|
||||
m_sink = sink;
|
||||
|
||||
// init the search trees with the two terminals
|
||||
m_tree_map[m_source] = Color::black;
|
||||
m_tree_map[m_sink] = Color::white;
|
||||
m_time_map[m_source] = 1;
|
||||
m_time_map[m_sink] = 1;
|
||||
|
||||
// augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
|
||||
augment_direct_paths();
|
||||
// start the main-loop
|
||||
while (true) {
|
||||
bool path_found;
|
||||
int connecting_edge;
|
||||
std::tie(connecting_edge, path_found) = grow(); // find a path from source to sink
|
||||
if (!path_found) {
|
||||
// we're finished, no more paths were found
|
||||
break;
|
||||
}
|
||||
++m_time;
|
||||
augment(connecting_edge); // augment that path
|
||||
adopt(); // rebuild search tree structure
|
||||
}
|
||||
return m_flow;
|
||||
}
|
||||
|
||||
protected:
|
||||
int lookup_edge(int source, int target)
|
||||
{
|
||||
for (const int e : m_graph_out_edges[source]) {
|
||||
if (m_graph_edges[e].target == target) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return NULL_EDGE;
|
||||
}
|
||||
|
||||
void augment_direct_paths()
|
||||
{
|
||||
// in a first step, we augment all direct paths from
|
||||
// source->NODE->sink and additionally paths from source->sink. This
|
||||
// improves especially graphcuts for segmentation, as most of the
|
||||
// nodes have source/sink connects but shouldn't have an impact on
|
||||
// other maxflow problems (this is done in grow() anyway)
|
||||
for (const int ei : m_graph_out_edges[m_source]) {
|
||||
int from_source = ei;
|
||||
int current_node = m_graph_edges[from_source].target;
|
||||
if (current_node == m_sink) {
|
||||
int cap = m_res_cap_map[from_source];
|
||||
m_res_cap_map[from_source] = 0;
|
||||
m_flow += cap;
|
||||
continue;
|
||||
}
|
||||
const int to_sink = lookup_edge(current_node, m_sink);
|
||||
if (to_sink != NULL_EDGE) {
|
||||
int cap_from_source = m_res_cap_map[from_source];
|
||||
int cap_to_sink = m_res_cap_map[to_sink];
|
||||
if (cap_from_source > cap_to_sink) {
|
||||
m_tree_map[current_node] = Color::black;
|
||||
add_active_node(current_node);
|
||||
set_edge_to_parent(current_node, from_source);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
// add stuff to flow and update residuals. we dont need
|
||||
// to update reverse_edges, as incoming/outgoing edges
|
||||
// to/from source/sink don't count for max-flow
|
||||
m_res_cap_map[from_source] = m_res_cap_map[from_source] - cap_to_sink;
|
||||
m_res_cap_map[to_sink] = 0;
|
||||
m_flow += cap_to_sink;
|
||||
}
|
||||
else if (cap_to_sink > 0) {
|
||||
m_tree_map[current_node] = Color::white;
|
||||
add_active_node(current_node);
|
||||
set_edge_to_parent(current_node, to_sink);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
// add stuff to flow and update residuals. we dont need
|
||||
// to update reverse_edges, as incoming/outgoing edges
|
||||
// to/from source/sink don't count for max-flow
|
||||
m_res_cap_map[to_sink] = m_res_cap_map[to_sink] - cap_from_source;
|
||||
m_res_cap_map[from_source] = 0;
|
||||
m_flow += cap_from_source;
|
||||
}
|
||||
}
|
||||
else if (m_res_cap_map[from_source]) {
|
||||
// there is no sink connect, so we can't augment this path,
|
||||
// but to avoid adding m_source to the active nodes, we just
|
||||
// activate this node and set the approciate things
|
||||
m_tree_map[current_node] = Color::black;
|
||||
set_edge_to_parent(current_node, from_source);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
add_active_node(current_node);
|
||||
}
|
||||
}
|
||||
for (const int ei : m_graph_out_edges[m_sink]) {
|
||||
int to_sink = m_rev_edge_map[ei];
|
||||
int current_node = m_graph_edges[to_sink].source;
|
||||
if (m_res_cap_map[to_sink]) {
|
||||
m_tree_map[current_node] = Color::white;
|
||||
set_edge_to_parent(current_node, to_sink);
|
||||
m_dist_map[current_node] = 1;
|
||||
m_time_map[current_node] = 1;
|
||||
add_active_node(current_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pair of an edge and a boolean. if the bool is true, the
|
||||
* edge is a connection of a found path from s->t , read "the link" and
|
||||
* m_graph_edges[returnVal].source is the end of the path found in the
|
||||
* source-tree m_graph_edges[returnVal].target is the beginning of the path found
|
||||
* in the sink-tree
|
||||
*/
|
||||
std::pair<int, bool> grow()
|
||||
{
|
||||
assert(m_orphans.empty());
|
||||
int current_node;
|
||||
while ((current_node = get_next_active_node()) != NULL_VERTEX) { // if there is one
|
||||
assert(m_tree_map[current_node] != Color::gray &&
|
||||
(has_parent(current_node) || current_node == m_source || current_node == m_sink));
|
||||
|
||||
if (m_tree_map[current_node] == Color::black) {
|
||||
// source tree growing
|
||||
if (current_node != m_last_grow_vertex) {
|
||||
m_last_grow_vertex = current_node;
|
||||
m_last_grow_out_edge = 0;
|
||||
}
|
||||
const std::vector<int> &out_edges = m_graph_out_edges[m_last_grow_vertex];
|
||||
for (; m_last_grow_out_edge < out_edges.size(); m_last_grow_out_edge++) {
|
||||
int out_edge = out_edges[m_last_grow_out_edge];
|
||||
if (m_res_cap_map[out_edge] > 0) { // check if we have capacity left on this edge
|
||||
int other_node = m_graph_edges[out_edge].target;
|
||||
if (m_tree_map[other_node] == Color::gray) { // it's a free node
|
||||
// aquire other node to our search tree
|
||||
m_tree_map[other_node] = Color::black;
|
||||
set_edge_to_parent(other_node, out_edge); // set us as parent
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1; // and update the
|
||||
// distance-heuristic
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
add_active_node(other_node);
|
||||
}
|
||||
else if (m_tree_map[other_node] == Color::black) {
|
||||
// we do this to get shorter paths. check if we
|
||||
// are nearer to the source as its parent is
|
||||
if (is_closer_to_terminal(current_node, other_node)) {
|
||||
set_edge_to_parent(other_node, out_edge);
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1;
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(m_tree_map[other_node] == Color::white);
|
||||
// kewl, found a path from one to the other
|
||||
// search tree, return
|
||||
// the connecting edge in src->sink dir
|
||||
return std::make_pair(out_edge, true);
|
||||
}
|
||||
}
|
||||
} // for all out-edges
|
||||
} // source-tree-growing
|
||||
else {
|
||||
assert(m_tree_map[current_node] == Color::white);
|
||||
if (current_node != m_last_grow_vertex) {
|
||||
m_last_grow_vertex = current_node;
|
||||
m_last_grow_out_edge = 0;
|
||||
}
|
||||
const std::vector<int> &out_edges = m_graph_out_edges[m_last_grow_vertex];
|
||||
for (; m_last_grow_out_edge < out_edges.size(); m_last_grow_out_edge++) {
|
||||
int in_edge = m_rev_edge_map[out_edges[m_last_grow_out_edge]];
|
||||
if (m_res_cap_map[in_edge] > 0) { // check if there is capacity left
|
||||
int other_node = m_graph_edges[in_edge].source;
|
||||
if (m_tree_map[other_node] == Color::gray) { // it's a free node
|
||||
// aquire other node to our search tree
|
||||
m_tree_map[other_node] = Color::white;
|
||||
set_edge_to_parent(other_node, in_edge); // set us as parent
|
||||
add_active_node(other_node); // activate that node
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1; // set its distance
|
||||
m_time_map[other_node] = m_time_map[current_node]; // and time
|
||||
}
|
||||
else if (m_tree_map[other_node] == Color::white) {
|
||||
if (is_closer_to_terminal(current_node, other_node)) {
|
||||
// we are closer to the sink than its parent
|
||||
// is, so we "adopt" him
|
||||
set_edge_to_parent(other_node, in_edge);
|
||||
m_dist_map[other_node] = m_dist_map[current_node] + 1;
|
||||
m_time_map[other_node] = m_time_map[current_node];
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(m_tree_map[other_node] == Color::black);
|
||||
// kewl, found a path from one to the other
|
||||
// search tree,
|
||||
// return the connecting edge in src->sink dir
|
||||
return std::make_pair(in_edge, true);
|
||||
}
|
||||
}
|
||||
} // for all out-edges
|
||||
} // sink-tree growing
|
||||
|
||||
// all edges of that node are processed, and no more paths were
|
||||
// found.
|
||||
// remove if from the front of the active queue
|
||||
finish_node(current_node);
|
||||
} // while active_nodes not empty
|
||||
|
||||
// no active nodes anymore and no path found, we're done
|
||||
return std::make_pair(int(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* augments path from s->t and updates residual graph
|
||||
* m_graph_edges[e].source is the end of the path found in the source-tree
|
||||
* m_graph_edges[e].target is the beginning of the path found in the sink-tree
|
||||
* this phase generates orphans on satured edges, if the attached verts
|
||||
* are from different search-trees orphans are ordered in distance to
|
||||
* sink/source. first the farest from the source are front_inserted into
|
||||
* the orphans list, and after that the sink-tree-orphans are
|
||||
* front_inserted. when going to adoption stage the orphans are
|
||||
* popped_front, and so we process the nearest verts to the terminals
|
||||
* first
|
||||
*/
|
||||
void augment(int e)
|
||||
{
|
||||
assert(m_tree_map[m_graph_edges[e].target] == Color::white);
|
||||
assert(m_tree_map[m_graph_edges[e].source] == Color::black);
|
||||
assert(m_orphans.empty());
|
||||
|
||||
const int bottleneck = find_bottleneck(e);
|
||||
// now we push the found flow through the path
|
||||
// for each edge we saturate we have to look for the verts that
|
||||
// belong to that edge, one of them becomes an orphans now process
|
||||
// the connecting edge
|
||||
m_res_cap_map[e] = m_res_cap_map[e] - bottleneck;
|
||||
assert(m_res_cap_map[e] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[e]] = m_res_cap_map[m_rev_edge_map[e]] + bottleneck;
|
||||
|
||||
// now we follow the path back to the source
|
||||
int current_node = m_graph_edges[e].source;
|
||||
while (current_node != m_source) {
|
||||
int pred = get_edge_to_parent(current_node);
|
||||
m_res_cap_map[pred] = m_res_cap_map[pred] - bottleneck;
|
||||
assert(m_res_cap_map[pred] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[pred]] = m_res_cap_map[m_rev_edge_map[pred]] + bottleneck;
|
||||
if (m_res_cap_map[pred] == 0) {
|
||||
set_no_parent(current_node);
|
||||
m_orphans.push_front(current_node);
|
||||
}
|
||||
current_node = m_graph_edges[pred].source;
|
||||
}
|
||||
// then go forward in the sink-tree
|
||||
current_node = m_graph_edges[e].target;
|
||||
while (current_node != m_sink) {
|
||||
int pred = get_edge_to_parent(current_node);
|
||||
m_res_cap_map[pred] = m_res_cap_map[pred] - bottleneck;
|
||||
assert(m_res_cap_map[pred] >= 0);
|
||||
m_res_cap_map[m_rev_edge_map[pred]] = m_res_cap_map[m_rev_edge_map[pred]] + bottleneck;
|
||||
if (m_res_cap_map[pred] == 0) {
|
||||
set_no_parent(current_node);
|
||||
m_orphans.push_front(current_node);
|
||||
}
|
||||
current_node = m_graph_edges[pred].target;
|
||||
}
|
||||
// and add it to the max-flow
|
||||
m_flow += bottleneck;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the bottleneck of a s->t path (end_of_path is last vertex in
|
||||
* source-tree, begin_of_path is first vertex in sink-tree)
|
||||
*/
|
||||
int find_bottleneck(int e)
|
||||
{
|
||||
int minimum_cap = m_res_cap_map[e];
|
||||
int current_node = m_graph_edges[e].source;
|
||||
// first go back in the source tree
|
||||
while (current_node != m_source) {
|
||||
int pred = get_edge_to_parent(current_node);
|
||||
minimum_cap = std::min(minimum_cap, m_res_cap_map[pred]);
|
||||
current_node = m_graph_edges[pred].source;
|
||||
}
|
||||
// then go forward in the sink-tree
|
||||
current_node = m_graph_edges[e].target;
|
||||
while (current_node != m_sink) {
|
||||
int pred = get_edge_to_parent(current_node);
|
||||
minimum_cap = std::min(minimum_cap, m_res_cap_map[pred]);
|
||||
current_node = m_graph_edges[pred].target;
|
||||
}
|
||||
return minimum_cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* rebuild search trees
|
||||
* empty the queue of orphans, and find new parents for them or just
|
||||
* drop them from the search trees
|
||||
*/
|
||||
void adopt()
|
||||
{
|
||||
while (!m_orphans.empty() || !m_child_orphans.empty()) {
|
||||
int current_node;
|
||||
if (m_child_orphans.empty()) {
|
||||
// get the next orphan from the main-queue and remove it
|
||||
current_node = m_orphans.front();
|
||||
m_orphans.pop_front();
|
||||
}
|
||||
else {
|
||||
current_node = m_child_orphans.front();
|
||||
m_child_orphans.pop();
|
||||
}
|
||||
if (m_tree_map[current_node] == Color::black) {
|
||||
// we're in the source-tree
|
||||
int min_distance = (std::numeric_limits<int>::max)();
|
||||
int new_parent_edge;
|
||||
for (const int ei : m_graph_out_edges[current_node]) {
|
||||
const int in_edge = m_rev_edge_map[ei];
|
||||
assert(m_graph_edges[in_edge].target == current_node); // we should be the target of
|
||||
// this edge
|
||||
if (m_res_cap_map[in_edge] > 0) {
|
||||
int other_node = m_graph_edges[in_edge].source;
|
||||
if (m_tree_map[other_node] == Color::black && has_source_connect(other_node)) {
|
||||
if (m_dist_map[other_node] < min_distance) {
|
||||
min_distance = m_dist_map[other_node];
|
||||
new_parent_edge = in_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (min_distance != (std::numeric_limits<int>::max)()) {
|
||||
set_edge_to_parent(current_node, new_parent_edge);
|
||||
m_dist_map[current_node] = min_distance + 1;
|
||||
m_time_map[current_node] = m_time;
|
||||
}
|
||||
else {
|
||||
m_time_map[current_node] = 0;
|
||||
for (const int ei : m_graph_out_edges[current_node]) {
|
||||
int in_edge = m_rev_edge_map[ei];
|
||||
int other_node = m_graph_edges[in_edge].source;
|
||||
if (m_tree_map[other_node] == Color::black && other_node != m_source) {
|
||||
if (m_res_cap_map[in_edge] > 0) {
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if (has_parent(other_node) &&
|
||||
m_graph_edges[get_edge_to_parent(other_node)].source == current_node)
|
||||
{
|
||||
// we are the parent of that node
|
||||
// it has to find a new parent, too
|
||||
set_no_parent(other_node);
|
||||
m_child_orphans.push(other_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_tree_map[current_node] = Color::gray;
|
||||
} // no parent found
|
||||
} // source-tree-adoption
|
||||
else {
|
||||
// now we should be in the sink-tree, check that...
|
||||
assert(m_tree_map[current_node] == Color::white);
|
||||
int new_parent_edge;
|
||||
int min_distance = (std::numeric_limits<int>::max)();
|
||||
for (const int ei : m_graph_out_edges[current_node]) {
|
||||
const int out_edge = ei;
|
||||
if (m_res_cap_map[out_edge] > 0) {
|
||||
const int other_node = m_graph_edges[out_edge].target;
|
||||
if (m_tree_map[other_node] == Color::white && has_sink_connect(other_node)) {
|
||||
if (m_dist_map[other_node] < min_distance) {
|
||||
min_distance = m_dist_map[other_node];
|
||||
new_parent_edge = out_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (min_distance != (std::numeric_limits<int>::max)()) {
|
||||
set_edge_to_parent(current_node, new_parent_edge);
|
||||
m_dist_map[current_node] = min_distance + 1;
|
||||
m_time_map[current_node] = m_time;
|
||||
}
|
||||
else {
|
||||
m_time_map[current_node] = 0;
|
||||
for (const int ei : m_graph_out_edges[current_node]) {
|
||||
const int out_edge = ei;
|
||||
const int other_node = m_graph_edges[out_edge].target;
|
||||
if (m_tree_map[other_node] == Color::white && other_node != m_sink) {
|
||||
if (m_res_cap_map[out_edge] > 0) {
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if (has_parent(other_node) &&
|
||||
m_graph_edges[get_edge_to_parent(other_node)].target == current_node)
|
||||
{
|
||||
// we were it's parent, so it has to find a
|
||||
// new one, too
|
||||
set_no_parent(other_node);
|
||||
m_child_orphans.push(other_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_tree_map[current_node] = Color::gray;
|
||||
} // no parent found
|
||||
} // sink-tree adoption
|
||||
} // while !orphans.empty()
|
||||
} // adopt
|
||||
|
||||
/**
|
||||
* return next active vertex if there is one, otherwise a null_vertex
|
||||
*/
|
||||
int get_next_active_node()
|
||||
{
|
||||
while (true) {
|
||||
if (m_active_nodes.empty()) {
|
||||
return NULL_VERTEX;
|
||||
}
|
||||
int v = m_active_nodes.front();
|
||||
|
||||
// if it has no parent, this node can't be active (if its not
|
||||
// source or sink)
|
||||
if (!has_parent(v) && v != m_source && v != m_sink) {
|
||||
m_active_nodes.pop();
|
||||
m_in_active_list_map[v] = false;
|
||||
}
|
||||
else {
|
||||
assert(m_tree_map[v] == Color::black || m_tree_map[v] == Color::white);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds v as an active vertex, but only if its not in the list already
|
||||
*/
|
||||
void add_active_node(int v)
|
||||
{
|
||||
assert(m_tree_map[v] != Color::gray);
|
||||
if (m_in_active_list_map[v]) {
|
||||
if (m_last_grow_vertex == v) {
|
||||
m_last_grow_vertex = NULL_VERTEX;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_in_active_list_map[v] = true;
|
||||
m_active_nodes.push(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* finish_node removes a node from the front of the active queue (its
|
||||
* called in grow phase, if no more paths can be found using this node)
|
||||
*/
|
||||
void finish_node(int v)
|
||||
{
|
||||
assert(m_active_nodes.front() == v);
|
||||
m_active_nodes.pop();
|
||||
m_in_active_list_map[v] = false;
|
||||
m_last_grow_vertex = NULL_VERTEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns edge to parent vertex of v;
|
||||
*/
|
||||
int get_edge_to_parent(int v) const
|
||||
{
|
||||
return m_pre_map[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the edge stored in m_pre_map[v] is a valid entry
|
||||
*/
|
||||
bool has_parent(int v) const
|
||||
{
|
||||
return m_has_parent_map[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* sets edge to parent vertex of v;
|
||||
*/
|
||||
void set_edge_to_parent(int v, int f_edge_to_parent)
|
||||
{
|
||||
assert(m_res_cap_map[f_edge_to_parent] > 0);
|
||||
m_pre_map[v] = f_edge_to_parent;
|
||||
m_has_parent_map[v] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the edge to parent of v (this is done by invalidating the
|
||||
* entry an additional map)
|
||||
*/
|
||||
void set_no_parent(int v)
|
||||
{
|
||||
m_has_parent_map[v] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if vertex v has a connect to the sink-vertex (@var m_sink)
|
||||
* @param v the vertex which is checked
|
||||
* @return true if a path to the sink was found, false if not
|
||||
*/
|
||||
bool has_sink_connect(int v)
|
||||
{
|
||||
int current_distance = 0;
|
||||
int current_vertex = v;
|
||||
while (true) {
|
||||
if (m_time_map[current_vertex] == m_time) {
|
||||
// we found a node which was already checked this round. use
|
||||
// it for distance calculations
|
||||
current_distance += m_dist_map[current_vertex];
|
||||
break;
|
||||
}
|
||||
if (current_vertex == m_sink) {
|
||||
m_time_map[m_sink] = m_time;
|
||||
break;
|
||||
}
|
||||
if (has_parent(current_vertex)) {
|
||||
// it has a parent, so get it
|
||||
current_vertex = m_graph_edges[get_edge_to_parent(current_vertex)].target;
|
||||
++current_distance;
|
||||
}
|
||||
else {
|
||||
// no path found
|
||||
return false;
|
||||
}
|
||||
}
|
||||
current_vertex = v;
|
||||
while (m_time_map[current_vertex] != m_time) {
|
||||
m_dist_map[current_vertex] = current_distance;
|
||||
--current_distance;
|
||||
m_time_map[current_vertex] = m_time;
|
||||
current_vertex = m_graph_edges[get_edge_to_parent(current_vertex)].target;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if vertex v has a connect to the source-vertex (@var m_source)
|
||||
* @param v the vertex which is checked
|
||||
* @return true if a path to the source was found, false if not
|
||||
*/
|
||||
bool has_source_connect(int v)
|
||||
{
|
||||
int current_distance = 0;
|
||||
int current_vertex = v;
|
||||
while (true) {
|
||||
if (m_time_map[current_vertex] == m_time) {
|
||||
// we found a node which was already checked this round. use
|
||||
// it for distance calculations
|
||||
current_distance += m_dist_map[current_vertex];
|
||||
break;
|
||||
}
|
||||
if (current_vertex == m_source) {
|
||||
m_time_map[m_source] = m_time;
|
||||
break;
|
||||
}
|
||||
if (has_parent(current_vertex)) {
|
||||
// it has a parent, so get it
|
||||
current_vertex = m_graph_edges[get_edge_to_parent(current_vertex)].source;
|
||||
++current_distance;
|
||||
}
|
||||
else {
|
||||
// no path found
|
||||
return false;
|
||||
}
|
||||
}
|
||||
current_vertex = v;
|
||||
while (m_time_map[current_vertex] != m_time) {
|
||||
m_dist_map[current_vertex] = current_distance;
|
||||
--current_distance;
|
||||
m_time_map[current_vertex] = m_time;
|
||||
current_vertex = m_graph_edges[get_edge_to_parent(current_vertex)].source;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true, if p is closer to a terminal than q
|
||||
*/
|
||||
bool is_closer_to_terminal(int p, int q)
|
||||
{
|
||||
// checks the timestamps first, to build no cycles, and after that
|
||||
// the real distance
|
||||
return (m_time_map[q] <= m_time_map[p] && m_dist_map[q] > m_dist_map[p] + 1);
|
||||
}
|
||||
|
||||
// Member variables
|
||||
std::vector<Edge> m_graph_edges;
|
||||
std::vector<std::vector<int>> m_graph_out_edges;
|
||||
|
||||
std::vector<int> m_cap_map;
|
||||
std::vector<int> m_res_cap_map;
|
||||
std::vector<int> m_rev_edge_map;
|
||||
std::vector<int> m_pre_map; // stores paths found in the growth stage
|
||||
std::vector<Color> m_tree_map; // maps each vertex into white, black or gray
|
||||
std::vector<int> m_dist_map; // stores distance to source/sink nodes
|
||||
|
||||
int m_source;
|
||||
int m_sink;
|
||||
|
||||
std::queue<int> m_active_nodes;
|
||||
std::vector<bool> m_in_active_list_map;
|
||||
|
||||
std::list<int> m_orphans;
|
||||
std::queue<int> m_child_orphans; // we use a second queuqe for child orphans, as
|
||||
// they are FIFO processed
|
||||
std::vector<bool> m_has_parent_map;
|
||||
|
||||
std::vector<int> m_time_map; // timestamp of each node, used for
|
||||
// sink/source-path calculations
|
||||
int m_flow = 0;
|
||||
int m_time = 1;
|
||||
|
||||
int m_last_grow_vertex = NULL_VERTEX;
|
||||
int m_last_grow_out_edge = 0;
|
||||
};
|
||||
|
||||
} // namespace qflow
|
||||
Reference in New Issue
Block a user