numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
tikhonov.h
Go to the documentation of this file.
1/*
2 * Copyright 2021 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 <utility>
23
24#include <Eigen/Core>
25#include <Eigen/SVD>
26
31#include "num_collect/regularization/impl/coeff_param.h" // IWYU pragma: keep
32#include "num_collect/util/impl/warn_fast_math_for_bdcsvc.h" // IWYU pragma: keep
33
35
37constexpr auto tikhonov_tag =
38 logging::log_tag_view("num_collect::regularization::tikhonov");
39
46template <base::concepts::dense_matrix Coeff, base::concepts::dense_matrix Data>
48 : public explicit_regularized_solver_base<tikhonov<Coeff, Data>, Data> {
49public:
51 using base_type =
53
54 using typename base_type::data_type;
55 using typename base_type::scalar_type;
56
58 using coeff_type = Coeff;
59
60 static_assert(std::is_same_v<typename coeff_type::Scalar,
61 typename data_type::Scalar>);
62 static_assert(data_type::RowsAtCompileTime == Eigen::Dynamic);
63
68
75 void compute(const coeff_type& coeff, const data_type& data) {
76 svd_.compute(coeff, Eigen::ComputeThinU | Eigen::ComputeThinV);
77 rot_data_ = svd_.matrixU().adjoint() * data;
78 const index_type rank = svd_.nonzeroSingularValues();
79 min_res_ = (data -
80 svd_.matrixU().leftCols(rank) *
81 svd_.matrixU().leftCols(rank).adjoint() * data)
82 .squaredNorm();
83 }
84
86 void solve(const scalar_type& param, data_type& solution) const {
87 solution = data_type::Zero(svd_.cols(), rot_data_.cols());
88 const index_type rank = svd_.nonzeroSingularValues();
89 for (index_type i = 0; i < rank; ++i) {
90 const scalar_type singular_value = singular_values()(i);
91 const scalar_type factor =
92 singular_value / (singular_value * singular_value + param);
93 solution += factor * svd_.matrixV().col(i) * rot_data_.row(i);
94 }
95 }
96
102 [[nodiscard]] auto singular_values() const -> const
103 typename Eigen::BDCSVD<coeff_type>::SingularValuesType& {
104 return svd_.singularValues();
105 }
106
108 [[nodiscard]] auto residual_norm(const scalar_type& param) const
109 -> scalar_type {
110 auto res = static_cast<scalar_type>(0);
111 const index_type rank = svd_.nonzeroSingularValues();
112 for (index_type i = 0; i < rank; ++i) {
113 const scalar_type singular_value = svd_.singularValues()(i);
114 const scalar_type den = singular_value * singular_value + param;
115 res +=
116 (param * param) / (den * den) * rot_data_.row(i).squaredNorm();
117 }
118 return res + min_res_;
119 }
120
122 [[nodiscard]] auto regularization_term(const scalar_type& param) const
123 -> scalar_type {
124 auto res = static_cast<scalar_type>(0);
125 const index_type rank = svd_.nonzeroSingularValues();
126 for (index_type i = 0; i < rank; ++i) {
127 const scalar_type singular_value = svd_.singularValues()(i);
128 const scalar_type den = singular_value * singular_value + param;
129 res += (singular_value * singular_value) / (den * den) *
130 rot_data_.row(i).squaredNorm();
131 }
132 return res;
133 }
134
137 const scalar_type& param) const -> scalar_type {
138 auto res = static_cast<scalar_type>(0);
139 const index_type rank = svd_.nonzeroSingularValues();
140 for (index_type i = 0; i < rank; ++i) {
141 const scalar_type singular_value = svd_.singularValues()(i);
142 const scalar_type den = singular_value * singular_value + param;
143 res += (static_cast<scalar_type>(2) * param * singular_value *
144 singular_value) /
145 (den * den * den) * rot_data_.row(i).squaredNorm();
146 }
147 return res;
148 }
149
152 const scalar_type& param) const -> scalar_type {
153 auto res = static_cast<scalar_type>(0);
154 const index_type rank = svd_.nonzeroSingularValues();
155 for (index_type i = 0; i < rank; ++i) {
156 const scalar_type singular_value = svd_.singularValues()(i);
157 const scalar_type den = singular_value * singular_value + param;
158 res += (-static_cast<scalar_type>(2) * singular_value *
159 singular_value) /
160 (den * den * den) * rot_data_.row(i).squaredNorm();
161 }
162 return res;
163 }
164
167 const scalar_type& param) const -> scalar_type {
168 auto res = static_cast<scalar_type>(0);
169 const index_type rank = svd_.nonzeroSingularValues();
170 for (index_type i = 0; i < rank; ++i) {
171 const scalar_type singular_value = svd_.singularValues()(i);
172 const scalar_type den = singular_value * singular_value + param;
173 res += (static_cast<scalar_type>(2) * singular_value *
174 singular_value * singular_value * singular_value -
175 static_cast<scalar_type>(4) * param * singular_value *
176 singular_value) /
177 (den * den * den * den) * rot_data_.row(i).squaredNorm();
178 }
179 return res;
180 }
181
184 const scalar_type& param) const -> scalar_type {
185 auto res = static_cast<scalar_type>(0);
186 const index_type rank = svd_.nonzeroSingularValues();
187 for (index_type i = 0; i < rank; ++i) {
188 const scalar_type singular_value = svd_.singularValues()(i);
189 const scalar_type den = singular_value * singular_value + param;
190 res += (static_cast<scalar_type>(6) * singular_value * // NOLINT
191 singular_value) /
192 (den * den * den * den) * rot_data_.row(i).squaredNorm();
193 }
194 return res;
195 }
196
198 [[nodiscard]] auto sum_of_filter_factor(const scalar_type& param) const
199 -> scalar_type {
200 auto res = static_cast<scalar_type>(0);
201 const index_type rank = svd_.nonzeroSingularValues();
202 for (index_type i = 0; i < rank; ++i) {
203 const scalar_type singular_value = svd_.singularValues()(i);
204 const scalar_type den = singular_value * singular_value + param;
205 res += singular_value * singular_value / den;
206 }
207 return res;
208 }
209
211 [[nodiscard]] auto data_size() const -> index_type { return svd_.rows(); }
212
214 [[nodiscard]] auto param_search_region() const
215 -> std::pair<scalar_type, scalar_type> {
216 const scalar_type max_singular_value = singular_values()(0);
217 const scalar_type squared_max_singular_value =
218 max_singular_value * max_singular_value;
219 return {impl::coeff_min_param<scalar_type> * squared_max_singular_value,
220 impl::coeff_max_param<scalar_type> * squared_max_singular_value};
221 }
222
223private:
225 Eigen::BDCSVD<coeff_type> svd_{};
226
229
232};
233
234} // namespace num_collect::regularization
Class of tags of logs without memory management.
Base class of solvers using explicit formulas for regularization.
typename Eigen::NumTraits< typename data_type::Scalar >::Real scalar_type
Class to perform Tikhonov regularization.
Definition tikhonov.h:48
auto singular_values() const -> const typename Eigen::BDCSVD< coeff_type >::SingularValuesType &
Get the singular values.
Definition tikhonov.h:102
auto second_derivative_of_residual_norm(const scalar_type &param) const -> scalar_type
Calculate the second-order derivative of the squared norm of the residual.
Definition tikhonov.h:166
auto data_size() const -> index_type
Get the size of data.
Definition tikhonov.h:211
auto sum_of_filter_factor(const scalar_type &param) const -> scalar_type
Calculate the sum of filter factors.
Definition tikhonov.h:198
void solve(const scalar_type &param, data_type &solution) const
Solve for a regularization parameter.
Definition tikhonov.h:86
auto first_derivative_of_residual_norm(const scalar_type &param) const -> scalar_type
Calculate the first-order derivative of the squared norm of the residual.
Definition tikhonov.h:136
auto param_search_region() const -> std::pair< scalar_type, scalar_type >
Get the default region to search for the optimal regularization parameter.
Definition tikhonov.h:214
auto regularization_term(const scalar_type &param) const -> scalar_type
Calculate the regularization term.
Definition tikhonov.h:122
data_type rot_data_
Data in the space of singular values.
Definition tikhonov.h:228
scalar_type min_res_
Minimum residual.
Definition tikhonov.h:231
Eigen::BDCSVD< coeff_type > svd_
SVD of the coefficient matrix.
Definition tikhonov.h:225
auto first_derivative_of_regularization_term(const scalar_type &param) const -> scalar_type
Calculate the first-order derivative of the Regularization term.
Definition tikhonov.h:151
auto residual_norm(const scalar_type &param) const -> scalar_type
Calculate the squared norm of the residual.
Definition tikhonov.h:108
Coeff coeff_type
Type of coefficient matrices.
Definition tikhonov.h:58
auto second_derivative_of_regularization_term(const scalar_type &param) const -> scalar_type
Calculate the send-order derivative of the Regularization term.
Definition tikhonov.h:183
void compute(const coeff_type &coeff, const data_type &data)
Compute internal matrices.
Definition tikhonov.h:75
Definition of tikhonov class.
Definition of dense_matrix concept.
Definition of explicit_regularized_solver_base class.
Definition of index_type type.
Definition of log_tag_view class.
Namespace of Eigen library.
Definition variable.h:416
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
constexpr auto coeff_max_param
Coefficient (maximum parameter to be searched) / (maximum singular value or eigen value).
Definition coeff_param.h:31
constexpr auto coeff_min_param
Coefficient (minimum parameter to be searched) / (maximum singular value or eigen value).
Definition coeff_param.h:40
Namespace of regularization algorithms.
constexpr auto tikhonov_tag
Tag of fista.
Definition tikhonov.h:37
STL namespace.
Header to check and warn about use of fast-math mode for Eigen::BDCSVD.