13#ifndef FLAG_COMPLEX_EDGE_COLLAPSER_H_
14#define FLAG_COMPLEX_EDGE_COLLAPSER_H_
16#include <gudhi/Debug_utils.h>
18#include <boost/container/flat_map.hpp>
19#include <boost/container/flat_set.hpp>
22#include <tbb/parallel_sort.h>
42template<
typename Vertex,
typename Filtration_value>
43struct Flag_complex_edge_collapser {
44 using Filtered_edge = std::tuple<Vertex, Vertex, Filtration_value>;
45 typedef std::pair<Vertex,Vertex> Edge;
46 struct Cmpi {
template<
class T,
class U>
bool operator()(T
const&a, U
const&b)
const{
return b<a; } };
47 typedef boost::container::flat_map<Vertex, Filtration_value> Ngb_list;
48 typedef std::vector<Ngb_list> Neighbors;
50 std::size_t num_vertices;
51 std::vector<std::tuple<Vertex, Vertex, Filtration_value>> res;
53#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
58 std::vector<Filtration_value> neighbors_data;
59 void init_neighbors_dense(){
60 neighbors_data.clear();
61 neighbors_data.resize(num_vertices*num_vertices, std::numeric_limits<Filtration_value>::infinity());
63 Filtration_value& neighbors_dense(Vertex i, Vertex j){
return neighbors_data[num_vertices*j+i];}
70#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
71 neighbors_dense(u,v)=f;
72 neighbors_dense(v,u)=f;
75 void remove_neighbor(Vertex u, Vertex v) {
76 neighbors[u].erase(v);
77 neighbors[v].erase(u);
78#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
79 neighbors_dense(u,v)=std::numeric_limits<Filtration_value>::infinity();
80 neighbors_dense(v,u)=std::numeric_limits<Filtration_value>::infinity();
84 template<
class FilteredEdgeRange>
85 void read_edges(FilteredEdgeRange
const&r){
86 neighbors.resize(num_vertices);
87#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
88 init_neighbors_dense();
91 std::vector<typename Ngb_list::sequence_type> neighbors_seq(num_vertices);
97 neighbors_seq[u].emplace_back(v, f);
98 neighbors_seq[v].emplace_back(u, f);
99#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
100 neighbors_dense(u,v)=f;
101 neighbors_dense(v,u)=f;
104 for(std::size_t i=0;i<neighbors_seq.size();++i){
105 neighbors_seq[i].emplace_back(i, -std::numeric_limits<Filtration_value>::infinity());
106 neighbors[i].adopt_sequence(std::move(neighbors_seq[i]));
107#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
108 neighbors_dense(i,i)=-std::numeric_limits<Filtration_value>::infinity();
116 void common_neighbors(boost::container::flat_set<Vertex>& e_ngb,
117 std::vector<std::pair<Filtration_value, Vertex>>& e_ngb_later,
120 Ngb_list
const&nu = neighbors[u];
121 Ngb_list
const&nv = neighbors[v];
122 auto ui = nu.begin();
124 auto vi = nv.begin();
126 assert(ui != ue && vi != ve);
127 while(ui != ue && vi != ve){
128 Vertex w = ui->first;
129 if(w < vi->first) { ++ui;
continue; }
130 if(w > vi->first) { ++vi;
continue; }
132 if(w != u && w != v) {
135 e_ngb_later.emplace_back(f, w);
137 e_ngb.insert(e_ngb.end(), w);
149#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
150 for(
auto v : e_ngb) {
152 if(neighbors_dense(v,c) > f)
return false;
156 auto&&nc = neighbors[c];
161 auto ci = nc.begin();
163 auto eni = e_ngb.begin();
164 auto ene = e_ngb.end();
170 Vertex vc = ci->first;
173 if(++ci == ce)
return false;
176 if(ve < vc)
return false;
178 if(ci->second > f)
return false;
179 if(++eni == ene)
return true;
182 if(++ci == ce)
return false;
187 template<
class FilteredEdgeRange,
class Delay>
188 void process_edges(FilteredEdgeRange
const& edges, Delay&& delay) {
190 Vertex maxi = 0, maxj = 0;
191 for(
auto& fe : edges) {
192 Vertex i = std::get<0>(fe);
193 Vertex j = std::get<1>(fe);
194 if (i > maxi) maxi = i;
195 if (j > maxj) maxj = j;
197 num_vertices = std::max(maxi, maxj) + 1;
202 boost::container::flat_set<Vertex> e_ngb;
203 e_ngb.reserve(num_vertices);
204 std::vector<std::pair<Filtration_value, Vertex>> e_ngb_later;
207 Vertex u = std::get<0>(e);
208 Vertex v = std::get<1>(e);
210 auto time = delay(input_time);
211 auto start_time = time;
214 common_neighbors(e_ngb, e_ngb_later, u, v, time);
217 auto cmp1=[](
auto const&a,
auto const&b){
return a.first > b.first;};
218 auto e_ngb_later_begin=e_ngb_later.begin();
219 auto e_ngb_later_end=e_ngb_later.end();
220 bool heapified =
false;
224 Vertex dominator = -1;
231 if(is_dominated_by(e_ngb, c, time)){
236 if(dominator==-1)
break;
239 for (
bool still_dominated =
true; still_dominated; ) {
240 if(e_ngb_later_begin == e_ngb_later_end) {
241 dead =
true;
goto end_move;
245 std::make_heap(e_ngb_later_begin, e_ngb_later_end, cmp1);
248 time = e_ngb_later_begin->first;
250 while (e_ngb_later_begin != e_ngb_later_end && e_ngb_later_begin->first <= time) {
251 Vertex w = e_ngb_later_begin->second;
252#ifdef GUDHI_COLLAPSE_USE_DENSE_ARRAY
253 if (neighbors_dense(dominator,w) > e_ngb_later_begin->first)
254 still_dominated =
false;
256 auto& ngb_dom = neighbors[dominator];
257 auto wit = ngb_dom.find(w);
258 if (wit == ngb_dom.end() || wit->second > e_ngb_later_begin->first)
259 still_dominated =
false;
262 std::pop_heap(e_ngb_later_begin, e_ngb_later_end--, cmp1);
268 remove_neighbor(u, v);
269 }
else if(start_time != time) {
270 delay_neighbor(u, v, time);
271 res.emplace_back(u, v, time);
273 res.emplace_back(u, v, input_time);
279 std::vector<Filtered_edge> output() {
280 return std::move(res);
285template<
class R> R to_range(R&& r) {
return std::move(r); }
286template<
class R,
class T> R to_range(T&& t) { R r; r.insert(r.end(), t.begin(), t.end());
return r; }
288template<
class FilteredEdgeRange,
class Delay>
291 auto first_edge_itr = std::begin(edges);
292 using Vertex = std::decay_t<decltype(std::get<0>(*first_edge_itr))>;
293 using Filtration_value = std::decay_t<decltype(std::get<2>(*first_edge_itr))>;
294 using Edge_collapser = Flag_complex_edge_collapser<Vertex, Filtration_value>;
295 if (first_edge_itr != std::end(edges)) {
296 auto edges2 = to_range<std::vector<typename Edge_collapser::Filtered_edge>>(std::forward<FilteredEdgeRange>(edges));
299 tbb::parallel_sort(edges2.begin(), edges2.end(),
300 [](
auto const&a,
auto const&b){return std::get<2>(a)>std::get<2>(b);});
302 std::sort(edges2.begin(), edges2.end(), [](
auto const&a,
auto const&b){return std::get<2>(a)>std::get<2>(b);});
304 Edge_collapser edge_collapser;
305 edge_collapser.process_edges(edges2, std::forward<Delay>(delay));
306 return edge_collapser.output();
308 return std::vector<typename Edge_collapser::Filtered_edge>();
auto flag_complex_collapse_edges(const FilteredEdgeRange &edges)
Implicitly constructs a flag complex from edges as an input, collapses edges while preserving the per...
Definition: Flag_complex_edge_collapser.h:329
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20