numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
implicit_gcv.h
Go to the documentation of this file.
1/*
2 * Copyright 2024 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <cmath>
23#include <random>
24
37
39
41constexpr auto implicit_gcv_tag =
42 logging::log_tag_view("num_collect::regularization::implicit_gcv");
43
49template <concepts::implicit_regularized_solver Solver>
51public:
53 using solver_type = Solver;
54
56 using scalar_type = typename solver_type::scalar_type;
57
59 using data_type = typename solver_type::data_type;
60
62 "Currently only vectors are supported as data.");
63
72 const data_type& initial_solution)
73 : solver_(&solver), data_(&data), initial_solution_(&initial_solution) {
75 num_samples(1);
76 }
77
84 [[nodiscard]] auto operator()(scalar_type param) -> scalar_type {
85 const index_type data_size = data_->size();
86 if (noise_.back().size() != data_size) {
88 }
89
91 solver_->change_data(*data_);
92 solver_->solve(param, solution_);
93 solver_->calculate_data_for(solution_, forwarded_data_);
94
95 auto trace_sum = static_cast<scalar_type>(0);
96 for (index_type i = 0; i < noise_.size(); ++i) {
98 solver_->change_data(data_with_noise_[i]);
99 solver_->solve(param, solution_with_noise_);
100 solver_->calculate_data_for(
102
103 trace_sum += noise_[i].dot(noise_[i] -
106 noise_[i].squaredNorm();
107 }
108 trace_sum /= static_cast<scalar_type>(noise_.size());
109
110 solver_->change_data(*data_);
111
112 const scalar_type denominator = trace_sum * trace_sum;
113 const scalar_type numerator = solver_->residual_norm(solution_) /
114 static_cast<scalar_type>(data_size);
115 return numerator / denominator;
116 }
117
125 NUM_COLLECT_PRECONDITION(value > static_cast<scalar_type>(0),
126 "Rate of noise must be a positive value.");
127 noise_rate_ = value;
128 using std::sqrt;
129 noise_multiplier_ = data_->norm() *
130 sqrt(noise_rate_ / static_cast<scalar_type>(data_->size()));
131 return *this;
132 }
133
142 value > 0, "Number of samples must be a positive value.");
143 noise_.resize(value);
145 return *this;
146 }
147
154 template <base::concepts::invocable<> RandomNumberGenerator>
155 void generate_noise(RandomNumberGenerator& generator) {
156 std::normal_distribution<scalar_type> distribution;
157 for (index_type i = 0; i < noise_.size(); ++i) {
158 noise_[i].resize(data_->size());
159 for (index_type j = 0; j < data_->size(); ++j) {
160 noise_[i](j) = distribution(generator);
161 }
162 data_with_noise_[i] = (*data_) + noise_multiplier_ * noise_[i];
163 }
164 }
165
170 std::mt19937 generator{std::random_device{}()};
171 generate_noise(generator);
172 }
173
179 [[nodiscard]] auto solver() const noexcept -> solver_type& {
180 return *solver_;
181 }
182
183private:
186
189
192
194 static constexpr scalar_type default_noise_rate = 1e-2;
195
198
201
204
207
210
213
216
219};
220
226template <concepts::implicit_regularized_solver Solver>
228public:
230 using solver_type = Solver;
231
233 using scalar_type = typename solver_type::scalar_type;
234
236 using data_type = typename solver_type::data_type;
237
245 implicit_gcv(solver_type& solver, const data_type& data,
246 const data_type& initial_solution)
248 calculator_(solver, data, initial_solution) {
250 optimizer_.configure_child_algorithm_logger_if_exists(
252 }
253
255 void search() {
256 using std::log10;
257 using std::pow;
258 const auto [min_param, max_param] =
259 calculator_.solver().param_search_region();
261 logger(), "Region of parameters: [{}, {}]", min_param, max_param);
262 const scalar_type log_min_param = log10(min_param);
263 const scalar_type log_max_param = log10(max_param);
264
265 const auto objective_function =
266 [this](scalar_type log_param) -> scalar_type {
267 using std::pow;
268 using std::log10;
269 const scalar_type param =
270 pow(static_cast<scalar_type>(10), // NOLINT
271 log_param);
272 const scalar_type gcv_value = calculator_(param);
273 NUM_COLLECT_LOG_TRACE(logger(), "gcv({}) = {}", param, gcv_value);
274 return log10(gcv_value);
275 };
276 optimizer_.change_objective_function(objective_function);
277
279 optimizer_.configure_child_algorithm_logger_if_exists(
281
282 constexpr index_type max_evaluations = 20;
283 optimizer_.max_evaluations(max_evaluations);
284
285 optimizer_.init(log_min_param, log_max_param);
286 optimizer_.solve();
287 opt_param_ = pow(static_cast<scalar_type>(10), // NOLINT
288 optimizer_.opt_variable());
289
290 NUM_COLLECT_LOG_SUMMARY(logger(), "Selected parameter: {}", opt_param_);
291 }
292
294 [[nodiscard]] auto opt_param() const -> scalar_type { return opt_param_; }
295
297 void solve(data_type& solution) const {
299 logger(), "Solve with an optimal parameter: {}", opt_param_);
300 calculator_.solver().solve(opt_param_, solution);
301 }
302
310 calculator_.noise_rate(value);
311 return *this;
312 }
313
322 return *this;
323 }
324
325private:
328
333
336};
337
338} // namespace num_collect::regularization
Definition of any_objective_function class.
Class of tags of logs without memory management.
Class to incorporate logging in algorithms.
void configure_child_algorithm_logger_if_exists(Child &child)
Configure a logger of a child algorithm if exists.
logging_mixin(log_tag_view tag)
Constructor.
auto logger() const noexcept -> const num_collect::logging::logger &
Access to the logger.
Class to store any type of objects of objective functions.
Class of Gaussian process optimization srinivas2010, brochu2010.
Class to calculate the objective function of GCV.
void generate_noise(RandomNumberGenerator &generator)
Generate noise to use in calculation.
implicit_gcv_calculator(solver_type &solver, const data_type &data, const data_type &initial_solution)
Constructor.
auto operator()(scalar_type param) -> scalar_type
Calculate GCV function.
auto solver() const noexcept -> solver_type &
Get the solver.
auto num_samples(index_type value) -> implicit_gcv_calculator &
Set the number of samples for approximation of denominator of GCV.
auto noise_rate(scalar_type value) -> implicit_gcv_calculator &
Set the rate of noise.
typename solver_type::data_type data_type
Type of data.
util::vector< data_type > data_with_noise_
Data with noise.
data_type forwarded_data_
Buffer of data generated from the solution.
static constexpr scalar_type default_noise_rate
Default rate of noise.
util::vector< data_type > noise_
Vector of noise.
void generate_noise()
Generate noise with a random seed.
scalar_type noise_multiplier_
Multiplier of noise.
typename solver_type::scalar_type scalar_type
Type of scalars.
const data_type * initial_solution_
Initial solution.
data_type solution_with_noise_
Buffer of the solution with noise.
data_type forwarded_data_with_noise_
Buffer of data generated from the solution with noise.
Class to search optimal regularization parameter using GCV.
auto opt_param() const -> scalar_type
Get the optimal regularization parameter.
auto num_samples(index_type value) -> implicit_gcv &
Set the number of samples for approximation of denominator of GCV.
opt::gaussian_process_optimizer< opt::any_objective_function< scalar_type(scalar_type)> > optimizer_
Optimizer.
auto noise_rate(scalar_type value) -> implicit_gcv &
Set the rate of noise.
implicit_gcv(solver_type &solver, const data_type &data, const data_type &initial_solution)
Constructor.
implicit_gcv_calculator< solver_type > calculator_
Calculator of GCV.
scalar_type opt_param_
Optimal regularization parameter.
void solve(data_type &solution) const
Solver with the optimal regularization parameter.
typename solver_type::scalar_type scalar_type
Type of scalars.
typename solver_type::data_type data_type
Type of data.
void search()
Search the optimal regularization parameter.
Class of vectors wrapping std::vector class to use singed integers as indices.
Definition vector.h:37
auto size() const -> index_type
Get the size of this vector.
Definition vector.h:226
void resize(index_type size)
Change the size.
Definition vector.h:244
auto back() -> reference
Access to the final element.
Definition vector.h:140
Concept of Eigen's dense vectors with real scalars.
Definition of exceptions.
Definition of gaussian_process_optimizer class.
Definition of implicit_regularized_solver concept.
Definition of index_type type.
Definition of invocable concept.
Definition of log_tag_view class.
Definition of macros for logging.
#define NUM_COLLECT_LOG_SUMMARY(LOGGER,...)
Write a summary log.
#define NUM_COLLECT_LOG_TRACE(LOGGER,...)
Write a trace log.
#define NUM_COLLECT_LOG_DEBUG(LOGGER,...)
Write a debug log.
Definition of logging_mixin class.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
Namespace of regularization algorithms.
constexpr auto implicit_gcv_tag
Tag of implicit_gcv.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.
Definition of real_scalar_dense_vector concept.
Definition of vector class.