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) reduction(+:local_cost)
42#endif
43 for(int i = 0; i < numberOfInputs_; i++) {
44 double const delta_lim = delta_lim_;
46 current_bidder_diagrams_[i], barycenter_goods_[i], wasserstein_,
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;
50 auction.initLowerBoundCostWeight(delta_lim);
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) reduction(+:local_cost)
92#endif
93 for(int i = 0; i < numberOfInputs_; i++) {
95 current_bidder_diagrams_[i], barycenter_goods_[i], wasserstein_,
96 geometrical_factor_, lambda_, delta_lim_, kdt, correspondence_kdt_map, 0,
97 (*min_diag_price)[i], use_kdt, nonMatchingWeight_);
98 std::vector<MatchingType> matchings;
99 double const cost = auction.run(matchings, i);
100 all_matchings->at(i) = matchings;
101 if(actual_distance) {
102 local_cost += sqrt(cost);
103 } else {
104 local_cost += cost;
105 }
106
107 // Resizes the diagram which was enrich with diagonal bidders
108 // during the auction
109 // TODO do this inside the auction !
110 current_bidder_diagrams_[i].resize(sizes[i]);
111 }
112 *total_cost = local_cost;
113}
114
116 std::vector<std::vector<MatchingType>> &matchings,
117 std::vector<std::vector<MatchingType>> &previous_matchings) {
118 if(points_added_ > 0 || points_deleted_ > 0 || previous_matchings.empty()) {
119 return false;
120 }
121
122 for(size_t j = 0; j < matchings.size(); j++) {
123 for(size_t i = 0; i < matchings[j].size(); i++) {
124 MatchingType t = matchings[j][i];
125 MatchingType previous_t = previous_matchings[j][i];
126
127 if(std::get<1>(t) != std::get<1>(previous_t)
128 && (std::get<0>(t) >= 0 && std::get<0>(previous_t) >= 0)) {
129 return false;
130 }
131 }
132 }
133 return true;
134}
135
136std::vector<std::vector<ttk::MatchingType>> ttk::PDBarycenter::correctMatchings(
137 std::vector<std::vector<MatchingType>> &previous_matchings) {
138
139 std::vector<std::vector<MatchingType>> corrected_matchings(numberOfInputs_);
140 for(int i = 0; i < numberOfInputs_; i++) {
141 // 1. Invert the current_bidder_ids_ vector
142 std::vector<int> new_to_old_id(current_bidder_diagrams_[i].size());
143 for(size_t j = 0; j < current_bidder_ids_[i].size(); j++) {
144 int const new_id = current_bidder_ids_[i][j];
145 if(new_id >= 0) {
146 new_to_old_id[new_id] = j;
147 }
148 }
149 // 2. Reconstruct the matchings
150 std::vector<MatchingType> matchings_diagram_i;
151 for(size_t j = 0; j < previous_matchings[i].size(); j++) {
152 MatchingType m = previous_matchings[i][j];
153 int const new_id = std::get<0>(m);
154 if(new_id >= 0 && std::get<1>(m) >= 0) {
155 std::get<0>(m) = new_to_old_id[new_id];
156 matchings_diagram_i.push_back(m);
157 }
158 }
159 corrected_matchings[i] = matchings_diagram_i;
160 }
161 return corrected_matchings;
162}
163
165 std::vector<std::vector<MatchingType>> &matchings) {
166 // 1. Initialize variables used in the sequel
167 Timer const t_update;
168 size_t const n_goods = barycenter_goods_[0].size();
169
170 size_t const n_diagrams = current_bidder_diagrams_.size();
171 points_added_ = 0;
172 points_deleted_ = 0;
173 double max_shift = 0;
174
175 std::vector<size_t> count_diag_matchings(
176 n_goods); // Number of diagonal matchings for each point of the barycenter
177 std::vector<double> x(n_goods);
178 std::vector<double> y(n_goods);
179 std::vector<double> crit_coords_x(n_goods);
180 std::vector<double> crit_coords_y(n_goods);
181 std::vector<double> crit_coords_z(n_goods);
182 for(size_t i = 0; i < n_goods; i++) {
183 count_diag_matchings[i] = 0;
184 x[i] = 0;
185 y[i] = 0;
186 crit_coords_x[i] = 0;
187 crit_coords_y[i] = 0;
188 crit_coords_z[i] = 0;
189 }
190 std::vector<double> min_prices(n_diagrams);
191 for(size_t j = 0; j < n_diagrams; j++) {
192 min_prices[j] = std::numeric_limits<double>::max();
193 }
194
195 std::vector<Bidder *>
196 points_to_append; // Will collect bidders linked to diagonal
197 // 2. Preprocess the matchings
198 for(size_t j = 0; j < matchings.size(); j++) {
199 for(size_t i = 0; i < matchings[j].size(); i++) {
200 int const bidder_id = std::get<0>(matchings[j][i]);
201 int const good_id = std::get<1>(matchings[j][i]);
202 if(good_id < 0 && bidder_id >= 0) {
203 // Future new barycenter point
204 points_to_append.push_back(&current_bidder_diagrams_[j].at(bidder_id));
205 }
206
207 else if(good_id >= 0 && bidder_id >= 0) {
208 // Update coordinates (to be divided by the number of diagrams later on)
209 x[good_id] += current_bidder_diagrams_[j].at(bidder_id).x_;
210 y[good_id] += current_bidder_diagrams_[j].at(bidder_id).y_;
211 if(geometrical_factor_ < 1) {
212 const auto &critical_coordinates = current_bidder_diagrams_[j]
213 .at(bidder_id)
214 .GetCriticalCoordinates();
215 crit_coords_x[good_id] += critical_coordinates[0];
216 crit_coords_y[good_id] += critical_coordinates[1];
217 crit_coords_z[good_id] += critical_coordinates[2];
218 }
219 } else if(good_id >= 0 && bidder_id < 0) {
220 // Counting the number of times this barycenter point is linked to the
221 // diagonal
222 count_diag_matchings[good_id] = count_diag_matchings[good_id] + 1;
223 }
224 }
225 }
226
227 // 3. Update the previous points of the barycenter
228 for(size_t i = 0; i < n_goods; i++) {
229 if(count_diag_matchings[i] < n_diagrams) {
230 // Barycenter point i is matched at least to one off-diagonal bidder
231 // 3.1 Compute the arithmetic mean of off-diagonal bidders linked to it
232 double const x_bar
233 = x[i] / (double)(n_diagrams - count_diag_matchings[i]);
234 double const y_bar
235 = y[i] / (double)(n_diagrams - count_diag_matchings[i]);
236 // 3.2 Compute the new coordinates of the point (the more linked to the
237 // diagonal it was, the closer to the diagonal it'll be)
238 double const new_x
239 = ((double)(n_diagrams - count_diag_matchings[i]) * x_bar
240 + (double)count_diag_matchings[i] * (x_bar + y_bar) / 2.)
241 / (double)n_diagrams;
242 double const new_y
243 = ((double)(n_diagrams - count_diag_matchings[i]) * y_bar
244 + (double)count_diag_matchings[i] * (x_bar + y_bar) / 2.)
245 / (double)n_diagrams;
246 // TODO Weight by persistence
247 double const new_crit_coord_x
248 = crit_coords_x[i] / (double)(n_diagrams - count_diag_matchings[i]);
249 double const new_crit_coord_y
250 = crit_coords_y[i] / (double)(n_diagrams - count_diag_matchings[i]);
251 double const new_crit_coord_z
252 = crit_coords_z[i] / (double)(n_diagrams - count_diag_matchings[i]);
253
254 // 3.3 Compute and store how much the point has shifted
255 // TODO adjust shift with geometrical_factor_
256 double const dx = barycenter_goods_[0].at(i).x_ - new_x;
257 double const dy = barycenter_goods_[0].at(i).y_ - new_y;
258 double const shift = Geometry::pow(std::abs(dx), wasserstein_)
259 + Geometry::pow(std::abs(dy), wasserstein_);
260 if(shift > max_shift) {
261 max_shift = shift;
262 }
263 // 3.4 Update the position of the point
264 for(size_t j = 0; j < n_diagrams; j++) {
265 barycenter_goods_[j].at(i).SetCoordinates(new_x, new_y);
266 if(geometrical_factor_ < 1) {
267 barycenter_goods_[j].at(i).SetCriticalCoordinates(
268 new_crit_coord_x, new_crit_coord_y, new_crit_coord_z);
269 }
270 if(barycenter_goods_[j].at(i).getPrice() < min_prices[j]) {
271 min_prices[j] = barycenter_goods_[j].at(i).getPrice();
272 }
273 }
274 // TODO Reinitialize/play with prices here if you wish
275 }
276 }
277 for(size_t j = 0; j < n_diagrams; j++) {
278 if(min_prices[j] >= std::numeric_limits<double>::max() / 2.) {
279 min_prices[j] = 0;
280 }
281 }
282
283 // 4. Delete off-diagonal barycenter points not linked to any
284 // off-diagonal bidder
285 for(size_t i = 0; i < n_goods; i++) {
286 if(count_diag_matchings[i] == n_diagrams) {
287 points_deleted_ += 1;
288 double const shift
289 = 2
291 barycenter_goods_[0].at(i).getPersistence() / 2., wasserstein_);
292 if(shift > max_shift) {
293 max_shift = shift;
294 }
295 for(size_t j = 0; j < n_diagrams; j++) {
296 barycenter_goods_[j].at(i).id_ = -1;
297 }
298 }
299 }
300
301 // 5. Append the new points to the barycenter
302 for(size_t k = 0; k < points_to_append.size(); k++) {
303 points_added_ += 1;
304 Bidder *b = points_to_append[k];
305 double const gx
306 = (b->x_ + (n_diagrams - 1) * (b->x_ + b->y_) / 2.) / (n_diagrams);
307 double const gy
308 = (b->y_ + (n_diagrams - 1) * (b->x_ + b->y_) / 2.) / (n_diagrams);
309 const auto &critical_coordinates = b->GetCriticalCoordinates();
310 for(size_t j = 0; j < n_diagrams; j++) {
311 Good g = Good(gx, gy, false, barycenter_goods_[j].size());
312 g.setPrice(min_prices[j]);
313 if(geometrical_factor_ < 1) {
314 g.SetCriticalCoordinates(std::get<0>(critical_coordinates),
315 std::get<1>(critical_coordinates),
316 std::get<2>(critical_coordinates));
317 }
318 barycenter_goods_[j].emplace_back(g);
319 double const shift
320 = 2
322 barycenter_goods_[j].at(g.id_).getPersistence() / 2., wasserstein_);
323 if(shift > max_shift) {
324 max_shift = shift;
325 }
326 }
327 }
328
329 // 6. Finally, recreate barycenter_goods
330 for(size_t j = 0; j < n_diagrams; j++) {
331 int count = 0;
332 GoodDiagram new_barycenter;
333 for(size_t i = 0; i < barycenter_goods_[j].size(); i++) {
334 Good g = barycenter_goods_[j].at(i);
335 if(g.id_ != -1) {
336 g.id_ = count;
337 new_barycenter.emplace_back(g);
338 count++;
339 }
340 }
341 barycenter_goods_[j] = new_barycenter;
342 }
343
344 return max_shift;
345}
346
348 return rho * rho / 8.0;
349}
350
351double ttk::PDBarycenter::getRho(double epsilon) {
352 return std::sqrt(8.0 * epsilon);
353}
354
356
357 for(int i = 0; i < numberOfInputs_; i++) {
358 DiagramType *CTDiagram = &((*inputDiagrams_)[i]);
359
360 BidderDiagram bidders;
361 for(size_t j = 0; j < CTDiagram->size(); j++) {
362 // Add bidder to bidders
363 Bidder b((*CTDiagram)[j], j, lambda_);
364
365 b.setPositionInAuction(bidders.size());
366 bidders.emplace_back(b);
367 if(b.isDiagonal() || b.x_ == b.y_) {
368 this->printWrn("Diagonal point in diagram !!!");
369 }
370 }
371 bidder_diagrams_.push_back(bidders);
372 current_bidder_diagrams_.emplace_back();
373 std::vector<int> ids(bidders.size());
374 for(size_t j = 0; j < ids.size(); j++) {
375 ids[j] = -1;
376 }
377 current_bidder_ids_.push_back(ids);
378 }
379}
380
382 double previous_min_persistence,
383 double min_persistence,
384 std::vector<double> &initial_diagonal_prices,
385 std::vector<double> &initial_off_diagonal_prices,
386 int min_points_to_add,
387 bool add_points_to_barycenter) {
388
389 double new_min_persistence = min_persistence;
390
391 // 1. Get size of the largest current diagram, deduce the maximal number of
392 // points to append
393 size_t max_diagram_size{};
394 for(int i = 0; i < numberOfInputs_; i++) {
395 if(current_bidder_diagrams_[i].size() > max_diagram_size) {
396 max_diagram_size = current_bidder_diagrams_[i].size();
397 }
398 }
399 int const max_points_to_add = std::max(
400 min_points_to_add, min_points_to_add + (int)(max_diagram_size / 10));
401
402 // 2. Get which points can be added, deduce the new minimal persistence
403 std::vector<std::vector<int>> candidates_to_be_added(numberOfInputs_);
404 std::vector<std::vector<int>> idx(numberOfInputs_);
405 for(int i = 0; i < numberOfInputs_; i++) {
406
407 std::vector<double> persistences;
408 for(size_t j = 0; j < bidder_diagrams_[i].size(); j++) {
409 Bidder const b = bidder_diagrams_[i].at(j);
410 double const persistence = b.getPersistence();
411 if(persistence >= min_persistence
412 && persistence < previous_min_persistence) {
413 candidates_to_be_added[i].push_back(j);
414 idx[i].push_back(idx[i].size());
415 persistences.push_back(persistence);
416 }
417 }
418 sort(idx[i].begin(), idx[i].end(), [&persistences](int &a, int &b) {
419 return ((persistences[a] > persistences[b])
420 || ((persistences[a] == persistences[b]) && (a > b)));
421 });
422 int const size = candidates_to_be_added[i].size();
423 if(size >= max_points_to_add) {
424 double const last_persistence_added
425 = persistences[idx[i][max_points_to_add - 1]];
426 if(last_persistence_added > new_min_persistence) {
427 new_min_persistence = last_persistence_added;
428 }
429 }
430 }
431
432 // 3. Add the points to the current diagrams
433
434 // only to give determinism
435 int compteur_for_adding_points = 0;
436
437 for(int i = 0; i < numberOfInputs_; i++) {
438 int const size = candidates_to_be_added[i].size();
439 for(int j = 0; j < std::min(max_points_to_add, size); j++) {
440 Bidder b = bidder_diagrams_[i].at(candidates_to_be_added[i][idx[i][j]]);
441 if(b.getPersistence() >= new_min_persistence) {
442 b.id_ = current_bidder_diagrams_[i].size();
443 b.setPositionInAuction(current_bidder_diagrams_[i].size());
444 b.setDiagonalPrice(initial_diagonal_prices[i]);
445 current_bidder_diagrams_[i].emplace_back(b);
446 // b.id_ --> position of b in current_bidder_diagrams_[i]
447 current_bidder_ids_[i][candidates_to_be_added[i][idx[i][j]]]
448 = current_bidder_diagrams_[i].size() - 1;
449
450 int const to_be_added_to_barycenter
451 = deterministic_ ? compteur_for_adding_points % numberOfInputs_
452 : rand() % numberOfInputs_;
453 // We add the bidder as a good with probability 1/n_diagrams
454 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
455 for(int k = 0; k < numberOfInputs_; k++) {
456 Good g = Good(b.x_, b.y_, false, barycenter_goods_[k].size());
457 g.setPrice(initial_off_diagonal_prices[k]);
458 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
459 barycenter_goods_[k].emplace_back(g);
460 }
461 }
462 }
463 compteur_for_adding_points++;
464 }
465 }
466 return new_min_persistence;
467}
468
470 double max_persistence = 0;
471 for(int i = 0; i < numberOfInputs_; i++) {
472 BidderDiagram &D = bidder_diagrams_[i];
473 for(size_t j = 0; j < D.size(); j++) {
474 // Add bidder to bidders
475 Bidder const &b = D.at(j);
476 double const persistence = b.getPersistence();
477 if(persistence > max_persistence) {
478 max_persistence = persistence;
479 }
480 }
481 }
482 return max_persistence;
483}
484
486 double min_price = std::numeric_limits<double>::max();
487
488 GoodDiagram &D = barycenter_goods_[i];
489 if(D.empty()) {
490 return 0;
491 }
492 for(size_t j = 0; j < D.size(); j++) {
493 Good const &b = D.at(j);
494 double const price = b.getPrice();
495 if(price < min_price) {
496 min_price = price;
497 }
498 }
499 if(min_price >= std::numeric_limits<double>::max() / 2.) {
500 return 0;
501 }
502 return min_price;
503}
504
506 double lowest_persistence = std::numeric_limits<double>::max();
507 for(int i = 0; i < numberOfInputs_; i++) {
508 BidderDiagram &D = bidder_diagrams_[i];
509 for(size_t j = 0; j < D.size(); j++) {
510 // Add bidder to bidders
511 Bidder const &b = D.at(j);
512 double const persistence = b.getPersistence();
513 if(persistence < lowest_persistence && persistence > 0) {
514 lowest_persistence = persistence;
515 }
516 }
517 }
518 if(lowest_persistence >= std::numeric_limits<double>::max() / 2.) {
519 return 0;
520 }
521 return lowest_persistence;
522}
523
524void ttk::PDBarycenter::setInitialBarycenter(double min_persistence) {
525 int size = 0;
526 int random_idx;
527 DiagramType *CTDiagram;
528 int iter = 0;
529 while(size == 0) {
530 random_idx
531 = deterministic_ ? iter % numberOfInputs_ : rand() % numberOfInputs_;
532 CTDiagram = &((*inputDiagrams_)[random_idx]);
533 for(int i = 0; i < numberOfInputs_; i++) {
534 GoodDiagram goods;
535 int count = 0;
536 for(size_t j = 0; j < CTDiagram->size(); j++) {
537 // Add bidder to bidders
538 Good const g = Good((*CTDiagram)[j], count, lambda_);
539 if(g.getPersistence() >= min_persistence) {
540 goods.emplace_back(g);
541 count++;
542 }
543 }
544 if(static_cast<int>(barycenter_goods_.size()) < (i + 1)) {
545 barycenter_goods_.push_back(goods);
546 } else {
547 barycenter_goods_[i] = goods;
548 }
549 }
550 size = barycenter_goods_[0].size();
551 iter++;
552 }
553}
554
556 Timer tm;
557 auto kdt = std::make_unique<KDT>(true, wasserstein_);
558
559 const int dimension = geometrical_factor_ >= 1 ? 2 : 5;
560
561 std::vector<double> coordinates;
562 std::vector<std::vector<double>> weights;
563
564 for(size_t i = 0; i < barycenter_goods_[0].size(); i++) {
565 const Good &g = barycenter_goods_[0].at(i);
566 coordinates.push_back(geometrical_factor_ * g.x_);
567 coordinates.push_back(geometrical_factor_ * g.y_);
568 if(geometrical_factor_ < 1) {
569 coordinates.push_back((1 - geometrical_factor_) * g.coords_[0]);
570 coordinates.push_back((1 - geometrical_factor_) * g.coords_[1]);
571 coordinates.push_back((1 - geometrical_factor_) * g.coords_[2]);
572 }
573 }
574
575 for(size_t idx = 0; idx < barycenter_goods_.size(); idx++) {
576 std::vector<double> const empty_weights;
577 weights.push_back(empty_weights);
578 for(size_t i = 0; i < barycenter_goods_[idx].size(); i++) {
579 const Good &g = barycenter_goods_[idx].at(i);
580 weights[idx].push_back(g.getPrice());
581 }
582 }
583 // Correspondence map : position in barycenter_goods_ --> KDT node
584
585 auto correspondence_kdt_map
586 = kdt->build(coordinates.data(), barycenter_goods_[0].size(), dimension,
587 weights, barycenter_goods_.size());
588 this->printMsg(" Building KDTree", 1, tm.getElapsedTime(),
590 return std::make_pair(std::move(kdt), correspondence_kdt_map);
591}
592
593std::vector<std::vector<ttk::MatchingType>>
595
596 std::vector<std::vector<MatchingType>> previous_matchings;
597 double const min_persistence = 0;
598 double min_cost = std::numeric_limits<double>::max();
599 int last_min_cost_obtained = 0;
600
601 this->setBidderDiagrams();
602 this->setInitialBarycenter(
603 min_persistence); // false for a determinist initialization
604
605 double const max_persistence = getMaxPersistence();
606
607 std::vector<double> min_diag_price(numberOfInputs_);
608 std::vector<double> min_price(numberOfInputs_);
609 for(int i = 0; i < numberOfInputs_; i++) {
610 min_diag_price[i] = 0;
611 min_price[i] = 0;
612 }
613
614 int const min_points_to_add = std::numeric_limits<int>::max();
615 this->enrichCurrentBidderDiagrams(2 * max_persistence, min_persistence,
616 min_diag_price, min_price,
617 min_points_to_add, false);
618
619 bool converged = false;
620 bool finished = false;
621 double total_cost;
622
623 while(!finished) {
624 Timer const tm;
625
626 std::pair<std::unique_ptr<KDT>, std::vector<KDT *>> pair;
627 bool use_kdt = false;
628 // If the barycenter is empty, do not compute the kdt (or it will crash :/)
629 // TODO Fix KDTree to handle empty inputs...
630 if(!barycenter_goods_[0].empty()) {
631 pair = this->getKDTree();
632 use_kdt = true;
633 }
634
635 std::vector<std::vector<MatchingType>> all_matchings(numberOfInputs_);
636 std::vector<int> sizes(numberOfInputs_);
637 for(int i = 0; i < numberOfInputs_; i++) {
638 sizes[i] = current_bidder_diagrams_[i].size();
639 }
640
641 total_cost = 0;
642
643 barycenter.clear();
644 for(size_t j = 0; j < barycenter_goods_[0].size(); j++) {
645 Good const &g = barycenter_goods_[0].at(j);
646 barycenter.emplace_back(PersistencePair{CriticalVertex{0, nt1_, g.x_, {}},
647 CriticalVertex{0, nt2_, g.y_, {}},
648 diagramType_, true});
649 }
650
651 bool const actual_distance = (numberOfInputs_ == 2);
652 runMatchingAuction(&total_cost, sizes, *pair.first, pair.second,
653 &min_diag_price, &all_matchings, use_kdt,
654 actual_distance);
655
656 this->printMsg("Barycenter cost : " + std::to_string(total_cost),
658
659 if(converged) {
660 finished = true;
661 }
662
663 if(!finished) {
664 updateBarycenter(all_matchings);
665
666 if(min_cost > total_cost) {
667 min_cost = total_cost;
668 last_min_cost_obtained = 0;
669 } else {
670 last_min_cost_obtained += 1;
671 }
672
673 converged = converged || last_min_cost_obtained > 1;
674 if(numberOfInputs_ == 2)
675 finished = true;
676 }
677
678 previous_matchings = std::move(all_matchings);
679 // END OF TIMER
680
681 for(size_t i = 0; i < barycenter_goods_.size(); ++i) {
682 for(size_t j = 0; j < barycenter_goods_[i].size(); ++j) {
683 barycenter_goods_[i].at(j).setPrice(0);
684 }
685 }
686 for(size_t i = 0; i < current_bidder_diagrams_.size(); ++i) {
687 for(size_t j = 0; j < current_bidder_diagrams_[i].size(); ++j) {
688 current_bidder_diagrams_[i].at(j).setDiagonalPrice(0);
689 }
690 }
691 for(int i = 0; i < numberOfInputs_; i++) {
692 min_diag_price[i] = 0;
693 min_price[i] = 0;
694 }
695 }
696 barycenter.resize(0);
697 for(size_t j = 0; j < barycenter_goods_[0].size(); j++) {
698 Good const &g = barycenter_goods_[0].at(j);
699 barycenter.emplace_back(PersistencePair{CriticalVertex{0, nt1_, g.x_, {}},
700 CriticalVertex{0, nt2_, g.y_, {}},
701 diagramType_, true});
702 }
703
704 cost_ = total_cost;
705 std::vector<std::vector<MatchingType>> corrected_matchings
706 = correctMatchings(previous_matchings);
707 return corrected_matchings;
708}
709
711 double total_real_cost = 0;
712 std::vector<MatchingType> fake_matchings;
713 for(int i = 0; i < numberOfInputs_; i++) {
714 PersistenceDiagramAuction auction(wasserstein_, geometrical_factor_,
715 lambda_, 0.01, true, nonMatchingWeight_);
716 GoodDiagram const current_barycenter = barycenter_goods_[0];
717 BidderDiagram const current_bidder_diagram = bidder_diagrams_[i];
718 auction.BuildAuctionDiagrams(current_bidder_diagram, current_barycenter);
719 double const cost = auction.run(fake_matchings);
720 total_real_cost += cost * cost;
721 }
722 return sqrt(total_real_cost);
723}
724
725bool ttk::PDBarycenter::isPrecisionObjectiveMet(double precision_objective,
726 int mode) {
727 if(mode == 0) { // ABSOLUTE PRECISION
728 for(int i_input = 0; i_input < numberOfInputs_; i_input++) {
729 if(precision_[i_input] > precision_objective) {
730 return false;
731 }
732 }
733 } else if(mode == 1) { // AVERAGE PRECISION
734 double const average_precision
735 = std::accumulate(precision_.begin(), precision_.end(), 0.0)
736 / numberOfInputs_;
737 if(average_precision > precision_objective) {
738 return false;
739 }
740 }
741 return true;
742}
void setDiagonalPrice(const double price)
void setPositionInAuction(const int pos)
void setPrice(const double price)
TTK KD-Tree.
Definition KDTree.h:21
std::vector< std::vector< MatchingType > > executeAuctionBarycenter(DiagramType &barycenter)
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
double getRho(double epsilon)
double updateBarycenter(std::vector< std::vector< MatchingType > > &matchings)
void setInitialBarycenter(double min_persistence)
bool isPrecisionObjectiveMet(double, int)
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)
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)
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
std::string to_string(__int128)
Definition ripserpy.cpp:99
T1 pow(const T1 val, const T2 n)
Definition Geometry.h:454
std::vector< Bidder > BidderDiagram
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.
std::tuple< int, int, double > MatchingType
Matching between two Persistence Diagram pairs.
std::vector< Good > GoodDiagram
T end(std::pair< T, T > &p)
Definition ripserpy.cpp:472
T begin(std::pair< T, T > &p)
Definition ripserpy.cpp:468
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)