11 bool parallelMatrixConstruction)
12 : n_(points.size()), bound_(upperBound), parallelSort_(parallelSort),
13 parallelMatrixConstruction_(parallelMatrixConstruction) {
15 this->setDebugMsgPrefix(
"PairCells");
17 for(
int i = 1; i < n_; ++i) {
18 for(
int j = 0; j < i; ++j)
19 compressedDM_.push_back(
20 sqrt(CGAL::squared_distance(points[i], points[j])));
29 bool parallelMatrixConstruction)
30 : n_(distanceMatrix ? (1 + sqrt(1 + 8 * points[0].size())) / 2
32 bound_(upperBound), parallelSort_(parallelSort),
33 parallelMatrixConstruction_(parallelMatrixConstruction) {
38 compressedDM_ = points[0];
40 const unsigned dim = points[0].size();
41 for(
int i = 1; i < n_; ++i) {
42 for(
int j = 0; j < i; ++j) {
44 for(
unsigned d = 0; d < dim; ++d)
45 s += (points[i][d] - points[j][d]) * (points[i][d] - points[j][d]);
46 compressedDM_.push_back(sqrt(s));
57 bool parallelMatrixConstruction)
58 : n_(n), bound_(upperBound), parallelSort_(parallelSort),
59 parallelMatrixConstruction_(parallelMatrixConstruction) {
63 for(
int i = 1; i < n_; ++i) {
64 for(
int j = 0; j < i; ++j) {
66 for(
int d = 0; d < dim; ++d)
67 s += (data[dim * i + d] - data[dim * j + d])
68 * (data[dim * i + d] - data[dim * j + d]);
69 compressedDM_.push_back(sqrt(s));
76 if(bound_ ==
inf || bound_ < 0)
79 initializeWithBound();
80 printMsg(
"Initialized (#p=" + std::to_string(n_)
81 +
", #e=" + std::to_string(nEdges_)
82 +
", #t=" + std::to_string(nTriangles_) +
")",
83 0, tm.getElapsedTime());
85 printMsg(
"Complete", 1, tm.getElapsedTime());
88void PairCells::initialize() {
90 for(
id_t i = 0; i < n_; ++i) {
91 for(
id_t j = i + 1; j < n_; ++j)
92 edges_.push_back({{i, j}, DM(i, j)});
94 nEdges_ = n_ * (n_ - 1) / 2;
98 nTriangles_ = n_ * (n_ - 1) * (n_ - 2) / 6;
99 triangles_.resize(nTriangles_);
100 boundaries_.resize(nTriangles_);
102#ifdef TTK_ENABLE_OPENMP
103#pragma omp parallel for if(parallelMatrixConstruction_)
107 for(
id_t i = 0; i < n_ - 2; ++i) {
108 const unsigned index_i
109 = i * (i * i - 3 * i * (n_ - 1) + 3 * n_ * n_ - 6 * n_ + 2) / 6;
110 for(
id_t j = i + 1; j < n_ - 1; ++j) {
111 const unsigned index_j = (i - j + 1) * (i + j - 2 * n_ + 2) / 2 + index_i;
112 for(
id_t k = j + 1; k < n_; ++k) {
113 const double diameter
114 = std::max(DM(i, j), std::max(DM(i, k), DM(j, k)));
115 triangles_[index_j + (k - j - 1)] = {{i, j, k}, diameter};
116 boundaries_[index_j + (k - j - 1)]
117 = {nEdges_ - 1 - (n_ - i) * (n_ - i - 1) / 2 + (j - i),
118 nEdges_ - 1 - (n_ - i) * (n_ - i - 1) / 2 + (k - i),
119 nEdges_ - 1 - (n_ - j) * (n_ - j - 1) / 2 + (k - j)};
127void PairCells::initializeWithBound() {
129 std::unordered_map<Edge, id_t, boost::hash<Edge>> edgeToIndex;
130 std::vector<std::set<id_t>> graph(n_);
131 for(
id_t i = 0; i < n_; ++i) {
132 for(
id_t j = i + 1; j < n_; ++j) {
133 if(DM(i, j) <= bound_) {
134 edgeToIndex[{i, j}] = edges_.size();
135 edges_.push_back({{i, j}, DM(i, j)});
140 nEdges_ = edges_.size();
144 for(
const auto &[e, f] : edges_) {
145 const auto &[i, j] = e;
146 for(
auto const &k : graph[j]) {
149 triangles_.push_back(
150 {{i, j, k}, std::max(DM(i, j), std::max(DM(i, k), DM(j, k)))});
151 boundaries_.push_back(
152 {edgeToIndex[{i, j}], edgeToIndex[{i, k}], edgeToIndex[{j, k}]});
156 nTriangles_ = triangles_.size();
161void PairCells::executeKruskal() {
163 edgesIndices_.resize(nEdges_);
164 edgesOrder_.resize(nEdges_);
165 edgesPartner_.resize(nEdges_, -1);
166 std::iota(edgesIndices_.begin(), edgesIndices_.end(), 0);
169 [&](
id_t i,
id_t j) { return edges_[i] < edges_[j]; })
171 std::sort(edgesIndices_.begin(), edgesIndices_.end(),
172 [&](
id_t i,
id_t j) { return edges_[i] < edges_[j]; });
173 symbolicPerturbation();
174 for(
unsigned i = 0; i < edgesIndices_.size(); ++i)
175 edgesOrder_[edgesIndices_[i]] = i;
176 for(
const id_t &
id : edgesIndices_) {
177 const auto &[s, f] = edges_[id];
179 UF.merge(s.first, s.second);
180 edgesPartner_[id] = -2;
181 if(++nPairedEdges_ == n_ - 1)
187void PairCells::symbolicPerturbation(
192 for(
unsigned i = 0; i + 1 < edgesIndices_.size(); ++i) {
193 if(edges_[edgesIndices_[i]].d >= edges_[edgesIndices_[i + 1]].d) {
195 FiltratedEdge &e = edges_[edgesIndices_[i + 1]];
197 DM(e.
e.first, e.
e.second) += eps;
204 [&](
id_t i,
id_t j) { return edges_[i] < edges_[j]; })
206 std::sort(edgesIndices_.begin(), edgesIndices_.end(),
207 [&](
id_t i,
id_t j) { return edges_[i] < edges_[j]; });
212void PairCells::apparentPairs() {
214 trianglesIndices_.resize(nTriangles_);
215 trianglesPartner_.resize(nTriangles_, -1);
216 cascadeEdges_.resize(nTriangles_);
219 std::iota(trianglesIndices_.begin(), trianglesIndices_.end(), 0);
222 trianglesIndices_.end(),
223 [&](
id_t i,
id_t j) { return triangles_[i] < triangles_[j]; })
225 std::sort(trianglesIndices_.begin(), trianglesIndices_.end(),
226 [&](
id_t i,
id_t j) { return triangles_[i] < triangles_[j]; });
230 for(
const id_t &e : edgesIndices_) {
231 const double f = edges_[e].d;
232 while(triangles_[trianglesIndices_[t]].d < f)
234 if(triangles_[trianglesIndices_[t]].d == f) {
235 edgesPartner_[e] = trianglesIndices_[t];
236 trianglesPartner_[trianglesIndices_[t]] = e;
242void PairCells::pairCells() {
243 for(
const id_t &s : trianglesIndices_) {
244 if(trianglesPartner_[s] == -1) {
245 const int e = eliminateBoundaries(s);
247 trianglesPartner_[s] = e;
248 edgesPartner_[e] = s;
249 if(++nPairedEdges_ == nEdges_)
257 BoundaryContainer bc(boundaries_[s], nEdges_);
258 while(!boundaries_[s].empty()) {
259 const id_t e = *std::max_element(
260 boundaries_[s].
begin(), boundaries_[s].
end(),
261 [&](
id_t i,
id_t j) {
return edgesOrder_[i] < edgesOrder_[j]; });
262 cascadeEdges_[s].push_back(e);
263 if(edgesPartner_[e] == -1)
266 bc.exclusiveAddBoundary(boundaries_[edgesPartner_[e]]);
273 for(
const id_t &e : edgesIndices_) {
274 if(edgesPartner_[e] == -2)
275 diagrams[0].emplace_back(
278 else if(edgesPartner_[e] > 0
279 && edges_[e].d < triangles_[edgesPartner_[e]].d) {
281 {edges_[e].e.first, edges_[e].e.second}, edges_[e].d);
283 {std::get<0>(triangles_[edgesPartner_[e]].t),
284 std::get<1>(triangles_[edgesPartner_[e]].t),
285 std::get<2>(triangles_[edgesPartner_[e]].t)},
286 triangles_[edgesPartner_[e]].d);
287 diagrams[1].emplace_back(birth, death);
290 diagrams[0].emplace_back(
296 std::vector<Generator1> &generators)
const {
298 for(
const id_t &e : edgesIndices_) {
299 if(edgesPartner_[e] == -2)
300 diagrams[0].emplace_back(
303 else if(edgesPartner_[e] > 0
304 && edges_[e].d < triangles_[edgesPartner_[e]].d) {
306 {edges_[e].e.first, edges_[e].e.second}, edges_[e].d);
308 {std::get<0>(triangles_[edgesPartner_[e]].t),
309 std::get<1>(triangles_[edgesPartner_[e]].t),
310 std::get<2>(triangles_[edgesPartner_[e]].t)},
311 triangles_[edgesPartner_[e]].d);
312 diagrams[1].emplace_back(birth, death);
315 for(
const id_t &edge : boundaries_[edgesPartner_[e]])
316 boundary.emplace_back(edges_[edge].e);
317 generators.emplace_back(
318 boundary, std::make_pair(edges_[e].d, triangles_[edgesPartner_[e]].d));
321 diagrams[0].emplace_back(
327 for(
const id_t &e : edgesIndices_) {
328 if(edgesPartner_[e] == -2)
329 critical[
DEATH0].emplace_back(edges_[e].e);
330 else if(edgesPartner_[e] > 0
331 && edges_[e].d < triangles_[edgesPartner_[e]].d) {
332 const Edge &killerEdge = edges_[cascadeEdges_[edgesPartner_[e]][0]].e;
333 critical[
BIRTH1].emplace_back(edges_[e].e);
334 critical[
DEATH1].emplace_back(killerEdge);
335 Cascade cascade = {killerEdge};
336 for(
unsigned i = 1; i < cascadeEdges_[edgesPartner_[e]].size() - 1; ++i)
337 cascade.emplace_back(edges_[cascadeEdges_[edgesPartner_[e]][i]].e);
338 cascades.emplace_back(cascade);
344 std::set<id_t> cascadeSet;
345 for(
const id_t &e : edgesIndices_) {
346 if(edgesPartner_[e] == -2)
347 critical[
DEATH0].emplace_back(edges_[e].e);
348 else if(edgesPartner_[e] > 0
349 && edges_[e].d < triangles_[edgesPartner_[e]].d) {
350 const Edge &killerEdge = edges_[cascadeEdges_[edgesPartner_[e]][0]].e;
351 critical[
BIRTH1].emplace_back(edges_[e].e);
352 critical[
DEATH1].emplace_back(killerEdge);
353 for(
unsigned i = 1; i < cascadeEdges_[edgesPartner_[e]].size() - 1; ++i)
354 cascadeSet.insert(cascadeEdges_[edgesPartner_[e]][i]);
357 for(
const id_t &e : cascadeSet)
358 critical[
CASC1].emplace_back(edges_[e].e);
363 std::vector<int>
const &globalIndices)
const {
364 for(
const id_t &e : edgesIndices_) {
365 if(edgesPartner_[e] > 0 && edges_[e].d < triangles_[edgesPartner_[e]].d) {
366 const Edge &killerEdge = edges_[cascadeEdges_[edgesPartner_[e]][0]].e;
367 critical[
DEATH1].emplace_back(
368 globalIndices[killerEdge.first],
369 globalIndices[killerEdge.second]);
370 for(
unsigned i = 1; i < cascadeEdges_[edgesPartner_[e]].size() - 1; ++i) {
371 const Edge &edge = edges_[cascadeEdges_[edgesPartner_[e]][i]].e;
373 globalIndices[edge.first], globalIndices[edge.second]);
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
void setDebugMsgPrefix(const std::string &prefix)
void getDiagram(MultidimensionalDiagram &diagrams) const
void getCascades(std::vector< Cascade > &cascades, EdgeSets3 &critical) const
void getDiagramAndGenerators(MultidimensionalDiagram &diagrams, std::vector< Generator1 > &generators) const
PairCells(const PointCloud &points, bool distanceMatrix=false, double upperBound=inf, bool parallelSort=false, bool parallelMatrixConstruction=false)
void enrichCascades(std::set< Edge > &cascadeSet, EdgeSets4 &critical, std::vector< int > const &globalIndices) const
std::pair< id_t, id_t > Edge
std::array< EdgeSet, 4 > EdgeSets4
std::vector< std::vector< value_t > > PointCloud
std::vector< Edge > EdgeSet
std::vector< Diagram > MultidimensionalDiagram
std::pair< Simplex, value_t > FiltratedSimplex
std::array< EdgeSet, 3 > EdgeSets3
COMMON_EXPORTS int globalThreadNumber_
T end(std::pair< T, T > &p)
T begin(std::pair< T, T > &p)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)