TTK
Loading...
Searching...
No Matches
PDClustering.cpp
Go to the documentation of this file.
1
14
15#include <PDClustering.h>
16
17#include <algorithm>
18#include <cmath>
19#include <cstdlib> /* srand, rand */
20#include <iostream>
21#include <iterator>
22#include <random>
23
25 std::vector<DiagramType> &final_centroids,
26 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
27 &all_matchings_per_type_and_cluster) {
28
29 all_matchings_per_type_and_cluster.resize(k_);
30 for(int c = 0; c < k_; c++) {
31 all_matchings_per_type_and_cluster[c].resize(3);
32 for(int i = 0; i < 3; i++) {
33 all_matchings_per_type_and_cluster[c][i].resize(numberOfInputs_);
34 }
35 }
36 int matchings_only = false;
37 Timer const tm;
38 {
39 // PARTICULARITIES FOR THE CASE OF ONE UNIQUE CLUSTER
40 if(k_ <= 1) {
41 use_accelerated_ = false;
42 use_kmeanspp_ = false;
44 use_progressive_ = false;
45 deterministic_ = true;
46 matchings_only = true;
47 time_limit_ = 99999999999;
48 }
49 }
50
51 std::vector<bool *> current_prec;
52 current_prec.emplace_back(&precision_min_);
53 current_prec.emplace_back(&precision_sad_);
54 current_prec.emplace_back(&precision_max_);
55
56 std::vector<bool *> current_dos;
57 current_dos.emplace_back(&do_min_);
58 current_dos.emplace_back(&do_sad_);
59 current_dos.emplace_back(&do_max_);
60 bool converged = false;
61 std::vector<bool> diagrams_complete(3);
62 for(int c = 0; c < 3; c++) {
63 diagrams_complete[c] = (!use_progressive_) || (!original_dos[c]);
64 }
65 n_iterations_ = 0;
66 double total_time = 0;
67
68 // double cost = std::numeric_limits<double>::max();
70 cost_ = std::numeric_limits<double>::max();
71 double min_cost_min = std::numeric_limits<double>::max();
72 double min_cost_max = std::numeric_limits<double>::max();
73 double min_cost_sad = std::numeric_limits<double>::max();
74 // double last_min_cost_obtained = -1;
75 double last_min_cost_obtained_min = -1;
76 double last_min_cost_obtained_sad = -1;
77 double last_min_cost_obtained_max = -1;
78 std::vector<double> epsilon0(3);
79 std::vector<double> epsilon_candidate(3);
80 std::vector<double> rho(3);
81
82 // Getting current diagrams (with only at most min_points_to_add points)
83 std::vector<double> max_persistence(3);
84 std::vector<double> lowest_persistence(3);
85 std::vector<double> min_persistence(3);
86
87 const auto square = [](const double a) { return a * a; };
88
89 for(int i_crit = 0; i_crit < 3; i_crit++) {
90 max_persistence[i_crit] = 2 * getMostPersistent(i_crit);
91 lowest_persistence[i_crit] = getLessPersistent(i_crit);
92 min_persistence[i_crit] = 0;
93 epsilon_[i_crit] = square(0.5 * max_persistence[i_crit])
94 / 8.; // max_persistence actually holds 2 times the
95 // highest persistence
96 epsilon0[i_crit] = epsilon_[i_crit];
97 }
98
99 std::vector<int> min_points_to_add(3);
100 min_points_to_add[0] = 10;
101 min_points_to_add[1] = 10;
102 min_points_to_add[2] = 10;
103
104 if(use_progressive_) {
105 } else {
106 min_points_to_add[0] = std::numeric_limits<int>::max();
107 min_points_to_add[1] = std::numeric_limits<int>::max();
108 min_points_to_add[2] = std::numeric_limits<int>::max();
109 }
110 std::vector<std::vector<double>> min_diag_price(3);
111 std::vector<std::vector<double>> min_off_diag_price(3);
112 for(int c = 0; c < 3; ++c) {
113 for(int i = 0; i < numberOfInputs_; i++) {
114 min_diag_price[c].emplace_back(0);
115 min_off_diag_price[c].emplace_back(0);
116 }
117 }
118 min_persistence = enrichCurrentBidderDiagrams(
119 max_persistence, min_persistence, min_diag_price, min_off_diag_price,
120 min_points_to_add, false, true);
121
122 for(int c = 0; c < 3; c++) {
123 if(min_persistence[c] <= lowest_persistence[c]) {
124 diagrams_complete[c] = true;
125 } // max_persistence actually holds 2 times the highest persistence
126 }
127 bool all_diagrams_complete
128 = diagrams_complete[0] && diagrams_complete[1] && diagrams_complete[2];
129 if(all_diagrams_complete) {
130 use_progressive_ = false;
131 }
132
133 // Initializing centroids and clusters
134 if(use_kmeanspp_) {
136 } else {
138 }
140 if(use_accelerated_) {
144 } else {
147 }
148 if(debugLevel_ > 3 && k_ > 1) {
149 printMsg("Initial Clustering: ");
151 }
152 initializeBarycenterComputers(min_persistence);
153 while(!converged || (!all_diagrams_complete && use_progressive_)) {
154 Timer t_inside;
155 {
157
158 for(int i_crit = 0; i_crit < 3; i_crit++) {
159 if(*(current_dos[i_crit])) {
160 rho[i_crit] = min_persistence[i_crit] > 0
161 ? std::sqrt(8.0 * epsilon_[i_crit])
162 : -1;
163 }
164 }
165
167
168 do_min_ = do_min_ && (min_persistence[0] > rho[0]);
169 do_sad_ = do_sad_ && (min_persistence[1] > rho[1]);
170 do_max_ = do_max_ && (min_persistence[2] > rho[2]);
171
172 for(int i_crit = 0; i_crit < 3; i_crit++) {
173 if(*(current_dos[i_crit])) {
174 epsilon_candidate[i_crit] = square(min_persistence[i_crit]) / 8.;
175 if(epsilon_candidate[i_crit] > epsilon_[i_crit]) {
176 // Should always be the case except if min_persistence is
177 // equal to zero
178 epsilon_[i_crit] = epsilon_candidate[i_crit];
179 }
180 }
181 }
182
183 if(epsilon_[0] < 5e-5) {
184 // Add all remaining points for final convergence.
185 // rho[0] = 0;
186 min_persistence[0] = 0;
187 min_points_to_add[0] = std::numeric_limits<int>::max();
188 }
189 if(epsilon_[1] < 5e-5) {
190 // Add all remaining points for final convergence.
191 // rho[1] = 0;
192 min_persistence[1] = 0;
193 min_points_to_add[1] = std::numeric_limits<int>::max();
194 }
195 if(epsilon_[2] < 5e-5) {
196 // Add all remaining points for final convergence.
197 // rho[2] = 0;
198 min_persistence[2] = 0;
199 min_points_to_add[2] = std::numeric_limits<int>::max();
200 }
201
202 if(do_min_ || do_sad_ || do_max_) {
203 min_persistence = enrichCurrentBidderDiagrams(
204 min_persistence, rho, min_diag_price, min_off_diag_price,
205 min_points_to_add, true, false);
206 }
208
209 for(int i_crit = 0; i_crit < 3; i_crit++) {
210 if(*(current_dos[i_crit])) {
211 if(min_persistence[i_crit] <= lowest_persistence[i_crit]) {
212 diagrams_complete[i_crit] = true;
213 }
214 }
215 }
216
217 if(diagrams_complete[0] && diagrams_complete[1]
218 && diagrams_complete[2]) {
219 use_progressive_ = false;
220 all_diagrams_complete = true;
221 }
222
224 }
225 std::vector<double> max_shift_vec = updateCentroidsPosition(
226 &min_off_diag_price, &min_diag_price,
227 all_matchings_per_type_and_cluster, matchings_only);
228 if(do_min_ && !UseDeltaLim_) {
229 precision_min_ = (epsilon_[0] < epsilon0[0] / 500.);
230 }
231 if(do_sad_ && !UseDeltaLim_) {
232 precision_sad_ = (epsilon_[1] < epsilon0[1] / 500.);
233 }
234 if(do_max_ && !UseDeltaLim_) {
235 precision_max_ = (epsilon_[2] < epsilon0[2] / 500.);
236 }
237
238 for(int i_crit = 0; i_crit < 3; i_crit++) {
239 if(*(current_dos[i_crit]) /*&& (!*(current_prec[i_crit]) || !diagrams_complete[i_crit] ) */) {
240 epsilon_candidate[i_crit] = std::min(
241 std::max(max_shift_vec[i_crit] / 8., epsilon_[i_crit] / 5.),
242 epsilon0[i_crit] / square(n_iterations_));
243
244 if((epsilon_candidate[i_crit] < epsilon_[i_crit]
245 && !diagrams_complete[i_crit])
246 || diagrams_complete[i_crit]) {
247 epsilon_[i_crit] = epsilon_candidate[i_crit];
248 } else {
249 epsilon_[i_crit] *= 0.95;
250 }
251 }
252 }
253
254 if(epsilon_[0] < epsilon_min_ /*&& diagrams_complete[0]*/) {
255 this->printMsg("[min barycenter] epsilon under minimal value ",
257 do_min_ = false;
259 diagrams_complete[0] = true;
260 }
261 if(epsilon_[1] < epsilon_min_ /*&& diagrams_complete[1]*/) {
262 this->printMsg("[sad barycenter] epsilon under minimal value ",
264 do_sad_ = false;
266 diagrams_complete[1] = true;
267 }
268 if(epsilon_[2] < epsilon_min_ /*&& diagrams_complete[2]*/) {
269 this->printWrn("[max barycenter] epsilon under minimal value ");
270 do_max_ = false;
272 diagrams_complete[2] = true;
273 }
274
275 if(diagrams_complete[0] && diagrams_complete[1]
276 && diagrams_complete[2]) {
277 use_progressive_ = false;
278 all_diagrams_complete = true;
279 }
280 if(use_accelerated_) {
282 } else {
283 // updateClusters();
284 }
285
288 bool const precision_criterion_reached = precision_criterion_;
289
290 this->printMsg("Iteration " + std::to_string(n_iterations_)
291 + " epsilon " + std::to_string(epsilon_[0]) + " "
292 + std::to_string(epsilon_[1]) + " "
293 + std::to_string(epsilon_[2]),
295 this->printMsg(" complete " + std::to_string(diagrams_complete[0]) + " "
296 + std::to_string(diagrams_complete[1]) + " "
297 + std::to_string(diagrams_complete[2]),
299 this->printMsg(" precision " + std::to_string(precision_min_) + " "
300 + std::to_string(precision_sad_) + " "
301 + std::to_string(precision_max_),
303 this->printMsg(" cost " + std::to_string(cost_min_) + " "
304 + std::to_string(cost_sad_) + " "
305 + std::to_string(cost_max_),
307
309 && diagrams_complete[0] /*&& precision_min_*/) {
310 min_cost_min = cost_min_;
311 last_min_cost_obtained_min = 0;
312 } else if(n_iterations_ > 2 && precision_min_ && diagrams_complete[0]) {
313 last_min_cost_obtained_min += 1;
314 if(last_min_cost_obtained_min > 1) {
315 do_min_ = false;
316 }
317 }
318
320 && diagrams_complete[1] /*&& precision_sad_*/) {
321 min_cost_sad = cost_sad_;
322 last_min_cost_obtained_sad = 0;
323 } else if(n_iterations_ > 2 && precision_sad_ && diagrams_complete[1]) {
324 last_min_cost_obtained_sad += 1;
325 if(last_min_cost_obtained_sad > 1 && diagrams_complete[1]) {
326 do_sad_ = false;
327 }
328 }
329
331 && diagrams_complete[2] /*&& precision_max_*/) {
332 min_cost_max = cost_max_;
333 last_min_cost_obtained_max = 0;
334 } else if(n_iterations_ > 2 && precision_max_ && diagrams_complete[2]) {
335 last_min_cost_obtained_max += 1;
336 if(last_min_cost_obtained_max > 1 && diagrams_complete[2]) {
337 do_max_ = false;
338 }
339 }
340
341 if(debugLevel_ > 5) {
342 this->printMsg("Clustering result:", debug::Priority::DETAIL);
344 }
345 converged = converged
346 || (all_diagrams_complete && !do_min_ && !do_sad_
347 && !do_max_ && (precision_criterion_reached))
348 || (precision_criterion_reached && UseDeltaLim_
349 && numberOfInputs_ == 2);
350 }
351
352 total_time
353 += t_inside.getElapsedTime(); // - t_real_cost.getElapsedTime();
354
355 if(total_time + t_inside.getElapsedTime() > 0.9 * time_limit_) {
356 min_cost_min = cost_min_;
357 min_cost_sad = cost_sad_;
358 min_cost_max = cost_max_;
359 converged = true;
360 }
361 if(total_time > 0.1 * time_limit_) {
362 all_diagrams_complete = true;
363 diagrams_complete[0] = true;
364 diagrams_complete[1] = true;
365 diagrams_complete[2] = true;
366 use_progressive_ = false;
367 }
368 if(debugLevel_ > 4) {
369 std::cout << "== Iteration " << n_iterations_
370 << " == complete : " << all_diagrams_complete
371 << " , progressive : " << use_progressive_
372 << " , converged : " << converged << std::endl;
373 }
374 }
376
377 // display results
378 std::vector<std::vector<std::string>> const rows{
379 {" Min-saddle cost", std::to_string(cost_min_)},
380 {" Saddle-saddle cost", std::to_string(cost_sad_)},
381 {" Saddle-max cost", std::to_string(cost_max_)},
382 {matchings_only ? "Wasserstein Distance" : "Final Cost",
383 std::to_string(cost_min_ + cost_sad_ + cost_max_)},
384 };
385 this->printMsg(rows);
386
387 if(!use_progressive_ && k_ > 1) {
388 clustering_ = old_clustering_; // reverting to last clustering
389 }
390 invertClusters(); // this is to pass the old inverse clustering to the VTK
391 // wrapper
392 if(k_ > 1) {
393 this->printMsg("Clustering result:");
395 }
396 } // End of timer
397
398 // CORRECT MATCHINGS :
399 // correctMatchings(all_matchings);
400 if(matchings_only) {
401 computeBarycenterForTwoGlobal(all_matchings_per_type_and_cluster);
402 }
403 correctMatchings(all_matchings_per_type_and_cluster);
404 // Filling the final centroids for output
405
406 final_centroids.resize(k_);
407 centroids_sizes_.resize(k_);
408 for(int c = 0; c < k_; c++) {
409 centroids_sizes_[c].resize(3);
410 if(do_min_)
411 centroids_sizes_[c][0] = centroids_min_[c].size();
412 if(do_sad_)
413 centroids_sizes_[c][1] = centroids_saddle_[c].size();
414 if(do_max_)
415 centroids_sizes_[c][2] = centroids_max_[c].size();
416 }
417
418 for(int c = 0; c < k_; ++c) {
419 // if NumberOfClusters > 1, the global pair was duplicated
420 // and needs to be removed from the min-saddle problem
421 // It is the first pair.
422 int const removeFirstPairMin
423 = (k_ > 1 and original_dos[0] and original_dos[2]) ? 1 : 0;
424 int addedFirstPairMax = 0;
425 int addedFirstPairMin = removeFirstPairMin;
426
427 // min-max Pair
428 if(removeFirstPairMin or (!do_min_ and do_max_)) {
429 Good const &g = centroids_max_[c].at(0);
430 const auto &critCoords = g.GetCriticalCoordinates();
431 final_centroids[c].emplace_back(PersistencePair{
432 CriticalVertex{0, g.x_, {}, critCoords, CriticalType::Local_minimum},
433 CriticalVertex{0, g.y_, {}, critCoords, CriticalType::Local_maximum}, 0,
434 false});
435 addedFirstPairMax = 1;
436 } else if(do_min_) {
437 Good const &g = centroids_min_[c].at(0);
438 const auto &critCoords = g.GetCriticalCoordinates();
439 final_centroids[c].emplace_back(PersistencePair{
440 CriticalVertex{0, g.x_, {}, critCoords, CriticalType::Local_minimum},
441 CriticalVertex{0, g.y_, {}, critCoords, CriticalType::Local_maximum}, 0,
442 false});
443 addedFirstPairMin = 1;
444 }
445
446 if(do_min_) {
447 for(size_t i = addedFirstPairMin; i < centroids_min_[c].size(); ++i) {
448 Good const &g = centroids_min_[c].at(i);
449 const auto &critCoords = g.GetCriticalCoordinates();
450 final_centroids[c].emplace_back(PersistencePair{
451 CriticalVertex{0, g.x_, {}, critCoords, CriticalType::Local_minimum},
452 CriticalVertex{0, g.y_, {}, critCoords, CriticalType::Saddle1}, 0,
453 true});
454 if(g.getPersistence() > 1000) {
455 this->printMsg("Found a abnormally high persistence in min diagram",
457 }
458 }
459 }
460
461 if(do_sad_) {
462 for(size_t i = 0; i < centroids_saddle_[c].size(); ++i) {
463 Good const &g = centroids_saddle_[c].at(i);
464 const auto &critCoords = g.GetCriticalCoordinates();
465 final_centroids[c].emplace_back(PersistencePair{
466 CriticalVertex{0, g.x_, {}, critCoords, CriticalType::Saddle1},
467 CriticalVertex{0, g.y_, {}, critCoords, CriticalType::Saddle2}, 1,
468 true});
469 if(g.getPersistence() > 1000) {
470 this->printMsg("Found a abnormally high persistence in sad diagram",
472 }
473 }
474 }
475
476 if(do_max_) {
477 for(size_t i = addedFirstPairMax; i < centroids_max_[c].size(); ++i) {
478 Good const &g = centroids_max_[c].at(i);
479 const auto &critCoords = g.GetCriticalCoordinates();
480 ttk::CriticalType saddle_type;
481 if(do_sad_)
482 saddle_type = ttk::CriticalType::Saddle2;
483 else
484 saddle_type = ttk::CriticalType::Saddle1;
485
486 final_centroids[c].emplace_back(PersistencePair{
487 CriticalVertex{0, g.x_, {}, critCoords, saddle_type},
488 CriticalVertex{0, g.y_, {}, critCoords, CriticalType::Local_maximum},
489 2, true});
490
491 if(g.getPersistence() > 1000) {
492 this->printMsg("Found a abnormally high persistence in min diagram",
494 }
495 }
496 }
497 }
498
499 if(distanceWritingOptions_ == 1) {
501 } else if(distanceWritingOptions_ == 2) {
503 }
504
505 return inv_clustering_;
506}
507
509 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
510 &previous_matchings) {
511 for(int c = 0; c < k_; c++) {
512 for(size_t i = 0; i < clustering_[c].size(); i++) {
513 int const diagram_id = clustering_[c][i];
514 if(original_dos[0]) {
515 // 1. Invert the current_bidder_ids_ vector
516 std::vector<int> new_to_old_id(
517 current_bidder_diagrams_min_[diagram_id].size(), -1);
518 for(size_t j = 0; j < current_bidder_ids_min_[diagram_id].size(); j++) {
519 int const new_id = current_bidder_ids_min_[diagram_id][j];
520 if(new_id >= 0) {
521 new_to_old_id[new_id] = j;
522 }
523 }
524 // 2. Reconstruct the matchings
525 std::vector<MatchingType> matchings_diagram_i;
526 for(size_t j = 0; j < previous_matchings[c][0][i].size(); j++) {
527 MatchingType m = previous_matchings[c][0][i][j];
528 int const new_id = std::get<0>(m);
529 if(new_id >= 0 && std::get<1>(m) >= 0) {
530 std::get<0>(m) = new_to_old_id[new_id];
531 matchings_diagram_i.emplace_back(m);
532 } else if(std::get<1>(m)
533 >= 0) { // new_id < 0 corresponds to a diagonal matching
534 std::get<0>(m) = -1;
535 matchings_diagram_i.emplace_back(m);
536 }
537 }
538 previous_matchings[c][0][i].resize(matchings_diagram_i.size());
539 previous_matchings[c][0][i] = matchings_diagram_i;
540 }
541 if(original_dos[1]) {
542 // 1. Invert the current_bidder_ids_ vector
543 std::vector<int> new_to_old_id(
544 current_bidder_diagrams_saddle_[diagram_id].size());
545 for(size_t j = 0; j < current_bidder_ids_sad_[diagram_id].size(); j++) {
546 int const new_id = current_bidder_ids_sad_[diagram_id][j];
547 if(new_id >= 0) {
548 new_to_old_id[new_id] = j;
549 }
550 }
551 // 2. Reconstruct the matchings
552 int zero_done = 0;
553 std::vector<MatchingType> matchings_diagram_i;
554 for(size_t j = 0; j < previous_matchings[c][1][i].size(); j++) {
555 MatchingType m = previous_matchings[c][1][i][j];
556 int const new_id = std::get<0>(m);
557 if(new_id >= 0 && std::get<1>(m) >= 0) {
558 int const old_id = new_to_old_id[new_id];
559 if(old_id > 0) {
560 std::get<0>(m) = old_id;
561 matchings_diagram_i.emplace_back(m);
562 } else {
563 if(!zero_done) {
564 zero_done = 1;
565 std::get<0>(m) = old_id;
566 matchings_diagram_i.emplace_back(m);
567 }
568 }
569 } else if(std::get<1>(m)
570 >= 0) { // new_id < 0 corresponds to a diagonal matching
571 std::get<0>(m) = -1;
572 matchings_diagram_i.emplace_back(m);
573 }
574 }
575 previous_matchings[c][1][i].resize(matchings_diagram_i.size());
576 previous_matchings[c][1][i] = matchings_diagram_i;
577 }
578 if(original_dos[2]) {
579 // 1. Invert the current_bidder_ids_ vector
580 std::vector<int> new_to_old_id(
581 current_bidder_diagrams_max_[diagram_id].size());
582 for(size_t j = 0; j < current_bidder_ids_max_[diagram_id].size(); j++) {
583 int const new_id = current_bidder_ids_max_[diagram_id][j];
584 if(new_id >= 0) {
585 new_to_old_id[new_id] = j;
586 }
587 }
588 // 2. Reconstruct the matchings
589 int zero_done = 0;
590 std::vector<MatchingType> matchings_diagram_i;
591 for(size_t j = 0; j < previous_matchings[c][2][i].size(); j++) {
592 MatchingType m = previous_matchings[c][2][i][j];
593 int const new_id = std::get<0>(m);
594 if(new_id >= 0 && std::get<1>(m) >= 0) {
595 int const old_id = new_to_old_id[new_id];
596 if(old_id > 0) {
597 std::get<0>(m) = old_id;
598 matchings_diagram_i.emplace_back(m);
599 } else {
600 if(!zero_done) {
601 zero_done = 1;
602 std::get<0>(m) = old_id;
603 matchings_diagram_i.emplace_back(m);
604 }
605 }
606 } else if(std::get<1>(m)
607 >= 0) { // new_id < 0 corresponds to a diagonal matching
608 std::get<0>(m) = -1;
609 matchings_diagram_i.emplace_back(m);
610 }
611 }
612 previous_matchings[c][2][i].resize(matchings_diagram_i.size());
613 previous_matchings[c][2][i] = matchings_diagram_i;
614 }
615 }
616 }
617}
618
620 std::vector<std::vector<std::vector<MatchingType>>> matchings) {
621 std::cout << "\n MATCHINGS : " << std::endl;
622 for(int d = 0; d < 3; d++) {
623 if(original_dos[d]) {
624 std::cout << "\n Diagram type : " << d << std::endl;
625 for(size_t i = 0; i < matchings[d].size(); i++) {
626 std::cout << " diagram " << i << " : ";
627 for(size_t j = 0; j < matchings[d][i].size(); j++) {
628 std::cout << std::get<0>(matchings[d][i][j]) << " ";
629 std::cout << std::get<1>(matchings[d][i][j]) << " ";
630 std::cout << std::get<2>(matchings[d][i][j]) << " | ";
631 }
632 std::cout << "\n";
633 }
634 }
635 }
636}
637
638std::vector<std::vector<int>> ttk::PDClustering::get_centroids_sizes() {
639 return centroids_sizes_;
640}
641
643 double max_persistence = 0;
644
645 if(do_min_ && (type == -1 || type == 0)) {
646 for(size_t i = 0; i < bidder_diagrams_min_.size(); ++i) {
647 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); ++j) {
648 Bidder const b = bidder_diagrams_min_[i].at(j);
649 double const persistence = b.getPersistence();
650 if(persistence > max_persistence) {
651 max_persistence = persistence;
652 }
653 }
654 }
655 }
656
657 if(do_sad_ && (type == -1 || type == 1)) {
658 for(size_t i = 0; i < bidder_diagrams_saddle_.size(); ++i) {
659 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); ++j) {
660 Bidder const b = bidder_diagrams_saddle_[i].at(j);
661 double const persistence = b.getPersistence();
662 if(persistence > max_persistence) {
663 max_persistence = persistence;
664 }
665 }
666 }
667 }
668
669 if(do_max_ && (type == -1 || type == 2)) {
670 for(size_t i = 0; i < bidder_diagrams_max_.size(); ++i) {
671 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); ++j) {
672 Bidder const b = bidder_diagrams_max_[i].at(j);
673 double const persistence = b.getPersistence();
674 if(persistence > max_persistence) {
675 max_persistence = persistence;
676 }
677 }
678 }
679 }
680 return max_persistence;
681}
682
684 // type == -1 : query the min of all the types of diagrams.
685 // type = 0 : min, 1 : sad, 2 : max
686
687 double min_persistence = std::numeric_limits<double>::max();
688 if(do_min_ && (type == -1 || type == 0)) {
689 for(size_t i = 0; i < bidder_diagrams_min_.size(); ++i) {
690 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); ++j) {
691 Bidder const b = bidder_diagrams_min_[i].at(j);
692 double const persistence = b.getPersistence();
693 if(persistence < min_persistence) {
694 min_persistence = persistence;
695 }
696 }
697 }
698 }
699
700 if(do_sad_ && (type == -1 || type == 1)) {
701 for(size_t i = 0; i < bidder_diagrams_saddle_.size(); ++i) {
702 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); ++j) {
703 Bidder const b = bidder_diagrams_saddle_[i].at(j);
704 double const persistence = b.getPersistence();
705 if(persistence < min_persistence) {
706 min_persistence = persistence;
707 }
708 }
709 }
710 }
711
712 if(do_max_ && (type == -1 || type == 2)) {
713 for(size_t i = 0; i < bidder_diagrams_max_.size(); ++i) {
714 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); ++j) {
715 Bidder const b = bidder_diagrams_max_[i].at(j);
716 double const persistence = b.getPersistence();
717 if(persistence < min_persistence) {
718 min_persistence = persistence;
719 }
720 }
721 }
722 }
723 return min_persistence;
724}
725
726std::vector<std::vector<double>> ttk::PDClustering::getMinPrices() {
727 std::vector<std::vector<double>> min_prices(3);
728
729 if(original_dos[0]) {
730 for(int i = 0; i < numberOfInputs_; ++i) {
731 min_prices[0].emplace_back(std::numeric_limits<double>::max());
732 for(size_t j = 0; j < centroids_with_price_min_[i].size(); ++j) {
733 Good const g = centroids_with_price_min_[i].at(j);
734 double const price = g.getPrice();
735 if(price < min_prices[0][i]) {
736 min_prices[0][i] = price;
737 }
738 }
739 }
740 }
741
742 if(original_dos[1]) {
743 for(int i = 0; i < numberOfInputs_; ++i) {
744 min_prices[1].emplace_back(std::numeric_limits<double>::max());
745 for(size_t j = 0; j < centroids_with_price_saddle_[i].size(); ++j) {
746 Good const g = centroids_with_price_saddle_[i].at(j);
747 double const price = g.getPrice();
748 if(price < min_prices[1][i]) {
749 min_prices[1][i] = price;
750 }
751 }
752 }
753 }
754
755 if(original_dos[2]) {
756 for(int i = 0; i < numberOfInputs_; ++i) {
757 min_prices[2].emplace_back(std::numeric_limits<double>::max());
758 for(size_t j = 0; j < centroids_with_price_max_[i].size(); ++j) {
759 Good const g = centroids_with_price_max_[i].at(j);
760 double const price = g.getPrice();
761 if(price < min_prices[2][i]) {
762 min_prices[2][i] = price;
763 }
764 }
765 }
766 }
767
768 return min_prices;
769}
770
771std::vector<std::vector<double>> ttk::PDClustering::getMinDiagonalPrices() {
772 std::vector<std::vector<double>> min_prices(3);
773 if(original_dos[0]) {
774 for(int i = 0; i < numberOfInputs_; ++i) {
775 min_prices[0].emplace_back(std::numeric_limits<double>::max());
776 for(size_t j = 0; j < current_bidder_diagrams_min_[i].size(); ++j) {
777 Bidder const b = current_bidder_diagrams_min_[i].at(j);
778 double const price = b.diagonal_price_;
779 if(price < min_prices[0][i]) {
780 min_prices[0][i] = price;
781 }
782 }
783 if(min_prices[0][i] >= std::numeric_limits<double>::max() / 2.) {
784 min_prices[0][i] = 0;
785 }
786 }
787 }
788
789 if(original_dos[1]) {
790 for(int i = 0; i < numberOfInputs_; ++i) {
791 min_prices[1].emplace_back(std::numeric_limits<double>::max());
792 for(size_t j = 0; j < current_bidder_diagrams_saddle_[i].size(); ++j) {
793 Bidder const b = current_bidder_diagrams_saddle_[i].at(j);
794 double const price = b.diagonal_price_;
795 if(price < min_prices[1][i]) {
796 min_prices[1][i] = price;
797 }
798 }
799 if(min_prices[1][i] >= std::numeric_limits<double>::max() / 2.) {
800 min_prices[1][i] = 0;
801 }
802 }
803 }
804
805 if(original_dos[2]) {
806 for(int i = 0; i < numberOfInputs_; ++i) {
807 min_prices[2].emplace_back(std::numeric_limits<double>::max());
808 for(size_t j = 0; j < current_bidder_diagrams_max_[i].size(); ++j) {
809 Bidder const b = current_bidder_diagrams_max_[i].at(j);
810 double const price = b.diagonal_price_;
811 if(price < min_prices[2][i]) {
812 min_prices[2][i] = price;
813 }
814 }
815 if(min_prices[2][i] >= std::numeric_limits<double>::max() / 2.) {
816 min_prices[2][i] = 0;
817 }
818 }
819 }
820 return min_prices;
821}
822
824 const BidderDiagram &D2,
825 const double delta_lim) {
826 GoodDiagram const D2_bis = diagramToCentroid(D2);
827 return computeDistance(D1, D2_bis, delta_lim);
828}
829
831 const GoodDiagram &D2,
832 const double delta_lim) {
833 std::vector<MatchingType> matchings;
834 const auto D2_bis = centroidWithZeroPrices(D2);
836 delta_lim, use_kdtree_, nonMatchingWeight_);
837 auction.BuildAuctionDiagrams(D1, D2_bis);
838 double const cost = auction.run(matchings);
839 return cost;
840}
841
843 const GoodDiagram *const D2,
844 const double delta_lim) {
845 std::vector<MatchingType> matchings;
847 delta_lim, use_kdtree_, nonMatchingWeight_);
848 int const size1 = D1->size();
849 auction.BuildAuctionDiagrams(*D1, *D2);
850 double const cost = auction.run(matchings);
851 // Diagonal Points were added in the original diagram. The following line
852 // removes them.
853 D1->resize(size1);
854 return cost;
855}
856
858 const GoodDiagram &D2,
859 const double delta_lim) {
860 BidderDiagram const D1_bis = centroidToDiagram(D1);
861 return computeDistance(D1_bis, D2, delta_lim);
862}
863
867 for(size_t i = 0; i < centroid.size(); i++) {
868 Good g = centroid.at(i);
869 g.setPrice(0);
870 GD.emplace_back(g);
871 }
872 return GD;
873}
874
878 for(size_t i = 0; i < diagram.size(); i++) {
879 Bidder b = diagram.at(i);
880 b.setDiagonalPrice(0);
881 BD.emplace_back(b);
882 }
883 return BD;
884}
885
889 for(size_t i = 0; i < centroid.size(); i++) {
890 Good g = centroid.at(i);
891
892 Bidder b = Bidder(g.x_, g.y_, g.isDiagonal(), BD.size());
893 b.SetCriticalCoordinates(g.coords_[0], g.coords_[1], g.coords_[2]);
894 b.setPositionInAuction(BD.size());
895 BD.emplace_back(b);
896 }
897 return BD;
898}
899
903 for(size_t i = 0; i < diagram.size(); i++) {
904 Bidder b = diagram.at(i);
905
906 Good g = Good(b.x_, b.y_, b.isDiagonal(), GD.size());
907 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
908 GD.emplace_back(g);
909 }
910 return GD;
911}
912
914 clustering_ = std::vector<std::vector<int>>(k_);
915}
916
918 std::vector<int> idx(numberOfInputs_);
919 // To perform a random draw with replacement, the vector {1, 2, ...,
920 // numberOfInputs_} is shuffled, and we consider its k_ first elements to be
921 // the initial centroids.
922 for(int i = 0; i < numberOfInputs_; i++) {
923 idx[i] = i;
924 }
925 if(!deterministic_)
926 std::shuffle(idx.begin(), idx.end(), std::random_device());
927
928 for(int c = 0; c < k_; c++) {
929 if(do_min_) {
930 GoodDiagram const centroid_min
932 centroids_min_.emplace_back(centroid_min);
933 }
934 if(do_sad_) {
935 GoodDiagram const centroid_sad
937 centroids_saddle_.emplace_back(centroid_sad);
938 }
939 if(do_max_) {
940 GoodDiagram const centroid_max
942 centroids_max_.emplace_back(centroid_max);
943 }
944 }
945}
946
948 std::vector<int> indexes_clusters;
949 int const random_idx = deterministic_ ? 0 : rand() % numberOfInputs_;
950 indexes_clusters.emplace_back(random_idx);
951
952 if(do_min_) {
953 GoodDiagram const centroid_min
955 centroids_min_.emplace_back(centroid_min);
956 }
957 if(do_sad_) {
958 GoodDiagram const centroid_sad
960 centroids_saddle_.emplace_back(centroid_sad);
961 }
962 if(do_max_) {
963 GoodDiagram const centroid_max
965 centroids_max_.emplace_back(centroid_max);
966 }
967
968 const auto square = [](const double a) { return a * a; };
969
970 while((int)indexes_clusters.size() < k_) {
971 std::vector<double> min_distance_to_centroid(numberOfInputs_);
972 std::vector<double> probabilities(numberOfInputs_);
973
974 // Uncomment for a deterministic algorithm
975 double maximal_distance = 0;
976 int candidate_centroid = 0;
977
978 for(int i = 0; i < numberOfInputs_; i++) {
979
980 min_distance_to_centroid[i] = std::numeric_limits<double>::max();
981 if(std::find(indexes_clusters.begin(), indexes_clusters.end(), i)
982 != indexes_clusters.end()) {
983
984 min_distance_to_centroid[i] = 0;
985 } else {
986
987 for(size_t j = 0; j < indexes_clusters.size(); ++j) {
988
989 double distance = 0;
990 if(do_min_) {
991 GoodDiagram const centroid_min
993 distance += computeDistance(
994 current_bidder_diagrams_min_[i], centroid_min, 0.01);
995 }
996 if(do_sad_) {
997 GoodDiagram const centroid_saddle
999 distance += computeDistance(
1000 current_bidder_diagrams_saddle_[i], centroid_saddle, 0.01);
1001 }
1002 if(do_max_) {
1003 GoodDiagram const centroid_max
1005 distance += computeDistance(
1006 current_bidder_diagrams_max_[i], centroid_max, 0.01);
1007 }
1008 if(distance < min_distance_to_centroid[i]) {
1009 min_distance_to_centroid[i] = distance;
1010 }
1011 }
1012 }
1013 probabilities[i] = square(min_distance_to_centroid[i]);
1014
1015 // The following block is useful in case of need for a deterministic
1016 // algorithm
1017 if(deterministic_ && min_distance_to_centroid[i] > maximal_distance) {
1018 maximal_distance = min_distance_to_centroid[i];
1019 candidate_centroid = i;
1020 }
1021 }
1022 // Comment the following four lines to make it deterministic
1023 std::random_device rd;
1024 std::mt19937 gen(rd());
1025 std::discrete_distribution<int> distribution(
1026 probabilities.begin(), probabilities.end());
1027
1028 if(!deterministic_) {
1029 candidate_centroid = distribution(gen);
1030 }
1031
1032 indexes_clusters.emplace_back(candidate_centroid);
1033 if(do_min_) {
1034 GoodDiagram const centroid_min
1035 = diagramToCentroid(current_bidder_diagrams_min_[candidate_centroid]);
1036 centroids_min_.emplace_back(centroid_min);
1037 }
1038 if(do_sad_) {
1039 GoodDiagram const centroid_sad = diagramToCentroid(
1040 current_bidder_diagrams_saddle_[candidate_centroid]);
1041 centroids_saddle_.emplace_back(centroid_sad);
1042 }
1043 if(do_max_) {
1044 GoodDiagram const centroid_max
1045 = diagramToCentroid(current_bidder_diagrams_max_[candidate_centroid]);
1046 centroids_max_.emplace_back(centroid_max);
1047 }
1048 }
1049}
1050
1052 // r_ is a vector stating for each diagram if its distance to its centroid is
1053 // up to date (false) or needs to be recomputed (true)
1054 r_ = std::vector<bool>(numberOfInputs_);
1055 // u_ is a vector of upper bounds of the distance of each diagram to its
1056 // closest centroid
1057 u_ = std::vector<double>(numberOfInputs_);
1058 inv_clustering_ = std::vector<int>(numberOfInputs_);
1059 for(int i = 0; i < numberOfInputs_; i++) {
1060 r_[i] = true;
1061 u_[i] = std::numeric_limits<double>::max();
1062 inv_clustering_[i] = -1;
1063 }
1064 // l_ is the matrix of lower bounds for the distance from each diagram
1065 // to each centroid
1066 l_ = std::vector<std::vector<double>>(numberOfInputs_);
1067 for(int i = 0; i < numberOfInputs_; ++i) {
1068 l_[i] = std::vector<double>(k_);
1069 for(int c = 0; c < k_; ++c) {
1070 l_[i][c] = 0;
1071 }
1072 }
1073
1074 // And d_ is a (K x K) matrix storing the distances between each pair of
1075 // centroids
1077 for(int i = 0; i < k_; ++i) {
1078 centroidsDistanceMatrix_[i].resize(k_, 0.0);
1079 }
1080}
1081
1082std::vector<std::vector<double>> ttk::PDClustering::getDistanceMatrix() {
1083 std::vector<std::vector<double>> D(numberOfInputs_);
1084
1085 for(int i = 0; i < numberOfInputs_; ++i) {
1086 BidderDiagram D1_min, D1_sad, D1_max;
1087 if(do_min_) {
1089 }
1090 if(do_sad_) {
1092 }
1093 if(do_max_) {
1095 }
1096 for(int c = 0; c < k_; ++c) {
1097 GoodDiagram D2_min, D2_sad, D2_max;
1098 double distance = 0;
1099 if(do_min_) {
1100 D2_min = centroids_min_[c];
1101 distance += computeDistance(D1_min, D2_min, 0.01);
1102 }
1103 if(do_sad_) {
1104 D2_sad = centroids_saddle_[c];
1105 distance += computeDistance(D1_sad, D2_sad, 0.01);
1106 }
1107 if(do_max_) {
1108 D2_max = centroids_max_[c];
1109 distance += computeDistance(D1_max, D2_max, 0.01);
1110 }
1111 D[i].emplace_back(distance);
1112 }
1113 }
1114 return D;
1115}
1116
1118 for(int i = 0; i < k_; ++i) {
1119 GoodDiagram D1_min, D1_sad, D1_max;
1120 if(do_min_) {
1122 }
1123 if(do_sad_) {
1125 }
1126 if(do_max_) {
1128 }
1129 for(int j = i + 1; j < k_; ++j) {
1130 double distance{};
1131 GoodDiagram D2_min, D2_sad, D2_max;
1132 if(do_min_) {
1134 distance += computeDistance(D1_min, D2_min, 0.01);
1135 }
1136 if(do_sad_) {
1138 distance += computeDistance(D1_sad, D2_sad, 0.01);
1139 }
1140 if(do_max_) {
1142 distance += computeDistance(D1_max, D2_max, 0.01);
1143 }
1144
1145 centroidsDistanceMatrix_[i][j] = distance;
1146 centroidsDistanceMatrix_[j][i] = distance;
1147 }
1148 }
1149}
1150
1153
1154 for(int i = 0; i < numberOfInputs_; ++i) {
1155 double const delta_lim{0.01};
1156 double distance{};
1157 auto c = inv_clustering_[i];
1158 if(original_dos[0]) {
1159 GoodDiagram const centroid_min
1161 BidderDiagram const bidder_diag
1163 distance += computeDistance(bidder_diag, centroid_min, delta_lim);
1164 }
1165 if(original_dos[1]) {
1166 GoodDiagram const centroid_saddle
1168 BidderDiagram const bidder_diag
1170 distance += computeDistance(bidder_diag, centroid_saddle, delta_lim);
1171 }
1172 if(original_dos[2]) {
1173 GoodDiagram const centroid_max
1175 BidderDiagram const bidder_diag
1177 distance += computeDistance(bidder_diag, centroid_max, delta_lim);
1178 }
1179 distanceToCentroid_[i] = distance;
1180 }
1181}
1182
1184 if(k_ > 1) {
1185 std::vector<std::vector<double>> distance_matrix = getDistanceMatrix();
1189
1190 for(int i = 0; i < numberOfInputs_; ++i) {
1191 double min_distance_to_centroid = std::numeric_limits<double>::max();
1192 int cluster = -1;
1193 for(int c = 0; c < k_; ++c) {
1194 if(distance_matrix[i][c] < min_distance_to_centroid) {
1195 min_distance_to_centroid = distance_matrix[i][c];
1196 cluster = c;
1197 }
1198 }
1199
1200 clustering_[cluster].emplace_back(i);
1201 if(cluster != inv_clustering_[i]) {
1202 // New centroid attributed to this diagram
1205 if(do_min_) {
1208 }
1209 if(do_sad_) {
1212 }
1213 if(do_max_) {
1216 }
1217 inv_clustering_[i] = cluster;
1218 }
1219 }
1220
1221 } else {
1225
1226 for(int i = 0; i < numberOfInputs_; i++) {
1227 clustering_[0].emplace_back(i);
1228 if(n_iterations_ < 1) {
1229 if(do_min_) {
1232 }
1233 if(do_sad_) {
1236 }
1237 if(do_max_) {
1240 }
1241 }
1242 inv_clustering_[i] = 0;
1243 }
1244 }
1245}
1246
1251
1252 // Initializes clusters with -1
1253 inv_clustering_ = std::vector<int>(numberOfInputs_, -1);
1254
1255 // Fill in the clusters
1256 for(int c = 0; c < k_; ++c) {
1257 for(size_t j = 0; j < clustering_[c].size(); ++j) {
1258 int const idx = clustering_[c][j];
1259 inv_clustering_[idx] = c;
1260 }
1261 }
1262}
1263
1265 clustering_ = std::vector<std::vector<int>>(k_);
1266 for(int i = 0; i < numberOfInputs_; ++i) {
1267 clustering_[inv_clustering_[i]].emplace_back(i);
1268 }
1269
1270 // Check if a cluster was left without diagram
1271 for(int c = 0; c < k_; ++c) {
1272 if(clustering_[c].empty()) {
1273 std::cout << "Problem in invertInverseClusters()... \nCluster " << c
1274 << " was left with no diagram attached to it... " << std::endl;
1275 }
1276 }
1277}
1278
1280 // Step 1
1283 // self.old_clusters = copy.copy(self.clusters)
1286 bool const do_min = original_dos[0];
1287 bool const do_sad = original_dos[1];
1288 bool const do_max = original_dos[2];
1289
1290 for(int i = 0; i < numberOfInputs_; ++i) {
1291 // Step 3 find potential changes of clusters
1292 BidderDiagram D1_min, D1_sad, D1_max;
1293 if(do_min) {
1295 }
1296 if(do_sad) {
1298 }
1299 if(do_max) {
1301 }
1302
1303 for(int c = 0; c < k_; ++c) {
1304 if(inv_clustering_[i] == -1) {
1305 // If not yet assigned, assign it first to a random cluster
1306
1307 if(deterministic_) {
1308 inv_clustering_[i] = i % k_;
1309 } else {
1310 std::cout << " - ASSIGNED TO A RANDOM CLUSTER " << '\n';
1311 inv_clustering_[i] = rand() % (k_);
1312 }
1313
1314 r_[i] = true;
1315 if(do_min) {
1318 }
1319 if(do_sad) {
1322 }
1323 if(do_max) {
1326 }
1327 }
1328
1329 if(c != inv_clustering_[i] && u_[i] > l_[i][c]
1330 && u_[i] > 0.5 * centroidsDistanceMatrix_[inv_clustering_[i]][c]) {
1331 // Step 3a, If necessary, recompute the distance to centroid
1332 if(r_[i]) {
1333 double distance = 0;
1334 GoodDiagram centroid_min, centroid_sad, centroid_max;
1335 if(do_min) {
1336 centroid_min
1338 distance += computeDistance(D1_min, centroid_min, 0.01);
1339 }
1340 if(do_sad) {
1341 centroid_sad
1343 distance += computeDistance(D1_sad, centroid_sad, 0.01);
1344 }
1345 if(do_max) {
1346 centroid_max
1348 distance += computeDistance(D1_max, centroid_max, 0.01);
1349 }
1350 r_[i] = false;
1351 u_[i] = distance;
1352 l_[i][inv_clustering_[i]] = distance;
1353 }
1354 // Step 3b, check if still potential change of clusters
1355 if((n_iterations_ > 2 || n_iterations_ < 1)
1356 && (u_[i] > l_[i][c]
1357 || u_[i]
1358 > 0.5 * centroidsDistanceMatrix_[inv_clustering_[i]][c])) {
1359 BidderDiagram diagram_min, diagram_sad, diagram_max;
1360 GoodDiagram centroid_min, centroid_sad, centroid_max;
1361 double distance = 0;
1362
1363 if(do_min) {
1364 centroid_min = centroidWithZeroPrices(centroids_min_[c]);
1365 diagram_min
1367 distance += computeDistance(diagram_min, centroid_min, 0.01);
1368 }
1369 if(do_sad) {
1370 centroid_sad = centroidWithZeroPrices(centroids_saddle_[c]);
1371 diagram_sad
1373 distance += computeDistance(diagram_sad, centroid_sad, 0.01);
1374 }
1375 if(do_max) {
1376 centroid_max = centroidWithZeroPrices(centroids_max_[c]);
1377 diagram_max
1379 distance += computeDistance(diagram_max, centroid_max, 0.01);
1380 }
1381 l_[i][c] = distance;
1382 // TODO Prices are lost here... If distance<self.u[i], we should keep
1383 // the prices
1384 if(distance < u_[i]) {
1385 // Changing cluster
1388 u_[i] = distance;
1389 inv_clustering_[i] = c;
1390
1391 if(do_min) {
1394 }
1395 if(do_sad) {
1398 }
1399 if(do_max) {
1402 }
1403 }
1404 }
1405 }
1406 }
1407 }
1409 for(int c = 0; c < k_; ++c) {
1410 if(clustering_[c].empty()) {
1411 std::cout << "Adding artificial centroid because a cluster was empty"
1412 << std::endl;
1413 bool idx_acceptable = false;
1414 int idx = 0;
1415
1416 std::vector<double> copy_of_u(u_.size());
1417 copy_of_u = u_;
1418 while(!idx_acceptable) {
1419 auto argMax = std::max_element(copy_of_u.begin(), copy_of_u.end());
1420 idx = std::distance(copy_of_u.begin(), argMax);
1421 if(inv_clustering_[idx] < k_ && inv_clustering_[idx] >= 0
1422 && clustering_[inv_clustering_[idx]].size() > 1) {
1423 idx_acceptable = true;
1424 int const cluster_removal = inv_clustering_[idx];
1425 // Removing the index to remove
1426 clustering_[cluster_removal].erase(
1427 std::remove(clustering_[cluster_removal].begin(),
1428 clustering_[cluster_removal].end(), idx),
1429 clustering_[cluster_removal].end());
1430 } else {
1431 if(copy_of_u.size() > (size_t)idx) {
1432 copy_of_u.erase(argMax);
1433 } else {
1434 idx_acceptable = true;
1435 int cluster_max = 0;
1436 if(!clustering_[cluster_max].empty()) {
1437 idx = clustering_[cluster_max][0];
1438 }
1439 for(int i_test = 1; i_test < k_; i_test++) {
1440 if(clustering_[i_test].size() > clustering_[cluster_max].size()) {
1441 cluster_max = i_test;
1442 idx = clustering_[cluster_max][0];
1443 }
1444 }
1445 int const cluster_removal = inv_clustering_[idx];
1446 clustering_[cluster_removal].erase(
1447 std::remove(clustering_[cluster_removal].begin(),
1448 clustering_[cluster_removal].end(), idx),
1449 clustering_[cluster_removal].end());
1450 }
1451 }
1452 }
1453
1454 clustering_[c].emplace_back(idx);
1455 inv_clustering_[idx] = c;
1456
1457 if(do_min) {
1462 }
1463 if(do_sad) {
1468 }
1469 if(do_max) {
1474 }
1477 }
1478 }
1479}
1480
1482 std::vector<std::vector<double>> *min_price,
1483 std::vector<std::vector<double>> *min_diag_price,
1484 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
1485 &all_matchings_per_type_and_cluster,
1486 int only_matchings) {
1488 std::vector<double> max_shift_vector(3);
1489 max_shift_vector[0] = 0;
1490 max_shift_vector[1] = 0;
1491 max_shift_vector[2] = 0;
1492 double max_shift_c_min = 0;
1493 double max_shift_c_sad = 0;
1494 double max_shift_c_max = 0;
1495 double max_wasserstein_shift = 0;
1496 bool precision_min = true;
1497 bool precision_sad = true;
1498 bool precision_max = true;
1499 cost_ = 0;
1500 double const sq_dist_min = cost_min_;
1501 double const sq_dist_sad = cost_sad_;
1502 double const sq_dist_max = cost_max_;
1503 if(do_min_) {
1504 cost_min_ = 0;
1505 }
1506 if(do_sad_) {
1507 cost_sad_ = 0;
1508 }
1509 if(do_max_) {
1510 cost_max_ = 0;
1511 }
1512
1513 for(int c = 0; c < k_; ++c) {
1514 if(!clustering_[c].empty()) {
1515 std::vector<GoodDiagram> centroids_with_price_min,
1516 centroids_with_price_sad, centroids_with_price_max;
1517 int count = 0;
1518 for(int const idx : clustering_[c]) {
1519 // Timer time_first_thing;
1520 // Find the position of diagrams[idx] in old cluster c
1521 std::vector<int>::iterator const i = std::find(
1522 old_clustering_[c].begin(), old_clustering_[c].end(), idx);
1523 int const pos = (i == old_clustering_[c].end())
1524 ? -1
1525 : std::distance(old_clustering_[c].begin(), i);
1526 if(pos >= 0) {
1527 // Diagram was already linked to this centroid before
1528 if(do_min_) {
1529 centroids_with_price_min.emplace_back(
1531 }
1532 if(do_sad_) {
1533 centroids_with_price_sad.emplace_back(
1535 }
1536 if(do_max_) {
1537 centroids_with_price_max.emplace_back(
1539 }
1540 } else {
1541 int number_of_points_min = 0;
1542 int number_of_points_max = 0;
1543 int number_of_points_sad = 0;
1544
1545 // Otherwise, centroid is given 0 prices and the diagram is given 0
1546 // diagonal-prices
1547 if(do_min_) {
1548 centroids_with_price_min.emplace_back(
1552 number_of_points_min += centroids_with_price_min_[idx].size()
1553 + current_bidder_diagrams_min_[idx].size();
1554 }
1555 if(do_sad_) {
1556 centroids_with_price_sad.emplace_back(
1560 number_of_points_sad
1561 += centroids_with_price_saddle_[idx].size()
1562 + current_bidder_diagrams_saddle_[idx].size();
1563 }
1564 if(do_max_) {
1565 centroids_with_price_max.emplace_back(
1569 number_of_points_max += centroids_with_price_max_[idx].size()
1570 + current_bidder_diagrams_max_[idx].size();
1571 }
1572
1573 if(n_iterations_ > 1) {
1574 // If diagram new to cluster and we're not at first iteration,
1575 // precompute prices for the objects via compute_distance()
1576 // number_of_points /= (int)do_min_ + (int)do_sad_ + (int)do_max_;
1577 // double d_estimated = pow(cost_ / numberOfInputs_, 1. /
1578 // wasserstein_) + 1e-7; We use pointer in the auction in order to
1579 // keep the prices at the end
1580
1581 if(do_min_) {
1582 // double estimated_delta_lim = number_of_points_min *
1583 // epsilon_[0] / (2*sq_dist_min) ;
1584 double estimated_delta_lim
1585 = 1.
1586 / sqrt(1 - number_of_points_min * epsilon_[0] / sq_dist_min)
1587 - 1;
1588 if(estimated_delta_lim > 1) {
1589 estimated_delta_lim = 1;
1590 }
1592 &(centroids_with_price_min[count]),
1593 estimated_delta_lim);
1594 }
1595 if(do_sad_) {
1596 // double estimated_delta_lim = number_of_points_sad *
1597 // epsilon_[1] / (2*sq_dist_sad);
1598 double estimated_delta_lim
1599 = 1.
1600 / sqrt(1 - number_of_points_sad * epsilon_[1] / sq_dist_sad)
1601 - 1;
1602 if(estimated_delta_lim > 1) {
1603 estimated_delta_lim = 1;
1604 }
1606 &(centroids_with_price_sad[count]),
1607 estimated_delta_lim);
1608 }
1609 if(do_max_) {
1610 // double estimated_delta_lim = number_of_points_max *
1611 // epsilon_[2] / (2*sq_dist_max);
1612 double estimated_delta_lim
1613 = 1.
1614 / sqrt(1 - number_of_points_max * epsilon_[2] / sq_dist_max)
1615 - 1;
1616 if(estimated_delta_lim > 1) {
1617 estimated_delta_lim = 1;
1618 }
1620 &(centroids_with_price_max[count]),
1621 estimated_delta_lim);
1622 }
1623 }
1624 }
1625 count++;
1626 }
1627 double total_cost = 0;
1628 double wasserstein_shift = 0;
1629
1630 using KDTreePair = PDBarycenter::KDTreePair;
1631
1632 if(do_min_) {
1633 std::vector<std::vector<MatchingType>> all_matchings;
1634 std::vector<int> sizes;
1635 Timer const time_preprocess_bary;
1636 std::vector<BidderDiagram> diagrams_c_min;
1638 for(int const idx : clustering_[c]) {
1639 diagrams_c_min.emplace_back(current_bidder_diagrams_min_[idx]);
1640 }
1641 sizes.resize(diagrams_c_min.size());
1642 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1643 sizes[i] = diagrams_c_min[i].size();
1644 }
1645 barycenter_computer_min_[c].setNumberOfInputs(diagrams_c_min.size());
1646 barycenter_computer_min_[c].setCurrentBidders(diagrams_c_min);
1647
1648 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1649 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1650 i_diagram++) {
1651 barycenter_goods[i_diagram]
1652 = centroids_with_price_min_[clustering_[c][i_diagram]];
1653 }
1654 barycenter_computer_min_[c].setCurrentBarycenter(barycenter_goods);
1655 all_matchings.resize(diagrams_c_min.size());
1656 } else {
1657 sizes.resize(barycenter_computer_min_[c].getCurrentBidders().size());
1658 for(size_t i = 0;
1659 i < barycenter_computer_min_[c].getCurrentBidders().size(); i++) {
1660 sizes[i]
1661 = barycenter_computer_min_[c].getCurrentBidders().at(i).size();
1662 }
1663 diagrams_c_min.resize(
1664 barycenter_computer_min_[c].getCurrentBidders().size());
1665 all_matchings.resize(
1666 barycenter_computer_min_[c].getCurrentBidders().size());
1667 }
1668
1669 KDTreePair pair;
1670 bool use_kdt = false;
1671 if(!barycenter_computer_min_[c].getCurrentBarycenter()[0].empty()) {
1672 pair = barycenter_computer_min_[c].getKDTree();
1673 use_kdt = true;
1674 }
1675
1676 barycenter_computer_min_[c].runMatching(
1677 &total_cost, epsilon_[0], sizes, *pair.first, pair.second,
1678 &(min_diag_price->at(0)), &(min_price->at(0)), &(all_matchings),
1679 use_kdt, only_matchings);
1680 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1681 all_matchings_per_type_and_cluster[c][0][ii].resize(
1682 all_matchings[ii].size());
1683 all_matchings_per_type_and_cluster[c][0][ii] = all_matchings[ii];
1684 }
1685 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1686 all_matchings_per_type_and_cluster[c][0][ii].resize(0);
1687 }
1688
1689 precision_min
1690 = barycenter_computer_min_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1691 cost_min_ += total_cost;
1692 Timer const time_update;
1693 if(!only_matchings) {
1694 max_shift_c_min
1695 = barycenter_computer_min_[c].updateBarycenter(all_matchings);
1696 }
1697
1698 if(max_shift_c_min > max_shift_vector[0]) {
1699 max_shift_vector[0] = max_shift_c_min;
1700 }
1701
1702 // Now that barycenters and diagrams are updated in
1703 // PDBarycenter class, we import the results here.
1704 diagrams_c_min = barycenter_computer_min_[c].getCurrentBidders();
1705 centroids_with_price_min
1706 = barycenter_computer_min_[c].getCurrentBarycenter();
1707 int i = 0;
1708 for(int const idx : clustering_[c]) {
1709 current_bidder_diagrams_min_[idx] = diagrams_c_min[i];
1710 centroids_with_price_min_[idx] = centroids_with_price_min[i];
1711 i++;
1712 }
1713
1714 GoodDiagram const old_centroid = centroids_min_[c];
1717
1718 if(use_accelerated_) {
1719 wasserstein_shift
1720 += computeDistance(old_centroid, centroids_min_[c], 0.01);
1721 }
1722 }
1723
1724 if(do_sad_) {
1725 std::vector<std::vector<MatchingType>> all_matchings;
1726 total_cost = 0;
1727 std::vector<int> sizes;
1728
1729 std::vector<BidderDiagram> diagrams_c_min;
1731 for(int const idx : clustering_[c]) {
1732 diagrams_c_min.emplace_back(current_bidder_diagrams_saddle_[idx]);
1733 }
1734 sizes.resize(diagrams_c_min.size());
1735 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1736 sizes[i] = diagrams_c_min[i].size();
1737 }
1738 barycenter_computer_sad_[c].setNumberOfInputs(diagrams_c_min.size());
1739 barycenter_computer_sad_[c].setCurrentBidders(diagrams_c_min);
1740 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1741 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1742 i_diagram++) {
1743 barycenter_goods[i_diagram]
1745 }
1746 barycenter_computer_sad_[c].setCurrentBarycenter(barycenter_goods);
1747 all_matchings.resize(diagrams_c_min.size());
1748 } else {
1749 sizes.resize(barycenter_computer_sad_[c].getCurrentBidders().size());
1750 for(size_t i = 0;
1751 i < barycenter_computer_sad_[c].getCurrentBidders().size(); i++) {
1752 sizes[i]
1753 = barycenter_computer_sad_[c].getCurrentBidders().at(i).size();
1754 }
1755 all_matchings.resize(
1756 barycenter_computer_sad_[c].getCurrentBidders().size());
1757 diagrams_c_min.resize(
1758 barycenter_computer_sad_[c].getCurrentBidders().size());
1759 }
1760
1761 KDTreePair pair;
1762 bool use_kdt = false;
1763 if(!barycenter_computer_sad_[c].getCurrentBarycenter()[0].empty()) {
1764 pair = barycenter_computer_sad_[c].getKDTree();
1765 use_kdt = true;
1766 }
1767
1768 barycenter_computer_sad_[c].runMatching(
1769 &total_cost, epsilon_[1], sizes, *pair.first, pair.second,
1770 &(min_diag_price->at(1)), &(min_price->at(1)), &(all_matchings),
1771 use_kdt, only_matchings);
1772 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1773 all_matchings_per_type_and_cluster[c][1][ii].resize(
1774 all_matchings[ii].size());
1775 all_matchings_per_type_and_cluster[c][1][ii] = all_matchings[ii];
1776 }
1777 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1778 all_matchings_per_type_and_cluster[c][1][ii].resize(0);
1779 }
1780
1781 precision_sad
1782 = barycenter_computer_sad_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1783 if(!only_matchings) {
1784 max_shift_c_sad
1785 = barycenter_computer_sad_[c].updateBarycenter(all_matchings);
1786 }
1787
1788 cost_sad_ += total_cost;
1789
1790 if(max_shift_c_sad > max_shift_vector[1]) {
1791 max_shift_vector[1] = max_shift_c_sad;
1792 }
1793
1794 // Now that barycenters and diagrams are updated in PDBarycenter class,
1795 // we import the results here.
1796 diagrams_c_min = barycenter_computer_sad_[c].getCurrentBidders();
1797 centroids_with_price_sad
1798 = barycenter_computer_sad_[c].getCurrentBarycenter();
1799 int i = 0;
1800 for(int const idx : clustering_[c]) {
1801 current_bidder_diagrams_saddle_[idx] = diagrams_c_min[i];
1802 centroids_with_price_saddle_[idx] = centroids_with_price_sad[i];
1803 i++;
1804 }
1805 GoodDiagram const old_centroid = centroids_saddle_[c];
1809 wasserstein_shift
1810 += computeDistance(old_centroid, centroids_saddle_[c], 0.01);
1811 }
1812
1813 if(do_max_) {
1814 std::vector<std::vector<MatchingType>> all_matchings;
1815 Timer const time_preprocess_bary;
1816 total_cost = 0;
1817 std::vector<int> sizes;
1818 std::vector<BidderDiagram> diagrams_c_min;
1820 for(int const idx : clustering_[c]) {
1821 diagrams_c_min.emplace_back(current_bidder_diagrams_max_[idx]);
1822 }
1823 sizes.resize(diagrams_c_min.size());
1824 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1825 sizes[i] = diagrams_c_min[i].size();
1826 }
1827 barycenter_computer_max_[c].setNumberOfInputs(diagrams_c_min.size());
1828 barycenter_computer_max_[c].setCurrentBidders(diagrams_c_min);
1829 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1830 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1831 i_diagram++) {
1832 barycenter_goods[i_diagram]
1833 = centroids_with_price_max_[clustering_[c][i_diagram]];
1834 }
1835 barycenter_computer_max_[c].setCurrentBarycenter(barycenter_goods);
1836 all_matchings.resize(diagrams_c_min.size());
1837 } else {
1838 sizes.resize(barycenter_computer_max_[c].getCurrentBidders().size());
1839 for(size_t i = 0;
1840 i < barycenter_computer_max_[c].getCurrentBidders().size(); i++) {
1841 sizes[i]
1842 = barycenter_computer_max_[c].getCurrentBidders().at(i).size();
1843 }
1844
1845 diagrams_c_min.resize(
1846 barycenter_computer_max_[c].getCurrentBidders().size());
1847 all_matchings.resize(
1848 barycenter_computer_max_[c].getCurrentBidders().size());
1849 }
1850
1851 KDTreePair pair;
1852 bool use_kdt = false;
1853 if(!barycenter_computer_max_[c].getCurrentBarycenter()[0].empty()) {
1854 pair = barycenter_computer_max_[c].getKDTree();
1855 use_kdt = true;
1856 }
1857
1858 barycenter_computer_max_[c].runMatching(
1859 &total_cost, epsilon_[2], sizes, *pair.first, pair.second,
1860 &(min_diag_price->at(2)), &(min_price->at(2)), &(all_matchings),
1861 use_kdt, only_matchings);
1862 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1863 all_matchings_per_type_and_cluster[c][2][ii].resize(
1864 all_matchings[ii].size());
1865 all_matchings_per_type_and_cluster[c][2][ii] = all_matchings[ii];
1866 }
1867 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1868 all_matchings_per_type_and_cluster[c][2][ii].resize(0);
1869 }
1870 precision_max
1871 = barycenter_computer_max_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1872
1873 cost_max_ += total_cost;
1874 Timer const time_update;
1875 if(!only_matchings) {
1876 max_shift_c_max
1877 = barycenter_computer_max_[c].updateBarycenter(all_matchings);
1878 }
1879 if(max_shift_c_max > max_shift_vector[2]) {
1880 max_shift_vector[2] = max_shift_c_max;
1881 }
1882
1883 // Now that barycenters and diagrams are updated in PDBarycenter class,
1884 // we import the results here.
1885 diagrams_c_min = barycenter_computer_max_[c].getCurrentBidders();
1886 centroids_with_price_max
1887 = barycenter_computer_max_[c].getCurrentBarycenter();
1888 int i = 0;
1889 for(int const idx : clustering_[c]) {
1890 current_bidder_diagrams_max_[idx] = diagrams_c_min[i];
1891 centroids_with_price_max_[idx] = centroids_with_price_max[i];
1892 i++;
1893 }
1894 GoodDiagram const old_centroid = centroids_max_[c];
1897 if(use_accelerated_) {
1898 wasserstein_shift
1899 += computeDistance(old_centroid, centroids_max_[c], 0.01);
1900 }
1901 }
1902
1904 if(wasserstein_shift > max_wasserstein_shift) {
1905 max_wasserstein_shift = wasserstein_shift;
1906 }
1907 if(use_accelerated_) {
1908 for(int i = 0; i < numberOfInputs_; ++i) {
1909 // Step 5 of Accelerated KMeans: Update the lower bound on distance
1910 // thanks to the triangular inequality
1911 l_[i][c] = Geometry::pow(
1912 Geometry::pow(l_[i][c], 1. / wasserstein_)
1913 - Geometry::pow(wasserstein_shift, 1. / wasserstein_),
1914 wasserstein_);
1915 if(l_[i][c] < 0) {
1916 l_[i][c] = 0;
1917 }
1918 }
1919 for(int const idx : clustering_[c]) {
1920 // Step 6, update the upper bound on the distance to the centroid
1921 // thanks to the triangle inequality
1922 u_[idx] = Geometry::pow(
1923 Geometry::pow(u_[idx], 1. / wasserstein_)
1924 + Geometry::pow(wasserstein_shift, 1. / wasserstein_),
1925 wasserstein_);
1926 r_[idx] = true;
1927 }
1928 }
1929 }
1930 }
1931 // Normally return max_shift, but it seems there is a bug
1932 // yielding max_shift > 100 * max_wasserstein_shift
1933 // which should logically not really happen...
1934 // This is supposed to be only a temporary patch...
1935 precision_min_ = precision_min;
1936 precision_sad_ = precision_sad;
1937 precision_max_ = precision_max;
1938 precision_criterion_ = precision_min && precision_sad && precision_max;
1940 return max_shift_vector; // std::min(max_shift, max_wasserstein_shift);
1941}
1942
1944 for(int i = 0; i < numberOfInputs_; i++) {
1945 if(do_min_) {
1946 DiagramType *CTDiagram = &((*inputDiagramsMin_)[i]);
1947 BidderDiagram bidders;
1948 for(size_t j = 0; j < CTDiagram->size(); j++) {
1949 // Add bidder to bidders
1950 Bidder b((*CTDiagram)[j], j, lambda_);
1951
1952 b.setPositionInAuction(bidders.size());
1953 bidders.emplace_back(b);
1954 if(b.isDiagonal() || b.x_ == b.y_) {
1955 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
1956 }
1957 }
1958 bidder_diagrams_min_.emplace_back(bidders);
1959 current_bidder_diagrams_min_.emplace_back();
1960 centroids_with_price_min_.emplace_back();
1961 std::vector<int> ids(bidders.size(), -1);
1962 current_bidder_ids_min_.emplace_back(ids);
1963 }
1964
1965 if(do_sad_) {
1966 DiagramType *CTDiagram = &((*inputDiagramsSaddle_)[i]);
1967
1968 BidderDiagram bidders;
1969 for(size_t j = 0; j < CTDiagram->size(); j++) {
1970 // Add bidder to bidders
1971 Bidder b((*CTDiagram)[j], j, lambda_);
1972
1973 b.setPositionInAuction(bidders.size());
1974 bidders.emplace_back(b);
1975 if(b.isDiagonal() || b.x_ == b.y_) {
1976 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
1977 }
1978 }
1979 bidder_diagrams_saddle_.emplace_back(bidders);
1980 current_bidder_diagrams_saddle_.emplace_back();
1981 centroids_with_price_saddle_.emplace_back();
1982 std::vector<int> ids(bidders.size(), -1);
1983 current_bidder_ids_sad_.emplace_back(ids);
1984 }
1985
1986 if(do_max_) {
1987 DiagramType *CTDiagram = &((*inputDiagramsMax_)[i]);
1988
1989 BidderDiagram bidders;
1990 for(size_t j = 0; j < CTDiagram->size(); j++) {
1991 // Add bidder to bidders
1992 Bidder b((*CTDiagram)[j], j, lambda_);
1993
1994 b.setPositionInAuction(bidders.size());
1995 bidders.emplace_back(b);
1996 if(b.isDiagonal() || b.x_ == b.y_) {
1997 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
1998 }
1999 }
2000 bidder_diagrams_max_.emplace_back(bidders);
2001 current_bidder_diagrams_max_.emplace_back();
2002 centroids_with_price_max_.emplace_back();
2003 std::vector<int> ids(bidders.size(), -1);
2004 current_bidder_ids_max_.emplace_back(ids);
2005 }
2006 }
2007}
2008
2010 std::vector<double> &previous_min_persistence,
2011 std::vector<double> &min_persistence,
2012 std::vector<std::vector<double>> &initial_diagonal_prices,
2013 std::vector<std::vector<double>> &initial_off_diagonal_prices,
2014 std::vector<int> &min_points_to_add,
2015 bool add_points_to_barycenter,
2016 bool first_enrichment) {
2017
2018 std::vector<double> new_min_persistence
2019 = first_enrichment ? previous_min_persistence : min_persistence;
2020
2021 if(!do_min_) {
2022 new_min_persistence[0] = previous_min_persistence[0];
2023 }
2024 if(!do_sad_) {
2025 new_min_persistence[1] = previous_min_persistence[1];
2026 }
2027 if(!do_max_) {
2028 new_min_persistence[2] = previous_min_persistence[2];
2029 }
2030
2031 // 1. Get size of the largest current diagram, deduce the maximal number of
2032 // points to append
2033 size_t max_diagram_size_min{};
2034 size_t max_diagram_size_sad{};
2035 size_t max_diagram_size_max{};
2036 if(do_min_) {
2037 for(int i = 0; i < numberOfInputs_; i++) {
2038 if(current_bidder_diagrams_min_[i].size() > max_diagram_size_min) {
2039 max_diagram_size_min = current_bidder_diagrams_min_[i].size();
2040 }
2041 }
2042 }
2043 if(do_sad_) {
2044 for(int i = 0; i < numberOfInputs_; i++) {
2045 if(current_bidder_diagrams_saddle_[i].size() > max_diagram_size_sad) {
2046 max_diagram_size_sad = current_bidder_diagrams_saddle_[i].size();
2047 }
2048 }
2049 }
2050 if(do_max_) {
2051 for(int i = 0; i < numberOfInputs_; i++) {
2052 if(current_bidder_diagrams_max_[i].size() > max_diagram_size_max) {
2053 max_diagram_size_max = current_bidder_diagrams_max_[i].size();
2054 }
2055 }
2056 }
2057 int const max_points_to_add_min
2058 = std::max(min_points_to_add[0],
2059 min_points_to_add[0] + (int)(max_diagram_size_min / 10));
2060 int const max_points_to_add_sad
2061 = std::max(min_points_to_add[1],
2062 min_points_to_add[1] + (int)(max_diagram_size_sad / 10));
2063 int const max_points_to_add_max
2064 = std::max(min_points_to_add[2],
2065 min_points_to_add[2] + (int)(max_diagram_size_max / 10));
2066
2067 // 2. Get which points can be added, deduce the new minimal persistence
2068 std::vector<std::vector<int>> candidates_to_be_added_min(numberOfInputs_);
2069 std::vector<std::vector<int>> candidates_to_be_added_sad(numberOfInputs_);
2070 std::vector<std::vector<int>> candidates_to_be_added_max(numberOfInputs_);
2071 std::vector<std::vector<int>> idx_min(numberOfInputs_);
2072 std::vector<std::vector<int>> idx_sad(numberOfInputs_);
2073 std::vector<std::vector<int>> idx_max(numberOfInputs_);
2074
2075 if(do_min_) {
2076 for(int i = 0; i < numberOfInputs_; i++) {
2077 std::vector<double> persistences;
2078 int number_of_added_pairs = current_bidder_diagrams_min_[i].size();
2079 double last_added_persistence = number_of_added_pairs
2081 .at(number_of_added_pairs - 1)
2082 .getPersistence()
2083 : previous_min_persistence[0];
2084 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); j++) {
2085 const auto &b = bidder_diagrams_min_[i].at(j);
2086 const auto persistence = b.getPersistence();
2087 if(persistence >= min_persistence[0]
2088 && persistence < last_added_persistence) {
2089 candidates_to_be_added_min[i].emplace_back(j);
2090 idx_min[i].emplace_back(idx_min[i].size());
2091 persistences.emplace_back(persistence);
2092 }
2093 }
2094 std::sort(
2095 idx_min[i].begin(), idx_min[i].end(), [&persistences](int &a, int &b) {
2096 return ((persistences[a] > persistences[b])
2097 || ((persistences[a] == persistences[b]) && (a > b)));
2098 });
2099 int size = candidates_to_be_added_min[i].size();
2100 if(size > 0) {
2101 double last_persistence_added_min
2102 = persistences[idx_min[i][std::min(size, max_points_to_add_min) - 1]];
2103 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2104 // added per diagram
2105 if(i == 0) {
2106 new_min_persistence[0] = last_persistence_added_min;
2107 } else {
2108 if(last_persistence_added_min > new_min_persistence[0])
2109 new_min_persistence[0] = last_persistence_added_min;
2110 }
2111 } else { // a maxima max_point_to_add added per diagram
2112 if(last_persistence_added_min > new_min_persistence[0]) {
2113 new_min_persistence[0] = last_persistence_added_min;
2114 }
2115 }
2116 }
2117 }
2118 }
2119
2120 if(do_sad_) {
2121 for(int i = 0; i < numberOfInputs_; i++) {
2122 std::vector<double> persistences;
2123 int number_of_added_pairs = current_bidder_diagrams_saddle_[i].size();
2124 double last_added_persistence = number_of_added_pairs
2126 .at(number_of_added_pairs - 1)
2127 .getPersistence()
2128 : previous_min_persistence[1];
2129 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); j++) {
2130 const auto &b = bidder_diagrams_saddle_[i].at(j);
2131 const auto persistence = b.getPersistence();
2132 if(persistence >= min_persistence[1]
2133 && persistence < last_added_persistence) {
2134 candidates_to_be_added_sad[i].emplace_back(j);
2135 idx_sad[i].emplace_back(idx_sad[i].size());
2136 persistences.emplace_back(persistence);
2137 }
2138 }
2139 std::sort(
2140 idx_sad[i].begin(), idx_sad[i].end(), [&persistences](int &a, int &b) {
2141 return ((persistences[a] > persistences[b])
2142 || ((persistences[a] == persistences[b]) && (a > b)));
2143 });
2144 int size = candidates_to_be_added_sad[i].size();
2145 if(size > 0) {
2146 double last_persistence_added_sad
2147 = persistences[idx_sad[i][std::min(size, max_points_to_add_sad) - 1]];
2148 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2149 // added per diagram
2150 if(i == 0) {
2151 new_min_persistence[1] = last_persistence_added_sad;
2152 } else {
2153 if(last_persistence_added_sad > new_min_persistence[1])
2154 new_min_persistence[1] = last_persistence_added_sad;
2155 }
2156 } else { // a maxima max_point_to_add added per diagram
2157 if(last_persistence_added_sad > new_min_persistence[1]) {
2158 new_min_persistence[1] = last_persistence_added_sad;
2159 }
2160 }
2161 }
2162 }
2163 }
2164 if(do_max_) {
2165 for(int i = 0; i < numberOfInputs_; i++) {
2166 std::vector<double> persistences;
2167 int number_of_added_pairs = current_bidder_diagrams_max_[i].size();
2168 double last_added_persistence = number_of_added_pairs
2170 .at(number_of_added_pairs - 1)
2171 .getPersistence()
2172 : previous_min_persistence[2];
2173 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); j++) {
2174 const auto &b = bidder_diagrams_max_[i].at(j);
2175 const auto persistence = b.getPersistence();
2176
2177 if(persistence >= min_persistence[2]
2178 && persistence < last_added_persistence) {
2179 candidates_to_be_added_max[i].emplace_back(j);
2180 idx_max[i].emplace_back(idx_max[i].size());
2181 persistences.emplace_back(persistence);
2182 }
2183 }
2184 std::sort(
2185 idx_max[i].begin(), idx_max[i].end(), [&persistences](int &a, int &b) {
2186 return ((persistences[a] > persistences[b])
2187 || ((persistences[a] == persistences[b]) && (a > b)));
2188 });
2189 int size = candidates_to_be_added_max[i].size();
2190 if(size > 0) {
2191 double last_persistence_added_max
2192 = persistences[idx_max[i][std::min(size, max_points_to_add_max) - 1]];
2193 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2194 // added per diagram
2195 if(i == 0) {
2196 new_min_persistence[2] = last_persistence_added_max;
2197 } else {
2198 if(last_persistence_added_max > new_min_persistence[2])
2199 new_min_persistence[2] = last_persistence_added_max;
2200 }
2201 } else { // a maxima max_point_to_add added per diagram
2202 if(last_persistence_added_max > new_min_persistence[2]) {
2203 new_min_persistence[2] = last_persistence_added_max;
2204 }
2205 }
2206 }
2207 }
2208 }
2209
2210 // 3. Add the points to the current diagrams
2211 if(do_min_) {
2212 int counter_for_adding_points = 0;
2213 for(int i = 0; i < numberOfInputs_; i++) {
2214 int const size = candidates_to_be_added_min[i].size();
2215 for(int j = 0; j < std::min(max_points_to_add_min, size); j++) {
2216 Bidder b = bidder_diagrams_min_[i].at(
2217 candidates_to_be_added_min[i][idx_min[i][j]]);
2218 double persistence = b.getPersistence();
2219 if(persistence >= new_min_persistence[0] or first_enrichment) {
2220 b.id_ = current_bidder_diagrams_min_[i].size();
2222 b.setDiagonalPrice(initial_diagonal_prices[0][i]);
2223 current_bidder_diagrams_min_[i].emplace_back(b);
2225 [candidates_to_be_added_min[i][idx_min[i][j]]]
2226 = current_bidder_diagrams_min_[i].size() - 1;
2227
2228 if(use_accelerated_ && n_iterations_ > 0) {
2229 for(int c = 0; c < k_; ++c) {
2230 // Step 5 of Accelerated KMeans: Update the lower bound on
2231 // distance thanks to the triangular inequality
2232 l_[i][c]
2234 - persistence / sqrt(2),
2235 wasserstein_);
2236 if(l_[i][c] < 0) {
2237 l_[i][c] = 0;
2238 }
2239 }
2240 // Step 6, update the upper bound on the distance to the centroid
2241 // thanks to the triangle inequality
2242 u_[i] = Geometry::pow(
2243 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2244 wasserstein_);
2245 r_[i] = true;
2246 }
2247 int const to_be_added_to_barycenter
2248 = deterministic_ ? counter_for_adding_points % numberOfInputs_
2249 : rand() % numberOfInputs_;
2250 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2251 for(int k = 0; k < numberOfInputs_; k++) {
2252 if(inv_clustering_[i] == inv_clustering_[k]) {
2253 Good g = Good(
2254 b.x_, b.y_, false, centroids_with_price_min_[k].size());
2255 g.setPrice(initial_off_diagonal_prices[0][k]);
2257 b.coords_[0], b.coords_[1], b.coords_[2]);
2258 centroids_with_price_min_[k].emplace_back(g);
2259 }
2260 }
2261 Good g = Good(
2262 b.x_, b.y_, false, centroids_min_[inv_clustering_[i]].size());
2263 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2264 centroids_min_[inv_clustering_[i]].emplace_back(g);
2265 }
2266 }
2267 counter_for_adding_points++;
2268 }
2269 }
2270 }
2271 if(do_sad_) {
2272 int counter_for_adding_points = 0;
2273 for(int i = 0; i < numberOfInputs_; i++) {
2274 int const size = candidates_to_be_added_sad[i].size();
2275 for(int j = 0; j < std::min(max_points_to_add_sad, size); j++) {
2277 candidates_to_be_added_sad[i][idx_sad[i][j]]);
2278 double persistence = b.getPersistence();
2279 if(persistence >= new_min_persistence[1] or first_enrichment) {
2282 b.setDiagonalPrice(initial_diagonal_prices[1][i]);
2283 current_bidder_diagrams_saddle_[i].emplace_back(b);
2285 [candidates_to_be_added_sad[i][idx_sad[i][j]]]
2286 = current_bidder_diagrams_saddle_[i].size() - 1;
2287
2288 if(use_accelerated_ && n_iterations_ > 0) {
2289 for(int c = 0; c < k_; ++c) {
2290 // Step 5 of Accelerated KMeans: Update the lower bound on
2291 // distance thanks to the triangular inequality
2292 l_[i][c]
2294 - persistence / sqrt(2),
2295 wasserstein_);
2296 if(l_[i][c] < 0) {
2297 l_[i][c] = 0;
2298 }
2299 }
2300 // Step 6, update the upper bound on the distance to the centroid
2301 // thanks to the triangle inequality
2302 u_[i] = Geometry::pow(
2303 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2304 wasserstein_);
2305 r_[i] = true;
2306 }
2307 int const to_be_added_to_barycenter
2308 = deterministic_ ? counter_for_adding_points % numberOfInputs_
2309 : rand() % numberOfInputs_;
2310 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2311 for(int k = 0; k < numberOfInputs_; k++) {
2312 if(inv_clustering_[i] == inv_clustering_[k]) {
2313 Good g = Good(
2314 b.x_, b.y_, false, centroids_with_price_saddle_[k].size());
2315 g.setPrice(initial_off_diagonal_prices[1][k]);
2317 b.coords_[0], b.coords_[1], b.coords_[2]);
2318 centroids_with_price_saddle_[k].emplace_back(g);
2319 }
2320 }
2321 }
2322 }
2323 counter_for_adding_points++;
2324 }
2325 }
2326 }
2327 if(do_max_) {
2328 int counter_for_adding_points = 0;
2329 for(int i = 0; i < numberOfInputs_; i++) {
2330 int const size = candidates_to_be_added_max[i].size();
2331 for(int j = 0; j < std::min(max_points_to_add_max, size); j++) {
2332 Bidder b = bidder_diagrams_max_[i].at(
2333 candidates_to_be_added_max[i][idx_max[i][j]]);
2334 double persistence = b.getPersistence();
2335 if(persistence >= new_min_persistence[2] or first_enrichment) {
2336 b.id_ = current_bidder_diagrams_max_[i].size();
2338 b.setDiagonalPrice(initial_diagonal_prices[2][i]);
2339 current_bidder_diagrams_max_[i].emplace_back(b);
2341 [candidates_to_be_added_max[i][idx_max[i][j]]]
2342 = current_bidder_diagrams_max_[i].size() - 1;
2343
2344 if(use_accelerated_ && n_iterations_ > 0) {
2345 for(int c = 0; c < k_; ++c) {
2346 // Step 5 of Accelerated KMeans: Update the lower bound on
2347 // distance thanks to the triangular inequality
2348 l_[i][c]
2350 - persistence / sqrt(2),
2351 wasserstein_);
2352 if(l_[i][c] < 0) {
2353 l_[i][c] = 0;
2354 }
2355 }
2356 // Step 6, update the upper bound on the distance to the centroid
2357 // thanks to the triangle inequality
2358 u_[i] = Geometry::pow(
2359 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2360 wasserstein_);
2361 r_[i] = true;
2362 }
2363 int const to_be_added_to_barycenter
2364 = deterministic_ ? counter_for_adding_points % numberOfInputs_
2365 : rand() % numberOfInputs_;
2366 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2367 for(int k = 0; k < numberOfInputs_; k++) {
2368 if(inv_clustering_[i] == inv_clustering_[k]) {
2369 Good g = Good(
2370 b.x_, b.y_, false, centroids_with_price_max_[k].size());
2371 g.setPrice(initial_off_diagonal_prices[2][k]);
2373 b.coords_[0], b.coords_[1], b.coords_[2]);
2374 centroids_with_price_max_[k].emplace_back(g);
2375 }
2376 }
2377 Good g = Good(
2378 b.x_, b.y_, false, centroids_max_[inv_clustering_[i]].size());
2379 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2380 centroids_max_[inv_clustering_[i]].emplace_back(g);
2381 }
2382 }
2383 counter_for_adding_points++;
2384 }
2385 }
2386 }
2387
2388 return new_min_persistence;
2389}
2390
2392 std::vector<double> & /*min_persistence*/) {
2393
2394 if(do_min_) {
2396 for(int c = 0; c < k_; c++) {
2397 std::vector<BidderDiagram> diagrams_c;
2398 for(int const idx : clustering_[c]) {
2399 diagrams_c.emplace_back(current_bidder_diagrams_min_[idx]);
2400 }
2402 barycenter_computer_min_[c].setThreadNumber(threadNumber_);
2403 barycenter_computer_min_[c].setWasserstein(wasserstein_);
2404 barycenter_computer_min_[c].setDiagramType(0);
2405 barycenter_computer_min_[c].setUseProgressive(false);
2406 barycenter_computer_min_[c].setDeterministic(true);
2407 barycenter_computer_min_[c].setGeometricalFactor(geometrical_factor_);
2408 barycenter_computer_min_[c].setDebugLevel(debugLevel_);
2409 if(useCustomWeights_) {
2410 if(customWeights_ != nullptr
2411 and customWeights_->size() == diagrams_c.size()) {
2412 barycenter_computer_min_[c].setUseCustomWeights(useCustomWeights_);
2413 barycenter_computer_min_[c].setCustomWeights(customWeights_);
2414 } else {
2415 printErr("Weights incorrectly initialized, returning to balanced "
2416 "barycenter");
2417 }
2418 }
2419 barycenter_computer_min_[c].setNumberOfInputs(diagrams_c.size());
2420 barycenter_computer_min_[c].setCurrentBidders(diagrams_c);
2421 barycenter_computer_min_[c].setNonMatchingWeight(nonMatchingWeight_);
2422 }
2423 }
2424 if(do_sad_) {
2426 for(int c = 0; c < k_; c++) {
2427 std::vector<BidderDiagram> diagrams_c;
2428 for(int const idx : clustering_[c]) {
2429 diagrams_c.emplace_back(current_bidder_diagrams_saddle_[idx]);
2430 }
2432 barycenter_computer_sad_[c].setThreadNumber(threadNumber_);
2433 barycenter_computer_sad_[c].setWasserstein(wasserstein_);
2434 barycenter_computer_sad_[c].setDiagramType(1);
2435 barycenter_computer_sad_[c].setUseProgressive(false);
2436 barycenter_computer_sad_[c].setDeterministic(true);
2437 barycenter_computer_sad_[c].setGeometricalFactor(geometrical_factor_);
2438 barycenter_computer_sad_[c].setDebugLevel(debugLevel_);
2439 barycenter_computer_sad_[c].setNumberOfInputs(diagrams_c.size());
2440 barycenter_computer_sad_[c].setCurrentBidders(diagrams_c);
2441 if(useCustomWeights_) {
2442 if(customWeights_ != nullptr
2443 and customWeights_->size() == diagrams_c.size()) {
2444 barycenter_computer_sad_[c].setUseCustomWeights(useCustomWeights_);
2445 barycenter_computer_sad_[c].setCustomWeights(customWeights_);
2446 } else {
2447 printErr("Weights incorrectly initialized, returning to balanced "
2448 "barycenter");
2449 }
2450 }
2451
2452 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
2453 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
2454 i_diagram++) {
2455 barycenter_goods[i_diagram]
2457 }
2458 barycenter_computer_sad_[c].setCurrentBarycenter(barycenter_goods);
2459 }
2460 }
2461 if(do_max_) {
2463 for(int c = 0; c < k_; c++) {
2464 std::vector<BidderDiagram> diagrams_c;
2465 for(int const idx : clustering_[c]) {
2466 diagrams_c.emplace_back(current_bidder_diagrams_max_[idx]);
2467 }
2470 barycenter_computer_max_[c].setThreadNumber(threadNumber_);
2471 barycenter_computer_max_[c].setWasserstein(wasserstein_);
2472 barycenter_computer_max_[c].setDiagramType(2);
2473 barycenter_computer_max_[c].setUseProgressive(false);
2474 barycenter_computer_max_[c].setDeterministic(true);
2475 barycenter_computer_max_[c].setGeometricalFactor(geometrical_factor_);
2476 barycenter_computer_max_[c].setDebugLevel(debugLevel_);
2477 barycenter_computer_max_[c].setNumberOfInputs(diagrams_c.size());
2478 barycenter_computer_max_[c].setCurrentBidders(diagrams_c);
2479 if(useCustomWeights_) {
2480 if(customWeights_ != nullptr
2481 and customWeights_->size() == diagrams_c.size()) {
2482 barycenter_computer_max_[c].setUseCustomWeights(useCustomWeights_);
2483 barycenter_computer_max_[c].setCustomWeights(customWeights_);
2484 } else {
2485 printErr("Weights incorrectly initialized, returning to balanced "
2486 "barycenter");
2487 }
2488 }
2489
2490 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
2491 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
2492 i_diagram++) {
2493 barycenter_goods[i_diagram]
2494 = centroids_with_price_max_[clustering_[c][i_diagram]];
2495 }
2496 barycenter_computer_max_[c].setCurrentBarycenter(barycenter_goods);
2497 }
2498 }
2499}
2500
2502 std::ofstream ufile("u_vec.txt");
2503 std::ofstream lfile("l_mat.txt");
2504 std::ofstream approx_file("a_mat.txt");
2505 if(ufile.is_open() && lfile.is_open()) {
2506 for(int i = 0; i < numberOfInputs_; i++) {
2507 ufile << u_[i] << " ";
2508 for(int j = 0; j < k_; j++) {
2509 lfile << l_[i][j] << " ";
2510 }
2511 lfile << "\n";
2512 }
2513 }
2514
2515 for(int c = 0; c < k_; c++) {
2516 for(int const i : clustering_[c]) {
2517 approx_file << (u_[i] + l_[i][c]) / 2 << " ";
2518 }
2519 approx_file << "\n";
2520 }
2521 lfile.close();
2522 ufile.close();
2523 approx_file.close();
2524}
2525
2527 std::cout << "Computing real distances to every clusters" << std::endl;
2528 std::ofstream file("a_real_mat.txt");
2529 if(file.is_open()) {
2530 for(int c = 0; c < k_; c++) {
2531 for(int const i : clustering_[c]) {
2532 file << distanceToCentroid_[i] << " ";
2533 }
2534 file << "\n";
2535 }
2536 file.close();
2537 } else {
2538 std::cout << "file not open" << std::endl;
2539 }
2540}
2541
2543 std::ofstream file(
2544 "prices_evolution.txt", std::ofstream::out | std::ofstream::app);
2545 if(file.is_open()) {
2546 file << "\nITERATION " << iteration << "\n" << std::endl;
2547 for(int i = 0; i < k_; i++) {
2548 file << "\ncentroid " << i << std::endl;
2549
2550 for(size_t j = 0; j < centroids_with_price_max_[i].size(); j++) {
2551 Good const g = centroids_with_price_max_[i].at(j);
2552 file << g.getPrice() << " ";
2553 }
2554 }
2555 }
2556 file.close();
2557}
2558
2560 double total_real_cost_min = 0;
2561 double total_real_cost_max = 0;
2562 double total_real_cost_sad = 0;
2563 double sq_distance;
2564 if(original_dos[0]) {
2565 for(int c = 0; c < k_; c++) {
2566 double real_cost_cluster = 0;
2567 for(int i = 0; i < numberOfInputs_; i++) {
2568 GoodDiagram const current_barycenter
2570 sq_distance
2571 = computeDistance(bidder_diagrams_min_[i], current_barycenter, 0.01);
2572 real_cost_cluster += sq_distance;
2573 }
2574 total_real_cost_min += real_cost_cluster;
2575 }
2576 }
2577 if(original_dos[1]) {
2578 for(int c = 0; c < k_; c++) {
2579 double real_cost_cluster = 0;
2580 for(int i = 0; i < numberOfInputs_; i++) {
2581 GoodDiagram const current_barycenter
2583 sq_distance = computeDistance(
2584 bidder_diagrams_saddle_[i], current_barycenter, 0.01);
2585 real_cost_cluster += sq_distance;
2586 }
2587 total_real_cost_sad += real_cost_cluster;
2588 }
2589 }
2590 if(original_dos[2]) {
2591 for(int c = 0; c < k_; c++) {
2592 double real_cost_cluster = 0;
2593 for(int i = 0; i < numberOfInputs_; i++) {
2594 GoodDiagram const current_barycenter
2596 sq_distance
2597 = computeDistance(bidder_diagrams_max_[i], current_barycenter, 0.01);
2598 real_cost_cluster += sq_distance;
2599 }
2600 total_real_cost_max += real_cost_cluster;
2601 }
2602 }
2603 return total_real_cost_min + total_real_cost_sad + total_real_cost_max;
2604}
2605
2607 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
2608 &all_matchings_per_type_and_cluster) {
2609
2610 if(do_min_) {
2612 all_matchings_per_type_and_cluster[0][0], current_bidder_ids_min_,
2614 }
2615 if(do_sad_) {
2616 computeBarycenterForTwo(all_matchings_per_type_and_cluster[0][1],
2620 }
2621 if(do_max_) {
2623 all_matchings_per_type_and_cluster[0][2], current_bidder_ids_max_,
2625 }
2626}
2627
2629 std::vector<std::vector<MatchingType>> &matchings,
2630 std::vector<std::vector<int>> &bidders_ids,
2631 std::vector<BidderDiagram> &current_bidder_diagrams,
2632 std::vector<BidderDiagram> &bidder_diagrams,
2633 GoodDiagram &barycenter) {
2634
2635 auto &matchings0 = matchings[0];
2636 auto &diagram0 = bidder_diagrams[0];
2637 auto &current_diagram0 = current_bidder_diagrams[0];
2638 auto &ids0 = bidders_ids[0];
2639
2640 auto &matchings1 = matchings[1];
2641 auto &diagram1 = bidder_diagrams[1];
2642 auto &current_diagram1 = current_bidder_diagrams[1];
2643 auto &ids1 = bidders_ids[1];
2644
2645 std::vector<int> new_to_old_id(current_diagram1.size());
2646 // 1. Invert the current_bidder_ids_ vector
2647 for(size_t j = 0; j < ids1.size(); j++) {
2648 int const new_id = ids1[j];
2649 if(new_id >= 0) {
2650 new_to_old_id[new_id] = j;
2651 }
2652 }
2653
2654 std::vector<MatchingType> matching_to_add(0);
2655 std::vector<MatchingType> matching_to_add2(0);
2656
2657 for(size_t i = 0; i < matchings1.size(); i++) {
2658 MatchingType &t = matchings1[i];
2659 int const bidderId = std::get<0>(t);
2660 int const goodId = std::get<1>(t);
2661
2662 if(bidderId >= 0) {
2663 Bidder const b = diagram1.at(new_to_old_id[bidderId]);
2664 double const bx = b.x_;
2665 double const by = b.y_;
2666 if(goodId >= 0) {
2667 Good const g = barycenter.at(goodId);
2668 double const gx = g.x_;
2669 double const gy = g.y_;
2670 barycenter.at(goodId).x_ = (bx + gx) / 2;
2671 barycenter.at(goodId).y_ = (by + gy) / 2;
2672 // divide by 4 in order to display the cost of the half matching
2673 // i.e. the cost of matching to the barycenter
2674 std::get<2>(t) /= 4;
2675
2676 } else {
2677 double gx = (bx + by) / 2;
2678 double gy = (bx + by) / 2;
2679 gx = (gx + bx) / 2;
2680 gy = (gy + by) / 2;
2681 double const cost = nonMatchingWeight_
2682 * (Geometry::pow((gx - bx), wasserstein_)
2683 + Geometry::pow((gy - by), wasserstein_));
2684 MatchingType const t2
2685 = std::make_tuple(bidderId, barycenter.size(), cost);
2686 MatchingType const t3 = std::make_tuple(-1, barycenter.size(), cost);
2687 Good const g = Good(gx, gy, false, barycenter.size());
2688 // g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2689 barycenter.emplace_back(g);
2690 matching_to_add.emplace_back(t2);
2691 matching_to_add2.emplace_back(t3);
2692 }
2693 } else {
2694 if(goodId >= 0) {
2695 Good const g = barycenter.at(goodId);
2696 double const gx = (g.x_ + g.y_) / 2;
2697 double const gy = (g.x_ + g.y_) / 2;
2698 barycenter.at(goodId).x_ = (gx + g.x_) / 2;
2699 barycenter.at(goodId).y_ = (gy + g.y_) / 2;
2700 std::get<2>(t) /= 4;
2701 }
2702 }
2703 }
2704 for(size_t j = 0; j < matching_to_add.size(); j++) {
2705 matchings1.emplace_back(matching_to_add[j]);
2706 }
2707 for(size_t j = 0; j < matching_to_add2.size(); j++) {
2708 matchings0.emplace_back(matching_to_add2[j]);
2709 }
2710
2711 // correct the costs of matchings in diagram 0
2712 // costs are initially allzeros because the barycenter is identical
2713 // to diagram 0
2714 std::vector<int> new_to_old_id2(current_diagram0.size());
2715 // 1. Invert the current_bidder_ids_ vector
2716 for(size_t j = 0; j < ids0.size(); j++) {
2717 int const new_id = ids0[j];
2718 if(new_id >= 0) {
2719 new_to_old_id2[new_id] = j;
2720 }
2721 }
2722
2723 for(size_t i = 0; i < matchings0.size(); i++) {
2724 MatchingType &t = matchings0[i];
2725 int const bidderId = std::get<0>(t);
2726 int const goodId = std::get<1>(t);
2727
2728 if(bidderId >= 0 and goodId >= 0) {
2729 Bidder const b = diagram0.at(new_to_old_id2[bidderId]);
2730 double const bx = b.x_;
2731 double const by = b.y_;
2732 Good const g = barycenter.at(goodId);
2733 double const gx = g.x_;
2734 double const gy = g.y_;
2735 double const cost = Geometry::pow((gx - bx), wasserstein_)
2736 + Geometry::pow((gy - by), wasserstein_);
2737 std::get<2>(t) = cost;
2738 }
2739 }
2740}
void setDiagonalPrice(const double price)
void setPositionInAuction(const int pos)
int debugLevel_
Definition Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void setPrice(const double price)
std::pair< typename KDT::KDTreeRoot, typename KDT::KDTreeMap > KDTreePair
std::vector< std::vector< int > > old_clustering_
void initializeAcceleratedKMeans()
std::vector< double > enrichCurrentBidderDiagrams(std::vector< double > &previous_min_persistence, std::vector< double > &min_persistence, std::vector< std::vector< double > > &initial_diagonal_prices, std::vector< std::vector< double > > &initial_off_diagonal_prices, std::vector< int > &min_points_to_add, bool add_points_to_barycenter, bool first_enrichment)
std::vector< int > inv_clustering_
std::vector< double > u_
std::vector< bool > r_
double getLessPersistent(int type=-1)
std::vector< DiagramType > * inputDiagramsMax_
void computeBarycenterForTwo(std::vector< std::vector< MatchingType > > &matchings, std::vector< std::vector< int > > &bidders_ids, std::vector< BidderDiagram > &current_bidder_diagrams, std::vector< BidderDiagram > &bidder_diagrams, GoodDiagram &barycenter)
std::vector< std::vector< double > > centroidsDistanceMatrix_
std::vector< std::vector< double > > l_
std::vector< BidderDiagram > current_bidder_diagrams_saddle_
std::vector< PDBarycenter > barycenter_computer_min_
BidderDiagram centroidToDiagram(const GoodDiagram &centroid)
void initializeCentroidsKMeanspp()
double computeDistance(const BidderDiagram &D1, const BidderDiagram &D2, const double delta_lim)
std::vector< BidderDiagram > current_bidder_diagrams_min_
std::vector< BidderDiagram > bidder_diagrams_saddle_
std::vector< BidderDiagram > current_bidder_diagrams_max_
std::vector< PDBarycenter > barycenter_computer_max_
bool barycenter_inputs_reset_flag
std::vector< double > updateCentroidsPosition(std::vector< std::vector< double > > *min_price, std::vector< std::vector< double > > *min_diag_price, std::vector< std::vector< std::vector< std::vector< MatchingType > > > > &all_matchings, int only_matchings)
std::vector< GoodDiagram > centroids_with_price_min_
void printPricesToFile(int)
BidderDiagram diagramWithZeroPrices(const BidderDiagram &diagram)
double getMostPersistent(int type=-1)
std::vector< std::vector< int > > clustering_
std::vector< GoodDiagram > centroids_min_
GoodDiagram diagramToCentroid(const BidderDiagram &diagram)
std::vector< double > distanceToCentroid_
std::vector< PDBarycenter > barycenter_computer_sad_
std::vector< std::vector< int > > current_bidder_ids_sad_
std::array< double, 3 > epsilon_
std::vector< BidderDiagram > bidder_diagrams_min_
std::vector< BidderDiagram > bidder_diagrams_max_
std::vector< GoodDiagram > centroids_saddle_
std::vector< std::vector< double > > getMinDiagonalPrices()
void computeBarycenterForTwoGlobal(std::vector< std::vector< std::vector< std::vector< MatchingType > > > > &)
std::vector< std::vector< int > > centroids_sizes_
std::vector< std::vector< double > > getMinPrices()
void printMatchings(std::vector< std::vector< std::vector< MatchingType > > >)
std::vector< std::vector< double > > getDistanceMatrix()
void initializeBarycenterComputers(std::vector< double > &min_persistence)
std::vector< std::vector< int > > current_bidder_ids_min_
GoodDiagram centroidWithZeroPrices(const GoodDiagram &centroid)
std::vector< GoodDiagram > centroids_with_price_max_
std::vector< std::vector< int > > current_bidder_ids_max_
void resetDosToOriginalValues()
std::vector< GoodDiagram > centroids_max_
std::vector< double > * customWeights_
std::vector< int > execute(std::vector< DiagramType > &final_centroids, std::vector< std::vector< std::vector< std::vector< MatchingType > > > > &all_matchings)
std::array< bool, 3 > original_dos
std::vector< std::vector< int > > get_centroids_sizes()
void correctMatchings(std::vector< std::vector< std::vector< std::vector< MatchingType > > > > &previous_matchings)
std::vector< GoodDiagram > centroids_with_price_saddle_
void SetCriticalCoordinates(const float coords_x, const float coords_y, const float coords_z)
std::array< float, 3 > GetCriticalCoordinates() const
double run(std::vector< MatchingType > &matchings, const int kdt_index=0)
void BuildAuctionDiagrams(const BidderDiagram &BD, const GoodDiagram &GD)
double getElapsedTime()
Definition Timer.h:15
T1 pow(const T1 val, const T2 n)
Definition Geometry.h:456
CriticalType
default value for critical index
Definition DataTypes.h:88
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)