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]) + " "
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_) + " "
301 + std::to_string(precision_max_),
303 this->printMsg(" cost " + std::to_string(cost_min_) + " "
307
308 if(cost_min_ < min_cost_min && n_iterations_ > 2
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
319 if(cost_sad_ < min_cost_sad && n_iterations_ > 2
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
330 if(cost_max_ < min_cost_max && n_iterations_ > 2
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",
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{
433 CriticalVertex{0, CriticalType::Local_maximum, g.y_, critCoords}, 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{
441 CriticalVertex{0, CriticalType::Local_maximum, g.y_, critCoords}, 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{
452 CriticalVertex{0, CriticalType::Saddle1, g.y_, critCoords}, 0, true});
453 if(g.getPersistence() > 1000) {
454 this->printMsg("Found a abnormally high persistence in min diagram",
456 }
457 }
458 }
459
460 if(do_sad_) {
461 for(size_t i = 0; i < centroids_saddle_[c].size(); ++i) {
462 Good const &g = centroids_saddle_[c].at(i);
463 const auto &critCoords = g.GetCriticalCoordinates();
464 final_centroids[c].emplace_back(PersistencePair{
465 CriticalVertex{0, CriticalType::Saddle1, g.x_, critCoords},
466 CriticalVertex{0, CriticalType::Saddle2, g.y_, critCoords}, 1, true});
467 if(g.getPersistence() > 1000) {
468 this->printMsg("Found a abnormally high persistence in sad diagram",
470 }
471 }
472 }
473
474 if(do_max_) {
475 for(size_t i = addedFirstPairMax; i < centroids_max_[c].size(); ++i) {
476 Good const &g = centroids_max_[c].at(i);
477 const auto &critCoords = g.GetCriticalCoordinates();
478 ttk::CriticalType saddle_type;
479 if(do_sad_)
480 saddle_type = ttk::CriticalType::Saddle2;
481 else
482 saddle_type = ttk::CriticalType::Saddle1;
483
484 final_centroids[c].emplace_back(PersistencePair{
485 CriticalVertex{0, saddle_type, g.x_, critCoords},
486 CriticalVertex{0, CriticalType::Local_maximum, g.y_, critCoords}, 2,
487 true});
488
489 if(g.getPersistence() > 1000) {
490 this->printMsg("Found a abnormally high persistence in min diagram",
492 }
493 }
494 }
495 }
496
497 if(distanceWritingOptions_ == 1) {
499 } else if(distanceWritingOptions_ == 2) {
501 }
502
503 return inv_clustering_;
504}
505
507 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
508 &previous_matchings) {
509 for(int c = 0; c < k_; c++) {
510 for(size_t i = 0; i < clustering_[c].size(); i++) {
511 int const diagram_id = clustering_[c][i];
512 if(original_dos[0]) {
513 // 1. Invert the current_bidder_ids_ vector
514 std::vector<int> new_to_old_id(
515 current_bidder_diagrams_min_[diagram_id].size(), -1);
516 for(size_t j = 0; j < current_bidder_ids_min_[diagram_id].size(); j++) {
517 int const new_id = current_bidder_ids_min_[diagram_id][j];
518 if(new_id >= 0) {
519 new_to_old_id[new_id] = j;
520 }
521 }
522 // 2. Reconstruct the matchings
523 std::vector<MatchingType> matchings_diagram_i;
524 for(size_t j = 0; j < previous_matchings[c][0][i].size(); j++) {
525 MatchingType m = previous_matchings[c][0][i][j];
526 int const new_id = std::get<0>(m);
527 if(new_id >= 0 && std::get<1>(m) >= 0) {
528 std::get<0>(m) = new_to_old_id[new_id];
529 matchings_diagram_i.emplace_back(m);
530 } else if(std::get<1>(m)
531 >= 0) { // new_id < 0 corresponds to a diagonal matching
532 std::get<0>(m) = -1;
533 matchings_diagram_i.emplace_back(m);
534 }
535 }
536 previous_matchings[c][0][i].resize(matchings_diagram_i.size());
537 previous_matchings[c][0][i] = matchings_diagram_i;
538 }
539 if(original_dos[1]) {
540 // 1. Invert the current_bidder_ids_ vector
541 std::vector<int> new_to_old_id(
542 current_bidder_diagrams_saddle_[diagram_id].size());
543 for(size_t j = 0; j < current_bidder_ids_sad_[diagram_id].size(); j++) {
544 int const new_id = current_bidder_ids_sad_[diagram_id][j];
545 if(new_id >= 0) {
546 new_to_old_id[new_id] = j;
547 }
548 }
549 // 2. Reconstruct the matchings
550 int zero_done = 0;
551 std::vector<MatchingType> matchings_diagram_i;
552 for(size_t j = 0; j < previous_matchings[c][1][i].size(); j++) {
553 MatchingType m = previous_matchings[c][1][i][j];
554 int const new_id = std::get<0>(m);
555 if(new_id >= 0 && std::get<1>(m) >= 0) {
556 int const old_id = new_to_old_id[new_id];
557 if(old_id > 0) {
558 std::get<0>(m) = old_id;
559 matchings_diagram_i.emplace_back(m);
560 } else {
561 if(!zero_done) {
562 zero_done = 1;
563 std::get<0>(m) = old_id;
564 matchings_diagram_i.emplace_back(m);
565 }
566 }
567 } else if(std::get<1>(m)
568 >= 0) { // new_id < 0 corresponds to a diagonal matching
569 std::get<0>(m) = -1;
570 matchings_diagram_i.emplace_back(m);
571 }
572 }
573 previous_matchings[c][1][i].resize(matchings_diagram_i.size());
574 previous_matchings[c][1][i] = matchings_diagram_i;
575 }
576 if(original_dos[2]) {
577 // 1. Invert the current_bidder_ids_ vector
578 std::vector<int> new_to_old_id(
579 current_bidder_diagrams_max_[diagram_id].size());
580 for(size_t j = 0; j < current_bidder_ids_max_[diagram_id].size(); j++) {
581 int const new_id = current_bidder_ids_max_[diagram_id][j];
582 if(new_id >= 0) {
583 new_to_old_id[new_id] = j;
584 }
585 }
586 // 2. Reconstruct the matchings
587 int zero_done = 0;
588 std::vector<MatchingType> matchings_diagram_i;
589 for(size_t j = 0; j < previous_matchings[c][2][i].size(); j++) {
590 MatchingType m = previous_matchings[c][2][i][j];
591 int const new_id = std::get<0>(m);
592 if(new_id >= 0 && std::get<1>(m) >= 0) {
593 int const old_id = new_to_old_id[new_id];
594 if(old_id > 0) {
595 std::get<0>(m) = old_id;
596 matchings_diagram_i.emplace_back(m);
597 } else {
598 if(!zero_done) {
599 zero_done = 1;
600 std::get<0>(m) = old_id;
601 matchings_diagram_i.emplace_back(m);
602 }
603 }
604 } else if(std::get<1>(m)
605 >= 0) { // new_id < 0 corresponds to a diagonal matching
606 std::get<0>(m) = -1;
607 matchings_diagram_i.emplace_back(m);
608 }
609 }
610 previous_matchings[c][2][i].resize(matchings_diagram_i.size());
611 previous_matchings[c][2][i] = matchings_diagram_i;
612 }
613 }
614 }
615}
616
618 std::vector<std::vector<std::vector<MatchingType>>> matchings) {
619 std::cout << "\n MATCHINGS : " << std::endl;
620 for(int d = 0; d < 3; d++) {
621 if(original_dos[d]) {
622 std::cout << "\n Diagram type : " << d << std::endl;
623 for(size_t i = 0; i < matchings[d].size(); i++) {
624 std::cout << " diagram " << i << " : ";
625 for(size_t j = 0; j < matchings[d][i].size(); j++) {
626 std::cout << std::get<0>(matchings[d][i][j]) << " ";
627 std::cout << std::get<1>(matchings[d][i][j]) << " ";
628 std::cout << std::get<2>(matchings[d][i][j]) << " | ";
629 }
630 std::cout << "\n";
631 }
632 }
633 }
634}
635
636std::vector<std::vector<int>> ttk::PDClustering::get_centroids_sizes() {
637 return centroids_sizes_;
638}
639
641 double max_persistence = 0;
642
643 if(do_min_ && (type == -1 || type == 0)) {
644 for(size_t i = 0; i < bidder_diagrams_min_.size(); ++i) {
645 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); ++j) {
646 Bidder const b = bidder_diagrams_min_[i].at(j);
647 double const persistence = b.getPersistence();
648 if(persistence > max_persistence) {
649 max_persistence = persistence;
650 }
651 }
652 }
653 }
654
655 if(do_sad_ && (type == -1 || type == 1)) {
656 for(size_t i = 0; i < bidder_diagrams_saddle_.size(); ++i) {
657 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); ++j) {
658 Bidder const b = bidder_diagrams_saddle_[i].at(j);
659 double const persistence = b.getPersistence();
660 if(persistence > max_persistence) {
661 max_persistence = persistence;
662 }
663 }
664 }
665 }
666
667 if(do_max_ && (type == -1 || type == 2)) {
668 for(size_t i = 0; i < bidder_diagrams_max_.size(); ++i) {
669 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); ++j) {
670 Bidder const b = bidder_diagrams_max_[i].at(j);
671 double const persistence = b.getPersistence();
672 if(persistence > max_persistence) {
673 max_persistence = persistence;
674 }
675 }
676 }
677 }
678 return max_persistence;
679}
680
682 // type == -1 : query the min of all the types of diagrams.
683 // type = 0 : min, 1 : sad, 2 : max
684
685 double min_persistence = std::numeric_limits<double>::max();
686 if(do_min_ && (type == -1 || type == 0)) {
687 for(size_t i = 0; i < bidder_diagrams_min_.size(); ++i) {
688 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); ++j) {
689 Bidder const b = bidder_diagrams_min_[i].at(j);
690 double const persistence = b.getPersistence();
691 if(persistence < min_persistence) {
692 min_persistence = persistence;
693 }
694 }
695 }
696 }
697
698 if(do_sad_ && (type == -1 || type == 1)) {
699 for(size_t i = 0; i < bidder_diagrams_saddle_.size(); ++i) {
700 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); ++j) {
701 Bidder const b = bidder_diagrams_saddle_[i].at(j);
702 double const persistence = b.getPersistence();
703 if(persistence < min_persistence) {
704 min_persistence = persistence;
705 }
706 }
707 }
708 }
709
710 if(do_max_ && (type == -1 || type == 2)) {
711 for(size_t i = 0; i < bidder_diagrams_max_.size(); ++i) {
712 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); ++j) {
713 Bidder const b = bidder_diagrams_max_[i].at(j);
714 double const persistence = b.getPersistence();
715 if(persistence < min_persistence) {
716 min_persistence = persistence;
717 }
718 }
719 }
720 }
721 return min_persistence;
722}
723
724std::vector<std::vector<double>> ttk::PDClustering::getMinPrices() {
725 std::vector<std::vector<double>> min_prices(3);
726
727 if(original_dos[0]) {
728 for(int i = 0; i < numberOfInputs_; ++i) {
729 min_prices[0].emplace_back(std::numeric_limits<double>::max());
730 for(size_t j = 0; j < centroids_with_price_min_[i].size(); ++j) {
731 Good const g = centroids_with_price_min_[i].at(j);
732 double const price = g.getPrice();
733 if(price < min_prices[0][i]) {
734 min_prices[0][i] = price;
735 }
736 }
737 }
738 }
739
740 if(original_dos[1]) {
741 for(int i = 0; i < numberOfInputs_; ++i) {
742 min_prices[1].emplace_back(std::numeric_limits<double>::max());
743 for(size_t j = 0; j < centroids_with_price_saddle_[i].size(); ++j) {
744 Good const g = centroids_with_price_saddle_[i].at(j);
745 double const price = g.getPrice();
746 if(price < min_prices[1][i]) {
747 min_prices[1][i] = price;
748 }
749 }
750 }
751 }
752
753 if(original_dos[2]) {
754 for(int i = 0; i < numberOfInputs_; ++i) {
755 min_prices[2].emplace_back(std::numeric_limits<double>::max());
756 for(size_t j = 0; j < centroids_with_price_max_[i].size(); ++j) {
757 Good const g = centroids_with_price_max_[i].at(j);
758 double const price = g.getPrice();
759 if(price < min_prices[2][i]) {
760 min_prices[2][i] = price;
761 }
762 }
763 }
764 }
765
766 return min_prices;
767}
768
769std::vector<std::vector<double>> ttk::PDClustering::getMinDiagonalPrices() {
770 std::vector<std::vector<double>> min_prices(3);
771 if(original_dos[0]) {
772 for(int i = 0; i < numberOfInputs_; ++i) {
773 min_prices[0].emplace_back(std::numeric_limits<double>::max());
774 for(size_t j = 0; j < current_bidder_diagrams_min_[i].size(); ++j) {
775 Bidder const b = current_bidder_diagrams_min_[i].at(j);
776 double const price = b.diagonal_price_;
777 if(price < min_prices[0][i]) {
778 min_prices[0][i] = price;
779 }
780 }
781 if(min_prices[0][i] >= std::numeric_limits<double>::max() / 2.) {
782 min_prices[0][i] = 0;
783 }
784 }
785 }
786
787 if(original_dos[1]) {
788 for(int i = 0; i < numberOfInputs_; ++i) {
789 min_prices[1].emplace_back(std::numeric_limits<double>::max());
790 for(size_t j = 0; j < current_bidder_diagrams_saddle_[i].size(); ++j) {
791 Bidder const b = current_bidder_diagrams_saddle_[i].at(j);
792 double const price = b.diagonal_price_;
793 if(price < min_prices[1][i]) {
794 min_prices[1][i] = price;
795 }
796 }
797 if(min_prices[1][i] >= std::numeric_limits<double>::max() / 2.) {
798 min_prices[1][i] = 0;
799 }
800 }
801 }
802
803 if(original_dos[2]) {
804 for(int i = 0; i < numberOfInputs_; ++i) {
805 min_prices[2].emplace_back(std::numeric_limits<double>::max());
806 for(size_t j = 0; j < current_bidder_diagrams_max_[i].size(); ++j) {
807 Bidder const b = current_bidder_diagrams_max_[i].at(j);
808 double const price = b.diagonal_price_;
809 if(price < min_prices[2][i]) {
810 min_prices[2][i] = price;
811 }
812 }
813 if(min_prices[2][i] >= std::numeric_limits<double>::max() / 2.) {
814 min_prices[2][i] = 0;
815 }
816 }
817 }
818 return min_prices;
819}
820
822 const BidderDiagram &D2,
823 const double delta_lim) {
824 GoodDiagram const D2_bis = diagramToCentroid(D2);
825 return computeDistance(D1, D2_bis, delta_lim);
826}
827
829 const GoodDiagram &D2,
830 const double delta_lim) {
831 std::vector<MatchingType> matchings;
832 const auto D2_bis = centroidWithZeroPrices(D2);
833 PersistenceDiagramAuction auction(wasserstein_, geometrical_factor_, lambda_,
834 delta_lim, use_kdtree_, nonMatchingWeight_);
835 auction.BuildAuctionDiagrams(D1, D2_bis);
836 double const cost = auction.run(matchings);
837 return cost;
838}
839
841 const GoodDiagram *const D2,
842 const double delta_lim) {
843 std::vector<MatchingType> matchings;
844 PersistenceDiagramAuction auction(wasserstein_, geometrical_factor_, lambda_,
845 delta_lim, use_kdtree_, nonMatchingWeight_);
846 int const size1 = D1->size();
847 auction.BuildAuctionDiagrams(*D1, *D2);
848 double const cost = auction.run(matchings);
849 // Diagonal Points were added in the original diagram. The following line
850 // removes them.
851 D1->resize(size1);
852 return cost;
853}
854
856 const GoodDiagram &D2,
857 const double delta_lim) {
858 BidderDiagram const D1_bis = centroidToDiagram(D1);
859 return computeDistance(D1_bis, D2, delta_lim);
860}
861
865 for(size_t i = 0; i < centroid.size(); i++) {
866 Good g = centroid.at(i);
867 g.setPrice(0);
868 GD.emplace_back(g);
869 }
870 return GD;
871}
872
876 for(size_t i = 0; i < diagram.size(); i++) {
877 Bidder b = diagram.at(i);
878 b.setDiagonalPrice(0);
879 BD.emplace_back(b);
880 }
881 return BD;
882}
883
887 for(size_t i = 0; i < centroid.size(); i++) {
888 Good g = centroid.at(i);
889
890 Bidder b = Bidder(g.x_, g.y_, g.isDiagonal(), BD.size());
891 b.SetCriticalCoordinates(g.coords_[0], g.coords_[1], g.coords_[2]);
892 b.setPositionInAuction(BD.size());
893 BD.emplace_back(b);
894 }
895 return BD;
896}
897
901 for(size_t i = 0; i < diagram.size(); i++) {
902 Bidder b = diagram.at(i);
903
904 Good g = Good(b.x_, b.y_, b.isDiagonal(), GD.size());
905 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
906 GD.emplace_back(g);
907 }
908 return GD;
909}
910
912 clustering_ = std::vector<std::vector<int>>(k_);
913}
914
916 std::vector<int> idx(numberOfInputs_);
917 // To perform a random draw with replacement, the vector {1, 2, ...,
918 // numberOfInputs_} is shuffled, and we consider its k_ first elements to be
919 // the initial centroids.
920 for(int i = 0; i < numberOfInputs_; i++) {
921 idx[i] = i;
922 }
923 if(!deterministic_)
924 std::shuffle(idx.begin(), idx.end(), std::random_device());
925
926 for(int c = 0; c < k_; c++) {
927 if(do_min_) {
928 GoodDiagram const centroid_min
929 = diagramToCentroid(current_bidder_diagrams_min_[idx[c]]);
930 centroids_min_.emplace_back(centroid_min);
931 }
932 if(do_sad_) {
933 GoodDiagram const centroid_sad
934 = diagramToCentroid(current_bidder_diagrams_saddle_[idx[c]]);
935 centroids_saddle_.emplace_back(centroid_sad);
936 }
937 if(do_max_) {
938 GoodDiagram const centroid_max
939 = diagramToCentroid(current_bidder_diagrams_max_[idx[c]]);
940 centroids_max_.emplace_back(centroid_max);
941 }
942 }
943}
944
946 std::vector<int> indexes_clusters;
947 int const random_idx = deterministic_ ? 0 : rand() % numberOfInputs_;
948 indexes_clusters.emplace_back(random_idx);
949
950 if(do_min_) {
951 GoodDiagram const centroid_min
952 = diagramToCentroid(current_bidder_diagrams_min_[random_idx]);
953 centroids_min_.emplace_back(centroid_min);
954 }
955 if(do_sad_) {
956 GoodDiagram const centroid_sad
957 = diagramToCentroid(current_bidder_diagrams_saddle_[random_idx]);
958 centroids_saddle_.emplace_back(centroid_sad);
959 }
960 if(do_max_) {
961 GoodDiagram const centroid_max
962 = diagramToCentroid(current_bidder_diagrams_max_[random_idx]);
963 centroids_max_.emplace_back(centroid_max);
964 }
965
966 const auto square = [](const double a) { return a * a; };
967
968 while((int)indexes_clusters.size() < k_) {
969 std::vector<double> min_distance_to_centroid(numberOfInputs_);
970 std::vector<double> probabilities(numberOfInputs_);
971
972 // Uncomment for a deterministic algorithm
973 double maximal_distance = 0;
974 int candidate_centroid = 0;
975
976 for(int i = 0; i < numberOfInputs_; i++) {
977
978 min_distance_to_centroid[i] = std::numeric_limits<double>::max();
979 if(std::find(indexes_clusters.begin(), indexes_clusters.end(), i)
980 != indexes_clusters.end()) {
981
982 min_distance_to_centroid[i] = 0;
983 } else {
984
985 for(size_t j = 0; j < indexes_clusters.size(); ++j) {
986
987 double distance = 0;
988 if(do_min_) {
989 GoodDiagram const centroid_min
990 = centroidWithZeroPrices(centroids_min_[j]);
991 distance += computeDistance(
992 current_bidder_diagrams_min_[i], centroid_min, 0.01);
993 }
994 if(do_sad_) {
995 GoodDiagram const centroid_saddle
996 = centroidWithZeroPrices(centroids_saddle_[j]);
997 distance += computeDistance(
998 current_bidder_diagrams_saddle_[i], centroid_saddle, 0.01);
999 }
1000 if(do_max_) {
1001 GoodDiagram const centroid_max
1002 = centroidWithZeroPrices(centroids_max_[j]);
1003 distance += computeDistance(
1004 current_bidder_diagrams_max_[i], centroid_max, 0.01);
1005 }
1006 if(distance < min_distance_to_centroid[i]) {
1007 min_distance_to_centroid[i] = distance;
1008 }
1009 }
1010 }
1011 probabilities[i] = square(min_distance_to_centroid[i]);
1012
1013 // The following block is useful in case of need for a deterministic
1014 // algorithm
1015 if(deterministic_ && min_distance_to_centroid[i] > maximal_distance) {
1016 maximal_distance = min_distance_to_centroid[i];
1017 candidate_centroid = i;
1018 }
1019 }
1020 // Comment the following four lines to make it deterministic
1021 std::random_device rd;
1022 std::mt19937 gen(rd());
1023 std::discrete_distribution<int> distribution(
1024 probabilities.begin(), probabilities.end());
1025
1026 if(!deterministic_) {
1027 candidate_centroid = distribution(gen);
1028 }
1029
1030 indexes_clusters.emplace_back(candidate_centroid);
1031 if(do_min_) {
1032 GoodDiagram const centroid_min
1033 = diagramToCentroid(current_bidder_diagrams_min_[candidate_centroid]);
1034 centroids_min_.emplace_back(centroid_min);
1035 }
1036 if(do_sad_) {
1037 GoodDiagram const centroid_sad = diagramToCentroid(
1038 current_bidder_diagrams_saddle_[candidate_centroid]);
1039 centroids_saddle_.emplace_back(centroid_sad);
1040 }
1041 if(do_max_) {
1042 GoodDiagram const centroid_max
1043 = diagramToCentroid(current_bidder_diagrams_max_[candidate_centroid]);
1044 centroids_max_.emplace_back(centroid_max);
1045 }
1046 }
1047}
1048
1050 // r_ is a vector stating for each diagram if its distance to its centroid is
1051 // up to date (false) or needs to be recomputed (true)
1052 r_ = std::vector<bool>(numberOfInputs_);
1053 // u_ is a vector of upper bounds of the distance of each diagram to its
1054 // closest centroid
1055 u_ = std::vector<double>(numberOfInputs_);
1056 inv_clustering_ = std::vector<int>(numberOfInputs_);
1057 for(int i = 0; i < numberOfInputs_; i++) {
1058 r_[i] = true;
1059 u_[i] = std::numeric_limits<double>::max();
1060 inv_clustering_[i] = -1;
1061 }
1062 // l_ is the matrix of lower bounds for the distance from each diagram
1063 // to each centroid
1064 l_ = std::vector<std::vector<double>>(numberOfInputs_);
1065 for(int i = 0; i < numberOfInputs_; ++i) {
1066 l_[i] = std::vector<double>(k_);
1067 for(int c = 0; c < k_; ++c) {
1068 l_[i][c] = 0;
1069 }
1070 }
1071
1072 // And d_ is a (K x K) matrix storing the distances between each pair of
1073 // centroids
1074 centroidsDistanceMatrix_.resize(k_);
1075 for(int i = 0; i < k_; ++i) {
1076 centroidsDistanceMatrix_[i].resize(k_, 0.0);
1077 }
1078}
1079
1080std::vector<std::vector<double>> ttk::PDClustering::getDistanceMatrix() {
1081 std::vector<std::vector<double>> D(numberOfInputs_);
1082
1083 for(int i = 0; i < numberOfInputs_; ++i) {
1084 BidderDiagram D1_min, D1_sad, D1_max;
1085 if(do_min_) {
1086 D1_min = diagramWithZeroPrices(current_bidder_diagrams_min_[i]);
1087 }
1088 if(do_sad_) {
1089 D1_sad = diagramWithZeroPrices(current_bidder_diagrams_saddle_[i]);
1090 }
1091 if(do_max_) {
1092 D1_max = diagramWithZeroPrices(current_bidder_diagrams_max_[i]);
1093 }
1094 for(int c = 0; c < k_; ++c) {
1095 GoodDiagram D2_min, D2_sad, D2_max;
1096 double distance = 0;
1097 if(do_min_) {
1098 D2_min = centroids_min_[c];
1099 distance += computeDistance(D1_min, D2_min, 0.01);
1100 }
1101 if(do_sad_) {
1102 D2_sad = centroids_saddle_[c];
1103 distance += computeDistance(D1_sad, D2_sad, 0.01);
1104 }
1105 if(do_max_) {
1106 D2_max = centroids_max_[c];
1107 distance += computeDistance(D1_max, D2_max, 0.01);
1108 }
1109 D[i].emplace_back(distance);
1110 }
1111 }
1112 return D;
1113}
1114
1116 for(int i = 0; i < k_; ++i) {
1117 GoodDiagram D1_min, D1_sad, D1_max;
1118 if(do_min_) {
1119 D1_min = centroidWithZeroPrices(centroids_min_[i]);
1120 }
1121 if(do_sad_) {
1122 D1_sad = centroidWithZeroPrices(centroids_saddle_[i]);
1123 }
1124 if(do_max_) {
1125 D1_max = centroidWithZeroPrices(centroids_max_[i]);
1126 }
1127 for(int j = i + 1; j < k_; ++j) {
1128 double distance{};
1129 GoodDiagram D2_min, D2_sad, D2_max;
1130 if(do_min_) {
1131 D2_min = centroidWithZeroPrices(centroids_min_[j]);
1132 distance += computeDistance(D1_min, D2_min, 0.01);
1133 }
1134 if(do_sad_) {
1135 D2_sad = centroidWithZeroPrices(centroids_saddle_[j]);
1136 distance += computeDistance(D1_sad, D2_sad, 0.01);
1137 }
1138 if(do_max_) {
1139 D2_max = centroidWithZeroPrices(centroids_max_[j]);
1140 distance += computeDistance(D1_max, D2_max, 0.01);
1141 }
1142
1143 centroidsDistanceMatrix_[i][j] = distance;
1144 centroidsDistanceMatrix_[j][i] = distance;
1145 }
1146 }
1147}
1148
1150 distanceToCentroid_.resize(numberOfInputs_);
1151
1152 for(int i = 0; i < numberOfInputs_; ++i) {
1153 double const delta_lim{0.01};
1154 double distance{};
1155 auto c = inv_clustering_[i];
1156 if(original_dos[0]) {
1157 GoodDiagram const centroid_min
1158 = centroidWithZeroPrices(centroids_min_[c]);
1159 BidderDiagram const bidder_diag
1160 = diagramWithZeroPrices(current_bidder_diagrams_min_[i]);
1161 distance += computeDistance(bidder_diag, centroid_min, delta_lim);
1162 }
1163 if(original_dos[1]) {
1164 GoodDiagram const centroid_saddle
1165 = centroidWithZeroPrices(centroids_saddle_[c]);
1166 BidderDiagram const bidder_diag
1167 = diagramWithZeroPrices(current_bidder_diagrams_saddle_[i]);
1168 distance += computeDistance(bidder_diag, centroid_saddle, delta_lim);
1169 }
1170 if(original_dos[2]) {
1171 GoodDiagram const centroid_max
1172 = centroidWithZeroPrices(centroids_max_[c]);
1173 BidderDiagram const bidder_diag
1174 = diagramWithZeroPrices(current_bidder_diagrams_max_[i]);
1175 distance += computeDistance(bidder_diag, centroid_max, delta_lim);
1176 }
1177 distanceToCentroid_[i] = distance;
1178 }
1179}
1180
1182 if(k_ > 1) {
1183 std::vector<std::vector<double>> distance_matrix = getDistanceMatrix();
1184 old_clustering_ = clustering_;
1185 invertClusters();
1186 initializeEmptyClusters();
1187
1188 for(int i = 0; i < numberOfInputs_; ++i) {
1189 double min_distance_to_centroid = std::numeric_limits<double>::max();
1190 int cluster = -1;
1191 for(int c = 0; c < k_; ++c) {
1192 if(distance_matrix[i][c] < min_distance_to_centroid) {
1193 min_distance_to_centroid = distance_matrix[i][c];
1194 cluster = c;
1195 }
1196 }
1197
1198 clustering_[cluster].emplace_back(i);
1199 if(cluster != inv_clustering_[i]) {
1200 // New centroid attributed to this diagram
1201 resetDosToOriginalValues();
1202 barycenter_inputs_reset_flag = true;
1203 if(do_min_) {
1204 centroids_with_price_min_[i]
1205 = centroidWithZeroPrices(centroids_min_[cluster]);
1206 }
1207 if(do_sad_) {
1208 centroids_with_price_saddle_[i]
1209 = centroidWithZeroPrices(centroids_saddle_[cluster]);
1210 }
1211 if(do_max_) {
1212 centroids_with_price_max_[i]
1213 = centroidWithZeroPrices(centroids_max_[cluster]);
1214 }
1215 inv_clustering_[i] = cluster;
1216 }
1217 }
1218
1219 } else {
1220 old_clustering_ = clustering_;
1221 invertClusters();
1222 initializeEmptyClusters();
1223
1224 for(int i = 0; i < numberOfInputs_; i++) {
1225 clustering_[0].emplace_back(i);
1226 if(n_iterations_ < 1) {
1227 if(do_min_) {
1228 centroids_with_price_min_[i]
1229 = centroidWithZeroPrices(centroids_min_[0]);
1230 }
1231 if(do_sad_) {
1232 centroids_with_price_saddle_[i]
1233 = centroidWithZeroPrices(centroids_saddle_[0]);
1234 }
1235 if(do_max_) {
1236 centroids_with_price_max_[i]
1237 = centroidWithZeroPrices(centroids_max_[0]);
1238 }
1239 }
1240 inv_clustering_[i] = 0;
1241 }
1242 }
1243}
1244
1249
1250 // Initializes clusters with -1
1251 inv_clustering_ = std::vector<int>(numberOfInputs_);
1252 for(int i = 0; i < numberOfInputs_; ++i) {
1253 inv_clustering_[i] = -1;
1254 }
1255
1256 // Fill in the clusters
1257 for(int c = 0; c < k_; ++c) {
1258 for(size_t j = 0; j < clustering_[c].size(); ++j) {
1259 int const idx = clustering_[c][j];
1260 inv_clustering_[idx] = c;
1261 }
1262 }
1263}
1264
1266 clustering_ = std::vector<std::vector<int>>(k_);
1267 for(int i = 0; i < numberOfInputs_; ++i) {
1268 clustering_[inv_clustering_[i]].emplace_back(i);
1269 }
1270
1271 // Check if a cluster was left without diagram
1272 for(int c = 0; c < k_; ++c) {
1273 if(clustering_[c].empty()) {
1274 std::cout << "Problem in invertInverseClusters()... \nCluster " << c
1275 << " was left with no diagram attached to it... " << std::endl;
1276 }
1277 }
1278}
1279
1281 // Step 1
1282 getCentroidDistanceMatrix();
1283 old_clustering_ = clustering_;
1284 // self.old_clusters = copy.copy(self.clusters)
1285 invertClusters();
1286 initializeEmptyClusters();
1287 bool const do_min = original_dos[0];
1288 bool const do_sad = original_dos[1];
1289 bool const do_max = original_dos[2];
1290
1291 for(int i = 0; i < numberOfInputs_; ++i) {
1292 // Step 3 find potential changes of clusters
1293 BidderDiagram D1_min, D1_sad, D1_max;
1294 if(do_min) {
1295 D1_min = diagramWithZeroPrices(current_bidder_diagrams_min_[i]);
1296 }
1297 if(do_sad) {
1298 D1_sad = diagramWithZeroPrices(current_bidder_diagrams_saddle_[i]);
1299 }
1300 if(do_max) {
1301 D1_max = diagramWithZeroPrices(current_bidder_diagrams_max_[i]);
1302 }
1303
1304 for(int c = 0; c < k_; ++c) {
1305 if(inv_clustering_[i] == -1) {
1306 // If not yet assigned, assign it first to a random cluster
1307
1308 if(deterministic_) {
1309 inv_clustering_[i] = i % k_;
1310 } else {
1311 std::cout << " - ASSIGNED TO A RANDOM CLUSTER " << '\n';
1312 inv_clustering_[i] = rand() % (k_);
1313 }
1314
1315 r_[i] = true;
1316 if(do_min) {
1317 centroids_with_price_min_[i]
1318 = centroidWithZeroPrices(centroids_min_[inv_clustering_[i]]);
1319 }
1320 if(do_sad) {
1321 centroids_with_price_saddle_[i]
1322 = centroidWithZeroPrices(centroids_saddle_[inv_clustering_[i]]);
1323 }
1324 if(do_max) {
1325 centroids_with_price_max_[i]
1326 = centroidWithZeroPrices(centroids_max_[inv_clustering_[i]]);
1327 }
1328 }
1329
1330 if(c != inv_clustering_[i] && u_[i] > l_[i][c]
1331 && u_[i] > 0.5 * centroidsDistanceMatrix_[inv_clustering_[i]][c]) {
1332 // Step 3a, If necessary, recompute the distance to centroid
1333 if(r_[i]) {
1334 double distance = 0;
1335 GoodDiagram centroid_min, centroid_sad, centroid_max;
1336 if(do_min) {
1337 centroid_min
1338 = centroidWithZeroPrices(centroids_min_[inv_clustering_[i]]);
1339 distance += computeDistance(D1_min, centroid_min, 0.01);
1340 }
1341 if(do_sad) {
1342 centroid_sad
1343 = centroidWithZeroPrices(centroids_saddle_[inv_clustering_[i]]);
1344 distance += computeDistance(D1_sad, centroid_sad, 0.01);
1345 }
1346 if(do_max) {
1347 centroid_max
1348 = centroidWithZeroPrices(centroids_max_[inv_clustering_[i]]);
1349 distance += computeDistance(D1_max, centroid_max, 0.01);
1350 }
1351 r_[i] = false;
1352 u_[i] = distance;
1353 l_[i][inv_clustering_[i]] = distance;
1354 }
1355 // Step 3b, check if still potential change of clusters
1356 if((n_iterations_ > 2 || n_iterations_ < 1)
1357 && (u_[i] > l_[i][c]
1358 || u_[i]
1359 > 0.5 * centroidsDistanceMatrix_[inv_clustering_[i]][c])) {
1360 BidderDiagram diagram_min, diagram_sad, diagram_max;
1361 GoodDiagram centroid_min, centroid_sad, centroid_max;
1362 double distance = 0;
1363
1364 if(do_min) {
1365 centroid_min = centroidWithZeroPrices(centroids_min_[c]);
1366 diagram_min
1367 = diagramWithZeroPrices(current_bidder_diagrams_min_[i]);
1368 distance += computeDistance(diagram_min, centroid_min, 0.01);
1369 }
1370 if(do_sad) {
1371 centroid_sad = centroidWithZeroPrices(centroids_saddle_[c]);
1372 diagram_sad
1373 = diagramWithZeroPrices(current_bidder_diagrams_saddle_[i]);
1374 distance += computeDistance(diagram_sad, centroid_sad, 0.01);
1375 }
1376 if(do_max) {
1377 centroid_max = centroidWithZeroPrices(centroids_max_[c]);
1378 diagram_max
1379 = diagramWithZeroPrices(current_bidder_diagrams_max_[i]);
1380 distance += computeDistance(diagram_max, centroid_max, 0.01);
1381 }
1382 l_[i][c] = distance;
1383 // TODO Prices are lost here... If distance<self.u[i], we should keep
1384 // the prices
1385 if(distance < u_[i]) {
1386 // Changing cluster
1387 resetDosToOriginalValues();
1388 barycenter_inputs_reset_flag = true;
1389 u_[i] = distance;
1390 inv_clustering_[i] = c;
1391
1392 if(do_min) {
1393 centroids_with_price_min_[i]
1394 = centroidWithZeroPrices(centroids_min_[c]);
1395 }
1396 if(do_sad) {
1397 centroids_with_price_saddle_[i]
1398 = centroidWithZeroPrices(centroids_saddle_[c]);
1399 }
1400 if(do_max) {
1401 centroids_with_price_max_[i]
1402 = centroidWithZeroPrices(centroids_max_[c]);
1403 }
1404 }
1405 }
1406 }
1407 }
1408 }
1409 invertInverseClusters();
1410 for(int c = 0; c < k_; ++c) {
1411 if(clustering_[c].empty()) {
1412 std::cout << "Adding artificial centroid because a cluster was empty"
1413 << std::endl;
1414 bool idx_acceptable = false;
1415 int idx = 0;
1416
1417 std::vector<double> copy_of_u(u_.size());
1418 copy_of_u = u_;
1419 while(!idx_acceptable) {
1420 auto argMax = std::max_element(copy_of_u.begin(), copy_of_u.end());
1421 idx = std::distance(copy_of_u.begin(), argMax);
1422 if(inv_clustering_[idx] < k_ && inv_clustering_[idx] >= 0
1423 && clustering_[inv_clustering_[idx]].size() > 1) {
1424 idx_acceptable = true;
1425 int const cluster_removal = inv_clustering_[idx];
1426 // Removing the index to remove
1427 clustering_[cluster_removal].erase(
1428 std::remove(clustering_[cluster_removal].begin(),
1429 clustering_[cluster_removal].end(), idx),
1430 clustering_[cluster_removal].end());
1431 } else {
1432 if(copy_of_u.size() > (size_t)idx) {
1433 copy_of_u.erase(argMax);
1434 } else {
1435 idx_acceptable = true;
1436 int cluster_max = 0;
1437 if(!clustering_[cluster_max].empty()) {
1438 idx = clustering_[cluster_max][0];
1439 }
1440 for(int i_test = 1; i_test < k_; i_test++) {
1441 if(clustering_[i_test].size() > clustering_[cluster_max].size()) {
1442 cluster_max = i_test;
1443 idx = clustering_[cluster_max][0];
1444 }
1445 }
1446 int const cluster_removal = inv_clustering_[idx];
1447 clustering_[cluster_removal].erase(
1448 std::remove(clustering_[cluster_removal].begin(),
1449 clustering_[cluster_removal].end(), idx),
1450 clustering_[cluster_removal].end());
1451 }
1452 }
1453 }
1454
1455 clustering_[c].emplace_back(idx);
1456 inv_clustering_[idx] = c;
1457
1458 if(do_min) {
1459 centroids_min_[c]
1460 = diagramToCentroid(current_bidder_diagrams_min_[idx]);
1461 centroids_with_price_min_[idx]
1462 = centroidWithZeroPrices(centroids_min_[c]);
1463 }
1464 if(do_sad) {
1465 centroids_saddle_[c]
1466 = diagramToCentroid(current_bidder_diagrams_saddle_[idx]);
1467 centroids_with_price_saddle_[idx]
1468 = centroidWithZeroPrices(centroids_saddle_[c]);
1469 }
1470 if(do_max) {
1471 centroids_max_[c]
1472 = diagramToCentroid(current_bidder_diagrams_max_[idx]);
1473 centroids_with_price_max_[idx]
1474 = centroidWithZeroPrices(centroids_max_[c]);
1475 }
1476 resetDosToOriginalValues();
1477 barycenter_inputs_reset_flag = true;
1478 }
1479 }
1480}
1481
1483 std::vector<std::vector<double>> *min_price,
1484 std::vector<std::vector<double>> *min_diag_price,
1485 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
1486 &all_matchings_per_type_and_cluster,
1487 int only_matchings) {
1488 barycenter_inputs_reset_flag = true;
1489 std::vector<double> max_shift_vector(3);
1490 max_shift_vector[0] = 0;
1491 max_shift_vector[1] = 0;
1492 max_shift_vector[2] = 0;
1493 double max_shift_c_min = 0;
1494 double max_shift_c_sad = 0;
1495 double max_shift_c_max = 0;
1496 double max_wasserstein_shift = 0;
1497 bool precision_min = true;
1498 bool precision_sad = true;
1499 bool precision_max = true;
1500 cost_ = 0;
1501 double const sq_dist_min = cost_min_;
1502 double const sq_dist_sad = cost_sad_;
1503 double const sq_dist_max = cost_max_;
1504 if(do_min_) {
1505 cost_min_ = 0;
1506 }
1507 if(do_sad_) {
1508 cost_sad_ = 0;
1509 }
1510 if(do_max_) {
1511 cost_max_ = 0;
1512 }
1513
1514 for(int c = 0; c < k_; ++c) {
1515 if(!clustering_[c].empty()) {
1516 std::vector<GoodDiagram> centroids_with_price_min,
1517 centroids_with_price_sad, centroids_with_price_max;
1518 int count = 0;
1519 for(int const idx : clustering_[c]) {
1520 // Timer time_first_thing;
1521 // Find the position of diagrams[idx] in old cluster c
1522 std::vector<int>::iterator const i = std::find(
1523 old_clustering_[c].begin(), old_clustering_[c].end(), idx);
1524 int const pos = (i == old_clustering_[c].end())
1525 ? -1
1526 : std::distance(old_clustering_[c].begin(), i);
1527 if(pos >= 0) {
1528 // Diagram was already linked to this centroid before
1529 if(do_min_) {
1530 centroids_with_price_min.emplace_back(
1531 centroids_with_price_min_[idx]);
1532 }
1533 if(do_sad_) {
1534 centroids_with_price_sad.emplace_back(
1535 centroids_with_price_saddle_[idx]);
1536 }
1537 if(do_max_) {
1538 centroids_with_price_max.emplace_back(
1539 centroids_with_price_max_[idx]);
1540 }
1541 } else {
1542 int number_of_points_min = 0;
1543 int number_of_points_max = 0;
1544 int number_of_points_sad = 0;
1545
1546 // Otherwise, centroid is given 0 prices and the diagram is given 0
1547 // diagonal-prices
1548 if(do_min_) {
1549 centroids_with_price_min.emplace_back(
1550 centroidWithZeroPrices(centroids_min_[c]));
1551 current_bidder_diagrams_min_[idx]
1552 = diagramWithZeroPrices(current_bidder_diagrams_min_[idx]);
1553 number_of_points_min += centroids_with_price_min_[idx].size()
1554 + current_bidder_diagrams_min_[idx].size();
1555 }
1556 if(do_sad_) {
1557 centroids_with_price_sad.emplace_back(
1558 centroidWithZeroPrices(centroids_saddle_[c]));
1559 current_bidder_diagrams_saddle_[idx]
1560 = diagramWithZeroPrices(current_bidder_diagrams_saddle_[idx]);
1561 number_of_points_sad
1562 += centroids_with_price_saddle_[idx].size()
1563 + current_bidder_diagrams_saddle_[idx].size();
1564 }
1565 if(do_max_) {
1566 centroids_with_price_max.emplace_back(
1567 centroidWithZeroPrices(centroids_max_[c]));
1568 current_bidder_diagrams_max_[idx]
1569 = diagramWithZeroPrices(current_bidder_diagrams_max_[idx]);
1570 number_of_points_max += centroids_with_price_max_[idx].size()
1571 + current_bidder_diagrams_max_[idx].size();
1572 }
1573
1574 if(n_iterations_ > 1) {
1575 // If diagram new to cluster and we're not at first iteration,
1576 // precompute prices for the objects via compute_distance()
1577 // number_of_points /= (int)do_min_ + (int)do_sad_ + (int)do_max_;
1578 // double d_estimated = pow(cost_ / numberOfInputs_, 1. /
1579 // wasserstein_) + 1e-7; We use pointer in the auction in order to
1580 // keep the prices at the end
1581
1582 if(do_min_) {
1583 // double estimated_delta_lim = number_of_points_min *
1584 // epsilon_[0] / (2*sq_dist_min) ;
1585 double estimated_delta_lim
1586 = 1.
1587 / sqrt(1 - number_of_points_min * epsilon_[0] / sq_dist_min)
1588 - 1;
1589 if(estimated_delta_lim > 1) {
1590 estimated_delta_lim = 1;
1591 }
1592 computeDistance(&(current_bidder_diagrams_min_[idx]),
1593 &(centroids_with_price_min[count]),
1594 estimated_delta_lim);
1595 }
1596 if(do_sad_) {
1597 // double estimated_delta_lim = number_of_points_sad *
1598 // epsilon_[1] / (2*sq_dist_sad);
1599 double estimated_delta_lim
1600 = 1.
1601 / sqrt(1 - number_of_points_sad * epsilon_[1] / sq_dist_sad)
1602 - 1;
1603 if(estimated_delta_lim > 1) {
1604 estimated_delta_lim = 1;
1605 }
1606 computeDistance(&(current_bidder_diagrams_saddle_[idx]),
1607 &(centroids_with_price_sad[count]),
1608 estimated_delta_lim);
1609 }
1610 if(do_max_) {
1611 // double estimated_delta_lim = number_of_points_max *
1612 // epsilon_[2] / (2*sq_dist_max);
1613 double estimated_delta_lim
1614 = 1.
1615 / sqrt(1 - number_of_points_max * epsilon_[2] / sq_dist_max)
1616 - 1;
1617 if(estimated_delta_lim > 1) {
1618 estimated_delta_lim = 1;
1619 }
1620 computeDistance(&(current_bidder_diagrams_max_[idx]),
1621 &(centroids_with_price_max[count]),
1622 estimated_delta_lim);
1623 }
1624 }
1625 }
1626 count++;
1627 }
1628 double total_cost = 0;
1629 double wasserstein_shift = 0;
1630
1631 using KDTreePair = PDBarycenter::KDTreePair;
1632
1633 if(do_min_) {
1634 std::vector<std::vector<MatchingType>> all_matchings;
1635 std::vector<int> sizes;
1636 Timer const time_preprocess_bary;
1637 std::vector<BidderDiagram> diagrams_c_min;
1638 if(barycenter_inputs_reset_flag) {
1639 for(int const idx : clustering_[c]) {
1640 diagrams_c_min.emplace_back(current_bidder_diagrams_min_[idx]);
1641 }
1642 sizes.resize(diagrams_c_min.size());
1643 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1644 sizes[i] = diagrams_c_min[i].size();
1645 }
1646 barycenter_computer_min_[c].setNumberOfInputs(diagrams_c_min.size());
1647 barycenter_computer_min_[c].setCurrentBidders(diagrams_c_min);
1648
1649 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1650 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1651 i_diagram++) {
1652 barycenter_goods[i_diagram]
1653 = centroids_with_price_min_[clustering_[c][i_diagram]];
1654 }
1655 barycenter_computer_min_[c].setCurrentBarycenter(barycenter_goods);
1656 all_matchings.resize(diagrams_c_min.size());
1657 } else {
1658 sizes.resize(barycenter_computer_min_[c].getCurrentBidders().size());
1659 for(size_t i = 0;
1660 i < barycenter_computer_min_[c].getCurrentBidders().size(); i++) {
1661 sizes[i]
1662 = barycenter_computer_min_[c].getCurrentBidders().at(i).size();
1663 }
1664 diagrams_c_min.resize(
1665 barycenter_computer_min_[c].getCurrentBidders().size());
1666 all_matchings.resize(
1667 barycenter_computer_min_[c].getCurrentBidders().size());
1668 }
1669
1670 KDTreePair pair;
1671 bool use_kdt = false;
1672 if(!barycenter_computer_min_[c].getCurrentBarycenter()[0].empty()) {
1673 pair = barycenter_computer_min_[c].getKDTree();
1674 use_kdt = true;
1675 }
1676
1677 barycenter_computer_min_[c].runMatching(
1678 &total_cost, epsilon_[0], sizes, *pair.first, pair.second,
1679 &(min_diag_price->at(0)), &(min_price->at(0)), &(all_matchings),
1680 use_kdt, only_matchings);
1681 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1682 all_matchings_per_type_and_cluster[c][0][ii].resize(
1683 all_matchings[ii].size());
1684 all_matchings_per_type_and_cluster[c][0][ii] = all_matchings[ii];
1685 }
1686 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1687 all_matchings_per_type_and_cluster[c][0][ii].resize(0);
1688 }
1689
1690 precision_min
1691 = barycenter_computer_min_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1692 cost_min_ += total_cost;
1693 Timer const time_update;
1694 if(!only_matchings) {
1695 max_shift_c_min
1696 = barycenter_computer_min_[c].updateBarycenter(all_matchings);
1697 }
1698
1699 if(max_shift_c_min > max_shift_vector[0]) {
1700 max_shift_vector[0] = max_shift_c_min;
1701 }
1702
1703 // Now that barycenters and diagrams are updated in
1704 // PDBarycenter class, we import the results here.
1705 diagrams_c_min = barycenter_computer_min_[c].getCurrentBidders();
1706 centroids_with_price_min
1707 = barycenter_computer_min_[c].getCurrentBarycenter();
1708 int i = 0;
1709 for(int const idx : clustering_[c]) {
1710 current_bidder_diagrams_min_[idx] = diagrams_c_min[i];
1711 centroids_with_price_min_[idx] = centroids_with_price_min[i];
1712 i++;
1713 }
1714
1715 GoodDiagram const old_centroid = centroids_min_[c];
1716 centroids_min_[c] = centroidWithZeroPrices(
1717 centroids_with_price_min_[clustering_[c][0]]);
1718
1719 if(use_accelerated_) {
1720 wasserstein_shift
1721 += computeDistance(old_centroid, centroids_min_[c], 0.01);
1722 }
1723 }
1724
1725 if(do_sad_) {
1726 std::vector<std::vector<MatchingType>> all_matchings;
1727 total_cost = 0;
1728 std::vector<int> sizes;
1729
1730 std::vector<BidderDiagram> diagrams_c_min;
1731 if(barycenter_inputs_reset_flag) {
1732 for(int const idx : clustering_[c]) {
1733 diagrams_c_min.emplace_back(current_bidder_diagrams_saddle_[idx]);
1734 }
1735 sizes.resize(diagrams_c_min.size());
1736 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1737 sizes[i] = diagrams_c_min[i].size();
1738 }
1739 barycenter_computer_sad_[c].setNumberOfInputs(diagrams_c_min.size());
1740 barycenter_computer_sad_[c].setCurrentBidders(diagrams_c_min);
1741 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1742 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1743 i_diagram++) {
1744 barycenter_goods[i_diagram]
1745 = centroids_with_price_saddle_[clustering_[c][i_diagram]];
1746 }
1747 barycenter_computer_sad_[c].setCurrentBarycenter(barycenter_goods);
1748 all_matchings.resize(diagrams_c_min.size());
1749 } else {
1750 sizes.resize(barycenter_computer_sad_[c].getCurrentBidders().size());
1751 for(size_t i = 0;
1752 i < barycenter_computer_sad_[c].getCurrentBidders().size(); i++) {
1753 sizes[i]
1754 = barycenter_computer_sad_[c].getCurrentBidders().at(i).size();
1755 }
1756 all_matchings.resize(
1757 barycenter_computer_sad_[c].getCurrentBidders().size());
1758 diagrams_c_min.resize(
1759 barycenter_computer_sad_[c].getCurrentBidders().size());
1760 }
1761
1762 KDTreePair pair;
1763 bool use_kdt = false;
1764 if(!barycenter_computer_sad_[c].getCurrentBarycenter()[0].empty()) {
1765 pair = barycenter_computer_sad_[c].getKDTree();
1766 use_kdt = true;
1767 }
1768
1769 barycenter_computer_sad_[c].runMatching(
1770 &total_cost, epsilon_[1], sizes, *pair.first, pair.second,
1771 &(min_diag_price->at(1)), &(min_price->at(1)), &(all_matchings),
1772 use_kdt, only_matchings);
1773 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1774 all_matchings_per_type_and_cluster[c][1][ii].resize(
1775 all_matchings[ii].size());
1776 all_matchings_per_type_and_cluster[c][1][ii] = all_matchings[ii];
1777 }
1778 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1779 all_matchings_per_type_and_cluster[c][1][ii].resize(0);
1780 }
1781
1782 precision_sad
1783 = barycenter_computer_sad_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1784 if(!only_matchings) {
1785 max_shift_c_sad
1786 = barycenter_computer_sad_[c].updateBarycenter(all_matchings);
1787 }
1788
1789 cost_sad_ += total_cost;
1790
1791 if(max_shift_c_sad > max_shift_vector[1]) {
1792 max_shift_vector[1] = max_shift_c_sad;
1793 }
1794
1795 // Now that barycenters and diagrams are updated in PDBarycenter class,
1796 // we import the results here.
1797 diagrams_c_min = barycenter_computer_sad_[c].getCurrentBidders();
1798 centroids_with_price_sad
1799 = barycenter_computer_sad_[c].getCurrentBarycenter();
1800 int i = 0;
1801 for(int const idx : clustering_[c]) {
1802 current_bidder_diagrams_saddle_[idx] = diagrams_c_min[i];
1803 centroids_with_price_saddle_[idx] = centroids_with_price_sad[i];
1804 i++;
1805 }
1806 GoodDiagram const old_centroid = centroids_saddle_[c];
1807 centroids_saddle_[c] = centroidWithZeroPrices(
1808 centroids_with_price_saddle_[clustering_[c][0]]);
1809 if(use_accelerated_)
1810 wasserstein_shift
1811 += computeDistance(old_centroid, centroids_saddle_[c], 0.01);
1812 }
1813
1814 if(do_max_) {
1815 std::vector<std::vector<MatchingType>> all_matchings;
1816 Timer const time_preprocess_bary;
1817 total_cost = 0;
1818 std::vector<int> sizes;
1819 std::vector<BidderDiagram> diagrams_c_min;
1820 if(barycenter_inputs_reset_flag) {
1821 for(int const idx : clustering_[c]) {
1822 diagrams_c_min.emplace_back(current_bidder_diagrams_max_[idx]);
1823 }
1824 sizes.resize(diagrams_c_min.size());
1825 for(size_t i = 0; i < diagrams_c_min.size(); i++) {
1826 sizes[i] = diagrams_c_min[i].size();
1827 }
1828 barycenter_computer_max_[c].setNumberOfInputs(diagrams_c_min.size());
1829 barycenter_computer_max_[c].setCurrentBidders(diagrams_c_min);
1830 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
1831 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
1832 i_diagram++) {
1833 barycenter_goods[i_diagram]
1834 = centroids_with_price_max_[clustering_[c][i_diagram]];
1835 }
1836 barycenter_computer_max_[c].setCurrentBarycenter(barycenter_goods);
1837 all_matchings.resize(diagrams_c_min.size());
1838 } else {
1839 sizes.resize(barycenter_computer_max_[c].getCurrentBidders().size());
1840 for(size_t i = 0;
1841 i < barycenter_computer_max_[c].getCurrentBidders().size(); i++) {
1842 sizes[i]
1843 = barycenter_computer_max_[c].getCurrentBidders().at(i).size();
1844 }
1845
1846 diagrams_c_min.resize(
1847 barycenter_computer_max_[c].getCurrentBidders().size());
1848 all_matchings.resize(
1849 barycenter_computer_max_[c].getCurrentBidders().size());
1850 }
1851
1852 KDTreePair pair;
1853 bool use_kdt = false;
1854 if(!barycenter_computer_max_[c].getCurrentBarycenter()[0].empty()) {
1855 pair = barycenter_computer_max_[c].getKDTree();
1856 use_kdt = true;
1857 }
1858
1859 barycenter_computer_max_[c].runMatching(
1860 &total_cost, epsilon_[2], sizes, *pair.first, pair.second,
1861 &(min_diag_price->at(2)), &(min_price->at(2)), &(all_matchings),
1862 use_kdt, only_matchings);
1863 for(size_t ii = 0; ii < all_matchings.size(); ii++) {
1864 all_matchings_per_type_and_cluster[c][2][ii].resize(
1865 all_matchings[ii].size());
1866 all_matchings_per_type_and_cluster[c][2][ii] = all_matchings[ii];
1867 }
1868 for(int ii = all_matchings.size(); ii < numberOfInputs_; ii++) {
1869 all_matchings_per_type_and_cluster[c][2][ii].resize(0);
1870 }
1871 precision_max
1872 = barycenter_computer_max_[c].isPrecisionObjectiveMet(deltaLim_, 0);
1873
1874 cost_max_ += total_cost;
1875 Timer const time_update;
1876 if(!only_matchings) {
1877 max_shift_c_max
1878 = barycenter_computer_max_[c].updateBarycenter(all_matchings);
1879 }
1880 if(max_shift_c_max > max_shift_vector[2]) {
1881 max_shift_vector[2] = max_shift_c_max;
1882 }
1883
1884 // Now that barycenters and diagrams are updated in PDBarycenter class,
1885 // we import the results here.
1886 diagrams_c_min = barycenter_computer_max_[c].getCurrentBidders();
1887 centroids_with_price_max
1888 = barycenter_computer_max_[c].getCurrentBarycenter();
1889 int i = 0;
1890 for(int const idx : clustering_[c]) {
1891 current_bidder_diagrams_max_[idx] = diagrams_c_min[i];
1892 centroids_with_price_max_[idx] = centroids_with_price_max[i];
1893 i++;
1894 }
1895 GoodDiagram const old_centroid = centroids_max_[c];
1896 centroids_max_[c] = centroidWithZeroPrices(
1897 centroids_with_price_max_[clustering_[c][0]]);
1898 if(use_accelerated_) {
1899 wasserstein_shift
1900 += computeDistance(old_centroid, centroids_max_[c], 0.01);
1901 }
1902 }
1903
1904 cost_ = cost_min_ + cost_sad_ + cost_max_;
1905 if(wasserstein_shift > max_wasserstein_shift) {
1906 max_wasserstein_shift = wasserstein_shift;
1907 }
1908 if(use_accelerated_) {
1909 for(int i = 0; i < numberOfInputs_; ++i) {
1910 // Step 5 of Accelerated KMeans: Update the lower bound on distance
1911 // thanks to the triangular inequality
1912 l_[i][c] = Geometry::pow(
1913 Geometry::pow(l_[i][c], 1. / wasserstein_)
1914 - Geometry::pow(wasserstein_shift, 1. / wasserstein_),
1915 wasserstein_);
1916 if(l_[i][c] < 0) {
1917 l_[i][c] = 0;
1918 }
1919 }
1920 for(int const idx : clustering_[c]) {
1921 // Step 6, update the upper bound on the distance to the centroid
1922 // thanks to the triangle inequality
1923 u_[idx] = Geometry::pow(
1924 Geometry::pow(u_[idx], 1. / wasserstein_)
1925 + Geometry::pow(wasserstein_shift, 1. / wasserstein_),
1926 wasserstein_);
1927 r_[idx] = true;
1928 }
1929 }
1930 }
1931 }
1932 // Normally return max_shift, but it seems there is a bug
1933 // yielding max_shift > 100 * max_wasserstein_shift
1934 // which should logically not really happen...
1935 // This is supposed to be only a temporary patch...
1936 precision_min_ = precision_min;
1937 precision_sad_ = precision_sad;
1938 precision_max_ = precision_max;
1939 precision_criterion_ = precision_min && precision_sad && precision_max;
1940 barycenter_inputs_reset_flag = false;
1941 return max_shift_vector; // std::min(max_shift, max_wasserstein_shift);
1942}
1943
1945 for(int i = 0; i < numberOfInputs_; i++) {
1946 if(do_min_) {
1947 DiagramType *CTDiagram = &((*inputDiagramsMin_)[i]);
1948 BidderDiagram bidders;
1949 for(size_t j = 0; j < CTDiagram->size(); j++) {
1950 // Add bidder to bidders
1951 Bidder b((*CTDiagram)[j], j, lambda_);
1952
1953 b.setPositionInAuction(bidders.size());
1954 bidders.emplace_back(b);
1955 if(b.isDiagonal() || b.x_ == b.y_) {
1956 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
1957 }
1958 }
1959 bidder_diagrams_min_.emplace_back(bidders);
1960 current_bidder_diagrams_min_.emplace_back();
1961 centroids_with_price_min_.emplace_back();
1962 std::vector<int> ids(bidders.size());
1963 for(size_t j = 0; j < ids.size(); j++) {
1964 ids[j] = -1;
1965 }
1966 current_bidder_ids_min_.emplace_back(ids);
1967 }
1968
1969 if(do_sad_) {
1970 DiagramType *CTDiagram = &((*inputDiagramsSaddle_)[i]);
1971
1972 BidderDiagram bidders;
1973 for(size_t j = 0; j < CTDiagram->size(); j++) {
1974 // Add bidder to bidders
1975 Bidder b((*CTDiagram)[j], j, lambda_);
1976
1977 b.setPositionInAuction(bidders.size());
1978 bidders.emplace_back(b);
1979 if(b.isDiagonal() || b.x_ == b.y_) {
1980 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
1981 }
1982 }
1983 bidder_diagrams_saddle_.emplace_back(bidders);
1984 current_bidder_diagrams_saddle_.emplace_back();
1985 centroids_with_price_saddle_.emplace_back();
1986 std::vector<int> ids(bidders.size());
1987 for(size_t j = 0; j < ids.size(); j++) {
1988 ids[j] = -1;
1989 }
1990 current_bidder_ids_sad_.emplace_back(ids);
1991 }
1992
1993 if(do_max_) {
1994 DiagramType *CTDiagram = &((*inputDiagramsMax_)[i]);
1995
1996 BidderDiagram bidders;
1997 for(size_t j = 0; j < CTDiagram->size(); j++) {
1998 // Add bidder to bidders
1999 Bidder b((*CTDiagram)[j], j, lambda_);
2000
2001 b.setPositionInAuction(bidders.size());
2002 bidders.emplace_back(b);
2003 if(b.isDiagonal() || b.x_ == b.y_) {
2004 this->printMsg("Diagonal point in diagram", debug::Priority::DETAIL);
2005 }
2006 }
2007 bidder_diagrams_max_.emplace_back(bidders);
2008 current_bidder_diagrams_max_.emplace_back();
2009 centroids_with_price_max_.emplace_back();
2010 std::vector<int> ids(bidders.size());
2011 for(size_t j = 0; j < ids.size(); j++) {
2012 ids[j] = -1;
2013 }
2014 current_bidder_ids_max_.emplace_back(ids);
2015 }
2016 }
2017}
2018
2020 std::vector<double> &previous_min_persistence,
2021 std::vector<double> &min_persistence,
2022 std::vector<std::vector<double>> &initial_diagonal_prices,
2023 std::vector<std::vector<double>> &initial_off_diagonal_prices,
2024 std::vector<int> &min_points_to_add,
2025 bool add_points_to_barycenter,
2026 bool first_enrichment) {
2027
2028 std::vector<double> new_min_persistence = min_persistence;
2029
2030 if(!do_min_) {
2031 new_min_persistence[0] = previous_min_persistence[0];
2032 }
2033 if(!do_sad_) {
2034 new_min_persistence[1] = previous_min_persistence[1];
2035 }
2036 if(!do_max_) {
2037 new_min_persistence[2] = previous_min_persistence[2];
2038 }
2039
2040 // 1. Get size of the largest current diagram, deduce the maximal number of
2041 // points to append
2042 size_t max_diagram_size_min{};
2043 size_t max_diagram_size_sad{};
2044 size_t max_diagram_size_max{};
2045 if(do_min_) {
2046 for(int i = 0; i < numberOfInputs_; i++) {
2047 if(current_bidder_diagrams_min_[i].size() > max_diagram_size_min) {
2048 max_diagram_size_min = current_bidder_diagrams_min_[i].size();
2049 }
2050 }
2051 }
2052 if(do_sad_) {
2053 for(int i = 0; i < numberOfInputs_; i++) {
2054 if(current_bidder_diagrams_saddle_[i].size() > max_diagram_size_sad) {
2055 max_diagram_size_sad = current_bidder_diagrams_saddle_[i].size();
2056 }
2057 }
2058 }
2059 if(do_max_) {
2060 for(int i = 0; i < numberOfInputs_; i++) {
2061 if(current_bidder_diagrams_max_[i].size() > max_diagram_size_max) {
2062 max_diagram_size_max = current_bidder_diagrams_max_[i].size();
2063 }
2064 }
2065 }
2066 int const max_points_to_add_min
2067 = std::max(min_points_to_add[0],
2068 min_points_to_add[0] + (int)(max_diagram_size_min / 10));
2069 int const max_points_to_add_sad
2070 = std::max(min_points_to_add[1],
2071 min_points_to_add[1] + (int)(max_diagram_size_sad / 10));
2072 int const max_points_to_add_max
2073 = std::max(min_points_to_add[2],
2074 min_points_to_add[2] + (int)(max_diagram_size_max / 10));
2075
2076 // 2. Get which points can be added, deduce the new minimal persistence
2077 std::vector<std::vector<int>> candidates_to_be_added_min(numberOfInputs_);
2078 std::vector<std::vector<int>> candidates_to_be_added_sad(numberOfInputs_);
2079 std::vector<std::vector<int>> candidates_to_be_added_max(numberOfInputs_);
2080 std::vector<std::vector<int>> idx_min(numberOfInputs_);
2081 std::vector<std::vector<int>> idx_sad(numberOfInputs_);
2082 std::vector<std::vector<int>> idx_max(numberOfInputs_);
2083
2084 if(do_min_) {
2085 for(int i = 0; i < numberOfInputs_; i++) {
2086 std::vector<double> persistences;
2087 for(size_t j = 0; j < bidder_diagrams_min_[i].size(); j++) {
2088 Bidder const b = bidder_diagrams_min_[i].at(j);
2089 double const persistence = b.getPersistence();
2090 if(persistence >= min_persistence[0]
2091 && persistence <= previous_min_persistence[0]) {
2092 candidates_to_be_added_min[i].emplace_back(j);
2093 idx_min[i].emplace_back(idx_min[i].size());
2094 persistences.emplace_back(persistence);
2095 }
2096 }
2097 sort(
2098 idx_min[i].begin(), idx_min[i].end(), [&persistences](int &a, int &b) {
2099 return ((persistences[a] > persistences[b])
2100 || ((persistences[a] == persistences[b]) && (a > b)));
2101 });
2102 int const size = candidates_to_be_added_min[i].size();
2103 if(size >= max_points_to_add_min) {
2104 double const last_persistence_added_min
2105 = persistences[idx_min[i][max_points_to_add_min - 1]];
2106 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2107 // added per diagram
2108 if(i == 0) {
2109 new_min_persistence[0] = last_persistence_added_min;
2110 } else {
2111 if(last_persistence_added_min < new_min_persistence[0])
2112 new_min_persistence[0] = last_persistence_added_min;
2113 }
2114 } else { // a maxima max_point_to_add added per diagram
2115 if(last_persistence_added_min > new_min_persistence[0]) {
2116 new_min_persistence[0] = last_persistence_added_min;
2117 }
2118 }
2119 }
2120 }
2121 }
2122
2123 if(do_sad_) {
2124 for(int i = 0; i < numberOfInputs_; i++) {
2125 std::vector<double> persistences;
2126 for(size_t j = 0; j < bidder_diagrams_saddle_[i].size(); j++) {
2127 Bidder const b = bidder_diagrams_saddle_[i].at(j);
2128 double const persistence = b.getPersistence();
2129 if(persistence >= min_persistence[1]
2130 && persistence <= previous_min_persistence[1]) {
2131 candidates_to_be_added_sad[i].emplace_back(j);
2132 idx_sad[i].emplace_back(idx_sad[i].size());
2133 persistences.emplace_back(persistence);
2134 }
2135 }
2136 sort(
2137 idx_sad[i].begin(), idx_sad[i].end(), [&persistences](int &a, int &b) {
2138 return ((persistences[a] > persistences[b])
2139 || ((persistences[a] == persistences[b]) && (a > b)));
2140 });
2141 int const size = candidates_to_be_added_sad[i].size();
2142 if(size >= max_points_to_add_sad) {
2143 double const last_persistence_added_sad
2144 = persistences[idx_sad[i][max_points_to_add_sad - 1]];
2145 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2146 // added per diagram
2147 if(i == 0) {
2148 new_min_persistence[1] = last_persistence_added_sad;
2149 } else {
2150 if(last_persistence_added_sad < new_min_persistence[1])
2151 new_min_persistence[1] = last_persistence_added_sad;
2152 }
2153 } else { // a maxima max_point_to_add added per diagram
2154 if(last_persistence_added_sad > new_min_persistence[1]) {
2155 new_min_persistence[1] = last_persistence_added_sad;
2156 }
2157 }
2158 }
2159 }
2160 }
2161 if(do_max_) {
2162 for(int i = 0; i < numberOfInputs_; i++) {
2163 std::vector<double> persistences;
2164 for(size_t j = 0; j < bidder_diagrams_max_[i].size(); j++) {
2165 Bidder const b = bidder_diagrams_max_[i].at(j);
2166 double const persistence = b.getPersistence();
2167 if(persistence >= min_persistence[2]
2168 && persistence <= previous_min_persistence[2]) {
2169 candidates_to_be_added_max[i].emplace_back(j);
2170 idx_max[i].emplace_back(idx_max[i].size());
2171 persistences.emplace_back(persistence);
2172 }
2173 }
2174 sort(
2175 idx_max[i].begin(), idx_max[i].end(), [&persistences](int &a, int &b) {
2176 return ((persistences[a] > persistences[b])
2177 || ((persistences[a] == persistences[b]) && (a > b)));
2178 });
2179 int const size = candidates_to_be_added_max[i].size();
2180 if(size >= max_points_to_add_max) {
2181 double const last_persistence_added_max
2182 = persistences[idx_max[i][max_points_to_add_max - 1]];
2183 if(first_enrichment) { // a minima min_point_to_add (=max_point_to_add)
2184 // added per diagram
2185 if(i == 0) {
2186 new_min_persistence[2] = last_persistence_added_max;
2187 } else {
2188 if(last_persistence_added_max < new_min_persistence[2])
2189 new_min_persistence[2] = last_persistence_added_max;
2190 }
2191 } else { // a maxima max_point_to_add added per diagram
2192 if(last_persistence_added_max > new_min_persistence[2]) {
2193 new_min_persistence[2] = last_persistence_added_max;
2194 }
2195 }
2196 }
2197 }
2198 }
2199
2200 // 3. Add the points to the current diagrams
2201 if(do_min_) {
2202 int compteur_for_adding_points = 0;
2203 for(int i = 0; i < numberOfInputs_; i++) {
2204 int const size = candidates_to_be_added_min[i].size();
2205 for(int j = 0; j < std::min(max_points_to_add_min, size); j++) {
2206 Bidder b = bidder_diagrams_min_[i].at(
2207 candidates_to_be_added_min[i][idx_min[i][j]]);
2208 double const persistence = b.getPersistence();
2209 if(persistence >= new_min_persistence[0]) {
2210 b.id_ = current_bidder_diagrams_min_[i].size();
2211 b.setPositionInAuction(current_bidder_diagrams_min_[i].size());
2212 b.setDiagonalPrice(initial_diagonal_prices[0][i]);
2213 current_bidder_diagrams_min_[i].emplace_back(b);
2214 current_bidder_ids_min_[i]
2215 [candidates_to_be_added_min[i][idx_min[i][j]]]
2216 = current_bidder_diagrams_min_[i].size() - 1;
2217
2218 if(use_accelerated_ && n_iterations_ > 0) {
2219 for(int c = 0; c < k_; ++c) {
2220 // Step 5 of Accelerated KMeans: Update the lower bound on
2221 // distance thanks to the triangular inequality
2222 l_[i][c]
2223 = Geometry::pow(Geometry::pow(l_[i][c], 1. / wasserstein_)
2224 - persistence / sqrt(2),
2225 wasserstein_);
2226 if(l_[i][c] < 0) {
2227 l_[i][c] = 0;
2228 }
2229 }
2230 // Step 6, update the upper bound on the distance to the centroid
2231 // thanks to the triangle inequality
2232 u_[i] = Geometry::pow(
2233 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2234 wasserstein_);
2235 r_[i] = true;
2236 }
2237 int const to_be_added_to_barycenter
2238 = deterministic_ ? compteur_for_adding_points % numberOfInputs_
2239 : rand() % numberOfInputs_;
2240 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2241 for(int k = 0; k < numberOfInputs_; k++) {
2242 if(inv_clustering_[i] == inv_clustering_[k]) {
2243 Good g = Good(
2244 b.x_, b.y_, false, centroids_with_price_min_[k].size());
2245 g.setPrice(initial_off_diagonal_prices[0][k]);
2247 b.coords_[0], b.coords_[1], b.coords_[2]);
2248 centroids_with_price_min_[k].emplace_back(g);
2249 }
2250 }
2251 Good g = Good(
2252 b.x_, b.y_, false, centroids_min_[inv_clustering_[i]].size());
2253 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2254 centroids_min_[inv_clustering_[i]].emplace_back(g);
2255 }
2256 }
2257 compteur_for_adding_points++;
2258 }
2259 }
2260 }
2261 if(do_sad_) {
2262 int compteur_for_adding_points = 0;
2263 for(int i = 0; i < numberOfInputs_; i++) {
2264 int const size = candidates_to_be_added_sad[i].size();
2265 for(int j = 0; j < std::min(max_points_to_add_sad, size); j++) {
2266 Bidder b = bidder_diagrams_saddle_[i].at(
2267 candidates_to_be_added_sad[i][idx_sad[i][j]]);
2268 double const persistence = b.getPersistence();
2269 if(persistence >= new_min_persistence[1]) {
2270 b.id_ = current_bidder_diagrams_saddle_[i].size();
2271 b.setPositionInAuction(current_bidder_diagrams_saddle_[i].size());
2272 b.setDiagonalPrice(initial_diagonal_prices[1][i]);
2273 current_bidder_diagrams_saddle_[i].emplace_back(b);
2274 current_bidder_ids_sad_[i]
2275 [candidates_to_be_added_sad[i][idx_sad[i][j]]]
2276 = current_bidder_diagrams_saddle_[i].size() - 1;
2277
2278 if(use_accelerated_ && n_iterations_ > 0) {
2279 for(int c = 0; c < k_; ++c) {
2280 // Step 5 of Accelerated KMeans: Update the lower bound on
2281 // distance thanks to the triangular inequality
2282 l_[i][c]
2283 = Geometry::pow(Geometry::pow(l_[i][c], 1. / wasserstein_)
2284 - persistence / sqrt(2),
2285 wasserstein_);
2286 if(l_[i][c] < 0) {
2287 l_[i][c] = 0;
2288 }
2289 }
2290 // Step 6, update the upper bound on the distance to the centroid
2291 // thanks to the triangle inequality
2292 u_[i] = Geometry::pow(
2293 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2294 wasserstein_);
2295 r_[i] = true;
2296 }
2297 int const to_be_added_to_barycenter
2298 = deterministic_ ? compteur_for_adding_points % numberOfInputs_
2299 : rand() % numberOfInputs_;
2300 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2301 for(int k = 0; k < numberOfInputs_; k++) {
2302 if(inv_clustering_[i] == inv_clustering_[k]) {
2303 Good g = Good(
2304 b.x_, b.y_, false, centroids_with_price_saddle_[k].size());
2305 g.setPrice(initial_off_diagonal_prices[1][k]);
2307 b.coords_[0], b.coords_[1], b.coords_[2]);
2308 centroids_with_price_saddle_[k].emplace_back(g);
2309 }
2310 }
2311 }
2312 }
2313 compteur_for_adding_points++;
2314 }
2315 }
2316 }
2317 if(do_max_) {
2318 int compteur_for_adding_points = 0;
2319 for(int i = 0; i < numberOfInputs_; i++) {
2320 int const size = candidates_to_be_added_max[i].size();
2321 for(int j = 0; j < std::min(max_points_to_add_max, size); j++) {
2322 Bidder b = bidder_diagrams_max_[i].at(
2323 candidates_to_be_added_max[i][idx_max[i][j]]);
2324 double const persistence = b.getPersistence();
2325 if(persistence >= new_min_persistence[2]) {
2326 b.id_ = current_bidder_diagrams_max_[i].size();
2327 b.setPositionInAuction(current_bidder_diagrams_max_[i].size());
2328 b.setDiagonalPrice(initial_diagonal_prices[2][i]);
2329 current_bidder_diagrams_max_[i].emplace_back(b);
2330 current_bidder_ids_max_[i]
2331 [candidates_to_be_added_max[i][idx_max[i][j]]]
2332 = current_bidder_diagrams_max_[i].size() - 1;
2333
2334 if(use_accelerated_ && n_iterations_ > 0) {
2335 for(int c = 0; c < k_; ++c) {
2336 // Step 5 of Accelerated KMeans: Update the lower bound on
2337 // distance thanks to the triangular inequality
2338 l_[i][c]
2339 = Geometry::pow(Geometry::pow(l_[i][c], 1. / wasserstein_)
2340 - persistence / sqrt(2),
2341 wasserstein_);
2342 if(l_[i][c] < 0) {
2343 l_[i][c] = 0;
2344 }
2345 }
2346 // Step 6, update the upper bound on the distance to the centroid
2347 // thanks to the triangle inequality
2348 u_[i] = Geometry::pow(
2349 Geometry::pow(u_[i], 1. / wasserstein_) + persistence / sqrt(2),
2350 wasserstein_);
2351 r_[i] = true;
2352 }
2353 int const to_be_added_to_barycenter
2354 = deterministic_ ? compteur_for_adding_points % numberOfInputs_
2355 : rand() % numberOfInputs_;
2356 if(to_be_added_to_barycenter == 0 && add_points_to_barycenter) {
2357 for(int k = 0; k < numberOfInputs_; k++) {
2358 if(inv_clustering_[i] == inv_clustering_[k]) {
2359 Good g = Good(
2360 b.x_, b.y_, false, centroids_with_price_max_[k].size());
2361 g.setPrice(initial_off_diagonal_prices[2][k]);
2363 b.coords_[0], b.coords_[1], b.coords_[2]);
2364 centroids_with_price_max_[k].emplace_back(g);
2365 }
2366 }
2367 Good g = Good(
2368 b.x_, b.y_, false, centroids_max_[inv_clustering_[i]].size());
2369 g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2370 centroids_max_[inv_clustering_[i]].emplace_back(g);
2371 }
2372 }
2373 compteur_for_adding_points++;
2374 }
2375 }
2376 }
2377
2378 return new_min_persistence;
2379}
2380
2382 std::vector<double> & /*min_persistence*/) {
2383
2384 if(do_min_) {
2385 barycenter_computer_min_.resize(k_);
2386 for(int c = 0; c < k_; c++) {
2387 std::vector<BidderDiagram> diagrams_c;
2388 for(int const idx : clustering_[c]) {
2389 diagrams_c.emplace_back(current_bidder_diagrams_min_[idx]);
2390 }
2391 barycenter_computer_min_[c] = {};
2392 barycenter_computer_min_[c].setThreadNumber(threadNumber_);
2393 barycenter_computer_min_[c].setWasserstein(wasserstein_);
2394 barycenter_computer_min_[c].setDiagramType(0);
2395 barycenter_computer_min_[c].setUseProgressive(false);
2396 barycenter_computer_min_[c].setDeterministic(true);
2397 barycenter_computer_min_[c].setGeometricalFactor(geometrical_factor_);
2398 barycenter_computer_min_[c].setDebugLevel(debugLevel_);
2399 barycenter_computer_min_[c].setNumberOfInputs(diagrams_c.size());
2400 barycenter_computer_min_[c].setCurrentBidders(diagrams_c);
2401 barycenter_computer_min_[c].setNonMatchingWeight(nonMatchingWeight_);
2402 }
2403 }
2404 if(do_sad_) {
2405 barycenter_computer_sad_.resize(k_);
2406 for(int c = 0; c < k_; c++) {
2407 std::vector<BidderDiagram> diagrams_c;
2408 for(int const idx : clustering_[c]) {
2409 diagrams_c.emplace_back(current_bidder_diagrams_saddle_[idx]);
2410 }
2411 barycenter_computer_sad_[c] = {};
2412 barycenter_computer_sad_[c].setThreadNumber(threadNumber_);
2413 barycenter_computer_sad_[c].setWasserstein(wasserstein_);
2414 barycenter_computer_sad_[c].setDiagramType(1);
2415 barycenter_computer_sad_[c].setUseProgressive(false);
2416 barycenter_computer_sad_[c].setDeterministic(true);
2417 barycenter_computer_sad_[c].setGeometricalFactor(geometrical_factor_);
2418 barycenter_computer_sad_[c].setDebugLevel(debugLevel_);
2419 barycenter_computer_sad_[c].setNumberOfInputs(diagrams_c.size());
2420 barycenter_computer_sad_[c].setCurrentBidders(diagrams_c);
2421 barycenter_computer_sad_[c].setNonMatchingWeight(nonMatchingWeight_);
2422
2423 std::vector<GoodDiagram> barycenter_goods(clustering_[c].size());
2424 for(size_t i_diagram = 0; i_diagram < clustering_[c].size();
2425 i_diagram++) {
2426 barycenter_goods[i_diagram]
2427 = centroids_with_price_saddle_[clustering_[c][i_diagram]];
2428 }
2429 barycenter_computer_sad_[c].setCurrentBarycenter(barycenter_goods);
2430 }
2431 }
2432 if(do_max_) {
2433 barycenter_computer_max_.resize(k_);
2434 for(int c = 0; c < k_; c++) {
2435 std::vector<BidderDiagram> diagrams_c;
2436 for(int const idx : clustering_[c]) {
2437 diagrams_c.emplace_back(current_bidder_diagrams_max_[idx]);
2438 }
2439 barycenter_computer_max_[c] = {};
2440 barycenter_computer_max_[c].setDiagrams(inputDiagramsMax_);
2441 barycenter_computer_max_[c].setThreadNumber(threadNumber_);
2442 barycenter_computer_max_[c].setWasserstein(wasserstein_);
2443 barycenter_computer_max_[c].setDiagramType(2);
2444 barycenter_computer_max_[c].setUseProgressive(false);
2445 barycenter_computer_max_[c].setDeterministic(true);
2446 barycenter_computer_max_[c].setGeometricalFactor(geometrical_factor_);
2447 barycenter_computer_max_[c].setDebugLevel(debugLevel_);
2448 barycenter_computer_max_[c].setNumberOfInputs(diagrams_c.size());
2449 barycenter_computer_max_[c].setCurrentBidders(diagrams_c);
2450 barycenter_computer_max_[c].setNonMatchingWeight(nonMatchingWeight_);
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]
2456 = centroids_with_price_max_[clustering_[c][i_diagram]];
2457 }
2458 barycenter_computer_max_[c].setCurrentBarycenter(barycenter_goods);
2459 }
2460 }
2461}
2462
2464 std::ofstream ufile("u_vec.txt");
2465 std::ofstream lfile("l_mat.txt");
2466 std::ofstream approx_file("a_mat.txt");
2467 if(ufile.is_open() && lfile.is_open()) {
2468 for(int i = 0; i < numberOfInputs_; i++) {
2469 ufile << u_[i] << " ";
2470 for(int j = 0; j < k_; j++) {
2471 lfile << l_[i][j] << " ";
2472 }
2473 lfile << "\n";
2474 }
2475 }
2476
2477 for(int c = 0; c < k_; c++) {
2478 for(int const i : clustering_[c]) {
2479 approx_file << (u_[i] + l_[i][c]) / 2 << " ";
2480 }
2481 approx_file << "\n";
2482 }
2483 lfile.close();
2484 ufile.close();
2485 approx_file.close();
2486}
2487
2489 std::cout << "Computing real distances to every clusters" << std::endl;
2490 std::ofstream file("a_real_mat.txt");
2491 if(file.is_open()) {
2492 for(int c = 0; c < k_; c++) {
2493 for(int const i : clustering_[c]) {
2494 file << distanceToCentroid_[i] << " ";
2495 }
2496 file << "\n";
2497 }
2498 file.close();
2499 } else {
2500 std::cout << "file not open" << std::endl;
2501 }
2502}
2503
2505 std::ofstream file(
2506 "prices_evolution.txt", std::ofstream::out | std::ofstream::app);
2507 if(file.is_open()) {
2508 file << "\nITERATION " << iteration << "\n" << std::endl;
2509 for(int i = 0; i < k_; i++) {
2510 file << "\ncentroid " << i << std::endl;
2511
2512 for(size_t j = 0; j < centroids_with_price_max_[i].size(); j++) {
2513 Good const g = centroids_with_price_max_[i].at(j);
2514 file << g.getPrice() << " ";
2515 }
2516 }
2517 }
2518 file.close();
2519}
2520
2522 double total_real_cost_min = 0;
2523 double total_real_cost_max = 0;
2524 double total_real_cost_sad = 0;
2525 double sq_distance;
2526 if(original_dos[0]) {
2527 for(int c = 0; c < k_; c++) {
2528 double real_cost_cluster = 0;
2529 for(int i = 0; i < numberOfInputs_; i++) {
2530 GoodDiagram const current_barycenter
2531 = centroidWithZeroPrices(centroids_min_[c]);
2532 sq_distance
2533 = computeDistance(bidder_diagrams_min_[i], current_barycenter, 0.01);
2534 real_cost_cluster += sq_distance;
2535 }
2536 total_real_cost_min += real_cost_cluster;
2537 }
2538 }
2539 if(original_dos[1]) {
2540 for(int c = 0; c < k_; c++) {
2541 double real_cost_cluster = 0;
2542 for(int i = 0; i < numberOfInputs_; i++) {
2543 GoodDiagram const current_barycenter
2544 = centroidWithZeroPrices(centroids_saddle_[c]);
2545 sq_distance = computeDistance(
2546 bidder_diagrams_saddle_[i], current_barycenter, 0.01);
2547 real_cost_cluster += sq_distance;
2548 }
2549 total_real_cost_sad += real_cost_cluster;
2550 }
2551 }
2552 if(original_dos[2]) {
2553 for(int c = 0; c < k_; c++) {
2554 double real_cost_cluster = 0;
2555 for(int i = 0; i < numberOfInputs_; i++) {
2556 GoodDiagram const current_barycenter
2557 = centroidWithZeroPrices(centroids_max_[c]);
2558 sq_distance
2559 = computeDistance(bidder_diagrams_max_[i], current_barycenter, 0.01);
2560 real_cost_cluster += sq_distance;
2561 }
2562 total_real_cost_max += real_cost_cluster;
2563 }
2564 }
2565 return total_real_cost_min + total_real_cost_sad + total_real_cost_max;
2566}
2567
2569 std::vector<std::vector<std::vector<std::vector<MatchingType>>>>
2570 &all_matchings_per_type_and_cluster) {
2571
2572 if(do_min_) {
2573 computeBarycenterForTwo(
2574 all_matchings_per_type_and_cluster[0][0], current_bidder_ids_min_,
2575 current_bidder_diagrams_min_, bidder_diagrams_min_, centroids_min_[0]);
2576 }
2577 if(do_sad_) {
2578 computeBarycenterForTwo(all_matchings_per_type_and_cluster[0][1],
2579 current_bidder_ids_sad_,
2580 current_bidder_diagrams_saddle_,
2581 bidder_diagrams_saddle_, centroids_saddle_[0]);
2582 }
2583 if(do_max_) {
2584 computeBarycenterForTwo(
2585 all_matchings_per_type_and_cluster[0][2], current_bidder_ids_max_,
2586 current_bidder_diagrams_max_, bidder_diagrams_max_, centroids_max_[0]);
2587 }
2588}
2589
2591 std::vector<std::vector<MatchingType>> &matchings,
2592 std::vector<std::vector<int>> &bidders_ids,
2593 std::vector<BidderDiagram> &current_bidder_diagrams,
2594 std::vector<BidderDiagram> &bidder_diagrams,
2595 GoodDiagram &barycenter) {
2596
2597 auto &matchings0 = matchings[0];
2598 auto &diagram0 = bidder_diagrams[0];
2599 auto &current_diagram0 = current_bidder_diagrams[0];
2600 auto &ids0 = bidders_ids[0];
2601
2602 auto &matchings1 = matchings[1];
2603 auto &diagram1 = bidder_diagrams[1];
2604 auto &current_diagram1 = current_bidder_diagrams[1];
2605 auto &ids1 = bidders_ids[1];
2606
2607 std::vector<int> new_to_old_id(current_diagram1.size());
2608 // 1. Invert the current_bidder_ids_ vector
2609 for(size_t j = 0; j < ids1.size(); j++) {
2610 int const new_id = ids1[j];
2611 if(new_id >= 0) {
2612 new_to_old_id[new_id] = j;
2613 }
2614 }
2615
2616 std::vector<MatchingType> matching_to_add(0);
2617 std::vector<MatchingType> matching_to_add2(0);
2618
2619 for(size_t i = 0; i < matchings1.size(); i++) {
2620 MatchingType &t = matchings1[i];
2621 int const bidderId = std::get<0>(t);
2622 int const goodId = std::get<1>(t);
2623
2624 if(bidderId >= 0) {
2625 Bidder const b = diagram1.at(new_to_old_id[bidderId]);
2626 double const bx = b.x_;
2627 double const by = b.y_;
2628 if(goodId >= 0) {
2629 Good const g = barycenter.at(goodId);
2630 double const gx = g.x_;
2631 double const gy = g.y_;
2632 barycenter.at(goodId).x_ = (bx + gx) / 2;
2633 barycenter.at(goodId).y_ = (by + gy) / 2;
2634 // divide by 4 in order to display the cost of the half matching
2635 // i.e. the cost of matching to the barycenter
2636 std::get<2>(t) /= 4;
2637
2638 } else {
2639 double gx = (bx + by) / 2;
2640 double gy = (bx + by) / 2;
2641 gx = (gx + bx) / 2;
2642 gy = (gy + by) / 2;
2643 double const cost = nonMatchingWeight_
2644 * (Geometry::pow((gx - bx), wasserstein_)
2645 + Geometry::pow((gy - by), wasserstein_));
2646 MatchingType const t2
2647 = std::make_tuple(bidderId, barycenter.size(), cost);
2648 MatchingType const t3 = std::make_tuple(-1, barycenter.size(), cost);
2649 Good const g = Good(gx, gy, false, barycenter.size());
2650 // g.SetCriticalCoordinates(b.coords_[0], b.coords_[1], b.coords_[2]);
2651 barycenter.emplace_back(g);
2652 matching_to_add.emplace_back(t2);
2653 matching_to_add2.emplace_back(t3);
2654 }
2655 } else {
2656 if(goodId >= 0) {
2657 Good const g = barycenter.at(goodId);
2658 double const gx = (g.x_ + g.y_) / 2;
2659 double const gy = (g.x_ + g.y_) / 2;
2660 barycenter.at(goodId).x_ = (gx + g.x_) / 2;
2661 barycenter.at(goodId).y_ = (gy + g.y_) / 2;
2662 std::get<2>(t) /= 4;
2663 }
2664 }
2665 }
2666 for(size_t j = 0; j < matching_to_add.size(); j++) {
2667 matchings1.emplace_back(matching_to_add[j]);
2668 }
2669 for(size_t j = 0; j < matching_to_add2.size(); j++) {
2670 matchings0.emplace_back(matching_to_add2[j]);
2671 }
2672
2673 // correct the costs of matchings in diagram 0
2674 // costs are initially allzeros because the barycenter is identical
2675 // to diagram 0
2676 std::vector<int> new_to_old_id2(current_diagram0.size());
2677 // 1. Invert the current_bidder_ids_ vector
2678 for(size_t j = 0; j < ids0.size(); j++) {
2679 int const new_id = ids0[j];
2680 if(new_id >= 0) {
2681 new_to_old_id2[new_id] = j;
2682 }
2683 }
2684
2685 for(size_t i = 0; i < matchings0.size(); i++) {
2686 MatchingType &t = matchings0[i];
2687 int const bidderId = std::get<0>(t);
2688 int const goodId = std::get<1>(t);
2689
2690 if(bidderId >= 0 and goodId >= 0) {
2691 Bidder const b = diagram0.at(new_to_old_id2[bidderId]);
2692 double const bx = b.x_;
2693 double const by = b.y_;
2694 Good const g = barycenter.at(goodId);
2695 double const gx = g.x_;
2696 double const gy = g.y_;
2697 double const cost = Geometry::pow((gx - bx), wasserstein_)
2698 + Geometry::pow((gy - by), wasserstein_);
2699 std::get<2>(t) = cost;
2700 }
2701 }
2702}
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
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_
double getLessPersistent(int type=-1)
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)
BidderDiagram centroidToDiagram(const GoodDiagram &centroid)
void initializeCentroidsKMeanspp()
double computeDistance(const BidderDiagram &D1, const BidderDiagram &D2, const double delta_lim)
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)
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::array< double, 3 > epsilon_
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)
GoodDiagram centroidWithZeroPrices(const GoodDiagram &centroid)
void resetDosToOriginalValues()
std::vector< GoodDiagram > centroids_max_
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)
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
std::string to_string(__int128)
Definition ripserpy.cpp:99
T1 pow(const T1 val, const T2 n)
Definition Geometry.h:454
std::vector< Bidder > BidderDiagram
CriticalType
default value for critical index
Definition DataTypes.h:80
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.
std::tuple< int, int, double > MatchingType
Matching between two Persistence Diagram pairs.
std::vector< Good > GoodDiagram
T end(std::pair< T, T > &p)
Definition ripserpy.cpp:472
T begin(std::pair< T, T > &p)
Definition ripserpy.cpp:468
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)