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

// sparse_matrix_concepts.hpp
//
// 疎行列のコンセプト定義
//
// このファイルでは、疎行列に関するコンセプトとインターフェースを定義します。
// これにより、異なる疎行列の表現形式（CSR、CSC、COOなど）に対して
// 共通の操作を定義することができます。
//
// 主な機能:
// - 疎行列のコンセプト定義
// - 疎行列の基本操作の制約
// - 疎行列の表現形式間の変換要件

#ifndef CALX_SPARSE_MATRIX_CONCEPTS_HPP
#define CALX_SPARSE_MATRIX_CONCEPTS_HPP

#include "vector.hpp"
#include "concepts/algebraic_concepts.hpp"

#include <concepts>
#include <type_traits>
#include <utility>

namespace calx {
namespace concepts {

// 疎行列の基本コンセプト
// 疎行列に共通する基本的な操作を定義
template<typename M>
concept SparseMatrix = requires(M m) {
    typename M::value_type;                  // 値の型
    typename M::size_type;                   // サイズの型
    typename M::index_type;                  // インデックスの型

    { m.rows() } -> std::convertible_to<typename M::size_type>;  // 行数の取得
    { m.cols() } -> std::convertible_to<typename M::size_type>;  // 列数の取得
    { m.nnz() } -> std::convertible_to<typename M::size_type>;   // 非ゼロ要素数の取得
    
    // 要素のアクセス（疎行列なので効率的なアクセスとは限らない）
    { m(m.rows() - 1, m.cols() - 1) } -> std::convertible_to<typename M::value_type>;
};

// CSR形式（Compressed Sparse Row）の疎行列コンセプト
template<typename M>
concept CSRMatrix = SparseMatrix<M> && requires(M m) {
    { m.row_ptr() } -> std::convertible_to<const typename M::index_type*>;  // 行ポインタ配列
    { m.col_ind() } -> std::convertible_to<const typename M::index_type*>;  // 列インデックス配列
    { m.values() } -> std::convertible_to<const typename M::value_type*>;   // 値配列
};

// CSC形式（Compressed Sparse Column）の疎行列コンセプト
template<typename M>
concept CSCMatrix = SparseMatrix<M> && requires(M m) {
    { m.col_ptr() } -> std::convertible_to<const typename M::index_type*>;  // 列ポインタ配列
    { m.row_ind() } -> std::convertible_to<const typename M::index_type*>;  // 行インデックス配列
    { m.values() } -> std::convertible_to<const typename M::value_type*>;   // 値配列
};

// COO形式（Coordinate）の疎行列コンセプト
template<typename M>
concept COOMatrix = SparseMatrix<M> && requires(M m) {
    { m.row_ind() } -> std::convertible_to<const typename M::index_type*>;  // 行インデックス配列
    { m.col_ind() } -> std::convertible_to<const typename M::index_type*>;  // 列インデックス配列
    { m.values() } -> std::convertible_to<const typename M::value_type*>;   // 値配列
};

// 疎行列・ベクトル積演算が可能なコンセプト
template<typename M, typename V1, typename V2>
concept SparseMatrixVectorMultiplicable = 
    SparseMatrix<M> && 
    requires(const M& m, const V1& v1, V2& v2) {
        typename M::value_type;
        typename V1::value_type;
        typename V2::value_type;
        
        // 行列・ベクトル積 v2 = m * v1 の演算
        { m.multiply(v1, v2) } -> std::same_as<void>;
        
        // サイズの一致を確認
        requires m.cols() == v1.size() && m.rows() == v2.size();
    };

// 疎行列・行列積演算が可能なコンセプト
template<typename M1, typename M2, typename M3>
concept SparseMatrixMatrixMultiplicable = 
    SparseMatrix<M1> && 
    SparseMatrix<M2> && 
    SparseMatrix<M3> && 
    requires(const M1& m1, const M2& m2, M3& m3) {
        typename M1::value_type;
        typename M2::value_type;
        typename M3::value_type;
        
        // 行列・行列積 m3 = m1 * m2 の演算
        { multiply(m1, m2, m3) } -> std::same_as<void>;
        
        // サイズの一致を確認
        requires m1.cols() == m2.rows() && m1.rows() == m3.rows() && m2.cols() == m3.cols();
    };

// 疎行列の転置が可能なコンセプト
template<typename M>
concept TransposableSparseMatrix = 
    SparseMatrix<M> && 
    requires(const M& m, M& result) {
        // 行列の転置操作
        { m.transpose(result) } -> std::same_as<void>;
        
        // サイズの変化を確認
        requires result.rows() == m.cols() && result.cols() == m.rows();
    };

// 疎行列の加算が可能なコンセプト
template<typename M1, typename M2, typename M3>
concept SparsePlusable = 
    SparseMatrix<M1> && 
    SparseMatrix<M2> && 
    SparseMatrix<M3> && 
    requires(const M1& m1, const M2& m2, M3& m3) {
        // 行列の加算操作
        { add(m1, m2, m3) } -> std::same_as<void>;
        
        // サイズの一致を確認
        requires m1.rows() == m2.rows() && m1.cols() == m2.cols() &&
                 m3.rows() == m1.rows() && m3.cols() == m1.cols();
    };

} // namespace concepts
} // namespace calx

#endif // CALX_SPARSE_MATRIX_CONCEPTS_HPP