Back

Linear Algebra Functions

Overview

The DataFrame library provides a comprehensive set of linear algebra types and functions for working with vectors and matrices. These types are fixed-size, stack-allocated, and designed for performance in scientific computing. All algebra functions operate on Serie containers and have bind_* versions for pipeline usage.

Types

Vectors

Vector Types

// Generic fixed-size vector
template <typename T, size_t N>
using Vector = std::array<T, N>;

// Common aliases
using Vector2D = Vector<double, 2>;
using Vector3D = Vector<double, 3>;
using Vector4D = Vector<double, 4>;

Full Matrices

Full Matrix Types

// Generic NxN full matrix (stored as flat array of N*N elements)
template <typename T, size_t N>
using FullMatrix = std::array<T, N * N>;

// Common aliases
using Matrix2D = FullMatrix<double, 2>;   // 4 components
using Matrix3D = FullMatrix<double, 3>;   // 9 components
using Matrix4D = FullMatrix<double, 4>;   // 16 components

Symmetric Matrices

Symmetric Matrix Types

// Symmetric NxN matrix (stores only upper triangle)
// 2x2: 3 components, 3x3: 6 components, 4x4: 10 components
template <typename T, size_t N>
using SymmetricMatrix = std::array<T, N * (N + 1) / 2>;

// Common aliases
using SMatrix2D = SymmetricMatrix<double, 2>;  // 3 components
using SMatrix3D = SymmetricMatrix<double, 3>;  // 6 components (Stress3D, Strain3D)
using SMatrix4D = SymmetricMatrix<double, 4>;  // 10 components

// Stress and strain tensors
using Stress2D = SymmetricMatrix<double, 2>;
using Strain2D = SymmetricMatrix<double, 2>;
using Stress3D = SymmetricMatrix<double, 3>;
using Strain3D = SymmetricMatrix<double, 3>;

Vector Operations

Cross Product

Cross Product

// Cross product of two 3D vector Series
Serie<Vector3D> cross(const Serie<Vector3D> &a, const Serie<Vector3D> &b);

// Pipeline version
auto bind_cross(const Serie<Vector3D> &b);

Dot Product

Dot Product

// Dot product of two vector Series
template <typename T, size_t N>
Serie<T> dot(const Serie<Vector<T,N>> &a, const Serie<Vector<T,N>> &b);

// Pipeline version
template <typename T, size_t N>
auto bind_dot(const Serie<Vector<T,N>> &b);

Norm

Vector Norm (Magnitude)

// Compute the magnitude (Euclidean norm) of each vector
template <typename T, size_t N>
Serie<T> norm(const Serie<Vector<T,N>> &serie);

// Pipeline version
template <typename T, size_t N>
auto bind_norm();
Vector Operations Example

df::Serie<Vector3D> a{{1, 0, 0}, {0, 1, 0}, {1, 1, 0}};
df::Serie<Vector3D> b{{0, 1, 0}, {0, 0, 1}, {0, 1, 0}};

// Cross product
auto c = df::algebra::cross(a, b);
// c[0] = {0, 0, 1}, c[1] = {1, 0, 0}, c[2] = {0, 0, 1}

// Dot product
auto d = df::algebra::dot(a, b);
// d = {0, 0, 1}

// Norm
auto magnitudes = df::algebra::norm(a);
// magnitudes = {1.0, 1.0, 1.414...}

// Pipeline usage
auto result = a | df::algebra::bind_cross(b);
auto norms  = a | df::algebra::bind_norm<double, 3>();

Matrix Operations

Determinant

Determinant

// Determinant of full matrices
template <typename T, size_t N>
Serie<T> det(const Serie<FullMatrix<T,N>> &matrices);

// Determinant of symmetric matrices
template <typename T, size_t N>
Serie<T> det(const Serie<SymmetricMatrix<T,N>> &matrices);

// Pipeline versions
auto bind_det();

Inverse

Matrix Inverse

// Inverse for 1x1, 2x2, and 3x3 full matrices
template <typename T, size_t N>
Serie<FullMatrix<T,N>> inv(const Serie<FullMatrix<T,N>> &matrices);

// Inverse for symmetric matrices
template <typename T, size_t N>
Serie<SymmetricMatrix<T,N>> inv(const Serie<SymmetricMatrix<T,N>> &matrices);

// Pipeline version
auto bind_inv();

Transpose

Matrix Transpose

// Transpose for 2x2, 3x3, and 4x4 full matrices
template <typename T, size_t N>
Serie<FullMatrix<T,N>> transpose(const Serie<FullMatrix<T,N>> &matrices);

// Pipeline version
auto bind_transpose();

Solve Linear System

Solve Ax = b

// Solve the linear system Ax = b for each element
template <typename T, size_t N>
Serie<Vector<T,N>> solve(
    const Serie<FullMatrix<T,N>> &A,
    const Serie<Vector<T,N>> &b
);
Matrix Operations Example

// 2x2 matrix operations
df::Serie<Matrix2D> mats{
    {1, 2, 3, 4},    // [[1, 2], [3, 4]]
    {5, 6, 7, 8}     // [[5, 6], [7, 8]]
};

auto determinants = df::algebra::det(mats);
// determinants = {-2, -2}

auto inverses = df::algebra::inv(mats);
auto transposed = df::algebra::transpose(mats);

// Symmetric matrix (stress tensor) eigen decomposition
df::Serie<SMatrix3D> stresses{
    {1, 0, 0, 1, 0, 1},   // identity-like
    {2, 1, 0, 3, 0, 1}
};
auto dets = df::algebra::det(stresses);

// Solve linear system: Ax = b
df::Serie<Matrix3D> A{
    {2, 1, 0, 1, 3, 1, 0, 1, 2}
};
df::Serie<Vector3D> b{{1, 2, 3}};
auto x = df::algebra::solve(A, b);

Eigen Decomposition

Eigen Functions (Symmetric Matrices Only)

// Eigenvalues of symmetric matrices (returned sorted)
template <typename T, size_t N>
Serie<Vector<T,N>> eigenValues(const Serie<SymmetricMatrix<T,N>> &matrices);

// Eigenvectors of symmetric matrices
template <typename T, size_t N>
Serie<FullMatrix<T,N>> eigenVectors(const Serie<SymmetricMatrix<T,N>> &matrices);

// Both eigenvalues and eigenvectors at once
template <typename T, size_t N>
std::pair<Serie<Vector<T,N>>, Serie<FullMatrix<T,N>>>
eigenSystem(const Serie<SymmetricMatrix<T,N>> &matrices);

// Pipeline versions
auto bind_eigenValues();
auto bind_eigenVectors();
auto bind_eigenSystem();
Eigen Decomposition Example

// Stress tensor eigen decomposition
df::Serie<SMatrix3D> stresses{
    {10.0, 0.0, 0.0, 5.0, 0.0, 3.0},
    {20.0, 1.0, 0.5, 15.0, 0.0, 8.0}
};

// Get eigenvalues (principal stresses)
auto principals = df::algebra::eigenValues(stresses);
// principals[i] = {sigma1, sigma2, sigma3} sorted

// Get eigenvectors (principal directions)
auto directions = df::algebra::eigenVectors(stresses);

// Get both at once (more efficient)
auto [values, vectors] = df::algebra::eigenSystem(stresses);

// Pipeline usage
auto evals = stresses | df::algebra::bind_eigenValues<double, 3>();

Complete Example

Stress Analysis Example

#include <dataframe/Serie.h>
#include <dataframe/algebra.h>
#include <iostream>

int main() {
    // Define stress tensors at mesh nodes (symmetric 3x3)
    // Components: {xx, xy, xz, yy, yz, zz}
    df::Serie<Stress3D> stresses{
        {100.0, 10.0, 0.0, 50.0, 5.0, 30.0},
        {200.0, 20.0, 5.0, 150.0, 10.0, 80.0},
        {80.0,  5.0,  0.0, 40.0, 2.0, 25.0}
    };

    // Compute principal stresses (eigenvalues)
    auto [principals, directions] = df::algebra::eigenSystem(stresses);

    for (size_t i = 0; i < stresses.size(); ++i) {
        std::cout << "Node " << i << ": "
                  << "sigma1=" << principals[i][0]
                  << " sigma2=" << principals[i][1]
                  << " sigma3=" << principals[i][2] << "\n";
    }

    // Compute determinant of each stress tensor
    auto dets = df::algebra::det(stresses);

    // Compute inverse
    auto inv_stresses = df::algebra::inv(stresses);

    // Vector operations: displacement field
    df::Serie<Vector3D> displacements{
        {0.1, 0.2, 0.0},
        {0.3, 0.1, 0.05},
        {0.05, 0.15, 0.0}
    };

    auto magnitudes = df::algebra::norm(displacements);

    std::cout << "Displacement magnitudes: ";
    for (size_t i = 0; i < magnitudes.size(); ++i) {
        std::cout << magnitudes[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}