Vector デモ — 数値ベクトルの活用
Vector<T> は動的サイズの数値ベクトル、
StaticVector<T, N> はコンパイル時にサイズが決まる固定長ベクトルである。
内積 (dot)、ノルム (norm)、正規化 (normalized) など
ベクトル演算の基本操作を提供する。
このページでは 3 つのデモを通じて、ベクトル演算の実用的な応用を紹介する。 以下の出力はすべて calx で実際に計算したものである。 ソースコードはページ末尾に掲載しており、 calx をビルドすれば手元で同じ結果を確認できる。
Demo 1: PageRank — べき乗法で Web ページをランキング
Google の PageRank アルゴリズムをべき乗法で計算する。
4 ページの Web グラフに対してランキングベクトルを反復的に更新し、
各ページの重要度を求める。
ダンピングファクター 0.85、収束判定に norm(next - r) を使用している。
Demo 2: 3D 光線反射 — dot product で反射ベクトルを計算
光線の 3D 反射を dot product で計算する。
反射公式 $\mathbf{r}' = \mathbf{r} - 2(\mathbf{r} \cdot \mathbf{n})\mathbf{n}$ を
StaticVector で実装している。
入射角は $\cos^{-1}(-\mathbf{r} \cdot \mathbf{n})$ で求められる。
Demo 3: コサイン類似度 — 文書間の意味的距離
文書をベクトル空間モデルで表現し、 コサイン類似度 $\cos\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}$ で類似度を計算する。情報検索や機械学習の基本手法である。
ソースコードと実行方法
このページの全出力は以下の C++ プログラムから生成された。 calx をビルドすれば、手元で同じ結果を確認できる。
example_vector_demo.cpp (クリックで展開)
// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later
// example_vector_demo.cpp
// Vector demo: showcasing Vector's capabilities in 3 scenarios
//
// Build:
// cl /std:c++latest /EHsc /O2 /MD /utf-8 /I<calx>/include examples\example_vector_demo.cpp /MACHINE:X64
#include <math/core/vector.hpp>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <vector>
using namespace calx;
// ============================================================================
// Demo 1: PageRank -- Ranking Web Pages with the Power Method
// -- Google's original algorithm, computed with vector iteration
// ============================================================================
static void demo_pagerank() {
std::cout << "============================================================\n";
std::cout << " Demo 1: PageRank -- Ranking Web Pages\n";
std::cout << "============================================================\n\n";
// A small web graph (4 pages):
// Page 0 -> Page 1, Page 2
// Page 1 -> Page 2
// Page 2 -> Page 0
// Page 3 -> Page 0, Page 1, Page 2
const int N = 4;
const double damping = 0.85;
const std::string names[] = {"Home", "About", "Blog", "External"};
// Build column-stochastic transition matrix (stored as rows for simplicity)
// M[i][j] = probability of going from page j to page i
double M[N][N] = {};
// Page 0 links to 1, 2 (each gets 1/2)
M[1][0] = 0.5; M[2][0] = 0.5;
// Page 1 links to 2
M[2][1] = 1.0;
// Page 2 links to 0
M[0][2] = 1.0;
// Page 3 links to 0, 1, 2 (each gets 1/3)
M[0][3] = 1.0/3; M[1][3] = 1.0/3; M[2][3] = 1.0/3;
// Power iteration: r = d * M * r + (1-d)/N
Vector<double> r(N, 1.0 / N); // uniform initial
const double teleport = (1.0 - damping) / N;
std::cout << " Iterating with damping factor = " << damping << " ...\n\n";
for (int iter = 0; iter < 50; ++iter) {
Vector<double> next(N, teleport);
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
next[i] += damping * M[i][j] * r[j];
double diff = norm(next - r);
r = std::move(next);
if (diff < 1e-10) {
std::cout << " Converged after " << (iter + 1) << " iterations.\n\n";
break;
}
}
// Display rankings
std::cout << std::fixed << std::setprecision(4);
std::cout << " Page Rankings:\n";
for (int i = 0; i < N; ++i) {
int bar_len = static_cast<int>(r[i] * 100);
std::cout << " " << std::setw(10) << names[i] << ": " << r[i]
<< " " << std::string(bar_len, '#') << "\n";
}
std::cout << " Sum = " << (r[0] + r[1] + r[2] + r[3]) << "\n\n";
}
// ============================================================================
// Demo 2: Ray Reflection in 3D -- Light Bouncing Off Mirrors
// -- Using dot product and cross product for geometric computation
// ============================================================================
static void demo_ray_reflection() {
std::cout << "============================================================\n";
std::cout << " Demo 2: Ray Reflection in 3D\n";
std::cout << "============================================================\n\n";
// Incident ray direction (pointing downward at 45 degrees)
StaticVector<double, 3> ray{1.0, -1.0, 0.0};
ray = ray.normalized();
// Mirror surface normals for 3 bounces
StaticVector<double, 3> normals[] = {
StaticVector<double, 3>{0.0, 1.0, 0.0}, // horizontal floor
StaticVector<double, 3>{-1.0, 1.0, 0.0}.normalized(), // tilted wall
StaticVector<double, 3>{0.0, 0.0, 1.0}, // vertical wall (z)
};
auto print_v3 = [](const char* label, const StaticVector<double, 3>& v) {
std::cout << " " << std::setw(16) << label << ": ("
<< std::setw(7) << v[0] << ", "
<< std::setw(7) << v[1] << ", "
<< std::setw(7) << v[2] << ")\n";
};
std::cout << std::fixed << std::setprecision(4);
print_v3("Initial ray", ray);
for (int bounce = 0; bounce < 3; ++bounce) {
const auto& n = normals[bounce];
// Reflection formula: r' = r - 2(r . n)n
double dn = dot(ray, n);
StaticVector<double, 3> reflected;
for (int i = 0; i < 3; ++i)
reflected[i] = ray[i] - 2.0 * dn * n[i];
// Angle of incidence
double angle = std::acos(-dn) * 180.0 / 3.14159265358979;
std::cout << "\n Bounce " << (bounce + 1) << ":\n";
print_v3("Surface normal", n);
std::cout << " Angle of incidence: " << angle << " degrees\n";
print_v3("Reflected ray", reflected);
ray = reflected;
}
std::cout << std::endl;
}
// ============================================================================
// Demo 3: Cosine Similarity -- How Similar Are Two Vectors?
// -- A fundamental operation in information retrieval and machine learning
// ============================================================================
static void demo_cosine_similarity() {
std::cout << "============================================================\n";
std::cout << " Demo 3: Cosine Similarity -- Document Comparison\n";
std::cout << "============================================================\n\n";
// Term frequency vectors for 5 documents
// Dimensions: [math, science, art, music, sports]
struct Doc {
const char* name;
Vector<double> tf;
};
Doc docs[] = {
{"Algebra Textbook", Vector<double>{9.0, 3.0, 0.0, 0.0, 0.0}},
{"Physics Paper", Vector<double>{5.0, 8.0, 0.0, 0.0, 1.0}},
{"Art History", Vector<double>{0.0, 0.0, 9.0, 2.0, 0.0}},
{"Music Theory", Vector<double>{2.0, 0.0, 3.0, 8.0, 0.0}},
{"Sports Analytics", Vector<double>{4.0, 2.0, 0.0, 0.0, 9.0}},
};
const int nd = 5;
std::cout << " Documents (term frequencies: [math, science, art, music, sports]):\n";
for (auto& d : docs) {
std::cout << " " << std::setw(20) << d.name << ": [";
for (size_t i = 0; i < d.tf.size(); ++i)
std::cout << (i ? ", " : "") << static_cast<int>(d.tf[i]);
std::cout << "]\n";
}
// Cosine similarity matrix
const char* abbr[] = {"Algebra", "Physics", "Art", "Music", "Sports"};
std::cout << "\n Cosine Similarity Matrix:\n\n";
std::cout << std::setw(22) << "";
for (int i = 0; i < nd; ++i) std::cout << std::setw(10) << abbr[i];
std::cout << "\n";
std::cout << std::fixed << std::setprecision(3);
for (int i = 0; i < nd; ++i) {
std::cout << " " << std::setw(18) << docs[i].name;
for (int j = 0; j < nd; ++j) {
double sim = dot(docs[i].tf, docs[j].tf) / (norm(docs[i].tf) * norm(docs[j].tf));
std::cout << std::setw(10) << sim;
}
std::cout << "\n";
}
std::cout << "\n Most similar pair: Algebra Textbook <-> Physics Paper\n";
std::cout << " Most different: Art History <-> Sports Analytics\n";
std::cout << std::endl;
}
// ============================================================================
// main
// ============================================================================
int main() {
std::cout << "###########################################################\n";
std::cout << "# calx Vector Demo #\n";
std::cout << "###########################################################\n\n";
demo_pagerank();
demo_ray_reflection();
demo_cosine_similarity();
std::cout << "###########################################################\n";
std::cout << "# All demos completed #\n";
std::cout << "###########################################################\n";
return 0;
}
API の詳細は Vector API リファレンス を参照のこと。
ビルドと実行
cd calx
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release --target example-vector-demo
examples\Release\example-vector-demo.exe