SemiDiscreteOT 1.0
Semi-Discrete Optimal Transport Library
Loading...
Searching...
No Matches
EpsilonScalingHandler.cc
Go to the documentation of this file.
2#include <algorithm>
3#include <iostream>
4#include <iomanip>
5
7 const MPI_Comm& comm,
8 double initial_epsilon,
9 double scaling_factor,
10 unsigned int num_steps)
11 : mpi_communicator(comm)
12 , this_mpi_process(Utilities::MPI::this_mpi_process(comm))
13 , pcout(std::cout, this_mpi_process == 0)
14 , initial_epsilon(initial_epsilon)
15 , scaling_factor(scaling_factor)
16 , num_steps(num_steps)
17{
18 // Validate parameters
19 if (scaling_factor <= 1.0) {
20 pcout << "Warning: Epsilon scaling factor should be > 1.0. Using default value of 2.0." << std::endl;
21 this->scaling_factor = 2.0;
22 }
23
24 if (num_steps == 0) {
25 pcout << "Warning: Number of epsilon scaling steps cannot be 0. Using default value of 1." << std::endl;
26 this->num_steps = 1;
27 }
28}
29
31{
32 std::vector<double> epsilon_sequence;
33 epsilon_sequence.reserve(num_steps);
34
35 // Generate sequence from largest to smallest epsilon
36 for (unsigned int i = 0; i < num_steps; ++i) {
37 double scale_factor = std::pow(scaling_factor, num_steps - 1 - i);
38 epsilon_sequence.push_back(initial_epsilon * scale_factor);
39 }
40
41 return epsilon_sequence;
42}
43
44std::vector<std::vector<double>> EpsilonScalingHandler::distribute_epsilon_values(
45 const std::vector<double>& epsilon_sequence,
46 unsigned int num_levels)
47{
48 std::vector<std::vector<double>> distribution(num_levels);
49
50 if (num_levels == 0) {
51 pcout << "Warning: No levels provided for epsilon distribution." << std::endl;
52 return distribution;
53 }
54
55 // If we have more epsilon values than levels, we need to assign multiple
56 // epsilon values to some levels (starting from the coarsest)
57 if (epsilon_sequence.size() <= num_levels) {
58 // Simple case: we have fewer or equal epsilon values than levels
59 // Assign one epsilon value per level, starting from the coarsest
60 for (unsigned int level = 0; level < num_levels; ++level) {
61 if (level < epsilon_sequence.size()) {
62 distribution[level].push_back(epsilon_sequence[level]);
63 } else {
64 // For levels without a dedicated epsilon, use the smallest epsilon
65 distribution[level].push_back(epsilon_sequence.back());
66 }
67 }
68 } else {
69 // Complex case: we have more epsilon values than levels
70 // Distribute them evenly, with more values assigned to coarser levels
71 unsigned int remaining_epsilons = epsilon_sequence.size();
72 unsigned int remaining_levels = num_levels;
73
74 unsigned int epsilon_index = 0;
75 for (unsigned int level = 0; level < num_levels; ++level) {
76 // Calculate how many epsilon values to assign to this level
77 unsigned int epsilons_for_level = (remaining_epsilons + remaining_levels - 1) / remaining_levels;
78
79 // Add epsilon values for this level
80 for (unsigned int i = 0; i < epsilons_for_level && epsilon_index < epsilon_sequence.size(); ++i) {
81 distribution[level].push_back(epsilon_sequence[epsilon_index++]);
82 }
83
84 remaining_epsilons -= epsilons_for_level;
85 remaining_levels--;
86 }
87 }
88
89 return distribution;
90}
91
93 unsigned int num_levels)
94{
95 // Generate the sequence of epsilon values
96 std::vector<double> epsilon_sequence = generate_epsilon_sequence();
97 // Distribute epsilon values across levels
98 epsilon_distribution = distribute_epsilon_values(epsilon_sequence, num_levels);
100}
101
103 unsigned int level_index) const
104{
105 if (level_index >= epsilon_distribution.size()) {
106 // Return empty vector for invalid level index
107 static const std::vector<double> empty_vector;
108 pcout << "Warning: Requested epsilon values for invalid level index: "
109 << level_index << std::endl;
110 return empty_vector;
111 }
112
113 return epsilon_distribution[level_index];
114}
115
117{
118 if (this_mpi_process != 0) return;
119
120 if (epsilon_distribution.empty()) {
121 pcout << "Epsilon distribution has not been computed yet." << std::endl;
122 return;
123 }
124
125 pcout << "\n----------------------------------------" << std::endl;
126 pcout << "Epsilon Scaling Distribution:" << std::endl;
127 pcout << "----------------------------------------" << std::endl;
128 pcout << "Initial epsilon: " << initial_epsilon << std::endl;
129 pcout << "Scaling factor: " << scaling_factor << std::endl;
130 pcout << "Number of steps: " << num_steps << std::endl;
131 pcout << "Number of levels: " << epsilon_distribution.size() << std::endl;
132 pcout << "----------------------------------------" << std::endl;
133 auto num_levels = epsilon_distribution.size()-1;
134
135 for (unsigned int level = 0; level < epsilon_distribution.size(); ++level) {
136 pcout << "Level " << num_levels - level << " (";
137 if (level == 0) {
138 pcout << "coarsest";
139 } else if (level == epsilon_distribution.size() - 1) {
140 pcout << "finest";
141 } else {
142 pcout << "intermediate";
143 }
144 pcout << "): ";
145
146 const auto& level_epsilons = epsilon_distribution[level];
147 pcout << level_epsilons.size() << " epsilon value(s): ";
148
149 for (unsigned int i = 0; i < level_epsilons.size(); ++i) {
150 pcout << std::scientific << std::setprecision(4) << level_epsilons[i];
151 if (i < level_epsilons.size() - 1) {
152 pcout << ", ";
153 }
154 }
155 pcout << std::endl;
156 }
157 pcout << "----------------------------------------" << std::endl;
158 pcout << std::defaultfloat;
159}
double initial_epsilon
The initial epsilon value.
void print_epsilon_distribution() const
Print the epsilon distribution.
double scaling_factor
The scaling factor for epsilon.
std::vector< double > generate_epsilon_sequence() const
Generate the sequence of epsilon values.
std::vector< std::vector< double > > distribute_epsilon_values(const std::vector< double > &epsilon_sequence, unsigned int num_levels)
Distribute epsilon values across levels.
std::vector< std::vector< double > > epsilon_distribution
The computed epsilon distribution.
const std::vector< double > & get_epsilon_values_for_level(unsigned int level_index) const
Get epsilon values for a specific level.
unsigned int num_steps
The total number of epsilon scaling steps.
EpsilonScalingHandler(const MPI_Comm &comm, double initial_epsilon, double scaling_factor, unsigned int num_steps)
Constructor.
std::vector< std::vector< double > > compute_epsilon_distribution(unsigned int num_levels)
Compute epsilon distribution for multilevel optimization.
ConditionalOStream pcout
A conditional output stream for parallel printing.
const unsigned int this_mpi_process
The rank of the current MPI process.