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 に所属。Vector と StaticVector は VecExpr<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 + b や s * 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)正規化されたコピー
norm と norm2 は VecExpr<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)
axpy と axpby は Vector<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 リポジトリでビルド・実行検証済。