TTK
Loading...
Searching...
No Matches
DimensionReductionMetrics.cpp
Go to the documentation of this file.
2
3#include <random>
4
6#include <ripser.h>
7
9 // inherited from Debug: prefix will be printed at the beginning of every msg
10 this->setDebugMsgPrefix("DimensionReductionMetrics");
11}
12
14 std::vector<std::vector<double>> const &input,
15 std::vector<std::vector<double>> const &latent) {
16 Timer tm{};
17
18 if(input.size() != latent.size()) {
19 printErr("Input and representation have different sizes");
20 return;
21 }
22 if(input.size() == 0) {
23 printErr("Empty input / representation");
24 return;
25 }
26
27 n_ = input.size();
28 dimHigh_ = input[0].size();
29 dimLow_ = latent[0].size();
30 printMsg("#pts: " + std::to_string(n_) + ", highDim: "
31 + std::to_string(dimHigh_) + ", lowDim: " + std::to_string(dimLow_));
32
33 inputCompressedDistanceMatrix_.clear();
34 latentCompressedDistanceMatrix_.clear();
35
36 for(unsigned i = 1; i < n_; ++i) {
37 for(unsigned j = 0; j < i; ++j) {
38 double sHigh = 0., sLow = 0.;
39 for(unsigned d = 0; d < dimHigh_; ++d)
40 sHigh += (input[i][d] - input[j][d]) * (input[i][d] - input[j][d]);
41 inputCompressedDistanceMatrix_.push_back(sqrt(sHigh));
42 for(unsigned d = 0; d < dimLow_; ++d)
43 sLow += (latent[i][d] - latent[j][d]) * (latent[i][d] - latent[j][d]);
44 latentCompressedDistanceMatrix_.push_back(sqrt(sLow));
45 }
46 }
47
48 printMsg("Computing Wasserstein metrics", 0, tm.getElapsedTime());
49 computeTopologicalMetrics();
50 printMsg("Computing triplet accuracy", 0, tm.getElapsedTime());
51 computeTripletAccuracy();
52 printMsg("Computing distance-based measures", 0, tm.getElapsedTime());
53 computePairwiseDistanceBasedMetrics();
54 printMsg("Computing rank-based measures", 0, tm.getElapsedTime());
55 computeRankBasedMetrics();
56 printMsg("Complete", 1, tm.getElapsedTime());
57}
58
59void ttk::DimensionReductionMetrics::computeTopologicalMetrics() {
60 rpd::MultidimensionalDiagram inputPD, latentPD;
61 ripser::ripser({inputCompressedDistanceMatrix_}, inputPD, rpd::inf, 1, true);
63 {latentCompressedDistanceMatrix_}, latentPD, rpd::inf, 1, true);
64 inputPD[0].pop_back();
65 latentPD[0].pop_back();
66
67 PersistenceDiagramWarmRestartAuction auction0(inputPD[0]);
68 auction0.setNewBidder(latentPD[0]);
69 auction0.setWasserstein(Wasserstein);
70 w0_ = auction0.runAuction();
71
72 PersistenceDiagramWarmRestartAuction auction1(inputPD[1]);
73 auction1.setNewBidder(latentPD[1]);
74 auction1.setWasserstein(Wasserstein);
75 w1_ = auction1.runAuction();
76}
77
78bool ttk::DimensionReductionMetrics::tripletOrderPreserved(int i,
79 int j,
80 int k) const {
81 std::vector<std::pair<double, char>> inputTriangle
82 = {{inputDM(i, j), 0}, {inputDM(i, k), 1}, {inputDM(j, k), 2}};
83 std::vector<std::pair<double, char>> latentTriangle
84 = {{latentDM(i, j), 0}, {latentDM(i, k), 1}, {latentDM(j, k), 2}};
85 std::sort(inputTriangle.begin(), inputTriangle.end());
86 std::sort(latentTriangle.begin(), latentTriangle.end());
87 return inputTriangle[0].second == latentTriangle[0].second
88 && inputTriangle[1].second == latentTriangle[1].second
89 && inputTriangle[2].second == latentTriangle[2].second;
90}
91
92void ttk::DimensionReductionMetrics::computeTripletAccuracy() {
93 unsigned stableTriplets = 0;
94 if(SampleSize <= -1) {
95 for(unsigned i = 0; i < n_; ++i) {
96 for(unsigned j = i + 1; j < n_; ++j) {
97 for(unsigned k = j + 1; k < n_; ++k) {
98 if(tripletOrderPreserved(i, j, k))
99 ++stableTriplets;
100 }
101 }
102 }
103 ta_ = double(stableTriplets) * 6 / (n_ * (n_ - 1) * (n_ - 2));
104 } else {
105 std::random_device rd;
106 std::mt19937 gen(rd());
107 std::uniform_int_distribution<> uniform(0, n_ - 1);
108 for(int s = 0; s < SampleSize; ++s) {
109 if(tripletOrderPreserved(uniform(gen), uniform(gen), uniform(gen)))
110 ++stableTriplets;
111 }
112 ta_ = double(stableTriplets) / SampleSize;
113 }
114}
115
116void ttk::DimensionReductionMetrics::computePairwiseDistanceBasedMetrics() {
117 double sumX = 0., sumY = 0., sumXY = 0.;
118 double sqSumX = 0., sqSumY = 0.;
119 double sqSumDiff = 0.;
120 const unsigned Ndis = n_ * (n_ - 1) / 2;
121 for(unsigned i = 0; i < Ndis; ++i) {
122 const double x = inputCompressedDistanceMatrix_[i];
123 const double y = latentCompressedDistanceMatrix_[i];
124 sumX += x;
125 sqSumX += x * x;
126 sumY += y;
127 sqSumY += y * y;
128 sumXY += x * y;
129 sqSumDiff += (x - y) * (x - y);
130 }
131 lc_ = (Ndis * sumXY - sumX * sumY)
132 / sqrt((Ndis * sqSumX - sumX * sumX) * (Ndis * sqSumY - sumY * sumY));
133 rmse_ = sqrt(sqSumDiff / Ndis);
134}
135
136void ttk::DimensionReductionMetrics::computeRankBasedMetrics() {
137 NeighborhoodSize = std::min(NeighborhoodSize, n_ - 1);
138
139 int trustworthinessSum = 0;
140 int continuitySum = 0;
141 int LCMCSum = 0;
142 double inputMRRESum = 0;
143 double latentMRRESum = 0;
144 const int normalizingTC
145 = (NeighborhoodSize < n_ / 2)
146 ? n_ * NeighborhoodSize * (2 * n_ - 3 * NeighborhoodSize - 1)
147 : n_ * (n_ - NeighborhoodSize) * (n_ - NeighborhoodSize - 1);
148 double normalizingMRRE = 0.;
149 for(unsigned k = 1; k < NeighborhoodSize; ++k)
150 normalizingMRRE += n_ * std::abs(double(n_) - 2 * k + 1) / k;
151
152 for(unsigned i = 0; i < n_; ++i) {
153 std::vector<std::pair<double, unsigned>> inputNeighborhood;
154 std::vector<std::pair<double, unsigned>> latentNeighborhood;
155 for(unsigned j = 0; j < n_; ++j) {
156 inputNeighborhood.emplace_back(inputDM(i, j), j);
157 latentNeighborhood.emplace_back(latentDM(i, j), j);
158 }
159 std::sort(inputNeighborhood.begin(), inputNeighborhood.end());
160 std::sort(latentNeighborhood.begin(), latentNeighborhood.end());
161
162 std::vector<unsigned> inputRanks(n_);
163 std::vector<unsigned> latentRanks(n_);
164 for(unsigned s = 0; s < n_; ++s) {
165 inputRanks[inputNeighborhood[s].second] = s;
166 latentRanks[latentNeighborhood[s].second] = s;
167 }
168
169 for(unsigned j = 0; j < n_; ++j) {
170 if(latentRanks[j] <= NeighborhoodSize && inputRanks[j] > NeighborhoodSize)
171 trustworthinessSum += inputRanks[j] - NeighborhoodSize;
172 else if(inputRanks[j] <= NeighborhoodSize
173 && latentRanks[j] > NeighborhoodSize)
174 continuitySum += latentRanks[j] - NeighborhoodSize;
175 else if(inputRanks[j] <= NeighborhoodSize
176 && latentRanks[j] <= NeighborhoodSize && i != j)
177 LCMCSum += 1;
178 }
179
180 for(unsigned s = 1; s <= NeighborhoodSize; ++s) {
181 const unsigned inputNeighbor = inputNeighborhood[s].second;
182 inputMRRESum += double(std::abs(int(s) - int(latentRanks[inputNeighbor])))
183 / latentRanks[inputNeighbor];
184 const unsigned latentNeighbor = latentNeighborhood[s].second;
185 latentMRRESum
186 += double(std::abs(int(s) - int(inputRanks[latentNeighbor])))
187 / inputRanks[latentNeighbor];
188 }
189 }
190
191 trust_ = 1. - 2 * double(trustworthinessSum) / normalizingTC;
192 cont_ = 1. - 2 * double(continuitySum) / normalizingTC;
193 lcmc_ = (double(LCMCSum) / (n_ * NeighborhoodSize)
194 - double(NeighborhoodSize) / (n_ - 1))
195 / (1 - double(NeighborhoodSize) / (n_ - 1));
196 mrreh_ = inputMRRESum / normalizingMRRE;
197 mrrel_ = latentMRRESum / normalizingMRRE;
198}
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void execute(std::vector< std::vector< double > > const &input, std::vector< std::vector< double > > const &latent)
Main entry point.
TTK base class that computes the Wasserstein distance between two persistence diagrams.
void ripser(std::vector< std::vector< value_t > > points, PersistenceType &ph, value_t threshold, index_t dim_max, bool distanceMatrix, bool criticalEdgesOnly=true, bool infinitePairs=true, coefficient_t modulus=2)
Definition ripser.cpp:1136
constexpr value_t inf
std::vector< Diagram > MultidimensionalDiagram
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)