TTK
Loading...
Searching...
No Matches
LegacyTopologicalSimplification.h
Go to the documentation of this file.
1
91
92#pragma once
93
94// base code includes
95#include <Debug.h>
96#include <Triangulation.h>
97
98#include <cmath>
99#include <set>
100#include <tuple>
101#include <type_traits>
102
103namespace ttk {
104
105 class SweepCmp {
106 bool isIncreasingOrder_{};
107
108 public:
109 SweepCmp() = default;
110
111 SweepCmp(bool isIncreasingOrder) : isIncreasingOrder_{isIncreasingOrder} {
112 }
113
114 inline void setIsIncreasingOrder(bool isIncreasingOrder) {
115 isIncreasingOrder_ = isIncreasingOrder;
116 }
117
118 template <typename dataType>
119 bool
120 operator()(const std::tuple<dataType, SimplexId, SimplexId> &v0,
121 const std::tuple<dataType, SimplexId, SimplexId> &v1) const {
122 if(isIncreasingOrder_) {
123 return std::get<1>(v0) < std::get<1>(v1);
124 } else {
125 return std::get<1>(v0) > std::get<1>(v1);
126 }
127 }
128 };
129
130 class LegacyTopologicalSimplification : virtual public Debug {
131 public:
133
134 template <typename triangulationType>
135 int getCriticalType(SimplexId vertexId,
136 const SimplexId *const offsets,
137 const triangulationType &triangulation) const;
138
139 template <typename triangulationType>
140 int getCriticalPoints(const SimplexId *const offsets,
141 std::vector<SimplexId> &minList,
142 std::vector<SimplexId> &maxList,
143 const triangulationType &triangulation) const;
144
145 template <typename triangulationType>
146 int getCriticalPoints(const SimplexId *const offsets,
147 std::vector<SimplexId> &minList,
148 std::vector<SimplexId> &maxList,
149 std::vector<bool> &blackList,
150 const triangulationType &triangulation) const;
151
152 template <typename dataType>
153 int addPerturbation(dataType *const scalars,
154 SimplexId *const offsets) const;
155
164 template <typename dataType, typename triangulationType>
165 int execute(const dataType *const inputScalars,
166 dataType *const outputScalars,
167 const SimplexId *const identifiers,
168 const SimplexId *const inputOffsets,
169 SimplexId *const offsets,
170 const SimplexId constraintNumber,
171 const triangulationType &triangulation) const;
172
174 if(triangulation) {
175 vertexNumber_ = triangulation->getNumberOfVertices();
176 triangulation->preconditionVertexNeighbors();
177 }
178 return 0;
179 }
180
181 inline void setConsiderIdentifierAsBlackList(bool onOff) {
183 }
184
185 inline void setAddPerturbation(bool onOff) {
186 addPerturbation_ = onOff;
187 }
188
189 protected:
192 bool addPerturbation_{false};
193 };
194} // namespace ttk
195
196// if the package is a pure template typename, uncomment the following line
197// #include <LegacyTopologicalSimplification.cpp>
198
199template <typename triangulationType>
201 SimplexId vertex,
202 const SimplexId *const offsets,
203 const triangulationType &triangulation) const {
204
205 bool isMinima{true};
206 bool isMaxima{true};
207 SimplexId const neighborNumber
208 = triangulation.getVertexNeighborNumber(vertex);
209 for(SimplexId i = 0; i < neighborNumber; ++i) {
210 SimplexId neighbor{-1};
211 triangulation.getVertexNeighbor(vertex, i, neighbor);
212
213 if(offsets[neighbor] < offsets[vertex])
214 isMinima = false;
215 if(offsets[neighbor] > offsets[vertex])
216 isMaxima = false;
217 if(!isMinima and !isMaxima) {
218 return 0;
219 }
220 }
221
222 if(isMinima)
223 return -1;
224 if(isMaxima)
225 return 1;
226
227 return 0;
228}
229
230template <typename triangulationType>
232 const SimplexId *const offsets,
233 std::vector<SimplexId> &minima,
234 std::vector<SimplexId> &maxima,
235 const triangulationType &triangulation) const {
236
237 std::vector<int> type(vertexNumber_, 0);
238
239#ifdef TTK_ENABLE_OPENMP
240#pragma omp parallel for
241#endif
242 for(SimplexId k = 0; k < vertexNumber_; ++k)
243 type[k] = getCriticalType(k, offsets, triangulation);
244
245 for(SimplexId k = 0; k < vertexNumber_; ++k) {
246 if(type[k] < 0)
247 minima.push_back(k);
248 else if(type[k] > 0)
249 maxima.push_back(k);
250 }
251 return 0;
252}
253
254template <typename triangulationType>
256 const SimplexId *const offsets,
257 std::vector<SimplexId> &minima,
258 std::vector<SimplexId> &maxima,
259 std::vector<bool> &extrema,
260 const triangulationType &triangulation) const {
261 std::vector<int> type(vertexNumber_);
262#ifdef TTK_ENABLE_OPENMP
263#pragma omp parallel for num_threads(threadNumber_)
264#endif
265 for(SimplexId k = 0; k < vertexNumber_; ++k) {
266 if(considerIdentifierAsBlackList_ xor extrema[k]) {
267 type[k] = getCriticalType(k, offsets, triangulation);
268 }
269 }
270
271 for(SimplexId k = 0; k < vertexNumber_; ++k) {
272 if(type[k] < 0)
273 minima.push_back(k);
274 else if(type[k] > 0)
275 maxima.push_back(k);
276 }
277 return 0;
278}
279
280template <typename dataType>
282 dataType *const scalars, SimplexId *const offsets) const {
283 dataType epsilon{};
284
285 if(std::is_same<dataType, double>::value)
286 epsilon = Geometry::powIntTen<dataType>(1 - DBL_DIG);
287 else if(std::is_same<dataType, float>::value)
288 epsilon = Geometry::powIntTen<dataType>(1 - FLT_DIG);
289 else
290 return -1;
291
292 std::vector<std::tuple<dataType, SimplexId, SimplexId>> perturbation(
293 vertexNumber_);
294 for(SimplexId i = 0; i < vertexNumber_; ++i) {
295 std::get<0>(perturbation[i]) = scalars[i];
296 std::get<1>(perturbation[i]) = offsets[i];
297 std::get<2>(perturbation[i]) = i;
298 }
299
300 SweepCmp const cmp(true);
301 sort(perturbation.begin(), perturbation.end(), cmp);
302
303 for(SimplexId i = 0; i < vertexNumber_; ++i) {
304 if(i) {
305 if(std::get<0>(perturbation[i]) <= std::get<0>(perturbation[i - 1]))
306 std::get<0>(perturbation[i])
307 = std::get<0>(perturbation[i - 1]) + epsilon;
308 }
309 scalars[std::get<2>(perturbation[i])] = std::get<0>(perturbation[i]);
310 }
311
312 return 0;
313}
314
315template <typename dataType, typename triangulationType>
317 const dataType *const inputScalars,
318 dataType *const outputScalars,
319 const SimplexId *const identifiers,
320 const SimplexId *const inputOffsets,
321 SimplexId *const offsets,
322 const SimplexId constraintNumber,
323 const triangulationType &triangulation) const {
324
325 Timer t;
326
327 // pre-processing
328#ifdef TTK_ENABLE_OPENMP
329#pragma omp parallel for num_threads(threadNumber_)
330#endif
331 for(SimplexId k = 0; k < vertexNumber_; ++k) {
332 outputScalars[k] = inputScalars[k];
333 if(std::isnan((double)outputScalars[k]))
334 outputScalars[k] = 0;
335
336 offsets[k] = inputOffsets[k];
337 }
338
339 // get the user extremum list
340 std::vector<bool> extrema(vertexNumber_, false);
341 for(SimplexId k = 0; k < constraintNumber; ++k) {
342 const SimplexId identifierId = identifiers[k];
343
344#ifndef TTK_ENABLE_KAMIKAZE
345 if(identifierId >= 0 and identifierId < vertexNumber_)
346#endif
347 extrema[identifierId] = true;
348 }
349
350 std::vector<SimplexId> authorizedMinima;
351 std::vector<SimplexId> authorizedMaxima;
352 std::vector<bool> authorizedExtrema(vertexNumber_, false);
353
354 getCriticalPoints(
355 offsets, authorizedMinima, authorizedMaxima, extrema, triangulation);
356
357 this->printMsg("Maintaining " + std::to_string(constraintNumber)
358 + " constraints (" + std::to_string(authorizedMinima.size())
359 + " minima and " + std::to_string(authorizedMaxima.size())
360 + " maxima)",
362
363 // declare the tuple-comparison functor
364 SweepCmp cmp;
365
366 // processing
367 for(SimplexId i = 0; i < vertexNumber_; ++i) {
368
369 this->printMsg("Starting simplifying iteration #" + std::to_string(i),
371
372 for(int j = 0; j < 2; ++j) {
373
374 bool const isIncreasingOrder = !j;
375
376 if(isIncreasingOrder && authorizedMinima.empty()) {
377 continue;
378 }
379 if(!isIncreasingOrder && authorizedMaxima.empty()) {
380 continue;
381 }
382
383 cmp.setIsIncreasingOrder(isIncreasingOrder);
384 std::set<std::tuple<dataType, SimplexId, SimplexId>, decltype(cmp)>
385 sweepFront(cmp);
386 std::vector<bool> visitedVertices(vertexNumber_, false);
387 std::vector<SimplexId> adjustmentSequence(vertexNumber_);
388
389 // add the seeds
390 if(isIncreasingOrder) {
391 for(SimplexId const k : authorizedMinima) {
392 authorizedExtrema[k] = true;
393 sweepFront.emplace(outputScalars[k], offsets[k], k);
394 visitedVertices[k] = true;
395 }
396 } else {
397 for(SimplexId const k : authorizedMaxima) {
398 authorizedExtrema[k] = true;
399 sweepFront.emplace(outputScalars[k], offsets[k], k);
400 visitedVertices[k] = true;
401 }
402 }
403
404 // growth by neighborhood of the seeds
405 SimplexId adjustmentPos = 0;
406 do {
407 auto front = sweepFront.begin();
408 if(front == sweepFront.end())
409 return -1;
410
411 SimplexId const vertexId = std::get<2>(*front);
412 sweepFront.erase(front);
413
414 SimplexId const neighborNumber
415 = triangulation.getVertexNeighborNumber(vertexId);
416 for(SimplexId k = 0; k < neighborNumber; ++k) {
417 SimplexId neighbor{-1};
418 triangulation.getVertexNeighbor(vertexId, k, neighbor);
419 if(!visitedVertices[neighbor]) {
420 sweepFront.emplace(
421 outputScalars[neighbor], offsets[neighbor], neighbor);
422 visitedVertices[neighbor] = true;
423 }
424 }
425 adjustmentSequence[adjustmentPos] = vertexId;
426 ++adjustmentPos;
427 } while(!sweepFront.empty());
428
429 // save offsets and rearrange outputScalars
430 SimplexId offset = (isIncreasingOrder ? 0 : vertexNumber_);
431
432 for(SimplexId k = 0; k < vertexNumber_; ++k) {
433
434 if(isIncreasingOrder) {
435 if(k
436 && outputScalars[adjustmentSequence[k]]
437 <= outputScalars[adjustmentSequence[k - 1]])
438 outputScalars[adjustmentSequence[k]]
439 = outputScalars[adjustmentSequence[k - 1]];
440 ++offset;
441 } else {
442 if(k
443 && outputScalars[adjustmentSequence[k]]
444 >= outputScalars[adjustmentSequence[k - 1]])
445 outputScalars[adjustmentSequence[k]]
446 = outputScalars[adjustmentSequence[k - 1]];
447 --offset;
448 }
449 offsets[adjustmentSequence[k]] = offset;
450 }
451 }
452
453 // test convergence
454 bool needForMoreIterations{false};
455 std::vector<SimplexId> minima;
456 std::vector<SimplexId> maxima;
457 getCriticalPoints(offsets, minima, maxima, triangulation);
458
459 if(maxima.size() > authorizedMaxima.size())
460 needForMoreIterations = true;
461 if(minima.size() > authorizedMinima.size())
462 needForMoreIterations = true;
463
464 this->printMsg(
465 std::vector<std::vector<std::string>>{
466 {"#Minima", std::to_string(minima.size())},
467 {"#Maxima", std::to_string(maxima.size())},
468 },
470
471 if(!needForMoreIterations) {
472 for(SimplexId const k : minima) {
473 if(!authorizedExtrema[k]) {
474 needForMoreIterations = true;
475 break;
476 }
477 }
478 }
479 if(!needForMoreIterations) {
480 for(SimplexId const k : maxima) {
481 if(!authorizedExtrema[k]) {
482 needForMoreIterations = true;
483 break;
484 }
485 }
486 }
487
488 // optional adding of perturbation
489 if(addPerturbation_)
490 addPerturbation<dataType>(outputScalars, offsets);
491
492 if(!needForMoreIterations)
493 break;
494 }
495
496 this->printMsg(
497 "Simplified scalar field", 1.0, t.getElapsedTime(), this->threadNumber_);
498
499 return 0;
500}
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual SimplexId getNumberOfVertices() const
Minimalist debugging class.
Definition Debug.h:88
TTK processing package for the topological simplification of scalar data.
int preconditionTriangulation(AbstractTriangulation *triangulation)
int execute(const dataType *const inputScalars, dataType *const outputScalars, const SimplexId *const identifiers, const SimplexId *const inputOffsets, SimplexId *const offsets, const SimplexId constraintNumber, const triangulationType &triangulation) const
int addPerturbation(dataType *const scalars, SimplexId *const offsets) const
int getCriticalType(SimplexId vertexId, const SimplexId *const offsets, const triangulationType &triangulation) const
int getCriticalPoints(const SimplexId *const offsets, std::vector< SimplexId > &minList, std::vector< SimplexId > &maxList, const triangulationType &triangulation) const
SweepCmp(bool isIncreasingOrder)
void setIsIncreasingOrder(bool isIncreasingOrder)
SweepCmp()=default
bool operator()(const std::tuple< dataType, SimplexId, SimplexId > &v0, const std::tuple< dataType, SimplexId, SimplexId > &v1) const
double getElapsedTime()
Definition Timer.h:15
std::string to_string(__int128)
Definition ripserpy.cpp:99
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)