TTK
Loading...
Searching...
No Matches
PersistenceDiagramConstrainedOptimization.cpp
Go to the documentation of this file.
2#include <cmath>
3#include <csignal>
4
5#ifdef TTK_ENABLE_EIGEN
6#include <Eigen/Dense>
7#include <Eigen/Eigenvalues>
8#endif // TTK_ENABLE_EIGEN
9
10using namespace ttk;
11
13 std::vector<Matrix> &hessianList,
14 std::vector<double> &weights,
15 const std::vector<double> &grad,
16 bool maxEigenValue) {
17 gradientDescentWeights(hessianList, weights, grad, maxEigenValue);
18 projectionOnSimplex(weights);
19}
20
22 std::vector<ttk::DiagramType> &DictDiagrams,
23 const std::vector<std::vector<ttk::MatchingType>> &matchings,
24 const ttk::DiagramType &Barycenter,
25 const std::vector<Matrix> &gradsLists,
26 const std::vector<int> &checkerAtomsExt,
27 std::vector<std::vector<int>> &projForDiag,
28 ttk::DiagramType &featuresToAdd,
29 std::vector<std::array<double, 2>> &projLocations,
30 std::vector<std::vector<double>> &vectorForProjContrib,
31 std::vector<std::vector<std::array<double, 2>>> &pairToAddGradList,
32 ttk::DiagramType &infoToAdd) {
33 gradientDescentAtoms(DictDiagrams, matchings, Barycenter, gradsLists,
34 checkerAtomsExt, projForDiag, featuresToAdd,
35 projLocations, vectorForProjContrib, pairToAddGradList,
36 infoToAdd);
37}
38
39// simple projection on simplex, aka where a vector has positive elements and
40// sum to 1.
42 std::vector<double> &weights) {
43
44 int n = weights.size();
45 std::vector<double> copy_temp = weights;
46 std::sort(copy_temp.rbegin(), copy_temp.rend());
47 double K = 1.;
48 double somme_u = copy_temp[0];
49 double theta = (somme_u - 1.) / K;
50 while(K < n && (somme_u + copy_temp[K] - 1.) / (K + 1.) < copy_temp[K]) {
51 somme_u += copy_temp[K];
52 K += 1.;
53 theta = (somme_u - 1.) / K;
54 }
55 for(int i = 0; i < n; ++i) {
56 weights[i] = std::max(weights[i] - theta, 0.);
57 }
58
59 double sum = 0.;
60 for(int i = 0; i < n - 1; ++i) {
61 weights[i] = trunc(weights[i] * 1e8) / 1e8;
62 sum += weights[i];
63 }
64 weights[n - 1] = 1. - sum;
65}
66
68 std::vector<Matrix> &hessianList,
69 std::vector<double> &weights,
70 const std::vector<double> &grad,
71 bool maxEigenValue) {
72
73 int n = weights.size();
74 double stepWeight;
75 double L = 0.;
76
77#ifndef TTK_ENABLE_EIGEN
78 maxEigenValue = false;
79#endif
80
81 if(maxEigenValue) {
82#ifdef TTK_ENABLE_EIGEN
83 for(size_t i = 0; i < hessianList.size(); ++i) {
84 auto &hessian = hessianList[i];
85 int m = hessian.size();
86 Eigen::MatrixXd H(m, m);
87 for(size_t j = 0; j < hessian.size(); ++j) {
88 for(size_t k = 0; k < hessian.size(); ++k) {
89 H(j, k) = hessian[j][k];
90 }
91 }
92 Eigen::EigenSolver<Eigen::MatrixXd> es;
93 es.compute(H, false);
94 Eigen::VectorXcd eigvals = es.eigenvalues();
95 L += eigvals.lpNorm<Eigen::Infinity>();
96 }
97#endif // TTK_ENABLE_EIGEN
98 } else {
99 for(size_t i = 0; i < hessianList.size(); ++i) {
100 auto &hessian = hessianList[i];
101 for(size_t k = 0; k < hessian.size(); ++k) {
102 double diag = hessian[k][k];
103 L += 1. * diag;
104 }
105 }
106 }
107
108 if(L > 0) {
109 stepWeight = 1. / L;
110 } else {
111 stepWeight = 0;
112 }
113
114 for(int i = 0; i < n; ++i) {
115 weights[i] = weights[i] - stepWeight * grad[i];
116 }
117}
118
120 std::vector<ttk::DiagramType> &DictDiagrams,
121 const std::vector<std::vector<ttk::MatchingType>> &matchings,
122 const ttk::DiagramType &Barycenter,
123 const std::vector<Matrix> &gradsLists,
124 const std::vector<int> &checkerAtomsExt,
125 std::vector<std::vector<int>> &projForDiag,
126 ttk::DiagramType &featuresToAdd,
127 std::vector<std::array<double, 2>> &projLocations,
128 std::vector<std::vector<double>> &vectorForProjContrib,
129 std::vector<std::vector<std::array<double, 2>>> &pairToAddGradList,
130 ttk::DiagramType &infoToAdd) {
131
132 // Here vector of diagramTuple because it is not a persistence diagram per
133 // say.
134 // we get the right pairs to update for each barycenter pair.
135
136 std::vector<double> miniBirth(matchings.size());
137 for(size_t i = 0; i < matchings.size(); ++i) {
138 auto &t = DictDiagrams[i][0];
139 miniBirth[i] = t.birth.sfValue;
140 }
141
142 std::vector<std::vector<std::array<double, 2>>> gradBuffersList(
143 Barycenter.size());
144 std::vector<std::vector<double>> projectionsBuffer(Barycenter.size());
145
146 for(size_t i = 0; i < Barycenter.size(); ++i) {
147 projectionsBuffer[i].resize(matchings.size());
148 }
149
150 for(size_t i = 0; i < gradBuffersList.size(); ++i) {
151 gradBuffersList[i].resize(matchings.size());
152 }
153
154 std::vector<std::vector<int>> checker(Barycenter.size());
155 for(size_t i = 0; i < checker.size(); ++i) {
156 checker[i].resize(matchings.size());
157 }
158 std::vector<int> tracker(Barycenter.size(), 0);
159 std::vector<std::vector<int>> trackerDiagonal(Barycenter.size());
160 std::vector<std::vector<int>> trackerMatch(Barycenter.size());
161 for(size_t i = 0; i < trackerDiagonal.size(); ++i) {
162 trackerDiagonal[i].resize(matchings.size());
163 }
164 for(size_t i = 0; i < trackerMatch.size(); ++i) {
165 trackerMatch[i].resize(matchings.size());
166 }
167
168 for(size_t i = 0; i < matchings.size(); ++i) {
169 for(size_t j = 0; j < matchings[i].size(); ++j) {
170 const auto &t = matchings[i][j];
171 // Id in atom
172 const SimplexId Id1 = std::get<0>(t);
173 // Id in barycenter
174 const SimplexId Id2 = std::get<1>(t);
175 if(Id2 < 0 || static_cast<SimplexId>(gradBuffersList.size()) <= Id2
176 || static_cast<SimplexId>(DictDiagrams[i].size()) <= Id1) {
177 continue;
178 } else {
179 if(Id1 < 0) {
180 const auto &t3 = Barycenter[Id2];
181 auto &point = gradBuffersList[Id2][i];
182 const double birthBarycenter = t3.birth.sfValue;
183 const double deathBarycenter = t3.death.sfValue;
184 const double birthDeathAtom
185 = birthBarycenter + (deathBarycenter - birthBarycenter) / 2.;
186 point[0] = birthDeathAtom;
187 point[1] = birthDeathAtom;
188 checker[Id2][i] = i;
189 tracker[Id2] = 1;
190 trackerMatch[Id2][i] = Id1;
191 trackerDiagonal[Id2][i] = 1;
192 projectionsBuffer[Id2][i] = birthDeathAtom;
193
194 } else {
195 const auto &t2 = DictDiagrams[i][Id1];
196 auto &point = gradBuffersList[Id2][i];
197 const double birthAtom = t2.birth.sfValue;
198 const double deathAtom = t2.death.sfValue;
199 point[0] = birthAtom;
200 point[1] = deathAtom;
201 checker[Id2][i] = i;
202 tracker[Id2] = 1;
203 trackerMatch[Id2][i] = Id1;
204 trackerDiagonal[Id2][i] = 0;
205 projectionsBuffer[Id2][i] = 0.;
206 }
207 }
208 }
209 }
210
211 gradBuffersList.insert(
212 gradBuffersList.end(), pairToAddGradList.begin(), pairToAddGradList.end());
213 for(size_t j = 0; j < pairToAddGradList.size(); ++j) {
214 std::vector<int> temp1(matchings.size(), 1);
215 std::vector<int> temp2(matchings.size(), -1);
216 std::vector<int> temp3(matchings.size());
217 for(size_t l = 0; l < matchings.size(); ++l) {
218 temp3[l] = static_cast<int>(l);
219 }
220 trackerDiagonal.push_back(temp1);
221 trackerMatch.push_back(temp1);
222 checker.push_back(temp3);
223 tracker.push_back(1);
224 }
225
226 for(size_t i = 0; i < gradBuffersList.size(); ++i) {
227 if(tracker[i] == 0 || checkerAtomsExt[i] == 0) {
228
229 continue;
230 } else {
231
232 std::vector<double> pos(gradBuffersList[i].size(), 0.);
233 for(size_t j = 0; j < checker[i].size(); ++j) {
234 auto &t = gradBuffersList[i][checker[i][j]];
235 double birth = t[0];
236 double death = t[1];
237 pos[j] = death - birth;
238 }
239 std::vector<bool> pos2(pos.size(), false);
240 std::vector<double> temp2;
241 for(size_t p = 0; p < checker[i].size(); ++p) {
242 auto &t = gradBuffersList[i][checker[i][p]];
243 double birth = t[0];
244 pos2[p] = birth == 0.;
245 if(birth > 0.) {
246 temp2.push_back(birth);
247 }
248 }
249 for(size_t p = 0; p < checker[i].size(); ++p) {
250 if(pos2[p]) {
251
252 auto &t = gradBuffersList[i][checker[i][p]];
253
254 t[1] = t[1] - (this->stepAtom_) * gradsLists[i][checker[i][p]][1];
255 } else if(pos[p] < 1e-7) {
256 continue;
257 } else {
258
259 auto &t0 = gradBuffersList[i][checker[i][p]];
260
261 t0[0] = t0[0] - (this->stepAtom_) * gradsLists[i][checker[i][p]][0];
262 t0[1] = t0[1] - (this->stepAtom_) * gradsLists[i][checker[i][p]][1];
263
264 if(t0[0] > t0[1]) {
265 t0[1] = t0[0];
266 }
267 }
268 }
269 }
270 }
271
272 for(size_t i = 0; i < checker.size(); ++i) {
273 if(tracker[i] == 0 || checkerAtomsExt[i] == 0) {
274 continue;
275 } else {
276 if(i < Barycenter.size()) {
277 for(size_t j = 0; j < checker[i].size(); ++j) {
278 auto &trackerTemp = trackerMatch[i][j];
279 if(trackerDiagonal[i][j] == 1 || trackerTemp == -1
280 || trackerTemp > 10000) {
281 std::vector<int> projAndIndex(DictDiagrams.size() + 1);
282 for(size_t m = 0; m < DictDiagrams.size(); ++m) {
283 projAndIndex[m] = trackerMatch[i][m];
284 }
285
286 } else {
287 auto &index = checker[i][j];
288 auto &t2 = gradBuffersList[i][index];
289
290 auto &t1 = DictDiagrams[index][trackerTemp];
291
292 if(t2[0] < miniBirth[index]) {
293 t1.birth.sfValue = miniBirth[index];
294 } else {
295 t1.birth.sfValue = t2[0];
296 }
297 if(t2[1] < t2[0]) {
298 t1.birth.sfValue = t2[0];
299 t1.death.sfValue = t2[0];
300 } else {
301 t1.death.sfValue = t2[1];
302 }
303 }
304 }
305 } else {
306 const auto &infos = infoToAdd[static_cast<int>(i)
307 - static_cast<int>(Barycenter.size())];
308
309 for(size_t j = 0; j < checker[i].size(); ++j) {
310 auto &trackerTemp = trackerMatch[i][j];
311 if(trackerDiagonal[i][j] == 1 || trackerTemp == -1
312 || trackerTemp > 10000) {
313 auto &index = checker[i][j];
314 std::vector<int> projAndIndex(DictDiagrams.size() + 1);
315 int atomIndex = static_cast<int>(index);
316 for(size_t m = 0; m < DictDiagrams.size(); ++m) {
317 projAndIndex[m] = trackerMatch[i][m];
318 }
319 projAndIndex[DictDiagrams.size()] = atomIndex;
320 projForDiag.push_back(projAndIndex);
321 featuresToAdd.push_back(infos);
322 projLocations.push_back(gradBuffersList[i][index]);
323 vectorForProjContrib.push_back(gradsLists[i][index]);
324 } else {
325 auto &index = checker[i][j];
326 auto &t2 = gradBuffersList[i][index];
327 auto &t1 = DictDiagrams[index][trackerTemp];
328 if(t2[0] < miniBirth[index]) {
329 t1.birth.sfValue = miniBirth[index];
330 } else {
331 t1.birth.sfValue = t2[0];
332 }
333 if(t2[1] < t2[0]) {
334 t1.birth.sfValue = t2[0];
335 t1.death.sfValue = t2[0];
336 } else {
337 t1.death.sfValue = t2[1];
338 }
339 }
340 }
341 }
342 }
343 }
344}
345
347 this->stepAtom_ = 1. / (2. * 2. * factEquiv);
348}
349
void gradientDescentWeights(std::vector< Matrix > &hessianList, std::vector< double > &weights, const std::vector< double > &grad, bool maxEigenValue)
void executeAtoms(std::vector< ttk::DiagramType > &DictDiagrams, const std::vector< std::vector< ttk::MatchingType > > &matchings, const ttk::DiagramType &Barycenter, const std::vector< Matrix > &gradsLists, const std::vector< int > &checkerAtomsExt, std::vector< std::vector< int > > &projForDiag, ttk::DiagramType &featuresToAdd, std::vector< std::array< double, 2 > > &projLocations, std::vector< std::vector< double > > &vectorForProjContrib, std::vector< std::vector< std::array< double, 2 > > > &pairToAddGradList, ttk::DiagramType &infoToAdd)
void gradientDescentAtoms(std::vector< ttk::DiagramType > &DictDiagrams, const std::vector< std::vector< ttk::MatchingType > > &matchings, const ttk::DiagramType &Barycenter, const std::vector< Matrix > &gradsLists, const std::vector< int > &checkerAtomsExt, std::vector< std::vector< int > > &projForDiag, ttk::DiagramType &featuresToAdd, std::vector< std::array< double, 2 > > &projLocations, std::vector< std::vector< double > > &vectorForProjContrib, std::vector< std::vector< std::array< double, 2 > > > &pairToAddGradList, ttk::DiagramType &infoToAdd)
void executeWeightsProjected(std::vector< Matrix > &hessianList, std::vector< double > &weights, const std::vector< double > &grad, bool maxEigenValue)
TTK base package defining the standard types.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.