// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later namespace sangi { // Int型の前方宣言(循環参照を避けるため) class Int; namespace concepts { // 基本コンセプトの前方宣言 template concept Field = requires(T a, T b) { { a + b } -> std::convertible_to; { a - b } -> std::convertible_to; { a* b } -> std::convertible_to; { a / b } -> std::convertible_to; { -a } -> std::convertible_to; { T(0) } -> std::convertible_to; { T(1) } -> std::convertible_to; }; template concept OrderedField = Field && requires(T a, T b) { { a < b } -> std::convertible_to; { a <= b } -> std::convertible_to; { a > b } -> std::convertible_to; { a >= b } -> std::convertible_to; }; template concept VectorSpace = requires(V v, V w, S s) { { v + w } -> std::convertible_to; { v - w } -> std::convertible_to; { s* v } -> std::convertible_to; { v* s } -> std::convertible_to; { -v } -> std::convertible_to; }; template concept MatrixOf = requires(M m, std::size_t i, std::size_t j) { typename M::value_type; { m(i, j) } -> std::convertible_to; { m.rows() } -> std::convertible_to; { m.cols() } -> std::convertible_to; }; template concept VectorOf = requires(V v, std::size_t i) { typename V::value_type; { v[i] } -> std::convertible_to; { v.size() } -> std::convertible_to; }; // 数値状態管理のサポートコンセプト template concept HasDivergenceHandling = requires(T a) { { numeric_state_traits::isNotConverged(a) } -> std::convertible_to; { numeric_state_traits::getDivergenceDetail(a) } -> std::convertible_to; }; template concept HasOverflowDetection = requires(T a) { { numeric_state_traits::isOverflow(a) } -> std::convertible_to; }; // 数値状態管理の検出と処理が可能な型 template concept HasNumericState = requires(T a) { { a.isNormal() } -> std::convertible_to; { a.isNaN() } -> std::convertible_to; { a.isInfinite() } -> std::convertible_to; { a.getState() } -> std::convertible_to; }; } // 数値型特性 // 数値型カテゴリの識別 struct numeric_category_tag {}; struct real_tag : numeric_category_tag {}; struct complex_tag : numeric_category_tag {}; struct integer_tag : real_tag {}; struct floating_point_tag : real_tag {}; // 数値型特性の基本テンプレート template struct numeric_traits { // デフォルトは未定義 static constexpr bool is_supported = false; static constexpr T abs(T x) { return x < T(0) ? -x : x; } /// ピボット選択: a は b より良いピボットか? /// 既定: |a| > |b| (絶対値最大が安定) /// Rational 等の厳密型では高さ最小にオーバーライドする static bool pivotBetter(const T& a, const T& b) { return abs(a) > abs(b); } }; // 特殊化: 浮動小数点型 template<> struct numeric_traits { using value_type = float; using category = floating_point_tag; static constexpr bool is_supported = true; static constexpr bool is_complex = false; static constexpr bool is_integer = false; static constexpr bool is_floating_point = true; static constexpr float zero() { return 0.0f; } static constexpr float one() { return 1.0f; } static constexpr float epsilon() { return std::numeric_limits::epsilon(); } static constexpr float infinity() { return std::numeric_limits::infinity(); } static constexpr float quiet_NaN() { return std::numeric_limits::quiet_NaN(); } static constexpr float abs(float value) { return value < 0.0f ? -value : value; } static constexpr float conj(float value) { return value; } static constexpr float norm(float value) { return value * value; } static bool pivotBetter(float a, float b) { return abs(a) > abs(b); } // 数値状態関連のユーティリティ - constexprを削除 static bool isNaN(float value) { return std::isnan(value); } static bool isInfinite(float value) { return std::isinf(value); } static bool isNormal(float value) { return std::isnormal(value); } static bool isFinite(float value) { return std::isfinite(value); } static NumericState getState(float value) { if (std::isnan(value)) return NumericState::NaN; if (std::isinf(value)) { return value > 0 ? NumericState::PositiveInfinity : NumericState::NegativeInfinity; } if (std::isnormal(value) || value == 0.0f) return NumericState::Normal; return NumericState::Subnormal; } static NumericError getError(float value) { if (std::isnan(value)) return NumericError::ExplicitNaN; return NumericError::None; } }; template<> struct numeric_traits { using value_type = double; using category = floating_point_tag; static constexpr bool is_supported = true; static constexpr bool is_complex = false; static constexpr bool is_integer = false; static constexpr bool is_floating_point = true; static constexpr double zero() { return 0.0; } static constexpr double one() { return 1.0; } static constexpr double epsilon() { return std::numeric_limits::epsilon(); } static constexpr double infinity() { return std::numeric_limits::infinity(); } static constexpr double quiet_NaN() { return std::numeric_limits::quiet_NaN(); } static constexpr double abs(double value) { return value < 0.0 ? -value : value; } static constexpr double conj(double value) { return value; } static constexpr double norm(double value) { return value * value; } static bool pivotBetter(double a, double b) { return abs(a) > abs(b); } // 数値状態関連のユーティリティ - constexprを削除 static bool isNaN(double value) { return std::isnan(value); } static bool isInfinite(double value) { return std::isinf(value); } static bool isNormal(double value) { return std::isnormal(value); } static bool isFinite(double value) { return std::isfinite(value); } static NumericState getState(double value) { if (std::isnan(value)) return NumericState::NaN; if (std::isinf(value)) { return value > 0 ? NumericState::PositiveInfinity : NumericState::NegativeInfinity; } if (std::isnormal(value) || value == 0.0) return NumericState::Normal; return NumericState::Subnormal; } static NumericError getError(double value) { if (std::isnan(value)) return NumericError::ExplicitNaN; return NumericError::None; } }; // 長倍精度浮動小数点型(long double) template<> struct numeric_traits { using value_type = long double; using category = floating_point_tag; static constexpr bool is_supported = true; static constexpr bool is_complex = false; static constexpr bool is_integer = false; static constexpr bool is_floating_point = true; static constexpr long double zero() { return 0.0L; } static constexpr long double one() { return 1.0L; } static constexpr long double epsilon() { return std::numeric_limits::epsilon(); } static constexpr long double infinity() { return std::numeric_limits::infinity(); } static constexpr long double quiet_NaN() { return std::numeric_limits::quiet_NaN(); } static constexpr long double abs(long double value) { return value < 0.0L ? -value : value; } static constexpr long double conj(long double value) { return value; } static constexpr long double norm(long double value) { return value * value; } static bool pivotBetter(long double a, long double b) { return abs(a) > abs(b); } // 数値状態関連のユーティリティ - constexprを削除 static bool isNaN(long double value) { return std::isnan(value); } static bool isInfinite(long double value) { return std::isinf(value); } static bool isNormal(long double value) { return std::isnormal(value); } static bool isFinite(long double value) { return std::isfinite(value); } static NumericState getState(long double value) { if (std::isnan(value)) return NumericState::NaN; if (std::isinf(value)) { return value > 0 ? NumericState::PositiveInfinity : NumericState::NegativeInfinity; } if (std::isnormal(value) || value == 0.0L) return NumericState::Normal; return NumericState::Subnormal; } static NumericError getError(long double value) { if (std::isnan(value)) return NumericError::ExplicitNaN; return NumericError::None; } }; // 整数型の特殊化(int用) template<> struct numeric_traits { using value_type = int; using category = integer_tag; static constexpr bool is_supported = true; static constexpr bool is_complex = false; static constexpr bool is_integer = true; static constexpr bool is_floating_point = false; static constexpr int zero() { return 0; } static constexpr int one() { return 1; } static constexpr int epsilon() { return 1; } // 整数の最小単位は1 // 整数型では"infinity"は表現できないが、最大値を返す static constexpr int infinity() { return std::numeric_limits::max(); } // 整数型ではNaNは表現できない(特別な値をエラー状態として返す) static constexpr int quiet_NaN() { return std::numeric_limits::min(); } static constexpr int abs(int value) { return value < 0 ? (value == std::numeric_limits::min() ? std::numeric_limits::max() : -value) : value; } static constexpr int conj(int value) { return value; } // 整数は共役複素数が自分自身 static constexpr int norm(int value) { return value * value; } // 整数のノルムは二乗 static bool pivotBetter(int a, int b) { return abs(a) > abs(b); } static NumericState getState(int) { return NumericState::Normal; // 整数型は常にNormal } static NumericError getError(int) { return NumericError::None; // 整数型のデフォルトエラーはなし } static int getSign(int value) { return value < 0 ? -1 : (value > 0 ? 1 : 0); } }; // 他の整数型の特殊化 template<> struct numeric_traits : numeric_traits { using value_type = long; static constexpr long zero() { return 0L; } static constexpr long one() { return 1L; } static constexpr long abs(long value) { return value < 0L ? -value : value; } static NumericState getState(long) { return NumericState::Normal; } static NumericError getError(long) { return NumericError::None; } static int getSign(long value) { return value < 0L ? -1 : value > 0L ? 1 : 0; } }; template<> struct numeric_traits : numeric_traits { using value_type = long long; static constexpr long long zero() { return 0LL; } static constexpr long long one() { return 1LL; } static constexpr long long abs(long long value) { return value < 0LL ? -value : value; } static NumericState getState(long long) { return NumericState::Normal; } static NumericError getError(long long) { return NumericError::None; } static int getSign(long long value) { return value < 0LL ? -1 : value > 0LL ? 1 : 0; } }; // Intクラスの前方定義とトレイトの枠組み // 実際の実装はIntBase.hppで行う // ここではコンパイルエラーを避けるための仮実装を提供 template<> struct numeric_traits; // Int型の数値状態特性特殊化の前方定義 template<> struct numeric_state_traits; // 特殊化: 複素数型 template struct numeric_traits> { using value_type = std::complex; using real_type = T; using category = complex_tag; static constexpr bool is_supported = numeric_traits::is_supported; static constexpr bool is_complex = true; static constexpr bool is_integer = false; static constexpr bool is_floating_point = numeric_traits::is_floating_point; static std::complex zero() { return std::complex(0, 0); } static std::complex one() { return std::complex(1, 0); } static T epsilon() { return numeric_traits::epsilon(); } // constexprを削除(絶対値は実部と虚部の二乗和の平方根) static T abs(const std::complex& value) { const T real = value.real(); const T imag = value.imag(); return std::sqrt(real * real + imag * imag); } static std::complex conj(const std::complex& value) { return std::conj(value); } static T norm(const std::complex& value) { return std::norm(value); } static bool pivotBetter(const std::complex& a, const std::complex& b) { return abs(a) > abs(b); } // 複素数型の数値状態関連のユーティリティ - constexprを削除 static bool isNaN(const std::complex& value) { return numeric_traits::isNaN(value.real()) || numeric_traits::isNaN(value.imag()); } static bool isInfinite(const std::complex& value) { return numeric_traits::isInfinite(value.real()) || numeric_traits::isInfinite(value.imag()); } static bool isNormal(const std::complex& value) { return !isNaN(value) && !isInfinite(value) && (value.real() != 0 || value.imag() != 0); } static bool isFinite(const std::complex& value) { return numeric_traits::isFinite(value.real()) && numeric_traits::isFinite(value.imag()); } static NumericState getState(const std::complex& value) { if (isNaN(value)) return NumericState::NaN; bool real_inf = numeric_traits::isInfinite(value.real()); bool imag_inf = numeric_traits::isInfinite(value.imag()); if (real_inf || imag_inf) { // 複素無限大は符号を持たないが、実部/虚部の符号に基づいて特殊状態を返す if (real_inf && value.real() > 0) return NumericState::PositiveInfinity; if (real_inf && value.real() < 0) return NumericState::NegativeInfinity; if (imag_inf) return NumericState::ComplexInfinity; return NumericState::ComplexInfinity; } return NumericState::Normal; } static NumericError getError(const std::complex& value) { // NaNの場合はエラー原因を明確にする if (isNaN(value)) { return NumericError::ExplicitNaN; } // 無限大の場合でもエラー原因を明確にする if (isInfinite(value)) { return NumericError::OutOfRangeInput; } return NumericError::None; } static int getSign(const std::complex& value) { // 複素数の符号は実部の符号を優先 if (value.real() != 0) { return value.real() < 0 ? -1 : value.real() > 0 ? 1 : 0; } // 実部がゼロなら虚部の符号を使用 if (value.imag() != 0) { return value.imag() < 0 ? -1 : 1; } // 両方ゼロならゼロ return 0; } }; } // namespace sangi