Vector — 数値ベクトル

概要

Vector<T> は sangi の動的サイズ数値ベクトルテンプレートクラスである。 StaticVector<T,N> はコンパイル時固定サイズの変種。 どちらもヘッダオンリーで、追加のライブラリリンクは不要。

  • 式テンプレートa + 2.0 * b のような式は中間オブジェクトを生成せず、代入時に単一ループで評価
  • SIMD 自動ベクタライズPacketTraits<T> を通じた SIMD パケット評価 (SSE/AVX2)。4 アキュムレータ展開で帯域を最大化
  • ブロック操作head, tail, segment によるゼロコピービュー (Eigen スタイル)
  • BLAS Level-1 融合axpy, axpby を単一ループで実行
  • VectorMap — 外部メモリへのゼロコピービュー (Eigen::Map 相当)

クラス一覧

クラス説明
Vector<T>動的サイズベクトル。std::vector ベースのストレージ
StaticVector<T,N>コンパイル時固定サイズベクトル。std::array<T,N> ベース
VectorMap<T>外部メモリへの読み書き可能なビュー
ConstVectorMap<T>外部メモリへの読み取り専用ビュー

すべて namespace sangi に所属。VectorStaticVectorVecExpr<Derived> (CRTP) を継承し、式テンプレートに参加する。

Vector<T> クラス

コンストラクタ

シグネチャ説明
Vector()デフォルト構築。空ベクトル (size = 0)
Vector(size_type n)サイズ n のゼロ初期化ベクトル
Vector(size_type n, const T& value)サイズ n、全要素を value で初期化
Vector(size_type n, uninitialized_t)サイズ n、メモリ確保のみ (値は未初期化)。POD 型のパフォーマンス最適化用
Vector(std::initializer_list<T> init)初期化子リストから構築
Vector(const Vector&)コピーコンストラクタ
Vector(Vector&&) noexceptムーブコンストラクタ
Vector(const VecExpr<E>& expr)式テンプレートからの暗黙変換。SIMD パケット評価で代入
Vector<double> v1;                        // 空ベクトル
Vector<double> v2(5);                     // サイズ5、ゼロ初期化
Vector<double> v3(5, 1.0);               // サイズ5、全要素1.0
Vector<double> v4{1.0, 2.0, 3.0};        // 初期化子リスト

要素アクセス

メンバ関数説明
operator[](size_type i)要素参照 (assert による範囲チェック)
at(size_type i)要素参照 (例外による範囲チェック)
front()先頭要素。空なら IndexError
back()末尾要素。空なら IndexError
data()内部バッファへの生ポインタ
Vector<double> v{10, 20, 30};
double a = v[0];      // 10 (assert による範囲チェック)
double b = v.at(1);   // 20 (例外による範囲チェック)
v[2] = 99;            // 代入

イテレータ

メンバ関数説明
begin() / end()可変イテレータ
cbegin() / cend()const イテレータ

容量

メンバ関数説明
size()要素数
empty()空か
capacity()確保済み容量
reserve(size_type n)容量を事前確保
resize(size_type n)サイズ変更
resize(size_type n, const T& value)サイズ変更 (新要素を value で初期化)
shrink_to_fit()余分な容量を解放
clear()全要素を削除 (size = 0)

算術演算

演算説明
v += wベクトル加算 (要素ごと)
v -= wベクトル減算 (要素ごと)
v *= scalarスカラー乗算
v /= scalarスカラー除算 (ゼロ除算時 invalid_argument)
v += expr式テンプレートからの複合加算 (SIMD パケット評価)
v -= expr式テンプレートからの複合減算 (SIMD パケット評価)
Vector<double> a{1, 2, 3}, b{4, 5, 6};
Vector<double> c = a + b;       // 注意: auto より明示 Vector で受けると ET が確実に評価される
Vector<double> d = a - b;
Vector<double> e = 2.0 * a;
Vector<double> f = a / 2.0;
// 実行結果 (build & run 検証済):
//   c = {5, 7, 9}
//   d = {-3, -3, -3}
//   e = {2, 4, 6}
//   f = {0.5, 1, 1.5}

式テンプレート演算

以下の二項演算子は式テンプレートノードを返し、代入時に一括評価される。中間 Vector は生成されない。

説明
a + bベクトル加算
a - bベクトル減算
scalar * aスカラー・ベクトル乗算
a * scalarベクトル・スカラー乗算
Vector<double> a{1, 2, 3}, b{4, 5, 6}, c{7, 8, 9};
// 中間バッファなしで評価 (式テンプレート)
Vector<double> result = 2.0 * a + b - 0.5 * c;

auto と式テンプレート: a + bs * a の結果を auto で受けると、 型は Vector<T> ではなく式テンプレートの中間ノード型になる。 この中間型を Vector<T> を要求する関数に渡すとコンパイルエラーになることがある。 式の結果を他の関数に渡す場合は Vector<T> で明示的に受けること。

// NG: v の型が VecBinOp<...> になる
auto v = 2.0 * a + b;
someFunction(v);  // Vector<T> を期待する関数ではエラー

// OK: Vector<double> で受けると式が評価される
Vector<double> v = 2.0 * a + b;
someFunction(v);  // OK

内積・ノルム

メンバ関数説明
T dot(const Vector& rhs) const内積 $\langle \mathbf{a}, \mathbf{b} \rangle = \sum a_i b_i$。SIMD 4 アキュムレータ展開
T norm() constL2 ノルム $\|\mathbf{v}\| = \sqrt{\sum v_i^2}$
T norm_l1() constL1 ノルム $\|\mathbf{v}\|_1 = \sum |v_i|$
T norm_linf() const$L_\infty$ ノルム $\|\mathbf{v}\|_\infty = \max |v_i|$
T norm_lp(double p) const一般 $L_p$ ノルム $\|\mathbf{v}\|_p = \left(\sum |v_i|^p\right)^{1/p}$。$p \ge 1$ が必要
Vector<double> a{1, 2, 3}, b{4, 5, 6};
double d  = dot(a, b);
double n  = norm(a);
double n1 = norm_l1(a);
double ni = norm_linf(a);
double n3 = norm_lp(a, 3.0);
// 実行結果 (build & run 検証済):
//   dot(a,b)   = 32
//   norm(a)    = 3.74165738677394   (= sqrt(14), 15 桁)
//   norm_l1(a) = 6
//   norm_linf(a) = 3
//   norm_lp(a,3) = 3.30192724889463  (= (1+8+27)^(1/3) = 36^(1/3))

正規化

メンバ関数説明
Vector normalized() const正規化されたコピーを返す ($\|\mathbf{v}\| = 0$ のときゼロベクトル)
void normalize()自身を正規化 (in-place)
Vector<double> v{3, 4};
auto u = normalized(v);
// 実行結果 (build & run 検証済): u = {0.6, 0.8}、 norm(u) = 1 (正規化後の単位ベクトル)

ブロック操作

ゼロコピービュー (VectorView / ConstVectorView) を返す。ビュー経由の書き込みは元のベクトルに反映される。

メンバ関数説明
head(size_type n)先頭 n 要素のビュー
tail(size_type n)末尾 n 要素のビュー
segment(size_type offset, size_type count)位置 offset から count 要素のビュー
Vector<double> v{10, 20, 30, 40, 50};
auto h = v.head(2);          // ゼロコピービュー
auto t = v.tail(2);
auto s = v.segment(1, 3);
// 実行結果 (build & run 検証済): head(2)={10, 20}, tail(2)={40, 50}, segment(1,3)={20, 30, 40}
// 注意: v[1] = 99 のようにビュー経由 (s[0] = 99) で書き込むと、 元の v も書き換わる

その他

メンバ関数説明
void zero()全要素をゼロに設定
void assign(size_type n, const T& value)サイズ n、全要素を value に再設定

StaticVector<T,N> クラス

コンパイル時固定サイズのベクトル。内部ストレージは std::array<T,N>。 ヒープ割り当てなしで、小さいベクトル (3D 座標、クォータニオン等) に最適。

コンストラクタ

シグネチャ説明
StaticVector()デフォルト構築。全要素ゼロ
StaticVector(const T& value)全要素を value で初期化
StaticVector(std::initializer_list<T>)初期化子リストから構築
StaticVector(const VecExpr<E>&)式テンプレートからの構築

API

Vector<T> と同様のインタフェースを提供する。

  • 要素アクセス: operator[], at, data
  • イテレータ: begin, end, cbegin, cend
  • 容量: size() (constexpr), empty()
  • 算術演算: +=, -=, *=, /= (Vector 同士 + スカラー + 式テンプレート)
  • 内積・ノルム: dot, norm, norm_l1, norm_linf, norm_lp
  • 正規化: normalized, normalize
  • ブロック操作: head, tail, segment
  • その他: zero()

size()constexpr であり、コンパイル時にサイズが確定する。capacity, reserve, resize, shrink_to_fit, clear は提供されない。

フリー関数

以下のフリー関数は Vector<T>StaticVector<T,N> の両方に対応する。

内積・ノルム

関数説明
T dot(a, b)内積 $\sum a_i b_i$
T norm(v)L2 ノルム $\|\mathbf{v}\|$
T norm2(v)norm の別名 (ODE ソルバー等の汎用インタフェース用)
T norm_l1(v)L1 ノルム
T norm_linf(v)$L_\infty$ ノルム
T norm_lp(v, p)一般 $L_p$ ノルム
Vector<T> normalized(v)正規化されたコピー

normnorm2VecExpr<E> (式テンプレートノード) も直接受け付ける。具体化せずにパケット評価でノルムを計算。

外積

関数説明
StaticVector<T,3> cross(a, b)3D 外積。StaticVector<T,3> 専用
StaticVector<double, 3> i{1, 0, 0}, j{0, 1, 0};
auto k = cross(i, j);
// 実行結果 (build & run 検証済): k = {0, 0, 1} (= z 軸単位ベクトル)
// 右手系: cross(x, y) = z (= i × j = k)

BLAS Level-1 融合関数

一時オブジェクトを生成せず、単一ループで処理する。コンパイラの SIMD 自動ベクタライズが有効。

関数説明
void axpy(alpha, x, y)$\mathbf{y} \mathrel{+}= \alpha \mathbf{x}$ (DAXPY 相当)
void axpby(alpha, x, beta, y, result)$\mathbf{result} = \alpha \mathbf{x} + \beta \mathbf{y}$ (out-of-place)
void axpby(alpha, x, beta, y)$\mathbf{y} = \alpha \mathbf{x} + \beta \mathbf{y}$ (in-place)

axpyaxpbyVector<T> 版と StaticVector<T,N> 版の両方がある。

Vector<double> x{1, 2, 3}, y{10, 20, 30};
axpy(2.0, x, y);            // y += 2*x
// 実行結果 (build & run 検証済): y = {12, 24, 36}

Vector<double> a{1, 2, 3}, b{4, 5, 6}, r(3);
axpby(2.0, a, 3.0, b, r);   // r = 2a + 3b
// 実行結果 (build & run 検証済): r = {14, 19, 24}

VectorMap / ConstVectorMap

外部メモリ上の連続配列をコピーなしでベクトルとして参照するビュークラス。

VectorMap<T>

メンバ説明
VectorMap(T* data, size_type size)外部バッファからビューを構築
size()要素数
data()バッファへのポインタ
operator[](i)要素参照 (読み書き可能)
operator Vector<T>() constVector へのコピー変換
operator=(const Vector<T>&)Vector からの要素コピー代入

ConstVectorMap<T>

メンバ説明
ConstVectorMap(const T* data, size_type size)外部バッファからビューを構築
size()要素数
data()バッファへの const ポインタ
operator[](i) const要素参照 (読み取り専用)
operator Vector<T>() constVector へのコピー変換
double raw[] = {1.0, 2.0, 3.0};
sangi::VectorMap<double> v(raw, 3);
v[1] = 5.0;
// 実行結果 (build & run 検証済): raw[1] が 5.0 に上書きされる (元バッファへの書き込み確認)
double data[] = {1, 2, 3, 4, 5};
ConstVectorMap<double> view(data, 5);   // コピーなしの読み取り専用ビュー
// 注意: dot 等のフリー関数は ConstVectorMap を直接受け取らないため、
//       Vector<T> に変換してから渡す:
Vector<double> view_vec = view;          // 暗黙変換でコピー
double s = dot(view_vec, view_vec);
// 実行結果 (build & run 検証済): s = 55 (= 1+4+9+16+25)

使用例

#include <math/core/vector.hpp>
#include <iostream>
using namespace sangi;

int main() {
    // コンストラクタ
    Vector<double> a{1.0, 2.0, 3.0};
    Vector<double> b{4.0, 5.0, 6.0};

    // 式テンプレート — 中間オブジェクトなし
    Vector<double> c = a + 2.0 * b;  // {9, 12, 15}

    // 内積・ノルム
    std::cout << "dot(a,b) = " << dot(a, b) << std::endl;
    std::cout << "norm(a)  = " << norm(a) << std::endl;
    std::cout << "norm_l1  = " << norm_l1(a) << std::endl;
    std::cout << "norm_inf = " << norm_linf(a) << std::endl;
    // 出力: dot=32, norm=3.74165738677394 (=sqrt(14)), norm_l1=6, norm_inf=3

    // 正規化
    Vector<double> u = normalized(a);
    std::cout << "norm(normalized(a)) = " << norm(u) << std::endl;
    // 出力: 1 (正規化後は単位ベクトル)

    // StaticVector + 外積
    StaticVector<double, 3> xv{1.0, 0.0, 0.0};
    StaticVector<double, 3> yv{0.0, 1.0, 0.0};
    auto z = cross(xv, yv);
    std::cout << "cross = [" << z[0] << ", " << z[1] << ", " << z[2] << "]" << std::endl;
    // 出力: cross = [0, 0, 1]

    // ブロック操作
    Vector<double> v{10.0, 20.0, 30.0, 40.0, 50.0};
    auto h = v.head(3);       // ゼロコピービュー
    auto t = v.tail(2);
    auto s = v.segment(1, 3);
    // 出力ベクトル: head={10,20,30}, tail={40,50}, segment={20,30,40}

    // BLAS Level-1
    Vector<double> p{1.0, 2.0, 3.0};
    Vector<double> q{4.0, 5.0, 6.0};
    axpy(2.0, p, q);  // q += 2*p
    // 出力: q = {6, 9, 12}

    // VectorMap (外部メモリビュー)
    double raw[] = {1.0, 2.0, 3.0};
    VectorMap<double> map(raw, 3);
    map[0] = 99.0;
    // 出力: raw[0] = 99.0 (元バッファに反映)
}

※ 上記サンプルは examples/example_doc_vector_samples.cpp として lib リポジトリでビルド・実行検証済。