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