// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // root_finding_base.hpp #ifndef SANGI_ROOT_FINDING_BASE_HPP #define SANGI_ROOT_FINDING_BASE_HPP #include #include #include #include #include #include #include #include #include #include namespace sangi { /** * @brief 収束判定のための構造体 * 複数の基準を統合して収束判定を行う */ template struct ConvergenceCriteria { // 関数値の絶対許容誤差 T abs_ftol = std::numeric_limits::epsilon() * 100; // 変数値の絶対許容誤差 T abs_xtol = std::numeric_limits::epsilon() * 100; // 関数値の相対許容誤差 T rel_ftol = std::numeric_limits::epsilon() * 1000; // 変数値の相対許容誤差 T rel_xtol = std::numeric_limits::epsilon() * 1000; // 最大反復回数 size_t max_iterations = 100; // 収束判定のための関数値チェック bool is_function_converged(T fx, T fx_prev = T(0)) const { // 絶対値判定 if (std::abs(fx) < abs_ftol) { return true; } // 相対変化量判定 - 前回値がある場合のみ if (fx_prev != T(0)) { T rel_change = std::abs((fx - fx_prev)) / (std::abs(fx_prev) + std::numeric_limits::epsilon()); if (rel_change < rel_ftol) { return true; } } return false; } // 収束判定のための変数値チェック bool is_variable_converged(T x, T x_prev) const { // 絶対変化量判定 if (std::abs(x - x_prev) < abs_xtol) { return true; } // 相対変化量判定 T scale = std::max(T(1), std::abs(x_prev)); if (std::abs((x - x_prev) / scale) < rel_xtol) { return true; } return false; } // 区間幅による収束判定(二分法などで使用) bool is_interval_converged(T a, T b) const { return std::abs(b - a) < abs_xtol || std::abs((b - a) / std::max(T(1), std::max(std::abs(a), std::abs(b)))) < rel_xtol; } // 複合的な収束判定(関数値と変数値の両方を考慮) bool is_converged(T fx, T x, T x_prev) const { return is_function_converged(fx) && is_variable_converged(x, x_prev); } // ベクトル値関数に対する収束判定 template requires concepts::VectorOf bool is_vector_converged(const V& f, const V& x, const V& x_prev) const { T f_norm = norm2(f); T dx_norm = norm2(x - x_prev); T x_norm = norm2(x); return f_norm < abs_ftol || dx_norm < abs_xtol || dx_norm < rel_xtol * (x_norm + abs_xtol); } }; /** * @brief 求根結果を表す構造体 */ template struct RootFindingResult { std::optional root; // 根の近似値(失敗した場合はnullopt) bool converged; // 収束したかどうか size_t iterations; // 実行した反復回数 T error_estimate; // 誤差の推定値 // 成功結果を作成するヘルパー static RootFindingResult success(const T& root_value, size_t iter_count, T err = T(0)) { return {root_value, true, iter_count, err}; } // 失敗結果を作成するヘルパー static RootFindingResult failure(size_t iter_count, T err = T(0)) { return {std::nullopt, false, iter_count, err}; } // オプショナル成功結果(条件付き成功) static RootFindingResult partial_success(const T& root_value, bool conv, size_t iter_count, T err = T(0)) { return {root_value, conv, iter_count, err}; } }; // MKL利用可能性チェック inline constexpr bool has_mkl_support = SANGI_HAS_MKL == 1; } // namespace sangi #endif // SANGI_ROOT_FINDING_BASE_HPP