Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ name = "vs_linalg"
harness = false
required-features = [ "bench" ]

[[bench]]
name = "exact"
harness = false
required-features = [ "bench", "exact" ]

[profile.release]
lto = "fat"
codegen-units = 1
Expand Down
166 changes: 166 additions & 0 deletions benches/exact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//! Benchmarks for exact arithmetic operations.
//!
//! These benchmarks measure the performance of the `exact` feature's
//! arbitrary-precision methods across dimensions D=2..5 (the primary
//! target for geometric predicates).

use criterion::Criterion;
use la_stack::{Matrix, Vector};
use pastey::paste;
use std::hint::black_box;

#[inline]
#[allow(clippy::cast_precision_loss)]
fn matrix_entry<const D: usize>(r: usize, c: usize) -> f64 {
if r == c {
(r as f64).mul_add(1.0e-3, (D as f64) + 1.0)
} else {
0.1 / ((r + c + 1) as f64)
}
}

#[inline]
fn make_matrix_rows<const D: usize>() -> [[f64; D]; D] {
let mut rows = [[0.0; D]; D];
let mut r = 0;
while r < D {
let mut c = 0;
while c < D {
rows[r][c] = matrix_entry::<D>(r, c);
c += 1;
}
r += 1;
}
rows
}

#[inline]
#[allow(clippy::cast_precision_loss)]
fn make_vector_array<const D: usize>() -> [f64; D] {
let mut data = [0.0; D];
let mut i = 0;
while i < D {
data[i] = (i as f64) + 1.0;
i += 1;
}
data
}

/// Near-singular matrix: base singular matrix + tiny perturbation.
/// This forces the exact Bareiss fallback in `det_sign_exact` (the fast
/// f64 filter cannot resolve the sign).
#[inline]
fn near_singular_3x3() -> Matrix<3> {
let perturbation = f64::from_bits(0x3CD0_0000_0000_0000); // 2^-50
Matrix::<3>::from_rows([
[1.0 + perturbation, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
])
}

macro_rules! gen_exact_benches_for_dim {
($c:expr, $d:literal) => {
paste! {{
let a = Matrix::<$d>::from_rows(make_matrix_rows::<$d>());
let rhs = Vector::<$d>::new(make_vector_array::<$d>());

let mut [<group_d $d>] = ($c).benchmark_group(concat!("exact_d", stringify!($d)));

// === f64 baselines ===
[<group_d $d>].bench_function("det", |bencher| {
bencher.iter(|| {
let det = black_box(a)
.det(la_stack::DEFAULT_PIVOT_TOL)
.expect("should not fail");
black_box(det);
});
});

[<group_d $d>].bench_function("det_direct", |bencher| {
bencher.iter(|| {
let det = black_box(a).det_direct();
black_box(det);
});
});

// === det_exact (BigRational result) ===
[<group_d $d>].bench_function("det_exact", |bencher| {
bencher.iter(|| {
let det = black_box(a).det_exact().expect("should not fail");
black_box(det);
});
});

// === det_exact_f64 (exact → f64) ===
[<group_d $d>].bench_function("det_exact_f64", |bencher| {
bencher.iter(|| {
let det = black_box(a).det_exact_f64().expect("should not fail");
black_box(det);
});
});

// === det_sign_exact (adaptive: fast filter + exact fallback) ===
[<group_d $d>].bench_function("det_sign_exact", |bencher| {
bencher.iter(|| {
let sign = black_box(a).det_sign_exact().expect("should not fail");
black_box(sign);
});
});

// === solve_exact (BigRational result) ===
[<group_d $d>].bench_function("solve_exact", |bencher| {
bencher.iter(|| {
let x = black_box(a).solve_exact(black_box(rhs)).expect("should not fail");
black_box(x);
});
});

// === solve_exact_f64 (exact → f64) ===
[<group_d $d>].bench_function("solve_exact_f64", |bencher| {
bencher.iter(|| {
let x = black_box(a).solve_exact_f64(black_box(rhs)).expect("should not fail");
black_box(x);
});
});

[<group_d $d>].finish();
}};
};
}

fn main() {
let mut c = Criterion::default().configure_from_args();

#[allow(unused_must_use)]
{
gen_exact_benches_for_dim!(&mut c, 2);
gen_exact_benches_for_dim!(&mut c, 3);
gen_exact_benches_for_dim!(&mut c, 4);
gen_exact_benches_for_dim!(&mut c, 5);
}

// Near-singular 3×3: forces Bareiss fallback in det_sign_exact.
{
let m = near_singular_3x3();
let mut group = c.benchmark_group("exact_near_singular_3x3");

group.bench_function("det_sign_exact", |bencher| {
bencher.iter(|| {
let sign = black_box(m).det_sign_exact().expect("should not fail");
black_box(sign);
});
});

group.bench_function("det_exact", |bencher| {
bencher.iter(|| {
let det = black_box(m).det_exact().expect("should not fail");
black_box(det);
});
});

group.finish();
}

c.final_summary();
}
Loading
Loading