// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // vector_operations.hpp // // ベクトル操作の実装 // // このファイルでは、MKL代数ライブラリのベクトル操作関数を定義します。 // これらの関数は、ベクトルの算術演算、数学関数、およびユーティリティを提供します。 // // 主な機能: // - ベクトルの算術演算(加算、減算、スカラー乗算など) // - ベクトルの内積、外積、ノルム計算 // - 要素ごとの数学関数(絶対値、平方根など) // - 計算ポリシーによる実装の切り替え #ifndef CALX_VECTOR_OPERATIONS_HPP #define CALX_VECTOR_OPERATIONS_HPP #include "math/core/common.hpp" #include "math/core/traits.hpp" #include "math/concepts/algebraic_concepts.hpp" #include "computation_policy.hpp" #include #include #include #include #include namespace calx { namespace detail { namespace vector_operations { //----------------------------------------------------------------------------- // 基本ベクトル操作 //----------------------------------------------------------------------------- // ベクトル加算: result = a + b template> requires concepts::AdditiveGroup&& concepts::AdditiveGroup&& concepts::AdditiveGroup void add(const VectorA& a, const VectorB& b, VectorResult& result) { ComputationPolicy::add(a, b, result); } // ベクトル減算: result = a - b template> requires concepts::AdditiveGroup&& concepts::AdditiveGroup&& concepts::AdditiveGroup void subtract(const VectorA& a, const VectorB& b, VectorResult& result) { ComputationPolicy::subtract(a, b, result); } // スカラー乗算: result = alpha * a template> requires concepts::Ring&& concepts::Ring&& concepts::Ring void scale(const VectorA& a, const Scalar& alpha, VectorResult& result) { // サイズチェック if (result.size() != a.size()) { throw DimensionError("Vector scaling: size mismatch"); } // まず結果ベクトルにaをコピー if (&result != &a) { for (std::size_t i = 0; i < a.size(); ++i) { result[i] = a[i]; } } // 次にスケーリングを適用 ComputationPolicy::scale(result, alpha); } // ベクトルの符号反転: result = -a template> requires concepts::AdditiveGroup&& concepts::AdditiveGroup void negate(const VectorA& a, VectorResult& result) { scale(a, typename VectorA::value_type(-1), result); } // 内積: return = a・b template> requires concepts::Ring&& concepts::Ring auto dot_product(const VectorA& a, const VectorB& b) -> decltype(a[0] * b[0]) { return ComputationPolicy::dot_product(a, b); } // 要素ごとの積: result = a .* b(要素ごとの乗算) template> requires concepts::Ring&& concepts::Ring&& concepts::Ring void element_wise_multiply(const VectorA& a, const VectorB& b, VectorResult& result) { ComputationPolicy::element_wise_multiply(a, b, result); } // 要素ごとの除算: result = a ./ b(要素ごとの除算) template requires concepts::Field&& concepts::Field&& concepts::Field void element_wise_divide(const VectorA& a, const VectorB& b, VectorResult& result) { const auto size = a.size(); // サイズチェック if (b.size() != size || result.size() != size) { throw DimensionError("Vector element-wise division: size mismatch"); } // 要素ごとの除算(ゼロ除算チェック付き) for (std::size_t i = 0; i < size; ++i) { if (approximately_equal(b[i], numeric_traits::zero())) { throw MathError("Vector element-wise division: division by zero"); } result[i] = a[i] / b[i]; } } // axpy演算: y += alpha * x template> requires concepts::Ring&& concepts::Ring&& concepts::Ring void axpy(VectorY& y, const Scalar& alpha, const VectorX& x) { ComputationPolicy::axpy(y, alpha, x); } //----------------------------------------------------------------------------- // 数学関数 //----------------------------------------------------------------------------- // ベクトルの各要素に対する関数適用: result = f(a) template void apply_function(const VectorA& a, VectorResult& result, Function f) { const auto size = a.size(); // サイズチェック if (result.size() != size) { throw DimensionError("Vector function application: size mismatch"); } // 各要素に関数を適用 for (std::size_t i = 0; i < size; ++i) { result[i] = f(a[i]); } } // ベクトルの絶対値(要素ごと): result = |a| template requires requires(typename VectorA::value_type x) { { std::abs(x) } -> std::convertible_to; } void abs(const VectorA& a, VectorResult& result) { apply_function(a, result, [](const auto& x) { return std::abs(x); }); } // ベクトルの平方根(要素ごと): result = √a template requires requires(typename VectorA::value_type x) { { std::sqrt(x) } -> std::convertible_to; } void sqrt(const VectorA& a, VectorResult& result) { apply_function(a, result, [](const auto& x) { if (x < numeric_traits::zero()) { throw MathError("Vector sqrt: negative input"); } return std::sqrt(x); }); } // ベクトルの二乗(要素ごと): result = a² template requires concepts::Ring&& concepts::Ring void square(const VectorA& a, VectorResult& result) { apply_function(a, result, [](const auto& x) { return x * x; }); } // ベクトルの指数関数(要素ごと): result = e^a template requires requires(typename VectorA::value_type x) { { std::exp(x) } -> std::convertible_to; } void exp(const VectorA& a, VectorResult& result) { apply_function(a, result, [](const auto& x) { return std::exp(x); }); } // ベクトルの対数関数(要素ごと): result = log(a) template requires requires(typename VectorA::value_type x) { { std::log(x) } -> std::convertible_to; } void log(const VectorA& a, VectorResult& result) { apply_function(a, result, [](const auto& x) { if (x <= numeric_traits::zero()) { throw MathError("Vector log: non-positive input"); } return std::log(x); }); } // ベクトルのべき乗(要素ごと): result = a^exponent template requires requires(typename VectorA::value_type x, Exponent e) { { std::pow(x, e) } -> std::convertible_to; } void pow(const VectorA& a, VectorResult& result, const Exponent& exponent) { apply_function(a, result, [&exponent](const auto& x) { return std::pow(x, exponent); }); } //----------------------------------------------------------------------------- // ノルムと距離 //----------------------------------------------------------------------------- // ベクトルのL1ノルム(絶対値の和): ||a||₁ template requires requires(typename VectorA::value_type x) { { std::abs(x) } -> std::convertible_to; } auto l1_norm(const VectorA& a) -> typename VectorA::value_type { using value_type = typename VectorA::value_type; value_type sum = numeric_traits::zero(); for (std::size_t i = 0; i < a.size(); ++i) { sum += std::abs(a[i]); } return sum; } // ベクトルのL2ノルム(ユークリッドノルム): ||a||₂ template> requires concepts::Ring&& requires(typename VectorA::value_type x) { { std::sqrt(x) } -> std::convertible_to; } auto l2_norm(const VectorA& a) -> typename VectorA::value_type { return ComputationPolicy::norm2(a); } // ベクトルのL∞ノルム(最大絶対値): ||a||∞ template requires requires(typename VectorA::value_type x) { { std::abs(x) } -> std::convertible_to; } auto linf_norm(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { return numeric_traits::zero(); } using value_type = typename VectorA::value_type; value_type max_abs = std::abs(a[0]); for (std::size_t i = 1; i < a.size(); ++i) { max_abs = std::max(max_abs, std::abs(a[i])); } return max_abs; } // ベクトル間のL2距離: ||a - b||₂ template requires concepts::AdditiveGroup&& concepts::AdditiveGroup&& requires(typename VectorA::value_type x) { { std::sqrt(x) } -> std::convertible_to()))>; } auto l2_distance(const VectorA& a, const VectorB& b) -> decltype(std::sqrt(std::declval())) { const auto size = a.size(); // サイズチェック if (b.size() != size) { throw DimensionError("Vector L2 distance: size mismatch"); } using result_type = decltype(a[0] - b[0]); result_type sum_squares = numeric_traits::zero(); for (std::size_t i = 0; i < size; ++i) { const result_type diff = a[i] - b[i]; sum_squares += diff * diff; } return std::sqrt(sum_squares); } //----------------------------------------------------------------------------- // 統計関数 //----------------------------------------------------------------------------- // ベクトルの最小値 template requires concepts::Comparable auto min(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { throw IndexError("Vector min: empty vector"); } return *std::min_element(a.begin(), a.end()); } // ベクトルの最大値 template requires concepts::Comparable auto max(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { throw IndexError("Vector max: empty vector"); } return *std::max_element(a.begin(), a.end()); } // ベクトルの要素の和 template requires concepts::AdditiveGroup auto sum(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { return numeric_traits::zero(); } using value_type = typename VectorA::value_type; return std::accumulate(a.begin(), a.end(), numeric_traits::zero()); } // ベクトルの要素の積 template requires concepts::MultiplicativeMonoid auto product(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { return numeric_traits::one(); } using value_type = typename VectorA::value_type; return std::accumulate(a.begin(), a.end(), numeric_traits::one(), std::multiplies()); } // ベクトルの算術平均 template requires concepts::Field auto mean(const VectorA& a) -> typename VectorA::value_type { if (a.empty()) { throw IndexError("Vector mean: empty vector"); } using value_type = typename VectorA::value_type; const value_type total = sum(a); return total / static_cast(a.size()); } // ベクトルの分散 template requires concepts::Field auto variance(const VectorA& a) -> typename VectorA::value_type { if (a.empty() || a.size() == 1) { throw IndexError("Vector variance: insufficient data"); } const auto avg = mean(a); using value_type = typename VectorA::value_type; value_type sum_sq_diff = numeric_traits::zero(); for (std::size_t i = 0; i < a.size(); ++i) { const value_type diff = a[i] - avg; sum_sq_diff += diff * diff; } return sum_sq_diff / static_cast(a.size() - 1); } // ベクトルの標準偏差 template requires concepts::Field&& requires(typename VectorA::value_type x) { { std::sqrt(x) } -> std::convertible_to; } auto standard_deviation(const VectorA& a) -> typename VectorA::value_type { return std::sqrt(variance(a)); } // 数値状態を含むベクトルの内積計算 template requires HasNumericState&& HasNumericState auto dot_product_with_state(const VectorA& a, const VectorB& b) -> typename VectorA::value_type { const auto size = a.size(); // サイズチェック if (b.size() != size) { throw DimensionError("Vector dot product with state: size mismatch"); } // 特殊状態のチェック for (std::size_t i = 0; i < size; ++i) { if (numeric_state_traits::isNaN(a[i]) || numeric_state_traits::isNaN(b[i])) { // NaNが含まれる場合はNaNを返す return numeric_traits::quiet_NaN(); } if (numeric_state_traits::isInfinite(a[i]) || numeric_state_traits::isInfinite(b[i])) { // 無限大の場合は個別に処理 // 例: ∞ * 0 = NaN, ∞ * 非ゼロ = ∞ if ((numeric_state_traits::isInfinite(a[i]) && b[i] == numeric_traits::zero()) || (numeric_state_traits::isInfinite(b[i]) && a[i] == numeric_traits::zero())) { return numeric_traits::quiet_NaN(); } // その他の無限大の場合は無限大を返す // 符号は計算結果によって異なる return numeric_traits::infinity(); } } // 通常の内積計算 using result_type = typename VectorA::value_type; result_type sum = numeric_traits::zero(); for (std::size_t i = 0; i < size; ++i) { sum += a[i] * b[i]; } return sum; } // 数値状態を含むベクトルのL2ノルム計算 template requires HasNumericState auto l2_norm_with_state(const VectorA& a) -> typename VectorA::value_type { using value_type = typename VectorA::value_type; // 特殊状態のチェック for (std::size_t i = 0; i < a.size(); ++i) { if (numeric_state_traits::isNaN(a[i])) { // NaNが含まれる場合はNaNを返す return numeric_traits::quiet_NaN(); } if (numeric_state_traits::isInfinite(a[i])) { // 無限大の要素が含まれる場合は無限大を返す return numeric_traits::infinity(); } } // 通常のノルム計算 return l2_norm(a); } } // namespace vector_operations } // namespace detail } // namespace calx #endif // CALX_VECTOR_OPERATIONS_HPP