#![allow(deprecated)]
#![allow(clippy::result_large_err)]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use numrs2::array::Array;
use numrs2::prelude::*;
use std::hint::black_box;
const SMALL_SIZE: usize = 1_000;
const MEDIUM_SIZE: usize = 10_000;
const LARGE_SIZE: usize = 100_000;
const XLARGE_SIZE: usize = 1_000_000;
const MATRIX_SMALL: usize = 100;
const MATRIX_MEDIUM: usize = 500;
fn bench_array_creation(c: &mut Criterion) {
let mut group = c.benchmark_group("Array Creation");
let sizes = [SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE, XLARGE_SIZE];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
group.bench_with_input(BenchmarkId::new("zeros", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::zeros(&[size])))
});
group.bench_with_input(BenchmarkId::new("ones", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::ones(&[size])))
});
group.bench_with_input(BenchmarkId::new("full", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::full(&[size], std::f64::consts::PI)))
});
group.bench_with_input(BenchmarkId::new("from_vec", size), size, |b, &size| {
let data: Vec<f64> = (0..size).map(|x| x as f64).collect();
b.iter(|| black_box(Array::from_vec(data.clone())))
});
if *size <= MEDIUM_SIZE {
group.bench_with_input(BenchmarkId::new("linspace", size), size, |b, &size| {
b.iter(|| black_box(linspace(0.0f64, 100.0f64, size)))
});
}
if *size <= MEDIUM_SIZE {
group.bench_with_input(BenchmarkId::new("arange", size), size, |b, &size| {
b.iter(|| black_box(arange(0.0f64, size as f64, 1.0f64)))
});
}
}
group.finish();
}
fn bench_matrix_creation(c: &mut Criterion) {
let mut group = c.benchmark_group("Matrix Creation");
let sizes = [MATRIX_SMALL, MATRIX_MEDIUM];
for size in sizes.iter() {
let elements = size * size;
group.throughput(Throughput::Elements(elements as u64));
group.bench_with_input(BenchmarkId::new("zeros_2d", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::zeros(&[size, size])))
});
group.bench_with_input(BenchmarkId::new("ones_2d", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::ones(&[size, size])))
});
group.bench_with_input(BenchmarkId::new("identity", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::identity(size)))
});
group.bench_with_input(BenchmarkId::new("eye", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::eye(size, size, 0)))
});
}
group.finish();
}
fn bench_elementwise_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("Element-wise Operations");
let sizes = [SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
let a_data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.01 + 1.0).collect();
let b_data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.02 + 0.5).collect();
let a = Array::from_vec(a_data);
let b = Array::from_vec(b_data);
group.bench_with_input(BenchmarkId::new("add", size), size, |bench, _| {
bench.iter(|| black_box(&a + &b))
});
group.bench_with_input(BenchmarkId::new("sub", size), size, |bench, _| {
bench.iter(|| black_box(&a - &b))
});
group.bench_with_input(BenchmarkId::new("mul", size), size, |bench, _| {
bench.iter(|| black_box(&a * &b))
});
group.bench_with_input(BenchmarkId::new("div", size), size, |bench, _| {
bench.iter(|| black_box(&a / &b))
});
group.bench_with_input(BenchmarkId::new("scalar_add", size), size, |bench, _| {
bench.iter(|| black_box(a.add_scalar(2.5)))
});
}
group.finish();
}
fn bench_math_functions(c: &mut Criterion) {
let mut group = c.benchmark_group("Mathematical Functions");
let sizes = [SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
let data: Vec<f64> = (1..=*size).map(|x| x as f64).collect();
let a = Array::from_vec(data);
group.bench_with_input(BenchmarkId::new("sqrt", size), size, |bench, _| {
bench.iter(|| black_box(a.sqrt()))
});
let exp_data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.001).collect();
let exp_arr = Array::from_vec(exp_data);
group.bench_with_input(BenchmarkId::new("exp", size), size, |bench, _| {
bench.iter(|| black_box(exp_arr.exp()))
});
group.bench_with_input(BenchmarkId::new("log", size), size, |bench, _| {
bench.iter(|| black_box(a.log()))
});
let angle_data: Vec<f64> = (0..*size)
.map(|x| (x as f64) * 0.01 * std::f64::consts::PI)
.collect();
let angles = Array::from_vec(angle_data);
group.bench_with_input(BenchmarkId::new("sin", size), size, |bench, _| {
bench.iter(|| black_box(angles.sin()))
});
group.bench_with_input(BenchmarkId::new("cos", size), size, |bench, _| {
bench.iter(|| black_box(angles.cos()))
});
let mixed_data: Vec<f64> = (0..*size)
.map(|x| (x as f64) - (*size as f64) / 2.0)
.collect();
let mixed = Array::from_vec(mixed_data);
group.bench_with_input(BenchmarkId::new("abs", size), size, |bench, _| {
bench.iter(|| black_box(mixed.abs()))
});
}
group.finish();
}
fn bench_reductions(c: &mut Criterion) {
let mut group = c.benchmark_group("Reduction Operations");
let sizes = [SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE, XLARGE_SIZE];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
let data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.001).collect();
let a = Array::from_vec(data);
group.bench_with_input(BenchmarkId::new("sum", size), size, |bench, _| {
bench.iter(|| black_box(a.sum()))
});
group.bench_with_input(BenchmarkId::new("mean", size), size, |bench, _| {
bench.iter(|| black_box(a.mean()))
});
group.bench_with_input(BenchmarkId::new("var", size), size, |bench, _| {
bench.iter(|| black_box(a.var()))
});
group.bench_with_input(BenchmarkId::new("std", size), size, |bench, _| {
bench.iter(|| black_box(a.std()))
});
group.bench_with_input(BenchmarkId::new("min", size), size, |bench, _| {
bench.iter(|| black_box(a.min()))
});
group.bench_with_input(BenchmarkId::new("max", size), size, |bench, _| {
bench.iter(|| black_box(a.max()))
});
}
group.finish();
}
fn bench_array_manipulation(c: &mut Criterion) {
let mut group = c.benchmark_group("Array Manipulation");
let sizes = [SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
let data: Vec<f64> = (0..*size).map(|x| x as f64).collect();
let a = Array::from_vec(data);
let rows = (*size as f64).sqrt() as usize;
let cols = size / rows;
if rows * cols == *size && rows > 0 && cols > 0 {
group.bench_with_input(BenchmarkId::new("reshape", size), size, |bench, _| {
bench.iter(|| black_box(a.reshape(&[rows, cols])))
});
let matrix = a.reshape(&[rows, cols]);
group.bench_with_input(BenchmarkId::new("transpose", size), size, |bench, _| {
bench.iter(|| black_box(matrix.transpose()))
});
group.bench_with_input(BenchmarkId::new("flatten", size), size, |bench, _| {
bench.iter(|| black_box(matrix.flatten(None)))
});
}
group.bench_with_input(BenchmarkId::new("clone", size), size, |bench, _| {
bench.iter(|| black_box(a.clone()))
});
}
group.finish();
}
fn bench_linear_algebra(c: &mut Criterion) {
let mut group = c.benchmark_group("Linear Algebra");
group.sample_size(20);
let sizes = [50, 100, 200];
for size in sizes.iter() {
let elements = size * size;
group.throughput(Throughput::Elements(elements as u64));
let data: Vec<f64> = (0..elements)
.map(|i| ((i as f64 * 0.7) % 10.0) + 0.1)
.collect();
let a = Array::from_vec(data).reshape(&[*size, *size]);
let vec_data: Vec<f64> = (0..*size).map(|i| (i as f64) + 1.0).collect();
let v = Array::from_vec(vec_data);
group.bench_with_input(BenchmarkId::new("matmul", size), size, |bench, _| {
bench.iter(|| black_box(a.matmul(&a)))
});
group.bench_with_input(BenchmarkId::new("dot", size), size, |bench, _| {
bench.iter(|| black_box(v.dot(&v)))
});
group.bench_with_input(BenchmarkId::new("trace", size), size, |bench, _| {
bench.iter(|| black_box(numrs2::linalg::vector_ops::trace(&a)))
});
}
group.finish();
}
fn bench_polynomial_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("Polynomial Operations");
let degrees = [5, 10, 20, 50];
for degree in degrees.iter() {
let coeffs: Vec<f64> = (0..=*degree).map(|i| 1.0 / (i as f64 + 1.0)).collect();
let poly = Polynomial::new(coeffs);
group.bench_with_input(
BenchmarkId::new("evaluate_single", degree),
degree,
|bench, _| bench.iter(|| black_box(poly.evaluate(2.5))),
);
group.bench_with_input(
BenchmarkId::new("derivative", degree),
degree,
|bench, _| bench.iter(|| black_box(poly.derivative())),
);
group.bench_with_input(BenchmarkId::new("integral", degree), degree, |bench, _| {
bench.iter(|| black_box(poly.integral()))
});
}
let sizes = [5, 10, 20];
for size in sizes.iter() {
let coeffs1: Vec<f64> = (0..*size).map(|i| (i as f64) + 1.0).collect();
let coeffs2: Vec<f64> = (0..*size).map(|i| (i as f64) * 0.5 + 0.5).collect();
let p1 = Polynomial::new(coeffs1);
let p2 = Polynomial::new(coeffs2);
group.bench_with_input(BenchmarkId::new("multiply", size), size, |bench, _| {
bench.iter(|| black_box(p1.clone() * p2.clone()))
});
group.bench_with_input(BenchmarkId::new("add", size), size, |bench, _| {
bench.iter(|| black_box(p1.clone() + p2.clone()))
});
}
group.finish();
}
fn bench_scalability(c: &mut Criterion) {
let mut group = c.benchmark_group("Scalability");
group.sample_size(10);
let sizes: Vec<usize> = vec![1000, 5000, 10000, 50000, 100000, 500000, 1000000];
for size in sizes.iter() {
group.throughput(Throughput::Elements(*size as u64));
let data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.001).collect();
let a = Array::from_vec(data);
group.bench_with_input(BenchmarkId::new("sum_scale", size), size, |bench, _| {
bench.iter(|| black_box(a.sum()))
});
let b = a.add_scalar(1.0);
group.bench_with_input(BenchmarkId::new("add_scale", size), size, |bench, _| {
bench.iter(|| black_box(&a + &b))
});
group.bench_with_input(BenchmarkId::new("clone_scale", size), size, |bench, _| {
bench.iter(|| black_box(a.clone()))
});
}
group.finish();
}
criterion_group!(
benches,
bench_array_creation,
bench_matrix_creation,
bench_elementwise_ops,
bench_math_functions,
bench_reductions,
bench_array_manipulation,
bench_linear_algebra,
bench_polynomial_ops,
bench_scalability,
);
criterion_main!(benches);