/builds/MusicScience37Projects/numerical-analysis/numerical-collection-cpp/include/num_collect/regularization/full_gen_tikhonov.h
Line | Count | Source |
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 | | */ |
16 | | /*! |
17 | | * \file |
18 | | * \brief Definition of full_gen_tikhonov class. |
19 | | */ |
20 | | #pragma once |
21 | | |
22 | | #include <type_traits> |
23 | | |
24 | | #include <Eigen/Core> |
25 | | #include <Eigen/Householder> |
26 | | |
27 | | #include "num_collect/base/concepts/dense_matrix.h" |
28 | | #include "num_collect/base/exception.h" |
29 | | #include "num_collect/base/index_type.h" |
30 | | #include "num_collect/base/precondition.h" |
31 | | #include "num_collect/logging/log_tag_view.h" |
32 | | #include "num_collect/logging/logging_macros.h" |
33 | | #include "num_collect/regularization/explicit_regularized_solver_base.h" |
34 | | #include "num_collect/regularization/tikhonov.h" |
35 | | #include "num_collect/util/assert.h" |
36 | | |
37 | | namespace num_collect::regularization { |
38 | | |
39 | | //! Tag of fista. |
40 | | constexpr auto full_gen_tikhonov_tag = |
41 | | logging::log_tag_view("num_collect::regularization::full_gen_tikhonov"); |
42 | | |
43 | | /*! |
44 | | * \brief Class to perform generalized Tikhonov regularization on the condition |
45 | | * that the matrix in the regularization term which have full row rank |
46 | | * \cite Elden1982, \cite Hansen1994. |
47 | | * |
48 | | * \tparam Coeff Type of coefficient matrices. |
49 | | * \tparam Data Type of data vectors. |
50 | | */ |
51 | | template <base::concepts::dense_matrix Coeff, base::concepts::dense_matrix Data> |
52 | | class full_gen_tikhonov |
53 | | : public explicit_regularized_solver_base<full_gen_tikhonov<Coeff, Data>, |
54 | | Data> { |
55 | | public: |
56 | | //! Type of base class. |
57 | | using base_type = |
58 | | explicit_regularized_solver_base<full_gen_tikhonov<Coeff, Data>, Data>; |
59 | | |
60 | | using typename base_type::data_type; |
61 | | using typename base_type::scalar_type; |
62 | | |
63 | | //! Type of coefficient matrices. |
64 | | using coeff_type = Coeff; |
65 | | |
66 | | static_assert(std::is_same_v<typename coeff_type::Scalar, |
67 | | typename data_type::Scalar>); |
68 | | static_assert(data_type::RowsAtCompileTime == Eigen::Dynamic); |
69 | | |
70 | | /*! |
71 | | * \brief Constructor. |
72 | | */ |
73 | 5 | full_gen_tikhonov() : base_type(full_gen_tikhonov_tag) {} |
74 | | |
75 | | /*! |
76 | | * \brief Compute internal matrices. |
77 | | * |
78 | | * This generate arranged problem of Tikhonov regularization as in |
79 | | * \cite Elden1982, \cite Hansen1994. |
80 | | * |
81 | | * \param[in] coeff Coefficient matrix. |
82 | | * \param[in] data Data vector. |
83 | | * \param[in] reg_coeff Coefficient matrix for the regularization term. |
84 | | */ |
85 | | void compute(const coeff_type& coeff, const data_type& data, |
86 | 5 | const coeff_type& reg_coeff) { |
87 | 5 | NUM_COLLECT_PRECONDITION(coeff.rows() == data.rows(), this->logger(), |
88 | 5 | "The number of rows in the coefficient matrix must match the " |
89 | 5 | "number of rows in data."); |
90 | 5 | NUM_COLLECT_PRECONDITION(coeff.cols() == reg_coeff.cols(), |
91 | 5 | this->logger(), |
92 | 5 | "The number of columns in the coefficient matrix must match the " |
93 | 5 | "number of columns in the coefficient matrix of the regularization " |
94 | 5 | "term."); |
95 | 5 | NUM_COLLECT_PRECONDITION(reg_coeff.rows() < reg_coeff.cols(), |
96 | 5 | this->logger(), |
97 | 5 | "Coefficient matrix for the regularization term must have rows " |
98 | 5 | "less than columns."); |
99 | | |
100 | | // How can I implement those complex formulas with good variable names. |
101 | | |
102 | 5 | const index_type m = coeff.rows(); |
103 | 5 | const index_type n = coeff.cols(); |
104 | 5 | const index_type p = reg_coeff.rows(); |
105 | | |
106 | 5 | Eigen::ColPivHouseholderQR<coeff_type> qr_reg_adj; |
107 | 5 | qr_reg_adj.compute(reg_coeff.adjoint()); |
108 | 5 | NUM_COLLECT_PRECONDITION(qr_reg_adj.rank() >= qr_reg_adj.cols(), |
109 | 5 | this->logger(), "reg_coeff must have full row rank."); |
110 | 5 | const coeff_type v = qr_reg_adj.householderQ(); |
111 | | |
112 | 5 | Eigen::ColPivHouseholderQR<coeff_type> qr_coeff_v2; |
113 | 5 | qr_coeff_v2.compute(coeff * v.rightCols(n - p)); |
114 | 5 | NUM_COLLECT_PRECONDITION(qr_coeff_v2.rank() >= qr_coeff_v2.cols(), |
115 | 5 | this->logger(), |
116 | 5 | "reg_coeff and coeff must not have common elements " |
117 | 5 | "other than zero in their kernel."); |
118 | 5 | const coeff_type q = qr_coeff_v2.householderQ(); |
119 | | |
120 | 5 | const coeff_type coeff_arr = |
121 | 5 | qr_reg_adj.solve(coeff.adjoint() * q.rightCols(m - n + p)) |
122 | 5 | .adjoint(); |
123 | 5 | const data_type data_arr = q.rightCols(m - n + p).adjoint() * data; |
124 | 5 | tikhonov_.compute(coeff_arr, data_arr); |
125 | | |
126 | 5 | const coeff_type coeff_v2_inv_coeff = qr_coeff_v2.solve(coeff); |
127 | 5 | const coeff_type i_minus_v2_coeff_v2_inv_coeff = |
128 | 5 | coeff_type::Identity(n, n) - |
129 | 5 | v.rightCols(n - p) * coeff_v2_inv_coeff; |
130 | 5 | coeff_actual_solution_ = |
131 | 5 | qr_reg_adj.solve(i_minus_v2_coeff_v2_inv_coeff.adjoint()).adjoint(); |
132 | | |
133 | 5 | const data_type coeff_v2_inv_data = qr_coeff_v2.solve(data); |
134 | 5 | offset_actual_solution_ = v.rightCols(n - p) * coeff_v2_inv_data; |
135 | 5 | } |
136 | | |
137 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::solve |
138 | 3 | void solve(const scalar_type& param, data_type& solution) const { |
139 | 3 | data_type tikhonov_solution; |
140 | 3 | tikhonov_.solve(param, tikhonov_solution); |
141 | 3 | solution = coeff_actual_solution_ * tikhonov_solution + |
142 | 3 | offset_actual_solution_; |
143 | 3 | } |
144 | | |
145 | | /*! |
146 | | * \brief Get the singular values. |
147 | | * |
148 | | * \return Singular values. |
149 | | */ |
150 | | [[nodiscard]] auto singular_values() const -> const |
151 | 1 | typename Eigen::BDCSVD<coeff_type>::SingularValuesType& { |
152 | 1 | return tikhonov_.singular_values(); |
153 | 1 | } |
154 | | |
155 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::residual_norm |
156 | | [[nodiscard]] auto residual_norm(const scalar_type& param) const |
157 | 1 | -> scalar_type { |
158 | 1 | return tikhonov_.residual_norm(param); |
159 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE13residual_normERKd Line | Count | Source | 157 | 1 | -> scalar_type { | 158 | 1 | return tikhonov_.residual_norm(param); | 159 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E13residual_normERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE13residual_normERKd |
160 | | |
161 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::regularization_term |
162 | | [[nodiscard]] auto regularization_term(const scalar_type& param) const |
163 | 1 | -> scalar_type { |
164 | 1 | return tikhonov_.regularization_term(param); |
165 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE19regularization_termERKd Line | Count | Source | 163 | 1 | -> scalar_type { | 164 | 1 | return tikhonov_.regularization_term(param); | 165 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E19regularization_termERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE19regularization_termERKd |
166 | | |
167 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::first_derivative_of_residual_norm |
168 | | [[nodiscard]] auto first_derivative_of_residual_norm( |
169 | 1 | const scalar_type& param) const -> scalar_type { |
170 | 1 | return tikhonov_.first_derivative_of_residual_norm(param); |
171 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE33first_derivative_of_residual_normERKd Line | Count | Source | 169 | 1 | const scalar_type& param) const -> scalar_type { | 170 | 1 | return tikhonov_.first_derivative_of_residual_norm(param); | 171 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E33first_derivative_of_residual_normERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE33first_derivative_of_residual_normERKd |
172 | | |
173 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::first_derivative_of_regularization_term |
174 | | [[nodiscard]] auto first_derivative_of_regularization_term( |
175 | 1 | const scalar_type& param) const -> scalar_type { |
176 | 1 | return tikhonov_.first_derivative_of_regularization_term(param); |
177 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE39first_derivative_of_regularization_termERKd Line | Count | Source | 175 | 1 | const scalar_type& param) const -> scalar_type { | 176 | 1 | return tikhonov_.first_derivative_of_regularization_term(param); | 177 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E39first_derivative_of_regularization_termERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE39first_derivative_of_regularization_termERKd |
178 | | |
179 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::second_derivative_of_residual_norm |
180 | | [[nodiscard]] auto second_derivative_of_residual_norm( |
181 | 1 | const scalar_type& param) const -> scalar_type { |
182 | 1 | return tikhonov_.second_derivative_of_residual_norm(param); |
183 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE34second_derivative_of_residual_normERKd Line | Count | Source | 181 | 1 | const scalar_type& param) const -> scalar_type { | 182 | 1 | return tikhonov_.second_derivative_of_residual_norm(param); | 183 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E34second_derivative_of_residual_normERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE34second_derivative_of_residual_normERKd |
184 | | |
185 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::second_derivative_of_regularization_term |
186 | | [[nodiscard]] auto second_derivative_of_regularization_term( |
187 | 1 | const scalar_type& param) const -> scalar_type { |
188 | 1 | return tikhonov_.second_derivative_of_regularization_term(param); |
189 | 1 | } _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEENS3_IdLin1ELi1ELi0ELin1ELi1EEEE40second_derivative_of_regularization_termERKd Line | Count | Source | 187 | 1 | const scalar_type& param) const -> scalar_type { | 188 | 1 | return tikhonov_.second_derivative_of_regularization_term(param); | 189 | 1 | } |
Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixIdLin1ELin1ELi0ELin1ELin1EEES4_E40second_derivative_of_regularization_termERKd Unexecuted instantiation: _ZNK11num_collect14regularization17full_gen_tikhonovIN5Eigen6MatrixINSt3__17complexIdEELin1ELin1ELi0ELin1ELin1EEENS3_IS6_Lin1ELi1ELi0ELin1ELi1EEEE40second_derivative_of_regularization_termERKd |
190 | | |
191 | | //! \copydoc num_collect::regularization::explicit_regularized_solver_base::sum_of_filter_factor |
192 | | [[nodiscard]] auto sum_of_filter_factor(const scalar_type& param) const |
193 | 1 | -> scalar_type { |
194 | 1 | return tikhonov_.sum_of_filter_factor(param); |
195 | 1 | } |
196 | | |
197 | | //! \copydoc num_collect::regularization::regularized_solver_base::data_size |
198 | 1 | [[nodiscard]] auto data_size() const -> index_type { |
199 | 1 | return tikhonov_.data_size(); |
200 | 1 | } |
201 | | |
202 | | //! \copydoc num_collect::regularization::regularized_solver_base::param_search_region |
203 | | [[nodiscard]] auto param_search_region() const |
204 | 1 | -> std::pair<scalar_type, scalar_type> { |
205 | 1 | return tikhonov_.param_search_region(); |
206 | 1 | } |
207 | | |
208 | | /*! |
209 | | * \brief Access to the internal solver (for debug). |
210 | | * |
211 | | * \return Internal solver. |
212 | | */ |
213 | | [[nodiscard]] auto internal_solver() const |
214 | 10 | -> const tikhonov<coeff_type, data_type>& { |
215 | 10 | return tikhonov_; |
216 | 10 | } |
217 | | |
218 | | private: |
219 | | //! Object to perform Tikhonov regularization. |
220 | | tikhonov<coeff_type, data_type> tikhonov_{}; |
221 | | |
222 | | //! Coefficient matrix to calculate actual solution. |
223 | | Coeff coeff_actual_solution_{}; |
224 | | |
225 | | //! Offset vector to calculate actual solution. |
226 | | Data offset_actual_solution_{}; |
227 | | }; |
228 | | |
229 | | } // namespace num_collect::regularization |