// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later /** * @file convergence_criteria.hpp * @brief Definitions of convergence criteria for numerical algorithms * @author MKL Algebra Library */ #ifndef SANGI_CONVERGENCE_CRITERIA_HPP #define SANGI_CONVERGENCE_CRITERIA_HPP #include #include #include #include #include "../concepts/algebraic_concepts.hpp" namespace sangi { /** * @brief Convergence criteria class for numerical algorithms * * Defines convergence criteria for iterative numerical solvers. * Supports judgment by absolute error, relative error, and maximum iteration count. * * @tparam T value type (typically a floating-point type) */ template requires concepts::OrderedField class ConvergenceCriteria { private: T abs_tol_; ///< Absolute tolerance T rel_tol_; ///< Relative tolerance std::size_t max_iter_; ///< Maximum number of iterations public: /** * @brief Default constructor * * Sets default values: * - Absolute tolerance: 1e-8 (for double precision) * - Relative tolerance: 1e-6 (for double precision) * - Maximum iteration count: 1000 */ ConvergenceCriteria() : abs_tol_(std::is_same_v ? 1e-6f : 1e-8) , rel_tol_(std::is_same_v ? 1e-4f : 1e-6) , max_iter_(1000) { } /** * @brief Constructor with explicit parameters * * @param abs_tol absolute tolerance * @param rel_tol relative tolerance * @param max_iter maximum number of iterations */ ConvergenceCriteria(T abs_tol, T rel_tol, std::size_t max_iter) : abs_tol_(abs_tol) , rel_tol_(rel_tol) , max_iter_(max_iter) { validate_parameters(); } /** * @brief Get the absolute tolerance * * @return absolute tolerance */ T absolute_tolerance() const { return abs_tol_; } /** * @brief Set the absolute tolerance * * @param tol new absolute tolerance */ void set_absolute_tolerance(T tol) { abs_tol_ = tol; validate_parameters(); } /** * @brief Get the relative tolerance * * @return relative tolerance */ T relative_tolerance() const { return rel_tol_; } /** * @brief Set the relative tolerance * * @param tol new relative tolerance */ void set_relative_tolerance(T tol) { rel_tol_ = tol; validate_parameters(); } /** * @brief Get the maximum number of iterations * * @return maximum number of iterations */ std::size_t max_iterations() const { return max_iter_; } /** * @brief Set the maximum number of iterations * * @param iter new maximum number of iterations */ void set_max_iterations(std::size_t iter) { max_iter_ = iter; } /** * @brief Check whether the given norm value satisfies the convergence criterion * * Returns true if either the absolute or the relative criterion is satisfied. * * @param norm current norm value * @param initial_norm initial norm value (for relative error calculation) * @return true if the convergence criterion is satisfied */ bool converged(T norm, T initial_norm) const { return norm <= abs_tol_ || norm <= rel_tol_ * initial_norm; } /** * @brief Check whether the given error value satisfies the absolute-error criterion * * @param error current error value * @return true if the absolute-error criterion is satisfied */ bool absolute_converged(T error) const { return error <= abs_tol_; } /** * @brief Check whether the given error value satisfies the relative-error criterion * * @param error current error value * @param reference reference value (typically the norm of the initial or target value) * @return true if the relative-error criterion is satisfied */ bool relative_converged(T error, T reference) const { return error <= rel_tol_ * reference; } /** * @brief Check whether the given iteration count exceeds the maximum * * @param iter current iteration count * @return true if the iteration count exceeds the maximum */ bool max_iterations_exceeded(std::size_t iter) const { return iter >= max_iter_; } /** * @brief Set strict convergence judgment mode * * Strict mode requires both the absolute and the relative criteria to be satisfied. * * @param strict true to enable strict mode */ void set_strict_mode(bool strict = true) { // This simple implementation does not provide strict mode, // but the function is defined for future extensibility. } /** * @brief Get the details of the convergence criteria as a string * * @return string describing the convergence criteria */ std::string to_string() const { std::ostringstream oss; oss << "ConvergenceCriteria:\n"; oss << " Absolute tolerance: " << abs_tol_ << "\n"; oss << " Relative tolerance: " << rel_tol_ << "\n"; oss << " Maximum iterations: " << max_iter_; return oss.str(); } /** * @brief Convert convergence status to a numeric state * * @param converged whether convergence was achieved * @param max_iter_exceeded whether the maximum iteration count was exceeded * @param error variable into which error information is stored * @return the corresponding numeric state */ NumericState to_numeric_state(bool converged, bool max_iter_exceeded, NumericError& error) const { if (converged) { error = NumericError::None; return NumericState::Normal; } if (max_iter_exceeded) { error = NumericError::ConditionalConvergenceViolation; return NumericState::TruncatedConvergence; } error = NumericError::DivergenceError; return NumericState::NotConverged; } private: /** * @brief Validate parameters * * Throws an exception if invalid parameters are set. */ void validate_parameters() { if (abs_tol_ < 0) { throw std::invalid_argument("Absolute tolerance must be non-negative"); } if (rel_tol_ < 0) { throw std::invalid_argument("Relative tolerance must be non-negative"); } // If a value smaller than machine epsilon is set, we could issue a // warning or clamp it to the minimum value. const T eps = std::numeric_limits::epsilon(); if (abs_tol_ < eps) { abs_tol_ = eps; } if (rel_tol_ < eps) { rel_tol_ = eps; } } }; // Alias templates for common cases /** * @brief Convergence criteria for single-precision floating point */ using FloatConvergenceCriteria = ConvergenceCriteria; /** * @brief Convergence criteria for double-precision floating point */ using DoubleConvergenceCriteria = ConvergenceCriteria; // MKL-specific specializations (implement as needed) #ifdef SANGI_USE_MKL // Place MKL-specific specializations and extensions here #endif } // namespace sangi #endif // SANGI_CONVERGENCE_CRITERIA_HPP