russell_tensor 3.1.0

Tensor analysis, calculus, and functions for continuum mechanics
Documentation
//! Benchmarks for the `russell_tensor` crate.
//!
//! Each function is benchmarked in two variants:
//!
//! * `unrolled` — the production (manually-unrolled) implementation
//! * `loops` — the loop-based reference implementation from `russell_tensor::z_reference_loop_fns`

use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use russell_tensor::z_reference_loop_fns::{
    deriv_squared_tensor_loops, deriv2_invariant_jj3_loops, deriv2_invariant_lode_loops, dsd_fn_loops, qsd_fn_loops,
    ssd_fn_loops,
};
use russell_tensor::{SET, Tensor2, Tensor4, WorkspaceDeriv2Lode};
use russell_tensor::{deriv_squared_tensor, deriv2_invariant_jj3, deriv2_invariant_lode, dsd_fn, qsd_fn, ssd_fn};

/// Fixed symmetric 3×3 matrix used to build the input tensors
const SYMMETRIC: [[f64; 3]; 3] = [
    [1.0, 2.0, 3.0], // 1
    [2.0, 4.0, 5.0], // 2
    [3.0, 5.0, 6.0], // 3
];

/// Fixed general (non-symmetric) 3×3 matrix used to build the input tensors
const GENERAL: [[f64; 3]; 3] = [
    [1.0, 2.0, 3.0], // 1
    [4.0, 5.0, 6.0], // 2
    [7.0, 8.0, 9.0], // 3
];

/// Benchmarks `dsd_fn` (duo-sum-dyadic)
fn bench_dsd_fn(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("dsd_fn");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let bb = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            dsd_fn(&mut dd, SET, 1.0, &aa, &bb);
            std::hint::black_box(&dd);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let bb = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            dsd_fn_loops(&mut dd, 1.0, &aa, &bb);
            std::hint::black_box(&dd);
        });
    });

    group.finish();
}

/// Benchmarks `ssd_fn` (self-sum-dyadic)
fn bench_ssd_fn(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("ssd_fn");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            ssd_fn(&mut dd, SET, 1.0, &aa);
            std::hint::black_box(&dd);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            ssd_fn_loops(&mut dd, 1.0, &aa);
            std::hint::black_box(&dd);
        });
    });

    group.finish();
}

/// Benchmarks `qsd_fn` (quad-sum-dyadic)
fn bench_qsd_fn(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("qsd_fn");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let bb = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            qsd_fn(&mut dd, SET, 1.0, &aa, &bb);
            std::hint::black_box(&dd);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let aa = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let bb = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut dd = Tensor4::<6>::new();
        b.iter(|| {
            qsd_fn_loops(&mut dd, 1.0, &aa, &bb);
            std::hint::black_box(&dd);
        });
    });

    group.finish();
}

/// Benchmarks `deriv2_invariant_jj3` (second derivative of J3)
fn bench_deriv2_invariant_jj3(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("deriv2_invariant_jj3");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let a = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut d2 = Tensor4::<6>::new();
        b.iter(|| {
            deriv2_invariant_jj3(&mut d2, &a);
            std::hint::black_box(&d2);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let a = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut d2 = Tensor4::<6>::new();
        b.iter(|| {
            deriv2_invariant_jj3_loops(&mut d2, &a);
            std::hint::black_box(&d2);
        });
    });

    group.finish();
}

/// Benchmarks `deriv2_invariant_lode` (second derivative of the Lode invariant)
fn bench_deriv2_invariant_lode(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("deriv2_invariant_lode");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let a = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut d2 = Tensor4::<6>::new();
        let mut work = WorkspaceDeriv2Lode::new();
        b.iter(|| {
            deriv2_invariant_lode(&mut d2, &mut work, &a);
            std::hint::black_box(&d2);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let a = Tensor2::<6>::from_std_matrix(&SYMMETRIC).unwrap();
        let mut d2 = Tensor4::<6>::new();
        b.iter(|| {
            deriv2_invariant_lode_loops(&mut d2, &a);
            std::hint::black_box(&d2);
        });
    });

    group.finish();
}

/// Benchmarks `deriv_squared_tensor` (derivative of the squared tensor, general)
fn bench_deriv_squared_tensor(crit: &mut Criterion) {
    let mut group = crit.benchmark_group("deriv_squared_tensor");

    group.bench_with_input(BenchmarkId::new("unrolled", ""), &(), |b, _| {
        let aa = Tensor2::<9>::from_std_matrix(&GENERAL).unwrap();
        let mut da2_da = Tensor4::<9>::new();
        b.iter(|| {
            deriv_squared_tensor(&mut da2_da, &aa);
            std::hint::black_box(&da2_da);
        });
    });

    group.bench_with_input(BenchmarkId::new("loops", ""), &(), |b, _| {
        let aa = Tensor2::<9>::from_std_matrix(&GENERAL).unwrap();
        let mut da2_da = Tensor4::<9>::new();
        b.iter(|| {
            deriv_squared_tensor_loops(&mut da2_da, &aa);
            std::hint::black_box(&da2_da);
        });
    });

    group.finish();
}

criterion_group!(
    benches,
    bench_dsd_fn,
    bench_ssd_fn,
    bench_qsd_fn,
    bench_deriv2_invariant_jj3,
    bench_deriv2_invariant_lode,
    bench_deriv_squared_tensor
);
criterion_main!(benches);