281 const dataType *
const inputData,
283 dataType *outputData,
285 const triangulationType &triangulation) {
291 std::vector<std::tuple<dataType, int>> topoIndices;
295 dataType maxValue = inputData[0];
297 for(
int i = 1; i < vertexNumber; ++i) {
299 if(iter > maxValue) {
305 dataType minValue = inputData[0];
307 for(
int i = 1; i < vertexNumber; ++i) {
309 if(iter < minValue) {
315 topoIndices.push_back(std::make_tuple(maxValue, maxIndex));
316 topoIndices.push_back(std::make_tuple(minValue, minIndex));
317 double const tolerance = 0.01 * tol * (maxValue - minValue);
318 double const maxError = 0.01 * MaximumError * (maxValue - minValue);
321 "Computed min/max", 1.0, t.
getElapsedTime(), this->threadNumber_);
324 bool sqDomain =
false;
325 bool sqRange =
false;
327 const char *sq = SQMethod.c_str();
329 std::vector<SimplexId> simplifiedConstraints;
330 if(strcmp(sq,
"") == 0 && !ZFPOnly) {
333 std::vector<std::tuple<SimplexId, SimplexId, dataType>> JTPairs;
334 std::vector<std::tuple<SimplexId, SimplexId, dataType>> STPairs;
335 computePersistencePairs<dataType>(
336 JTPairs, STPairs, inputData, inputOffsets, triangulation);
339 this->threadNumber_);
342 int const nbJ = JTPairs.size();
343 int const nbS = STPairs.size();
344 std::vector<int> critConstraints(2 * nbJ + 2 * nbS);
346 dataType maxEpsilon = 0;
347 dataType epsilonSum2 = 0;
348 dataType epsilonSum1 = 0;
349 dataType persistentSum2 = 0;
350 dataType persistentSum1 = 0;
353 for(
int i = 0; i < nbJ; ++i) {
354 SimplexId const cp1 = std::get<0>(JTPairs[i]);
355 SimplexId const cp2 = std::get<1>(JTPairs[i]);
356 dataType idt1 = inputData[cp1];
357 dataType idt2 = inputData[cp2];
358 dataType p1 = std::max(idt2, idt1) - std::min(idt2, idt1);
360 persistentSum2 += (p1 * p1);
361 persistentSum1 += abs<dataType>(p1);
362 int const type1 = topologicalSimplification.getCriticalType(
363 cp1, inputOffsets, triangulation);
364 int const type2 = topologicalSimplification.getCriticalType(
365 cp2, inputOffsets, triangulation);
368 topoIndices.push_back(std::make_tuple(idt1, cp1));
372 topoIndices.push_back(std::make_tuple(idt2, cp2));
376 critConstraints[2 * i] = cp1;
377 critConstraints[2 * i + 1] = cp2;
379 if(maxEpsilon < abs<dataType>(p1))
380 maxEpsilon = abs<dataType>(p1);
381 epsilonSum2 += (p1 * p1);
382 epsilonSum1 += abs<dataType>(p1);
383 critConstraints[2 * i] = -1;
384 critConstraints[2 * i + 1] = -1;
389 this->threadNumber_);
393 for(
int i = nbJ; i < nbJ + nbS; ++i) {
394 int const si = i - nbJ;
395 SimplexId const cp1 = std::get<0>(STPairs[si]);
396 SimplexId const cp2 = std::get<1>(STPairs[si]);
397 dataType idt1 = inputData[cp1];
398 dataType idt2 = inputData[cp2];
399 dataType p1 = std::max(idt2, idt1) - std::min(idt2, idt1);
401 persistentSum2 += (p1 * p1);
402 persistentSum1 += abs<dataType>(p1);
404 int const type1 = topologicalSimplification.getCriticalType(
405 cp1, inputOffsets, triangulation);
406 int const type2 = topologicalSimplification.getCriticalType(
407 cp2, inputOffsets, triangulation);
410 topoIndices.push_back(std::make_tuple(idt1, cp1));
414 topoIndices.push_back(std::make_tuple(idt2, cp2));
418 critConstraints[2 * i] = cp1;
419 critConstraints[2 * i + 1] = cp2;
422 maxEpsilon = abs<dataType>(p1);
423 epsilonSum2 += (p1 * p1);
424 epsilonSum1 += abs<dataType>(p1);
425 critConstraints[2 * i] = -1;
426 critConstraints[2 * i + 1] = -1;
431 this->threadNumber_);
434 simplifiedConstraints.resize(nbCrit);
437 for(
int i = 0; i < 2 * nbJ + 2 * nbS; ++i) {
438 int const c = critConstraints[i];
440 simplifiedConstraints[j++] = c;
448 if(UseTopologicalSimplification) {
449 compressedOffsets_.resize(vertexNumber);
451 status = topologicalSimplification.execute<dataType>(
452 inputData, outputData, simplifiedConstraints.data(), inputOffsets,
453 compressedOffsets_.data(), nbCrit, triangulation);
460 "Performed simplification", 1.0, t.
getElapsedTime(), this->threadNumber_);
463 }
else if(strcmp(sq,
"r") == 0 || strcmp(sq,
"R") == 0) {
466 }
else if(strcmp(sq,
"d") == 0 || strcmp(sq,
"D") == 0) {
472 this->printErr(
"Unrecognized SQ option (" + SQMethod +
").");
478 auto cmp = [](
const std::tuple<dataType, int> &a,
479 const std::tuple<dataType, int> &b) {
480 return std::get<0>(a) < std::get<0>(b);
482 std::sort(topoIndices.begin(), topoIndices.end(), cmp);
483 std::vector<std::tuple<dataType, int>> segments;
487 auto l = (int)topoIndices.size();
489 this->
printMsg(
"Trivial subdivision performed.");
490 segments.push_back(topoIndices[l - 1]);
492 for(
int i = 0; i < l; ++i) {
493 dataType v0 = std::get<0>(topoIndices[i]);
495 segments.push_back(topoIndices[i]);
499 dataType v1 = std::get<0>(topoIndices[i + 1]);
500 int const i1 = std::get<1>(topoIndices[i + 1]);
501 auto diff = (double)(v1 - v0);
505 if(!Subdivide || (diff < (dataType)maxError)) {
506 segments.push_back(std::make_tuple(v1, i1));
509 double const nSegments = std::ceil(diff / maxError);
510 for(
int j = 0, nbs = (
int)nSegments; j < nbs; ++j) {
511 dataType sample = v0 + j * maxError;
513 segments.push_back(std::make_tuple(sample, int1));
519 this->
printMsg(
"Subdivision/topological index attribution", 1.0,
527 segmentation_.resize(vertexNumber + 32);
529 std::sort(segments.begin(), segments.end(), cmp);
530 for(
int i = 0; i < vertexNumber; ++i) {
531 dataType scalar = inputData[i];
533 auto begin = segments.begin();
534 auto end = segments.end();
535 auto it = std::lower_bound(
536 segments.begin(), segments.end(), std::make_tuple(scalar, -1), cmp);
539 std::tuple<dataType, int> tt = *it;
540 int const j = it -
begin;
541 int const last = (int)segments.size() - 1;
543 dataType dtv = std::get<0>(tt);
545 dtv = 0.5 * (dtv + std::get<0>(*(it - 1)));
550 segmentation_[i] = seg;
552 segmentation_[i] = last;
553 outputData[i] = std::get<0>(tt);
563 auto segmentsSize = (int)segments.size();
564 std::vector<bool> affectedSegments;
565 affectedSegments.resize(segmentsSize);
566 std::vector<int> oob;
567 for(
int i = 0; i < vertexNumber; ++i) {
568 int const seg = segmentation_[i];
569 if(seg >= segmentsSize
570 && std::find(oob.begin(), oob.end(), seg) == oob.end())
573 affectedSegments[seg] =
true;
575 this->printErr(
"Negative segment encountered (" + std::to_string(i)
579 std::vector<int> empty;
580 for(
int i = 0; i < segmentsSize; ++i) {
581 if(!affectedSegments[i])
585 std::sort(oob.begin(), oob.end());
586 std::sort(empty.begin(), empty.end());
588 if(oob.size() > empty.size()) {
589 this->printWrn(
"oob size > empty size: " + std::to_string(oob.size()) +
", "
590 + std::to_string(empty.size()));
593 for(
int i = 0; i < vertexNumber; ++i) {
594 int const seg = segmentation_[i];
595 if(seg >= segmentsSize) {
596 auto begin = oob.begin();
597 auto end = oob.end();
598 auto it = std::lower_bound(
begin,
end, seg);
600 int const j = (int)(it -
begin);
601 segmentation_[i] = empty[j];
602 affectedSegments[j] =
true;
604 }
else if(!affectedSegments[seg]) {
605 this->printErr(
"Something impossible happened");
609 if(empty.size() > oob.size()) {
610 std::vector<int> map2(segmentsSize, -1);
611 for(
int i = 0; i < segmentsSize; ++i) {
612 if(affectedSegments[i])
614 for(
int j = (segmentsSize - 1); j > i; --j) {
615 if(!affectedSegments[j] || map2[j] > 0)
618 affectedSegments[j] =
false;
619 affectedSegments[i] =
true;
624 bool doneAffecting =
false;
625 for(
int i = 0; i < segmentsSize; ++i) {
626 if(!affectedSegments[i]) {
627 doneAffecting =
true;
630 this->printWrn(
"Hole detected at " + std::to_string(i)
638 for(
int i = 0; i < vertexNumber; ++i) {
639 int const seg = segmentation_[i];
641 segmentation_[i] = map2[seg];
647 "Simplified mapping", 1.0, t.
getElapsedTime(), this->threadNumber_);
651 std::vector<bool> already(vertexNumber);
652 for(
int i = 0; i < vertexNumber; ++i)
655 for(
int i = 0; i < vertexNumber; ++i) {
656 int const vert = segmentation_[i];
658 already[vert] =
true;
659 dataType dttt = outputData[i];
660 mapping_.emplace_back((
double)dttt, vert);
670 if(sqDomain && !sqRange) {
671 std::vector<bool> markedVertices(vertexNumber);
672 std::vector<bool> markedSegments(segmentsSize);
673 int newIndex = segmentsSize;
675 for(
int i = 0; i < vertexNumber; ++i) {
677 if(markedVertices[i])
680 int const seg = segmentation_[i];
681 bool const newSegment = markedSegments[seg];
682 dataType minNewSegment = inputData[i];
683 dataType maxNewSegment = minNewSegment;
686 markedSegments[seg] =
true;
695 int const vertex = s.top();
699 markedVertices[vertex] =
true;
704 segmentation_[vertex] = newIndex;
706 dataType currentValue = inputData[vertex];
707 if(currentValue > maxNewSegment)
708 maxNewSegment = currentValue;
709 if(currentValue < minNewSegment)
710 minNewSegment = currentValue;
715 = triangulation.getVertexNeighborNumber(vertex);
716 for(
SimplexId j = 0; j < neighborNumber; ++j) {
718 triangulation.getVertexNeighbor(vertex, j, neighbor);
721 if(!markedVertices[neighbor] && segmentation_[neighbor] == seg) {
729 dataType result = (maxNewSegment + minNewSegment) / 2;
730 segments.push_back(std::make_tuple(result, newIndex));
731 mapping_.emplace_back((
double)result, newIndex);
737 "SQ-D correction step", 1.0, t.
getElapsedTime(), this->threadNumber_);
742 if(!sqDomain && !sqRange && !ZFPOnly) {
743 for(
int i = 0; i < nbCrit; ++i) {
744 SimplexId const id = simplifiedConstraints[i];
745 dataType val = inputData[id];
746 int const type = topologicalSimplification.getCriticalType(
747 id, inputOffsets, triangulation);
751 criticalConstraints_.emplace_back(
id, (
double)val, type);
757 "Exposed constraints", 1.0, t.
getElapsedTime(), this->threadNumber_);
762 if(indexLast > -1 && indexLast + 1 != (
int)mapping_.size()) {
763 this->printWrn(
"Possible affectation mismatch ("
764 + std::to_string(indexLast + 1) +
", "
765 + std::to_string(mapping_.size()) +
")");
769 = indexLast > -1 ? indexLast + 1 : (int)segments.size() - 1;
770 this->NbSegments = nSegments;
771 this->NbVertices = vertexNumber;
773 this->
printMsg(
"Assigned " + std::to_string(nSegments) +
" segment(s).",