numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
tv_admm.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 <algorithm>
23#include <limits>
24#include <utility>
25
38#include "num_collect/regularization/impl/weak_coeff_param.h" // IWYU pragma: keep
40
42
44constexpr auto tv_admm_tag =
45 logging::log_tag_view("num_collect::regularization::tv_admm");
46
56template <typename Coeff, typename DerivativeMatrix,
63 tv_admm<Coeff, DerivativeMatrix, Data>, Data> {
64public:
67
70
71 using typename base_type::data_type;
72 using typename base_type::scalar_type;
73
75 using coeff_type = Coeff;
76
78 using derivative_matrix_type = DerivativeMatrix;
79
84 this->configure_child_algorithm_logger_if_exists(conjugate_gradient_);
85 }
86
98 void compute(const Coeff& coeff, const DerivativeMatrix& derivative_matrix,
99 const Data& data) {
100 coeff_ = &coeff;
101 derivative_matrix_ = &derivative_matrix;
102 data_ = &data;
103 }
104
106 void init(const scalar_type& param, data_type& solution) {
107 (void)param;
108
109 NUM_COLLECT_PRECONDITION(coeff_->rows() == data_->rows(),
110 this->logger(),
111 "Coefficient matrix and data vector must have the same number of "
112 "rows.");
113 NUM_COLLECT_PRECONDITION(coeff_->cols() == solution.rows(),
114 this->logger(),
115 "The number of columns in the coefficient matrix must match the "
116 "number of rows in solution vector.");
117 NUM_COLLECT_PRECONDITION(data_->cols() == solution.cols(),
118 this->logger(),
119 "Data and solution must have the same number of columns.");
120 NUM_COLLECT_PRECONDITION(derivative_matrix_->cols() == solution.rows(),
121 this->logger(),
122 "The number of columns in the derivative matrix must match the "
123 "number of rows in solution vector.");
124
125 iterations_ = 0;
126 derivative_ = (*derivative_matrix_) * solution;
127 lagrange_multiplier_ = data_type::Zero(derivative_matrix_->rows());
128 temp_solution_ = solution;
129 residual_ = (*coeff_) * solution - (*data_);
130 update_rate_ = std::numeric_limits<scalar_type>::infinity();
131
132 const scalar_type conjugate_gradient_tolerance_rate =
133 rate_of_cg_tol_rate_to_tol_update_rate_ * tol_update_rate_;
134 conjugate_gradient_.tolerance_rate(conjugate_gradient_tolerance_rate);
135 }
136
138 void iterate(const scalar_type& param, data_type& solution) {
139 // Update solution.
140 temp_solution_ =
141 static_cast<scalar_type>(2) * (*coeff_).transpose() * (*data_) -
142 (*derivative_matrix_).transpose() * lagrange_multiplier_ +
143 derivative_constraint_coeff_ * (*derivative_matrix_).transpose() *
144 derivative_;
145 previous_solution_ = solution;
146 conjugate_gradient_.solve(
147 [this](const data_type& target, data_type& result) {
148 result = static_cast<scalar_type>(2) * (*coeff_).transpose() *
149 (*coeff_) * target;
150 result += derivative_constraint_coeff_ *
151 (*derivative_matrix_).transpose() * (*derivative_matrix_) *
152 target;
153 },
154 temp_solution_, solution);
155 update_rate_ = (solution - previous_solution_).norm() /
156 (solution.norm() + std::numeric_limits<scalar_type>::epsilon());
157 residual_ = (*coeff_) * solution - (*data_);
158
159 // Update derivative.
160 previous_derivative_ = derivative_;
161 derivative_ = (*derivative_matrix_) * solution +
162 lagrange_multiplier_ / derivative_constraint_coeff_;
163 const scalar_type derivative_shrinkage_threshold =
164 param / derivative_constraint_coeff_;
166 derivative_, derivative_shrinkage_threshold);
167 update_rate_ += (derivative_ - previous_derivative_).norm() /
168 (derivative_.norm() + std::numeric_limits<scalar_type>::epsilon());
169
170 // Update lagrange multiplier.
171 lagrange_multiplier_update_ = derivative_constraint_coeff_ *
172 ((*derivative_matrix_) * solution - derivative_);
173 lagrange_multiplier_ += lagrange_multiplier_update_;
174 update_rate_ += lagrange_multiplier_update_.norm() /
175 (lagrange_multiplier_.norm() +
176 std::numeric_limits<scalar_type>::epsilon());
177
178 ++iterations_;
179 }
180
182 [[nodiscard]] auto is_stop_criteria_satisfied(
183 const data_type& solution) const -> bool {
184 (void)solution;
185 return (iterations() > max_iterations()) ||
186 (update_rate() < tol_update_rate());
187 }
188
192 const {
193 iteration_logger.template append<index_type>(
194 "Iter.", &this_type::iterations);
195 iteration_logger.template append<scalar_type>(
196 "UpdateRate", &this_type::update_rate);
197 iteration_logger.template append<scalar_type>(
198 "Res.Rate", &this_type::residual_norm_rate);
199 }
200
202 [[nodiscard]] auto residual_norm(const data_type& solution) const
203 -> scalar_type {
204 return ((*coeff_) * solution - (*data_)).squaredNorm();
205 }
206
208 [[nodiscard]] auto regularization_term(const data_type& solution) const
209 -> scalar_type {
210 return (*derivative_matrix_ * solution).template lpNorm<1>();
211 }
212
214 void change_data(const data_type& data) { data_ = &data; }
215
217 void calculate_data_for(const data_type& solution, data_type& data) const {
218 data = (*coeff_) * solution;
219 }
220
222 [[nodiscard]] auto data_size() const -> index_type { return data_->size(); }
223
225 [[nodiscard]] auto param_search_region() const
226 -> std::pair<scalar_type, scalar_type> {
227 const data_type approx_order_of_solution = coeff_->transpose() *
228 (*data_) / impl::approximate_max_eigen_aat(*coeff_);
229 const scalar_type approx_order_of_param =
230 (*derivative_matrix_ * approx_order_of_solution)
231 .cwiseAbs()
232 .maxCoeff();
234 this->logger(), "approx_order_of_param={}", approx_order_of_param);
235 constexpr auto tol_update_coeff_multiplier =
236 static_cast<scalar_type>(10);
237 return {approx_order_of_param *
239 tol_update_coeff_multiplier * tol_update_rate_),
240 approx_order_of_param * impl::weak_coeff_max_param<scalar_type>};
241 }
242
248 [[nodiscard]] auto iterations() const noexcept -> index_type {
249 return iterations_;
250 }
251
258 [[nodiscard]] auto update_rate() const noexcept -> scalar_type {
259 return update_rate_;
260 }
261
267 [[nodiscard]] auto residual_norm_rate() const -> scalar_type {
268 return residual_.squaredNorm() / data_->squaredNorm();
269 }
270
276 [[nodiscard]] auto max_iterations() const -> index_type {
277 return max_iterations_;
278 }
279
287 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
288 "Maximum number of iterations must be a positive integer.");
289 max_iterations_ = value;
290 return *this;
291 }
292
298 [[nodiscard]] auto tol_update_rate() const -> scalar_type {
299 return tol_update_rate_;
300 }
301
309 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
310 "Tolerance of update rate of the solution must be a positive "
311 "value.");
312 tol_update_rate_ = value;
313 return *this;
314 }
315
316private:
318 const coeff_type* coeff_{nullptr};
319
321 const derivative_matrix_type* derivative_matrix_{nullptr};
322
324 const data_type* data_{nullptr};
325
327 index_type iterations_{};
328
330 data_type derivative_{};
331
333 data_type lagrange_multiplier_{};
334
336 data_type temp_solution_{};
337
339 data_type previous_solution_{};
340
342 data_type previous_derivative_{};
343
345 data_type lagrange_multiplier_update_{};
346
348 data_type residual_{};
349
351 scalar_type update_rate_{};
352
355
357 static constexpr auto default_derivative_constraint_coeff =
358 static_cast<scalar_type>(1);
359
361 scalar_type derivative_constraint_coeff_{
362 default_derivative_constraint_coeff};
363
365 static constexpr index_type default_max_iterations = 1000;
366
368 index_type max_iterations_{default_max_iterations};
369
371 static constexpr auto default_tol_update_rate =
372 static_cast<scalar_type>(1e-4);
373
375 scalar_type tol_update_rate_{default_tol_update_rate};
376
378 static constexpr auto default_rate_of_cg_tol_rate_to_tol_update_rate =
379 static_cast<scalar_type>(1e-2);
380
382 scalar_type rate_of_cg_tol_rate_to_tol_update_rate_{
383 default_rate_of_cg_tol_rate_to_tol_update_rate};
384};
385
386} // namespace num_collect::regularization
Definition of apply_shrinkage_operator function.
Definition of max_eigen_aat function.
Class to perform conjugate gradient (CG) method golub2013 for linear operators.
Class of tags of logs without memory management.
Base class of solvers using iterative formulas for regularization.
typename Eigen::NumTraits< typename data_type::Scalar >::Real scalar_type
Type of scalars.
Class to solve linear equations with total variation (TV) regularization using the alternating direct...
Definition tv_admm.h:63
auto param_search_region() const -> std::pair< scalar_type, scalar_type >
Get the default region to search for the optimal regularization parameter.
Definition tv_admm.h:225
void iterate(const scalar_type &param, data_type &solution)
Iterate the algorithm once.
Definition tv_admm.h:138
auto update_rate() const noexcept -> scalar_type
Get the rate of the norm of the update of the solution in the last iteration.
Definition tv_admm.h:258
auto residual_norm_rate() const -> scalar_type
Get the rate of the last residual norm.
Definition tv_admm.h:267
auto residual_norm(const data_type &solution) const -> scalar_type
Calculate the squared norm of the residual.
Definition tv_admm.h:202
auto data_size() const -> index_type
Get the size of data.
Definition tv_admm.h:222
auto max_iterations() const -> index_type
Get the maximum number of iterations.
Definition tv_admm.h:276
Coeff coeff_type
Type of coefficient matrices.
Definition tv_admm.h:75
void calculate_data_for(const data_type &solution, data_type &data) const
Calculate data for a solution.
Definition tv_admm.h:217
auto tol_update_rate(scalar_type value) -> tv_admm &
Set the tolerance of update rate of the solution.
Definition tv_admm.h:308
auto iterations() const noexcept -> index_type
Get the number of iterations.
Definition tv_admm.h:248
auto tol_update_rate() const -> scalar_type
Get the tolerance of update rate of the solution.
Definition tv_admm.h:298
auto max_iterations(index_type value) -> tv_admm &
Set the maximum number of iterations.
Definition tv_admm.h:286
void configure_iteration_logger(logging::iterations::iteration_logger< this_type > &iteration_logger) const
Configure an iteration logger.
Definition tv_admm.h:190
DerivativeMatrix derivative_matrix_type
Type of matrices to compute derivatives.
Definition tv_admm.h:78
void compute(const Coeff &coeff, const DerivativeMatrix &derivative_matrix, const Data &data)
Compute internal parameters.
Definition tv_admm.h:98
void init(const scalar_type &param, data_type &solution)
Initialize.
Definition tv_admm.h:106
auto is_stop_criteria_satisfied(const data_type &solution) const -> bool
Determine if stopping criteria of the algorithm are satisfied.
Definition tv_admm.h:182
auto regularization_term(const data_type &solution) const -> scalar_type
Calculate the regularization term.
Definition tv_admm.h:208
void change_data(const data_type &data)
Change data.
Definition tv_admm.h:214
Concept of Eigen's dense matrices.
Concept of Eigen's dense vectors.
Definition of dense_matrix concept.
Definition of dense_vector concept.
Definition of exceptions.
Definition of index_type type.
Definition of iteration_logger class.
Definition of iterative_regularized_solver_base class.
Definition of log_tag_view class.
Definition of macros for logging.
#define NUM_COLLECT_LOG_TRACE(LOGGER,...)
Write a trace log.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
auto norm(const Matrix &matrix)
Calculate norm of a matrix.
Definition norm.h:39
constexpr auto weak_coeff_min_param
Coefficient (minimum parameter to be searched) / (maximum singular value or eigen value).
auto approximate_max_eigen_aat(const Matrix &matrix) -> typename Matrix::Scalar
Approximate the maximum eigenvalue of for a matrix .
void apply_shrinkage_operator(Vector &target, typename Vector::Scalar threshold)
Apply shrinkage operator to a vector.
constexpr auto weak_coeff_max_param
Coefficient (maximum parameter to be searched) / (maximum singular value or eigen value).
Namespace of regularization algorithms.
constexpr auto tv_admm_tag
Tag of tv_admm.
Definition tv_admm.h:44
STL namespace.
Definition of operator_conjugate_gradient class.
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 sparse_matrix concept.
Definition of coefficients for regularization parameters.