TTK
Loading...
Searching...
No Matches
PDBarycenter.cpp
Go to the documentation of this file.
1
14
16
17#include <cmath>
18#include <cstdlib> /* srand, rand */
19#include <numeric>
20
21std::vector<std::vector<ttk::MatchingType>>
23 return executeAuctionBarycenter(barycenter);
24}
25
27 double *total_cost,
28 double epsilon,
29 std::vector<int> &sizes,
30 KDT &kdt,
31 std::vector<KDT *> &correspondence_kdt_map,
32 std::vector<double> *min_diag_price,
33 std::vector<double> *min_price,
34 std::vector<std::vector<MatchingType>> *all_matchings,
35 bool use_kdt,
36 bool actual_distance) {
37 Timer const time_matchings;
38
39 double local_cost = *total_cost;
40#ifdef TTK_ENABLE_OPENMP
41#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic, 1) \
42 reduction(+ : local_cost)
43#endif
44 for(int i = 0; i < numberOfInputs_; i++) {
47 geometrical_factor_, lambda_, delta_lim_, kdt, correspondence_kdt_map,
48 epsilon, min_diag_price->at(i), use_kdt, nonMatchingWeight_);
49 int n_biddings = 0;
51 auction.initLowerBoundCost(i);
52 auction.buildUnassignedBidders();
53 auction.reinitializeGoods();
54 auction.runAuctionRound(n_biddings, i);
55 auction.updateDiagonalPrices();
56 min_diag_price->at(i) = auction.getMinimalDiagonalPrice();
57 min_price->at(i) = getMinimalPrice(i);
58 std::vector<MatchingType> matchings;
59 double const cost = auction.getMatchingsAndDistance(matchings, true);
60 all_matchings->at(i) = matchings;
61 if(actual_distance) {
62 local_cost += sqrt(cost);
63 } else {
64 local_cost += cost;
65 }
66
67 double const quotient
68 = epsilon * auction.getAugmentedNumberOfBidders() / cost;
69 precision_[i] = quotient < 1 ? 1. / sqrt(1 - quotient) - 1 : 10;
70 if(auction.getRelativePrecision() == 0)
71 precision_[i] = 0;
72 // Resizes the diagram which was enrich with diagonal bidders
73 // during the auction
74 // TODO do this inside the auction !
75 current_bidder_diagrams_[i].resize(sizes[i]);
76 }
77 *total_cost = local_cost;
78}
79
81 double *total_cost,
82 std::vector<int> &sizes,
83 KDT &kdt,
84 std::vector<KDT *> &correspondence_kdt_map,
85 std::vector<double> *min_diag_price,
86 std::vector<std::vector<MatchingType>> *all_matchings,
87 bool use_kdt,
88 bool actual_distance) {
89 double local_cost = *total_cost;
90#ifdef TTK_ENABLE_OPENMP
91#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic, 1) \
92 reduction(+ : local_cost)
93#endif
94 for(int i = 0; i < numberOfInputs_; i++) {
97 geometrical_factor_, lambda_, delta_lim_, kdt, correspondence_kdt_map, 0,
98 (*min_diag_price)[i], use_kdt, nonMatchingWeight_);
99 std::vector<MatchingType> matchings;
100 double const cost = auction.run(matchings, i);
101 all_matchings->at(i) = matchings;
102 if(actual_distance) {
103 local_cost += sqrt(cost);
104 } else {
105 local_cost += cost;
106 }
107
108 // Resizes the diagram which was enrich with diagonal bidders
109 // during the auction
110 // TODO do this inside the auction !
111 current_bidder_diagrams_[i].resize(sizes[i]);
112 }
113 *total_cost = local_cost;
114}
115
117 std::vector<std::vector<MatchingType>> &matchings,
118 std::vector<std::vector<MatchingType>> &previous_matchings) {
119 if(points_added_ > 0 || points_deleted_ > 0 || previous_matchings.empty()) {
120 return false;
121 }
122
123 for(size_t j = 0; j < matchings.size(); j++) {
124 for(size_t i = 0; i < matchings[j].size(); i++) {
125 MatchingType t = matchings[j][i];
126 MatchingType previous_t = previous_matchings[j][i];
127
128 if(std::get<1>(t) != std::get<1>(previous_t)
129 && (std::get<0>(t) >= 0 && std::get<0>(previous_t) >= 0)) {
130 return false;
131 }
132 }
133 }
134 return true;
135}
136
137std::vector<std::vector<ttk::MatchingType>> ttk::PDBarycenter::correctMatchings(
138 std::vector<std::vector<MatchingType>> &previous_matchings) {
139
140 std::vector<std::vector<MatchingType>> corrected_matchings(numberOfInputs_);
141 for(int i = 0; i < numberOfInputs_; i++) {
142 // 1. Invert the current_bidder_ids_ vector
143 std::vector<int> new_to_old_id(current_bidder_diagrams_[i].size());
144 for(size_t j = 0; j < current_bidder_ids_[i].size(); j++) {
145 int const new_id = current_bidder_ids_[i][j];
146 if(new_id >= 0) {
147 new_to_old_id[new_id] = j;
148 }
149 }
150 // 2. Reconstruct the matchings
151 std::vector<MatchingType> matchings_diagram_i;
152 for(size_t j = 0; j < previous_matchings[i].size(); j++) {
153 MatchingType m = previous_matchings[i][j];
154 int const new_id = std::get<0>(m);
155 if(new_id >= 0 && std::get<1>(m) >= 0) {
156 std::get<0>(m) = new_to_old_id[new_id];
157 matchings_diagram_i.push_back(m);
158 }
159 }
160 corrected_matchings[i] = matchings_diagram_i;
161 }
162 return corrected_matchings;
163}
164
166 std::vector<std::vector<MatchingType>> &matchings) {
167 // 1. Initialize variables used in the sequel
168 Timer const t_update;
169 size_t const n_goods = barycenter_goods_[0].size();
170
171 size_t const n_diagrams = current_bidder_diagrams_.size();
172 points_added_ = 0;
173 points_deleted_ = 0;
174 double max_shift = 0;
175
176 std::vector<double> weight_diag_matchings(
177 n_goods); // Total weight for diagonal matchings for each point of the
178 // barycenter
179 std::vector<size_t> count_diag_matchings(
180 n_goods,
181 0); // Number of diagonal matchings for each point of the barycenter
182 std::vector<double> x(n_goods, 0);
183 std::vector<double> y(n_goods, 0);
184 std::vector<double> crit_coords_x(n_goods, 0);
185 std::vector<double> crit_coords_y(n_goods, 0);
186 std::vector<double> crit_coords_z(n_goods, 0);
187
188 std::vector<double> min_prices(
189 n_diagrams, std::numeric_limits<double>::max());
190
191 // Will collect bidders linked to diagonal
192 // second value indicate the corresponding weight.
193 std::vector<std::pair<Bidder *, double>> points_to_append;
194 std::vector<int> diagonalToNewGood;
195 if(numberOfInputs_ == 2)
196 diagonalToNewGood.resize(current_bidder_diagrams_[0].size()
197 + current_bidder_diagrams_[1].size());
198
199 // 2. Preprocess the matchings
200 for(size_t j = 0; j < matchings.size(); j++) {
201 double weight = useCustomWeights_ ? (*customWeights_)[j] : 0.0;
202 for(size_t i = 0; i < matchings[j].size(); i++) {
203 int const bidder_id = std::get<0>(matchings[j][i]);
204 int const good_id = std::get<1>(matchings[j][i]);
205 if(good_id < 0 && bidder_id >= 0) {
206 // Future new barycenter point
207 points_to_append.emplace_back(
208 &current_bidder_diagrams_[j].at(bidder_id), weight);
209 if(numberOfInputs_ == 2)
210 diagonalToNewGood[-good_id - 1]
211 = n_goods + points_to_append.size() - 1;
212 }
213
214 else if(good_id >= 0 && bidder_id >= 0) {
215 // Update coordinates (to be divided by the number of diagrams later on)
217 x[good_id] += weight * current_bidder_diagrams_[j].at(bidder_id).x_;
218 y[good_id] += weight * current_bidder_diagrams_[j].at(bidder_id).y_;
219 } else {
220 x[good_id] += current_bidder_diagrams_[j].at(bidder_id).x_;
221 y[good_id] += current_bidder_diagrams_[j].at(bidder_id).y_;
222 }
223 if(geometrical_factor_ < 1) {
224 const auto &critical_coordinates = current_bidder_diagrams_[j]
225 .at(bidder_id)
226 .GetCriticalCoordinates();
227 crit_coords_x[good_id] += critical_coordinates[0];
228 crit_coords_y[good_id] += critical_coordinates[1];
229 crit_coords_z[good_id] += critical_coordinates[2];
230 }
231 } else if(good_id >= 0 && bidder_id < 0) {
232 // Counting the number of times this barycenter point is linked to the
233 // diagonal
234 count_diag_matchings[good_id] = count_diag_matchings[good_id] + 1;
236 weight_diag_matchings[good_id]
237 = weight_diag_matchings[good_id] + weight;
238 }
239 }
240 }
241 }
242
243 // 3. Update the previous points of the barycenter
244 for(size_t i = 0; i < n_goods; i++) {
245 if(count_diag_matchings[i] < n_diagrams) {
246 // Barycenter point i is matched at least to one off-diagonal bidder
247 // 3.1 Compute the arithmetic mean of off-diagonal bidders linked to it
248 double x_bar = 0;
249 double y_bar = 0;
250
252 // weighted arithmetic mean of OFF-DIAGONAL points
253 // = sum_i weight[i]*x[i] / sum_j weight[j]
254 // if sum_j weight[j] = 0 (matched to off-diagonal points with weight
255 // zero), then skip the computation
256 if(weight_diag_matchings[i] < 1) {
257 x_bar = x[i] / (1 - weight_diag_matchings[i]);
258 y_bar = y[i] / (1 - weight_diag_matchings[i]);
259 }
260 } else {
261 x_bar = x[i] / (double)(n_diagrams - count_diag_matchings[i]);
262 y_bar = y[i] / (double)(n_diagrams - count_diag_matchings[i]);
263 }
264
265 // 3.2 Compute the new coordinates of the point (the more linked to the
266 // diagonal it was, the closer to the diagonal it'll be)
267 double new_x = 0;
268 double new_y = 0;
269
271 new_x = (1 - weight_diag_matchings[i]) * x_bar
272 + weight_diag_matchings[i] * (x_bar + y_bar) / 2.;
273 new_y = (1 - weight_diag_matchings[i]) * y_bar
274 + weight_diag_matchings[i] * (x_bar + y_bar) / 2.;
275 } else {
276 new_x = ((double)(n_diagrams - count_diag_matchings[i]) * x_bar
277 + (double)count_diag_matchings[i] * (x_bar + y_bar) / 2.)
278 / (double)n_diagrams;
279 new_y = ((double)(n_diagrams - count_diag_matchings[i]) * y_bar
280 + (double)count_diag_matchings[i] * (x_bar + y_bar) / 2.)
281 / (double)n_diagrams;
282 }
283
284 // TODO Weight by persistence
285 double const new_crit_coord_x
286 = crit_coords_x[i] / (double)(n_diagrams - count_diag_matchings[i]);
287 double const new_crit_coord_y
288 = crit_coords_y[i] / (double)(n_diagrams - count_diag_matchings[i]);
289 double const new_crit_coord_z
290 = crit_coords_z[i] / (double)(n_diagrams - count_diag_matchings[i]);
291
292 // 3.3 Compute and store how much the point has shifted
293 // TODO adjust shift with geometrical_factor_
294 double const dx = barycenter_goods_[0].at(i).x_ - new_x;
295 double const dy = barycenter_goods_[0].at(i).y_ - new_y;
296 double const shift = Geometry::pow(std::abs(dx), wasserstein_)
297 + Geometry::pow(std::abs(dy), wasserstein_);
298 if(shift > max_shift) {
299 max_shift = shift;
300 }
301 // 3.4 Update the position of the point
302 for(size_t j = 0; j < n_diagrams; j++) {
303 barycenter_goods_[j].at(i).SetCoordinates(new_x, new_y);
304 if(geometrical_factor_ < 1) {
305 barycenter_goods_[j].at(i).SetCriticalCoordinates(
306 new_crit_coord_x, new_crit_coord_y, new_crit_coord_z);
307 }
308 if(barycenter_goods_[j].at(i).getPrice() < min_prices[j]) {
309 min_prices[j] = barycenter_goods_[j].at(i).getPrice();
310 }
311 }
312 // TODO Reinitialize/play with prices here if you wish
313 }
314 }
315 for(size_t j = 0; j < n_diagrams; j++) {
316 if(min_prices[j] >= std::numeric_limits<double>::max() / 2.) {
317 min_prices[j] = 0;
318 }
319 }
320
321 // 4. Delete off-diagonal barycenter points not linked to any
322 // off-diagonal bidder
323 for(size_t i = 0; i < n_goods; i++) {
324 if(count_diag_matchings[i] == n_diagrams) {
325 points_deleted_ += 1;
326 double const shift
327 = 2
329 barycenter_goods_[0].at(i).getPersistence() / 2., wasserstein_);
330 if(shift > max_shift) {
331 max_shift = shift;
332 }
333 for(size_t j = 0; j < n_diagrams; j++) {
334 barycenter_goods_[j].at(i).id_ = -1;
335 }
336 }
337 }
338
339 // 5. Append the new points to the barycenter
340 for(size_t k = 0; k < points_to_append.size(); k++) {
341 points_added_ += 1;
342 Bidder *b = points_to_append[k].first;
343 double gx
344 = (b->x_ + (n_diagrams - 1) * (b->x_ + b->y_) / 2.) / (n_diagrams);
345 double gy
346 = (b->y_ + (n_diagrams - 1) * (b->x_ + b->y_) / 2.) / (n_diagrams);
348 // need to retrieve the correct weight here
349 double weight = points_to_append[k].second;
350 gx = weight * b->x_ + (1 - weight) * (b->x_ + b->y_) / 2.;
351 gy = weight * b->y_ + (1 - weight) * (b->x_ + b->y_) / 2.;
352 }
353 const auto &critical_coordinates = b->GetCriticalCoordinates();
354 for(size_t j = 0; j < n_diagrams; j++) {
355 Good g = Good(gx, gy, false, barycenter_goods_[j].size());
356 g.setPrice(min_prices[j]);
357 if(geometrical_factor_ < 1) {
358 g.SetCriticalCoordinates(std::get<0>(critical_coordinates),
359 std::get<1>(critical_coordinates),
360 std::get<2>(critical_coordinates));
361 }
362 barycenter_goods_[j].emplace_back(g);
363 double const shift
364 = 2
366 barycenter_goods_[j].at(g.id_).getPersistence() / 2., wasserstein_);
367 if(shift > max_shift) {
368 max_shift = shift;
369 }
370 }
371 }
372
373 // 6. Finally, recreate barycenter_goods
374 for(size_t j = 0; j < n_diagrams; j++) {
375 int count = 0;
376 GoodDiagram new_barycenter;
377 for(size_t i = 0; i < barycenter_goods_[j].size(); i++) {
378 Good g = barycenter_goods_[j].at(i);
379 if(g.id_ != -1) {
380 g.id_ = count;
381 new_barycenter.emplace_back(g);
382 count++;
383 }
384 }
385 barycenter_goods_[j] = new_barycenter;
386 }
387
388 // final update of matchings here if there are only 2 input diagrams
389 if(numberOfInputs_ == 2) {
390 std::vector<double> costs(n_goods + points_to_append.size(), 0.);
391 for(int i = 0; i < 2; ++i) {
392 for(auto &[b_id, g_id, c] : matchings[i]) {
393 if(g_id < 0 && diagonalToNewGood[-g_id - 1] > 0)
394 g_id = diagonalToNewGood[-g_id - 1];
395 if(g_id >= 0)
396 costs[g_id] += c;
397 }
398 }
399 for(int i = 0; i < 2; ++i) {
400 for(auto &[b_id, g_id, c] : matchings[i]) {
401 if(g_id >= 0)
402 c = costs[g_id] / Geometry::pow(2, wasserstein_);
403 }
404 }
405 }
406
407 return max_shift;
408}
409
411 return rho * rho / 8.0;
412}
413
414double ttk::PDBarycenter::getRho(double epsilon) {
415 return std::sqrt(8.0 * epsilon);
416}
417
419
420 for(int i = 0; i < numberOfInputs_; i++) {
421 DiagramType *CTDiagram = &((*inputDiagrams_)[i]);
422
423 BidderDiagram bidders;
424 for(size_t j = 0; j < CTDiagram->size(); j++) {
425 // Add bidder to bidders
426 Bidder b((*CTDiagram)[j], j, lambda_);
427
428 b.setPositionInAuction(bidders.size());
429 bidders.emplace_back(b);
430 if(b.isDiagonal() || b.x_ == b.y_) {
431 this->printWrn("Diagonal point in diagram !!!");
432 }
433 }
434 bidder_diagrams_.push_back(bidders);
435 current_bidder_diagrams_.emplace_back();
436 std::vector<int> ids(bidders.size(), -1);
437 current_bidder_ids_.push_back(ids);
438 }
439}
440
442 double previous_min_persistence,
443 double min_persistence,
444 std::vector<double> &initial_diagonal_prices,
445 std::vector<double> &initial_off_diagonal_prices,
446 int min_points_to_add,
447 bool add_points_to_barycenter) {
448
449 double new_min_persistence = min_persistence;
450
451 // 1. Get size of the largest current diagram, deduce the maximal number of
452 // points to append
453 size_t max_diagram_size{};
454 for(int i = 0; i < numberOfInputs_; i++) {
455 if(current_bidder_diagrams_[i].size() > max_diagram_size) {
456 max_diagram_size = current_bidder_diagrams_[i].size();
457 }
458 }
459 int const max_points_to_add = std::max(
460 min_points_to_add, min_points_to_add + (int)(max_diagram_size / 10));
461
462 // 2. Get which points can be added, deduce the new minimal persistence
463 std::vector<std::vector<int>> candidates_to_be_added(numberOfInputs_);
464 std::vector<std::vector<int>> idx(numberOfInputs_);
465 for(int i = 0; i < numberOfInputs_; i++) {
466
467 std::vector<double> persistences;
468 for(size_t j = 0; j < bidder_diagrams_[i].size(); j++) {
469 Bidder const b = bidder_diagrams_[i].at(j);
470 double const persistence = b.getPersistence();
471 if(persistence >= min_persistence
472 && persistence < previous_min_persistence) {
473 candidates_to_be_added[i].push_back(j);
474 idx[i].push_back(idx[i].size());
475 persistences.push_back(persistence);
476 }
477 }
478 sort(idx[i].begin(), idx[i].end(), [&persistences](int &a, int &b) {
479 return ((persistences[a] > persistences[b])
480 || ((persistences[a] == persistences[b]) && (a > b)));
481 });
482 int const size = candidates_to_be_added[i].size();
483 if(size >= max_points_to_add) {
484 double const last_persistence_added
485 = persistences[idx[i][max_points_to_add - 1]];
486 if(last_persistence_added > new_min_persistence) {
487 new_min_persistence = last_persistence_added;
488 }
489 }
490 }
491
492 // 3. Add the points to the current diagrams
493
494 // only to give determinism
495 int counter_for_adding_points = 0;
496
497 for(int i = 0; i < numberOfInputs_; i++) {
498 int const size = candidates_to_be_added[i].size();
499 for(int j = 0; j < std::min(max_points_to_add, size); j++) {
500 Bidder b = bidder_diagrams_[i].at(candidates_to_be_added[i][idx[i][j]]);
501 if(b.getPersistence() >= new_min_persistence) {
502 b.id_ = current_bidder_diagrams_[i].size();
504 b.setDiagonalPrice(initial_diagonal_prices[i]);
505 current_bidder_diagrams_[i].emplace_back(b);
506 // b.id_ --> position of b in current_bidder_diagrams_[i]
507 current_bidder_ids_[i][candidates_to_be_added[i][idx[i][j]]]
508 = current_bidder_diagrams_[i].size() - 1;
509
510 int const to_be_added_to_barycenter
511 = deterministic_ ? counter_for_adding_points % numberOfInputs_
512 : rand() % numberOfInputs_;
513 // We add the bidder as a good with probability 1/n_diagrams
514 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
515 for(int k = 0; k < numberOfInputs_; k++) {
516 Good g = Good(b.x_, b.y_, false, barycenter_goods_[k].size());
517 g.setPrice(initial_off_diagonal_prices[k]);
518 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
519 barycenter_goods_[k].emplace_back(g);
520 }
521 }
522 }
523 counter_for_adding_points++;
524 }
525 }
526 return new_min_persistence;
527}
528
530 double max_persistence = 0;
531 for(int i = 0; i < numberOfInputs_; i++) {
533 for(size_t j = 0; j < D.size(); j++) {
534 // Add bidder to bidders
535 Bidder const &b = D.at(j);
536 double const persistence = b.getPersistence();
537 if(persistence > max_persistence) {
538 max_persistence = persistence;
539 }
540 }
541 }
542 return max_persistence;
543}
544
546 double min_price = std::numeric_limits<double>::max();
547
549 if(D.empty()) {
550 return 0;
551 }
552 for(size_t j = 0; j < D.size(); j++) {
553 Good const &b = D.at(j);
554 double const price = b.getPrice();
555 if(price < min_price) {
556 min_price = price;
557 }
558 }
559 if(min_price >= std::numeric_limits<double>::max() / 2.) {
560 return 0;
561 }
562 return min_price;
563}
564
566 double lowest_persistence = std::numeric_limits<double>::max();
567 for(int i = 0; i < numberOfInputs_; i++) {
569 for(size_t j = 0; j < D.size(); j++) {
570 // Add bidder to bidders
571 Bidder const &b = D.at(j);
572 double const persistence = b.getPersistence();
573 if(persistence < lowest_persistence && persistence > 0) {
574 lowest_persistence = persistence;
575 }
576 }
577 }
578 if(lowest_persistence >= std::numeric_limits<double>::max() / 2.) {
579 return 0;
580 }
581 return lowest_persistence;
582}
583
584void ttk::PDBarycenter::setInitialBarycenter(double min_persistence) {
585 int size = 0;
586 int random_idx;
587 DiagramType *CTDiagram;
588 int iter = 0;
589 while(size == 0) {
590 random_idx
591 = deterministic_ ? iter % numberOfInputs_ : rand() % numberOfInputs_;
592 CTDiagram = &((*inputDiagrams_)[random_idx]);
593 for(int i = 0; i < numberOfInputs_; i++) {
594 GoodDiagram goods;
595 int count = 0;
596 for(size_t j = 0; j < CTDiagram->size(); j++) {
597 // Add good to goods
598 Good const g = Good((*CTDiagram)[j], count, lambda_);
599 if(g.getPersistence() >= min_persistence) {
600 goods.emplace_back(g);
601 count++;
602 }
603 }
604 if(static_cast<int>(barycenter_goods_.size()) < (i + 1)) {
605 barycenter_goods_.push_back(goods);
606 } else {
607 barycenter_goods_[i] = goods;
608 }
609 }
610 size = barycenter_goods_[0].size();
611 iter++;
612 }
613}
614
616 Timer tm;
617 auto kdt = std::make_unique<KDT>(true, wasserstein_);
618
619 const int dimension = geometrical_factor_ >= 1 ? 2 : 5;
620
621 std::vector<double> coordinates;
622 std::vector<std::vector<double>> weights;
623
624 for(size_t i = 0; i < barycenter_goods_[0].size(); i++) {
625 const Good &g = barycenter_goods_[0].at(i);
626 coordinates.push_back(geometrical_factor_ * g.x_);
627 coordinates.push_back(geometrical_factor_ * g.y_);
628 if(geometrical_factor_ < 1) {
629 coordinates.push_back((1 - geometrical_factor_) * g.coords_[0]);
630 coordinates.push_back((1 - geometrical_factor_) * g.coords_[1]);
631 coordinates.push_back((1 - geometrical_factor_) * g.coords_[2]);
632 }
633 }
634
635 for(size_t idx = 0; idx < barycenter_goods_.size(); idx++) {
636 std::vector<double> const empty_weights;
637 weights.push_back(empty_weights);
638 for(size_t i = 0; i < barycenter_goods_[idx].size(); i++) {
639 const Good &g = barycenter_goods_[idx].at(i);
640 weights[idx].push_back(g.getPrice());
641 }
642 }
643 // Correspondence map : position in barycenter_goods_ --> KDT node
644
645 auto correspondence_kdt_map
646 = kdt->build(coordinates.data(), barycenter_goods_[0].size(), dimension,
647 weights, barycenter_goods_.size());
648 this->printMsg(" Building KDTree", 1, tm.getElapsedTime(),
650 return std::make_pair(std::move(kdt), correspondence_kdt_map);
651}
652
653std::vector<std::vector<ttk::MatchingType>>
655
656 std::vector<std::vector<MatchingType>> previous_matchings;
657 double const min_persistence = 0;
658 double min_cost = std::numeric_limits<double>::max();
659 int last_min_cost_obtained = 0;
660
661 this->setBidderDiagrams();
663 min_persistence); // false for a determinist initialization
664
665 double const max_persistence = getMaxPersistence();
666
667 std::vector<double> min_diag_price(numberOfInputs_, 0);
668 std::vector<double> min_price(numberOfInputs_, 0);
669
670 int const min_points_to_add = std::numeric_limits<int>::max();
671 this->enrichCurrentBidderDiagrams(2 * max_persistence, min_persistence,
672 min_diag_price, min_price,
673 min_points_to_add, false);
674
675 bool converged = false;
676 bool finished = false;
677 double total_cost;
678
679 while(!finished) {
680 Timer const tm;
681
682 std::pair<std::unique_ptr<KDT>, std::vector<KDT *>> pair;
683 bool use_kdt = false;
684 // If the barycenter is empty, do not compute the kdt (or it will crash :/)
685 // TODO Fix KDTree to handle empty inputs...
686 if(!barycenter_goods_[0].empty()) {
687 pair = this->getKDTree();
688 use_kdt = true;
689 }
690
691 std::vector<std::vector<MatchingType>> all_matchings(numberOfInputs_);
692 std::vector<int> sizes(numberOfInputs_);
693 for(int i = 0; i < numberOfInputs_; i++) {
694 sizes[i] = current_bidder_diagrams_[i].size();
695 }
696
697 total_cost = 0;
698
699 barycenter.clear();
700 for(size_t j = 0; j < barycenter_goods_[0].size(); j++) {
701 Good const &g = barycenter_goods_[0].at(j);
702 barycenter.emplace_back(PersistencePair{
703 CriticalVertex{0, g.x_, {}, {}, nt1_},
704 CriticalVertex{0, g.y_, {}, {}, nt2_}, diagramType_, true});
705 }
706
707 bool const actual_distance = (numberOfInputs_ == 2);
708 runMatchingAuction(&total_cost, sizes, *pair.first, pair.second,
709 &min_diag_price, &all_matchings, use_kdt,
710 actual_distance);
711
712 this->printMsg("Barycenter cost : " + std::to_string(total_cost),
714
715 if(converged) {
716 finished = true;
717 }
718
719 if(!finished) {
720 updateBarycenter(all_matchings);
721
722 if(min_cost > total_cost) {
723 min_cost = total_cost;
724 last_min_cost_obtained = 0;
725 } else {
726 last_min_cost_obtained += 1;
727 }
728
729 converged = last_min_cost_obtained > 1;
730 if(numberOfInputs_ == 2)
731 finished = true;
732 }
733
734 previous_matchings = std::move(all_matchings);
735 // END OF TIMER
736
737 for(size_t i = 0; i < barycenter_goods_.size(); ++i) {
738 for(size_t j = 0; j < barycenter_goods_[i].size(); ++j) {
739 barycenter_goods_[i].at(j).setPrice(0);
740 }
741 }
742 for(size_t i = 0; i < current_bidder_diagrams_.size(); ++i) {
743 for(size_t j = 0; j < current_bidder_diagrams_[i].size(); ++j) {
744 current_bidder_diagrams_[i].at(j).setDiagonalPrice(0);
745 }
746 }
747 min_diag_price.assign(numberOfInputs_, 0);
748 min_price.assign(numberOfInputs_, 0);
749 }
750 barycenter.resize(0);
751 for(size_t j = 0; j < barycenter_goods_[0].size(); j++) {
752 Good const &g = barycenter_goods_[0].at(j);
753 barycenter.emplace_back(PersistencePair{
754 CriticalVertex{0, g.x_, {}, {}, nt1_},
755 CriticalVertex{0, g.y_, {}, {}, nt2_}, diagramType_, true});
756 }
757
758 cost_ = total_cost;
759 std::vector<std::vector<MatchingType>> corrected_matchings
760 = correctMatchings(previous_matchings);
761 return corrected_matchings;
762}
763
765 double total_real_cost = 0;
766 std::vector<MatchingType> fake_matchings;
767 for(int i = 0; i < numberOfInputs_; i++) {
769 lambda_, 0.01, true, nonMatchingWeight_);
770 GoodDiagram const current_barycenter = barycenter_goods_[0];
771 BidderDiagram const current_bidder_diagram = bidder_diagrams_[i];
772 auction.BuildAuctionDiagrams(current_bidder_diagram, current_barycenter);
773 double const cost = auction.run(fake_matchings);
774 total_real_cost += cost * cost;
775 }
776 return sqrt(total_real_cost);
777}
778
779bool ttk::PDBarycenter::isPrecisionObjectiveMet(double precision_objective,
780 int mode) {
781 if(mode == 0) { // ABSOLUTE PRECISION
782 for(int i_input = 0; i_input < numberOfInputs_; i_input++) {
783 if(precision_[i_input] > precision_objective) {
784 return false;
785 }
786 }
787 } else if(mode == 1) { // AVERAGE PRECISION
788 double const average_precision
789 = std::accumulate(precision_.begin(), precision_.end(), 0.0)
791 if(average_precision > precision_objective) {
792 return false;
793 }
794 }
795 return true;
796}
void setDiagonalPrice(const double price)
void setPositionInAuction(const int pos)
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
void setPrice(const double price)
std::vector< std::vector< MatchingType > > executeAuctionBarycenter(DiagramType &barycenter)
std::vector< double > precision_
ttk::CriticalType nt1_
double getEpsilon(double rho)
void runMatching(double *total_cost, double epsilon, std::vector< int > &sizes, KDT &kdt, std::vector< KDT * > &correspondence_kdt_map, std::vector< double > *min_diag_price, std::vector< double > *min_price, std::vector< std::vector< MatchingType > > *all_matchings, bool use_kdt, bool actual_distance)
std::pair< typename KDT::KDTreeRoot, typename KDT::KDTreeMap > KDTreePair
ttk::CriticalType nt2_
std::vector< GoodDiagram > barycenter_goods_
double getRho(double epsilon)
std::vector< BidderDiagram > current_bidder_diagrams_
double updateBarycenter(std::vector< std::vector< MatchingType > > &matchings)
void setInitialBarycenter(double min_persistence)
bool isPrecisionObjectiveMet(double, int)
std::vector< BidderDiagram > bidder_diagrams_
KDTreePair getKDTree() const
std::vector< std::vector< MatchingType > > correctMatchings(std::vector< std::vector< MatchingType > > &previous_matchings)
void runMatchingAuction(double *total_cost, std::vector< int > &sizes, KDT &kdt, std::vector< KDT * > &correspondence_kdt_map, std::vector< double > *min_diag_price, std::vector< std::vector< MatchingType > > *all_matchings, bool use_kdt, bool actual_distance)
PersistenceDiagramAuction::KDT KDT
double getMinimalPrice(int i)
double getLowestPersistence()
std::vector< std::vector< MatchingType > > execute(DiagramType &barycenter)
bool hasBarycenterConverged(std::vector< std::vector< MatchingType > > &matchings, std::vector< std::vector< MatchingType > > &previous_matchings)
std::vector< std::vector< int > > current_bidder_ids_
double enrichCurrentBidderDiagrams(double previous_min_persistence, double min_persistence, std::vector< double > &initial_diagonal_prices, std::vector< double > &initial_off_diagonal_prices, int min_points_to_add, bool add_points_to_barycenter=true)
void SetCriticalCoordinates(const float coords_x, const float coords_y, const float coords_z)
std::array< float, 3 > GetCriticalCoordinates() const
void runAuctionRound(int &n_biddings, const int kdt_index=0)
double run(std::vector< MatchingType > &matchings, const int kdt_index=0)
double initLowerBoundCost(const int kdt_index=0)
double getMatchingsAndDistance(std::vector< MatchingType > &matchings, bool get_diagonal_matches=false)
void BuildAuctionDiagrams(const BidderDiagram &BD, const GoodDiagram &GD)
void initLowerBoundCostWeight(double delta_lim)
double getElapsedTime()
Definition Timer.h:15
T1 pow(const T1 val, const T2 n)
Definition Geometry.h:456
std::tuple< int, int, double > MatchingType
Matching between two Persistence Diagram pairs.
std::vector< Good > GoodDiagram
std::vector< Bidder > BidderDiagram
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.
T end(std::pair< T, T > &p)
Definition ripser.cpp:503
T begin(std::pair< T, T > &p)
Definition ripser.cpp:499
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)