// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later

// algebraic_concepts.hpp
//
// 代数的構造の概念（コンセプト）定義
//
// このファイルでは、抽象代数学の主要な概念をC++のコンセプトとして定義しています。
// これにより、型が特定の代数的構造（群、環、体など）の要件を満たすことを
// コンパイル時に検証できます。
//
// 対応構造:
// - 加法モノイド、加法群
// - 乗法モノイド、乗法群
// - 環、可換環、除環、体
// - 順序体
// - ベクトル空間
// - 構造的コンセプト: 四元数型、有理数型
// - 数値状態管理

#ifndef CALX_ALGEBRAIC_CONCEPTS_HPP
#define CALX_ALGEBRAIC_CONCEPTS_HPP

#include <concepts>
#include <type_traits>
#include <cmath>
#include <complex>
#include <math/core/traits.hpp> // traits.hppからコンセプトを使用

namespace calx::concepts {

    //-----------------------------------------------------------------------------
    // 基本的な数学演算のコンセプト
    //-----------------------------------------------------------------------------

    // 基本的な数学的演算が定義されている型
    template<typename T>
    concept HasBasicArithmetic = requires(T a, T b) {
        { a + b } -> std::convertible_to<T>;
        { a - b } -> std::convertible_to<T>;
        { a* b } -> std::convertible_to<T>;
        { a / b } -> std::convertible_to<T>;
        { -a } -> std::convertible_to<T>;
    };

    // 比較演算子が定義されている型
    template<typename T>
    concept Comparable = requires(T a, T b) {
        { a == b } -> std::convertible_to<bool>;
        { a != b } -> std::convertible_to<bool>;
        { a < b } -> std::convertible_to<bool>;
        { a <= b } -> std::convertible_to<bool>;
        { a > b } -> std::convertible_to<bool>;
        { a >= b } -> std::convertible_to<bool>;
    };

    // 等値比較のみ可能な型
    template<typename T>
    concept EqualityComparable = requires(T a, T b) {
        { a == b } -> std::convertible_to<bool>;
        { a != b } -> std::convertible_to<bool>;
    };

    // 数学定数（π, e など）にアクセス可能な型
    template<typename T>
    concept HasMathConstants = requires {
        { T::pi() } -> std::convertible_to<T>;
        { T::e() } -> std::convertible_to<T>;
    };

    //-----------------------------------------------------------------------------
    // 状態管理のコンセプト - traits.hppの定義を再利用
    //-----------------------------------------------------------------------------

    // 数値状態の検出と処理が可能な型
    // すでに traits.hpp で定義済み

    //-----------------------------------------------------------------------------
    // 代数的構造のコンセプト
    //-----------------------------------------------------------------------------

    // 加法モノイド
    // 要件: 結合律、単位元（ゼロ）
    template<typename T>
    concept AdditiveMonoid = requires(T a, T b) {
        { a + b } -> std::convertible_to<T>;  // 二項演算（閉じている）
        { T{ 0 } } -> std::convertible_to<T>;   // 加法単位元
        // 結合律 (a + b) + c == a + (b + c) はコンパイル時に検証不可能
    };

    // 加法群
    // 要件: 加法モノイド + 逆元
    template<typename T>
    concept AdditiveGroup = AdditiveMonoid<T> && requires(T a) {
        { -a } -> std::convertible_to<T>;     // 加法逆元
        { a - T{ 0 } } -> std::convertible_to<T>; // 減算
        // 交換律 a + b == b + a はコンパイル時に検証不可能
    };

    // 加法アーベル群（可換群）
    // 注: C++のコンセプトでは交換性を強制できないため、
    // 交換律を持つという意味を持つ追加のコンセプトとして定義
    template<typename T>
    concept AdditiveAbelianGroup = AdditiveGroup<T>;

    // 乗法モノイド
    // 要件: 結合律、単位元（1）
    template<typename T>
    concept MultiplicativeMonoid = requires(T a, T b) {
        { a* b } -> std::convertible_to<T>;  // 二項演算（閉じている）
        { T{ 1 } } -> std::convertible_to<T>;   // 乗法単位元
        // 結合律 (a * b) * c == a * (b * c) はコンパイル時に検証不可能
    };

    // 乗法群
    // 要件: 乗法モノイド + 逆元
    template<typename T>
    concept MultiplicativeGroup = MultiplicativeMonoid<T> && requires(T a) {
        { T{ 1 } / a } -> std::convertible_to<T>; // 乗法逆元
        // 交換律 a * b == b * a はコンパイル時に検証不可能
    };

    // 乗法アーベル群（可換群）
    template<typename T>
    concept MultiplicativeAbelianGroup = MultiplicativeGroup<T>;

    // 環
    // 要件: 加法アーベル群 + 乗法モノイド + 分配法則
    template<typename T>
    concept Ring = AdditiveAbelianGroup<T> && MultiplicativeMonoid<T>;
    // 分配法則 a * (b + c) == a * b + a * c はコンパイル時に検証不可能

    // 可換環
    // 要件: 環 + 乗法の交換律
    template<typename T>
    concept CommutativeRing = Ring<T>;
    // 乗法の交換律はコンパイル時に検証不可能だが、概念的に重要

    // 整域
    // 要件: 可換環 + ゼロ因子がない（ab=0 ⇒ a=0 または b=0）
    template<typename T>
    concept IntegralDomain = CommutativeRing<T>;
    // ゼロ因子がないという性質はコンパイル時に検証不可能

    // 体
    // traits.hppですでに定義されているので、直接使用
    // これに対応するコンセプトを一つにまとめる
    // OrderedFieldも同様に直接使用

    // 除環 (斜体, Division Ring)
    // 要件: 環 + ゼロでない全要素に乗法逆元が存在
    // 体 (Field) との違い: 乗法の可換性を要求しない
    // 例: Quaternion<T> (非可換), 体は除環の特殊ケース
    template<typename T>
    concept DivisionRing = Ring<T> && MultiplicativeGroup<T>;

    // スカラー場 - これはコード内でスカラーとして使用できる型を表す一般的な概念
    template<typename T>
    concept Scalar = Field<T> || std::integral<T>;

    // 状態管理付きスカラー
    template<typename T>
    concept ScalarWithStateManagement = Scalar<T> && HasNumericState<T>;

    //-----------------------------------------------------------------------------
    // ベクトル空間とその拡張 - traits.hppですでに定義されているものを優先
    //-----------------------------------------------------------------------------

    // 内積空間
    // 要件: ベクトル空間 + 内積演算
    template<typename V, typename S = double>
    concept InnerProductSpace = VectorSpace<V, S>&& requires(V v, V w) {
        { inner_product(v, w) } -> std::convertible_to<S>; // 内積
        // 内積の性質（正定値性、線形性、対称性）はコンパイル時に検証不可能
    };

    // 状態管理付き内積空間
    template<typename V, typename S = double>
    concept InnerProductSpaceWithStateManagement = InnerProductSpace<V, S>&& HasNumericState<V>&& HasNumericState<S>;

    // ノルム空間
    // 要件: ベクトル空間 + ノルム演算
    template<typename V, typename S = double>
    concept NormedVectorSpace = VectorSpace<V, S>&& requires(V v) {
        { norm(v) } -> std::convertible_to<S>; // ノルム
        // ノルムの性質（非負性、同次性、三角不等式）はコンパイル時に検証不可能
    };

    // 状態管理付きノルム空間
    template<typename V, typename S = double>
    concept NormedVectorSpaceWithStateManagement = NormedVectorSpace<V, S>&& HasNumericState<V>&& HasNumericState<S>;

    // バナッハ空間（完備なノルム空間）
    // 注: 完備性はコンパイル時に検証できないため、
    // これは概念的なマーカーとして使用
    template<typename V, typename S = double>
    concept BanachSpace = NormedVectorSpace<V, S>;

    // ヒルベルト空間（完備な内積空間）
    // 注: 完備性はコンパイル時に検証できないため、
    // これは概念的なマーカーとして使用
    template<typename V, typename S = double>
    concept HilbertSpace = InnerProductSpace<V, S>;

    // 線形写像の概念
    template<typename F, typename V1, typename V2, typename S>
    concept LinearMap = VectorSpace<V1, S>&& VectorSpace<V2, S>&& requires(F f, V1 v, V1 w, S s) {
        { f(v) } -> std::convertible_to<V2>;
        { f(v + w) } -> std::convertible_to<V2>; // 加法性
        { f(s * v) } -> std::convertible_to<V2>; // 斉次性
    };

    // 状態管理付き線形写像
    template<typename F, typename V1, typename V2, typename S>
    concept LinearMapWithStateManagement = LinearMap<F, V1, V2, S>&&
        HasNumericState<V1>&&
        HasNumericState<V2>&&
        HasNumericState<S>;

    // 共役線形写像の概念
    template<typename F, typename V1, typename V2, typename S>
    concept ConjugateLinearMap = VectorSpace<V1, S>&& VectorSpace<V2, S>&& requires(F f, V1 v, V1 w, S s) {
        { f(v) } -> std::convertible_to<V2>;
        { f(v + w) } -> std::convertible_to<V2>; // 加法性
        { f(s * v) } -> std::convertible_to<V2>; // 共役斉次性
        // 共役斉次性の完全な検証はできない（コンパイル時に f(s * v) == conj(s) * f(v) を確認できない）
    };

    //-----------------------------------------------------------------------------
    // 数値計算関連のコンセプト
    //-----------------------------------------------------------------------------

    // 数値演算が可能な型
    template<typename T>
    concept Numeric = HasBasicArithmetic<T> && requires(T a) {
        { std::abs(a) } -> std::convertible_to<T>;
        { std::max(a, a) } -> std::convertible_to<T>;
        { std::min(a, a) } -> std::convertible_to<T>;
    };

    // 状態管理付き数値型
    template<typename T>
    concept NumericWithState = Numeric<T> && HasNumericState<T>;

    // 整数型のコンセプト
    template<typename T>
    concept IntegerType = std::integral<T> && Ring<T>;

    // 状態管理付き整数型
    template<typename T>
    concept IntegerTypeWithStateManagement = IntegerType<T> && HasNumericState<T>;

    // 浮動小数点型のコンセプト
    template<typename T>
    concept FloatingPointType = std::floating_point<T> && OrderedField<T>;

    // 状態管理付き浮動小数点型
    template<typename T>
    concept FloatingPointTypeWithStateManagement = FloatingPointType<T> && HasNumericState<T>;

    // 複素数型のコンセプト
    template<typename T>
    concept ComplexType = requires(T a) {
        typename T::value_type; // 実部/虚部の型
        requires FloatingPointType<typename T::value_type>;
        { std::real(a) } -> std::convertible_to<typename T::value_type>;
        { std::imag(a) } -> std::convertible_to<typename T::value_type>;
        { std::abs(a) } -> std::convertible_to<typename T::value_type>;
        { std::arg(a) } -> std::convertible_to<typename T::value_type>;
        { std::conj(a) } -> std::convertible_to<T>;
    };

    // 状態管理付き複素数型
    template<typename T>
    concept ComplexTypeWithStateManagement = ComplexType<T> && HasNumericState<T>;

    // 四元数型のコンセプト（構造的）
    // 4 成分 (w, x, y, z)、共役、ノルム、逆元を持つ型
    // Quaternion<T> は DivisionRing を満たすが Field は満たさない（非可換）
    template<typename T>
    concept QuaternionType = requires(T q) {
        typename T::value_type;                                     // 成分の型
        { q.w } -> std::convertible_to<typename T::value_type>;     // スカラー部
        { q.x } -> std::convertible_to<typename T::value_type>;     // i 成分
        { q.y } -> std::convertible_to<typename T::value_type>;     // j 成分
        { q.z } -> std::convertible_to<typename T::value_type>;     // k 成分
        { q.conj() } -> std::convertible_to<T>;                     // 共役
        { q.norm() } -> std::convertible_to<typename T::value_type>; // ノルム
        { q.inverse() } -> std::convertible_to<T>;                  // 逆元
    };

    // 有理数型のコンセプト（構造的）
    // 分子・分母へのアクセスを持つ型
    // Rational は Field → OrderedField → Scalar を満たすため、
    // 汎用アルゴリズムでは Field/Scalar で制約すれば十分。
    // このコンセプトは分子・分母に直接アクセスする必要がある場合に使用。
    template<typename T>
    concept RationalType = Field<T> && requires(T r) {
        { r.numerator() };    // 分子
        { r.denominator() };  // 分母
    };

    //-----------------------------------------------------------------------------
    // 線形代数のコンセプト - traits.hppですでに定義されているものを優先
    //-----------------------------------------------------------------------------

    // 正方行列のコンセプト
    template<typename M, typename T>
    concept SquareMatrixOf = MatrixOf<M, T>&& requires(M m) {
        requires m.rows() == m.cols();
    { m.is_square() } -> std::convertible_to<bool>;
    };

    // 対称行列のコンセプト
    template<typename M, typename T>
    concept SymmetricMatrixOf = SquareMatrixOf<M, T>;
    // 対称性の実際のチェックはコンパイル時に行えないため、このコンセプトは
    // マーカーとして機能します。実行時の検証は別途必要です。

    // 直交行列のコンセプト
    template<typename M, typename T>
    concept OrthogonalMatrixOf = SquareMatrixOf<M, T>;
    // 直交性（m^T * m = I）の実際のチェックはコンパイル時に行えないため、
    // このコンセプトはマーカーとして機能します。

    // テンソルのコンセプト
    // rank(), shape(i), size() を持つ多次元配列型
    template<typename T, typename S>
    concept TensorOf = requires(T t, size_t i, size_t j) {
        { t.rank() }    -> std::convertible_to<size_t>;  // 階数
        { t.shape(i) }  -> std::convertible_to<size_t>;  // 各軸の次元
        { t.size() }    -> std::convertible_to<size_t>;  // 全要素数
        { t(i, j) }     -> std::convertible_to<S>;       // 要素アクセス (rank≥2)
    };

    //-----------------------------------------------------------------------------
    // C++23拡張（条件付きで有効）
    //-----------------------------------------------------------------------------
#if __cplusplus >= 202302L

    // 実数体の概念
    template<typename T>
    concept RealField = OrderedField<T> && requires(T a) {
        { std::sqrt(a) } -> std::convertible_to<T>;
        { std::abs(a) } -> std::convertible_to<T>;
        { std::pow(a, a) } -> std::convertible_to<T>;
        // その他の実数体に期待される操作
    };

    // 状態管理付き実数体
    template<typename T>
    concept RealFieldWithStateManagement = RealField<T> && HasNumericState<T>;

    // 複素数体の概念
    template<typename T>
    concept ComplexField = Field<T> && requires(T a) {
        typename T::value_type; // 実部/虚部の型
        { std::real(a) } -> std::convertible_to<typename T::value_type>;
        { std::imag(a) } -> std::convertible_to<typename T::value_type>;
        { std::abs(a) } -> std::convertible_to<typename T::value_type>;
        { std::arg(a) } -> std::convertible_to<typename T::value_type>;
        { std::conj(a) } -> std::convertible_to<T>;
        // その他の複素数体に期待される操作
    };

    // 状態管理付き複素数体
    template<typename T>
    concept ComplexFieldWithStateManagement = ComplexField<T> && HasNumericState<T>;

    // 実数ベクトル空間
    template<typename V, typename S>
    concept RealVectorSpace = VectorSpace<V, S>&& RealField<S>;

    // 状態管理付き実数ベクトル空間
    template<typename V, typename S>
    concept RealVectorSpaceWithStateManagement = RealVectorSpace<V, S>&&
        HasNumericState<V>&&
        HasNumericState<S>;

    // 複素数ベクトル空間
    template<typename V, typename S>
    concept ComplexVectorSpace = VectorSpace<V, S>&& ComplexField<S>;

    // 状態管理付き複素数ベクトル空間
    template<typename V, typename S>
    concept ComplexVectorSpaceWithStateManagement = ComplexVectorSpace<V, S>&&
        HasNumericState<V>&&
        HasNumericState<S>;

    // 特殊行列のコンセプト
    template<typename M, typename T>
    concept SparseMatrixOf = MatrixOf<M, T>&& requires(M m) {
        { m.non_zeros() } -> std::convertible_to<std::size_t>; // 非ゼロ要素数
    };

    // バンド行列（帯行列）のコンセプト
    template<typename M, typename T>
    concept BandMatrixOf = MatrixOf<M, T>&& requires(M m) {
        { m.lower_bandwidth() } -> std::convertible_to<std::size_t>;
        { m.upper_bandwidth() } -> std::convertible_to<std::size_t>;
    };

#endif // C++23 サポート

    //-----------------------------------------------------------------------------
    // 追加の数学的コンセプト
    //-----------------------------------------------------------------------------

    // モジュール（加群）- ベクトル空間の一般化
    template<typename M, typename R>
    concept Module = AdditiveAbelianGroup<M> && Ring<R> && requires(M m, M n, R r, R s) {
        { r* m } -> std::convertible_to<M>;  // スカラー乗法
        { m* r } -> std::convertible_to<M>;  // スカラー乗法（右からも可能）
        // モジュールの公理はコンパイル時に検証不可能
    };

    // 状態管理付きモジュール
    template<typename M, typename R>
    concept ModuleWithStateManagement = Module<M, R>&&
        HasNumericState<M>&&
        HasNumericState<R>;

    // 代数 - ベクトル空間に乗法が定義されたもの
    template<typename A, typename F>
    concept Algebra = VectorSpace<A, F>&& Ring<A>&& requires(A a, A b, F f) {
        { f* (a * b) } -> std::convertible_to<A>; // 双線形性の一部
        // 代数の公理はコンパイル時に検証不可能
    };

    // 状態管理付き代数
    template<typename A, typename F>
    concept AlgebraWithStateManagement = Algebra<A, F>&&
        HasNumericState<A>&&
        HasNumericState<F>;

    // 結合代数 - 乗法が結合的な代数
    template<typename A, typename F>
    concept AssociativeAlgebra = Algebra<A, F>;
    // 結合律はコンパイル時に検証できないため、このコンセプトはマーカーとして機能します。

    // 有限次元ベクトル空間
    // 注: 実際の次元はコンパイル時にチェックできないため、
    // 概念マーカーとしてのみ使用
    template<typename V, typename S>
    concept FiniteDimensionalVectorSpace = VectorSpace<V, S>&& requires(V v) {
        { v.size() } -> std::convertible_to<std::size_t>; // サイズメソッドがあること
    };

    // リー代数 - 非結合的な代数で反可換性を持つもの
    template<typename L, typename F>
    concept LieAlgebra = VectorSpace<L, F>&& requires(L a, L b) {
        { a* b } -> std::convertible_to<L>; // リー積
        // 反可換性やヤコビ恒等式の検証はコンパイル時に行えない
    };

    //-----------------------------------------------------------------------------
    // ヘルパー関数とメタ関数 - traits.hppですでに定義済みのものは参照
    //-----------------------------------------------------------------------------

    // すでにtraits.hppで定義されているため削除:
    // is_field_v, is_ordered_field_v, is_vector_space_v, is_matrix_of_v, is_vector_of_v
    // has_numeric_state_management_v, has_divergence_handling_v, has_overflow_detection_v

    // ダックタイピングサポート
    // すでにtraits.hppで定義されているため削除:
    // has_addition_v, has_multiplication_v, has_division_v, has_negation_v
    // has_equality_v, has_comparison_v, has_abs_v, has_sqrt_v
    // has_is_normal_v, has_is_nan_v, has_is_infinite_v, has_is_divergent_v

} // namespace calx::concepts

#endif // CALX_ALGEBRAIC_CONCEPTS_HPP