numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
tgv2_admm.h
Go to the documentation of this file.
1/*
2 * Copyright 2025 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
36#include "num_collect/regularization/impl/weak_coeff_param.h" // IWYU pragma: keep
38
40
42constexpr auto tgv2_admm_tag =
43 logging::log_tag_view("num_collect::regularization::tgv2_admm");
44
173template <typename Coeff, typename DerivativeMatrix,
180 tgv2_admm<Coeff, DerivativeMatrix, Data>, Data> {
181public:
184
187
188 using typename base_type::data_type;
189 using typename base_type::scalar_type;
190
192 using coeff_type = Coeff;
193
195 using derivative_matrix_type = DerivativeMatrix;
196
205
220 void compute(const Coeff& coeff,
221 const DerivativeMatrix& first_derivative_matrix,
222 const DerivativeMatrix& second_derivative_matrix, const Data& data) {
223 coeff_ = &coeff;
224 first_derivative_matrix_ = &first_derivative_matrix;
225 second_derivative_matrix_ = &second_derivative_matrix;
226 data_ = &data;
227 // Sizes will be checked in init.
228 }
229
231 void init(const scalar_type& param, data_type& solution) {
232 (void)param;
233
234 NUM_COLLECT_PRECONDITION(coeff_ != nullptr, this->logger(),
235 "Coefficient matrix is not set.");
237 this->logger(), "First order derivative matrix is not set.");
239 this->logger(), "Second order derivative matrix is not set.");
241 data_ != nullptr, this->logger(), "Data vector is not set.");
242
243 NUM_COLLECT_PRECONDITION(coeff_->rows() == data_->rows(),
244 this->logger(),
245 "Coefficient matrix and data vector must have the same number of "
246 "rows.");
247 NUM_COLLECT_PRECONDITION(coeff_->cols() == solution.rows(),
248 this->logger(),
249 "The number of columns in the coefficient matrix must match the "
250 "number of rows in solution vector.");
251 NUM_COLLECT_PRECONDITION(data_->cols() == solution.cols(),
252 this->logger(),
253 "Data and solution must have the same number of columns.");
255 first_derivative_matrix_->cols() == solution.rows(), this->logger(),
256 "The number of columns in the first order derivative matrix must "
257 "match the number of rows in solution vector.");
260 this->logger(),
261 "The number of columns in the second order derivative matrix must "
262 "match the number of rows in the first order derivative matrix.");
263
264 iterations_ = 0;
265
266 // Set variables to one of feasible solutions.
267 z_ = data_type::Zero(first_derivative_matrix_->rows());
268 s_ = (*first_derivative_matrix_) * solution;
269 t_ = data_type::Zero(second_derivative_matrix_->rows());
270 p_ = data_type::Zero(first_derivative_matrix_->rows());
271 u_ = data_type::Zero(second_derivative_matrix_->rows());
272
273 // Pre-allocate temporary vectors.
274 temp_solution_ = data_type::Zero(solution.rows());
275 temp_data_ = data_type::Zero(data_->rows());
276 temp_z_ = data_type::Zero(z_.rows());
277 temp_t_ = data_type::Zero(t_.rows());
278 previous_solution_ = data_type::Zero(solution.rows());
279 previous_z_ = data_type::Zero(z_.rows());
280 previous_s_ = data_type::Zero(s_.rows());
281 previous_t_ = data_type::Zero(t_.rows());
282 p_update_ = data_type::Zero(p_.rows());
283 u_update_ = data_type::Zero(u_.rows());
284
285 residual_ = (*coeff_) * solution - (*data_);
286 update_rate_ = std::numeric_limits<scalar_type>::infinity();
287
288 const scalar_type conjugate_gradient_tolerance_rate =
290 conjugate_gradient_solution_.tolerance_rate(
291 conjugate_gradient_tolerance_rate);
292 conjugate_gradient_z_.tolerance_rate(conjugate_gradient_tolerance_rate);
293 }
294
296 void iterate(const scalar_type& param, data_type& solution) {
297 update_rate_ = static_cast<scalar_type>(0);
298
299 update_solution(param, solution);
300 update_z(param, solution);
301 update_s(param, solution);
302 update_t(param, solution);
303 update_p(param, solution);
304 update_u(param, solution);
305
306 ++iterations_;
307 }
308
310 [[nodiscard]] auto is_stop_criteria_satisfied(
311 const data_type& solution) const -> bool {
312 (void)solution;
313 return (iterations() > max_iterations()) ||
315 }
316
320 const {
321 iteration_logger.template append<index_type>(
322 "Iter.", &this_type::iterations);
323 iteration_logger.template append<scalar_type>(
324 "UpdateRate", &this_type::update_rate);
325 iteration_logger.template append<scalar_type>(
326 "Res.Rate", &this_type::residual_norm_rate);
327 }
328
330 [[nodiscard]] auto residual_norm(const data_type& solution) const
331 -> scalar_type {
332 return ((*coeff_) * solution - (*data_)).squaredNorm();
333 }
334
336 [[nodiscard]] auto regularization_term(const data_type& solution) const
337 -> scalar_type {
338 return (*first_derivative_matrix_ * solution).template lpNorm<1>();
339 }
340
342 void change_data(const data_type& data) { data_ = &data; }
343
345 void calculate_data_for(const data_type& solution, data_type& data) const {
346 data = (*coeff_) * solution;
347 }
348
350 [[nodiscard]] auto data_size() const -> index_type { return data_->size(); }
351
353 [[nodiscard]] auto param_search_region() const
354 -> std::pair<scalar_type, scalar_type> {
355 const data_type approx_order_of_solution = coeff_->transpose() *
357 const scalar_type approx_order_of_param =
358 (*first_derivative_matrix_ * approx_order_of_solution)
359 .cwiseAbs()
360 .maxCoeff();
362 this->logger(), "approx_order_of_param={}", approx_order_of_param);
363 constexpr auto tol_update_coeff_multiplier =
364 static_cast<scalar_type>(10);
365 return {approx_order_of_param *
367 tol_update_coeff_multiplier * tol_update_rate_),
368 approx_order_of_param * impl::weak_coeff_max_param<scalar_type>};
369 }
370
376 [[nodiscard]] auto iterations() const noexcept -> index_type {
377 return iterations_;
378 }
379
386 [[nodiscard]] auto update_rate() const noexcept -> scalar_type {
387 return update_rate_;
388 }
389
395 [[nodiscard]] auto residual_norm_rate() const -> scalar_type {
396 return residual_.squaredNorm() / data_->squaredNorm();
397 }
398
404 [[nodiscard]] auto max_iterations() const -> index_type {
405 return max_iterations_;
406 }
407
415 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
416 "Maximum number of iterations must be a positive integer.");
417 max_iterations_ = value;
418 return *this;
419 }
420
426 [[nodiscard]] auto tol_update_rate() const -> scalar_type {
427 return tol_update_rate_;
428 }
429
437 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
438 "Tolerance of update rate of the solution must be a positive "
439 "value.");
440 tol_update_rate_ = value;
441 return *this;
442 }
443
444private:
451 void update_solution(const scalar_type& param, data_type& solution) {
452 (void)param; // Not used for update of solution.
453
455 temp_solution_.noalias() =
456 static_cast<scalar_type>(2) * (*coeff_).transpose() * (*data_);
457 temp_solution_.noalias() +=
458 (*first_derivative_matrix_).transpose() * temp_z_;
459 previous_solution_ = solution;
461 [this](const data_type& target, data_type& result) {
462 temp_data_.noalias() = (*coeff_) * target;
463 result.noalias() = static_cast<scalar_type>(2) *
464 (*coeff_).transpose() * temp_data_;
465 temp_z_.noalias() = (*first_derivative_matrix_) * target;
466 result.noalias() += constraint_coeff_ *
467 (*first_derivative_matrix_).transpose() * temp_z_;
468 },
469 temp_solution_, solution);
470 update_rate_ += (solution - previous_solution_).norm() /
471 (solution.norm() + std::numeric_limits<scalar_type>::epsilon());
472 residual_.noalias() = (*coeff_) * solution;
473 residual_ -= (*data_);
474 }
475
482 void update_z(const scalar_type& param, const data_type& solution) {
483 (void)param; // Not used for update of z_.
484
485 temp_z_ = p_;
486 temp_z_.noalias() -= (*second_derivative_matrix_).transpose() * u_;
487 temp_z_.noalias() +=
488 constraint_coeff_ * (*first_derivative_matrix_) * solution;
489 temp_z_.noalias() -= constraint_coeff_ * s_;
490 temp_z_.noalias() +=
491 constraint_coeff_ * (*second_derivative_matrix_).transpose() * t_;
492 previous_z_ = z_;
494 [this](const data_type& target, data_type& result) {
495 result.noalias() = constraint_coeff_ * target;
496 temp_t_.noalias() = (*second_derivative_matrix_) * target;
497 result.noalias() += constraint_coeff_ *
498 (*second_derivative_matrix_).transpose() * temp_t_;
499 },
500 temp_z_, z_);
502 (z_.norm() + std::numeric_limits<scalar_type>::epsilon());
503 }
504
511 void update_s(const scalar_type& param, const data_type& solution) {
512 previous_s_ = s_;
513 s_.noalias() = (*first_derivative_matrix_) * solution;
514 s_ += -z_ + p_ / constraint_coeff_;
517 (s_.norm() + std::numeric_limits<scalar_type>::epsilon());
518 }
519
526 void update_t(const scalar_type& param, const data_type& solution) {
527 (void)solution; // Not used for update of t_.
528
529 previous_t_ = t_;
530 t_.noalias() = (*second_derivative_matrix_) * z_;
535 (t_.norm() + std::numeric_limits<scalar_type>::epsilon());
536 }
537
544 void update_p(const scalar_type& param, const data_type& solution) {
545 (void)param; // Not used for update of p_.
546
547 p_update_.noalias() =
548 constraint_coeff_ * (*first_derivative_matrix_) * solution;
550 p_ += p_update_;
551 update_rate_ += p_update_.norm() /
552 (p_.norm() + std::numeric_limits<scalar_type>::epsilon());
553 }
554
561 void update_u(const scalar_type& param, const data_type& solution) {
562 (void)param; // Not used for update of u_.
563 (void)solution; // Not used for update of u_.
564
565 u_update_.noalias() =
566 constraint_coeff_ * (*second_derivative_matrix_) * z_;
568 u_ += u_update_;
569 update_rate_ += u_update_.norm() /
570 (u_.norm() + std::numeric_limits<scalar_type>::epsilon());
571 }
572
574 const coeff_type* coeff_{nullptr};
575
578
581
583 const data_type* data_{nullptr};
584
587
590
593
596
599
602
605
608
611
614
617
620
623
626
629
632
635
638
642
646
648 static constexpr auto default_second_derivative_ratio =
649 static_cast<scalar_type>(1);
650
653
655 static constexpr auto default_constraint_coeff =
656 static_cast<scalar_type>(1);
657
660
662 static constexpr index_type default_max_iterations = 100000;
663
666
668 static constexpr auto default_tol_update_rate =
669 static_cast<scalar_type>(1e-4);
670
673
676 static_cast<scalar_type>(1e-2);
677
681};
682
683} // 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.
void configure_child_algorithm_logger_if_exists(Child &child)
Configure a logger of a child algorithm if exists.
auto logger() const noexcept -> const num_collect::logging::logger &
Access to the logger.
typename Eigen::NumTraits< typename data_type::Scalar >::Real scalar_type
Type of scalars.
linear::impl::operator_conjugate_gradient< data_type > conjugate_gradient_solution_
Conjugate gradient solver for update of the solution.
Definition tgv2_admm.h:641
void update_solution(const scalar_type &param, data_type &solution)
Update the solution.
Definition tgv2_admm.h:451
scalar_type tol_update_rate_
Tolerance of update rate of the solution.
Definition tgv2_admm.h:672
data_type previous_solution_
Previous solution.
Definition tgv2_admm.h:616
void init(const scalar_type &param, data_type &solution)
Initialize.
Definition tgv2_admm.h:231
void change_data(const data_type &data)
Change data.
Definition tgv2_admm.h:342
index_type iterations_
Number of iterations.
Definition tgv2_admm.h:586
auto is_stop_criteria_satisfied(const data_type &solution) const -> bool
Determine if stopping criteria of the algorithm are satisfied.
Definition tgv2_admm.h:310
void update_p(const scalar_type &param, const data_type &solution)
Update p_.
Definition tgv2_admm.h:544
static constexpr auto default_constraint_coeff
Default coefficient of the constraint for the derivative.
Definition tgv2_admm.h:655
auto regularization_term(const data_type &solution) const -> scalar_type
Calculate the regularization term.
Definition tgv2_admm.h:336
static constexpr auto default_second_derivative_ratio
Default ratio of regularization term for the 2nd order derivative.
Definition tgv2_admm.h:648
auto param_search_region() const -> std::pair< scalar_type, scalar_type >
Get the default region to search for the optimal regularization parameter.
Definition tgv2_admm.h:353
void update_z(const scalar_type &param, const data_type &solution)
Update z_.
Definition tgv2_admm.h:482
data_type u_update_
Update of u_.
Definition tgv2_admm.h:631
static constexpr index_type default_max_iterations
Default maximum number of iterations.
Definition tgv2_admm.h:662
data_type p_
Lagrange multiplier for the 1st order derivative constraint.
Definition tgv2_admm.h:598
data_type previous_t_
Previous value of t_.
Definition tgv2_admm.h:625
data_type residual_
Residual vector.
Definition tgv2_admm.h:634
void compute(const Coeff &coeff, const DerivativeMatrix &first_derivative_matrix, const DerivativeMatrix &second_derivative_matrix, const Data &data)
Compute internal parameters.
Definition tgv2_admm.h:220
auto residual_norm_rate() const -> scalar_type
Get the rate of the last residual norm.
Definition tgv2_admm.h:395
data_type previous_z_
Previous value of z_.
Definition tgv2_admm.h:619
const derivative_matrix_type * second_derivative_matrix_
Matrix to compute the second order derivative.
Definition tgv2_admm.h:580
auto update_rate() const noexcept -> scalar_type
Get the rate of the norm of the update of the solution in the last iteration.
Definition tgv2_admm.h:386
scalar_type constraint_coeff_
Coefficient of the constraint for the derivative.
Definition tgv2_admm.h:659
scalar_type rate_of_cg_tol_rate_to_tol_update_rate_
Rate of the ratio of the rate of tolerance in CG method to the tolerance of update rate of the soluti...
Definition tgv2_admm.h:679
auto max_iterations(index_type value) -> this_type &
Set the maximum number of iterations.
Definition tgv2_admm.h:414
void configure_iteration_logger(logging::iterations::iteration_logger< this_type > &iteration_logger) const
Configure an iteration logger.
Definition tgv2_admm.h:318
void update_u(const scalar_type &param, const data_type &solution)
Update u_.
Definition tgv2_admm.h:561
auto data_size() const -> index_type
Get the size of data.
Definition tgv2_admm.h:350
data_type s_
Component of the 1st order derivative for regularization.
Definition tgv2_admm.h:592
data_type temp_solution_
Temporary vector for the update of the solution.
Definition tgv2_admm.h:604
auto residual_norm(const data_type &solution) const -> scalar_type
Calculate the squared norm of the residual.
Definition tgv2_admm.h:330
void update_t(const scalar_type &param, const data_type &solution)
Update t_.
Definition tgv2_admm.h:526
index_type max_iterations_
Maximum number of iterations.
Definition tgv2_admm.h:665
auto tol_update_rate(scalar_type value) -> this_type &
Set the tolerance of update rate of the solution.
Definition tgv2_admm.h:436
data_type temp_z_
Temporary vector for the update of the 1st order derivative.
Definition tgv2_admm.h:610
Coeff coeff_type
Type of coefficient matrices.
Definition tgv2_admm.h:192
data_type p_update_
Update of p_.
Definition tgv2_admm.h:628
void update_s(const scalar_type &param, const data_type &solution)
Update s_.
Definition tgv2_admm.h:511
static constexpr auto default_rate_of_cg_tol_rate_to_tol_update_rate
Default value of the ratio of the rate of tolerance in CG method to the tolerance of update rate of t...
Definition tgv2_admm.h:675
const data_type * data_
Data vector.
Definition tgv2_admm.h:583
data_type z_
Component of the 1st order derivative.
Definition tgv2_admm.h:589
const derivative_matrix_type * first_derivative_matrix_
Matrix to compute the first order derivative.
Definition tgv2_admm.h:577
data_type temp_data_
Temporary vector with the size of data.
Definition tgv2_admm.h:607
data_type t_
2nd order derivative of the solution.
Definition tgv2_admm.h:595
data_type previous_s_
Previous value of s_.
Definition tgv2_admm.h:622
void calculate_data_for(const data_type &solution, data_type &data) const
Calculate data for a solution.
Definition tgv2_admm.h:345
scalar_type update_rate_
Rate of norm of the update of the variables in the last iteration.
Definition tgv2_admm.h:637
data_type temp_t_
Temporary vector for the update of the 2nd order derivative.
Definition tgv2_admm.h:613
auto max_iterations() const -> index_type
Get the maximum number of iterations.
Definition tgv2_admm.h:404
DerivativeMatrix derivative_matrix_type
Type of matrices to compute derivatives.
Definition tgv2_admm.h:195
const coeff_type * coeff_
Coefficient matrix to compute data vector.
Definition tgv2_admm.h:574
tgv2_admm< Coeff, DerivativeMatrix, Data > this_type
This type.
Definition tgv2_admm.h:183
data_type u_
Lagrange multiplier for the 2nd order derivative constraint.
Definition tgv2_admm.h:601
auto iterations() const noexcept -> index_type
Get the number of iterations.
Definition tgv2_admm.h:376
auto tol_update_rate() const -> scalar_type
Get the tolerance of update rate of the solution.
Definition tgv2_admm.h:426
scalar_type second_derivative_ratio_
Ratio of regularization term for the 2nd order derivative.
Definition tgv2_admm.h:652
static constexpr auto default_tol_update_rate
Default tolerance of update rate of the solution.
Definition tgv2_admm.h:668
void iterate(const scalar_type &param, data_type &solution)
Iterate the algorithm once.
Definition tgv2_admm.h:296
linear::impl::operator_conjugate_gradient< data_type > conjugate_gradient_z_
Conjugate gradient solver for update of the 1st order derivative.
Definition tgv2_admm.h:645
iterative_regularized_solver_base< this_type, Data > base_type
Type of the base class.
Definition tgv2_admm.h:186
Concept of Eigen's dense matrices.
Concept of Eigen's dense vectors.
Definition of dense_matrix concept.
Definition of dense_vector concept.
Definition of index_type type.
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 tgv2_admm_tag
Tag of tgv2_admm.
Definition tgv2_admm.h:42
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.