Vector Demo — Practical Numeric Vectors

Vector<T> is a dynamically-sized numeric vector, and StaticVector<T, N> is a fixed-size vector whose dimension is determined at compile time. They provide fundamental vector operations including dot product (dot), norm (norm), and normalization (normalized).

This page presents three demos showcasing practical applications of vector operations. All outputs below were actually computed by calx. The source code is provided at the bottom of the page, and you can reproduce the same results by building calx.

Demo 1: PageRank — Ranking Web Pages with the Power Method

We compute Google's PageRank algorithm using the power method. The ranking vector is iteratively updated for a 4-page web graph to determine the importance of each page. A damping factor of 0.85 is used, with norm(next - r) for convergence testing.

Iterating with damping factor = 0.85 ... Converged after 43 iterations. Page Rankings: Home: 0.3732 ##################################### About: 0.2068 #################### Blog: 0.3825 ###################################### External: 0.0375 ### Sum = 1.0000
Blog has the highest rank because it receives links from all other pages.

Demo 2: 3D Ray Reflection — Computing the Reflection Vector with dot product

We compute 3D ray reflection using the dot product. The reflection formula $\mathbf{r}' = \mathbf{r} - 2(\mathbf{r} \cdot \mathbf{n})\mathbf{n}$ is implemented with StaticVector. The angle of incidence is obtained as $\cos^{-1}(-\mathbf{r} \cdot \mathbf{n})$.

Initial ray: ( 0.7071, -0.7071, 0.0000) Bounce 1: Surface normal: ( 0.0000, 1.0000, 0.0000) Angle of incidence: 45.0000 degrees Reflected ray: ( 0.7071, 0.7071, 0.0000) Bounce 2: Surface normal: (-0.7071, 0.7071, 0.0000) Angle of incidence: 90.0000 degrees Reflected ray: ( 0.7071, 0.7071, 0.0000) Bounce 3: Surface normal: ( 0.0000, 0.0000, 1.0000) Angle of incidence: 90.0000 degrees Reflected ray: ( 0.7071, 0.7071, 0.0000)
3D ray tracing can be implemented using only dot product and normalization.

Demo 3: Cosine Similarity — Semantic Distance Between Documents

We represent documents using the vector space model and compute their similarity with cosine similarity $\cos\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}$. This is a fundamental technique in information retrieval and machine learning.

Documents (term frequencies: [math, science, art, music, sports]): Algebra Textbook: [9, 3, 0, 0, 0] Physics Paper: [5, 8, 0, 0, 1] Art History: [0, 0, 9, 2, 0] Music Theory: [2, 0, 3, 8, 0] Sports Analytics: [4, 2, 0, 0, 9] Cosine Similarity Matrix: Algebra Physics Art Music Sports Algebra Textbook 1.000 0.767 0.000 0.216 0.441 Physics Paper 0.767 1.000 0.000 0.120 0.472 Art History 0.000 0.000 1.000 0.532 0.000 Music Theory 0.216 0.120 0.532 1.000 0.091 Sports Analytics 0.441 0.472 0.000 0.091 1.000
Algebra Textbook and Physics Paper have the highest similarity at 0.767, while Art History and Sports Analytics are 0.000 (completely unrelated). The angle between vectors reflects the semantic distance between documents.

Source Code and How to Run

All outputs on this page were generated from the following C++ program. You can reproduce the same results by building calx.

example_vector_demo.cpp (click to expand)
// 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;
}

For API details, see the Vector API Reference.

Build and Run

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