#![allow(deprecated)]
#![allow(clippy::result_large_err)]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use numrs2::array::Array;
use numrs2::new_modules::polynomial::polyfit;
use numrs2::prelude::*;
use std::hint::black_box;
use std::time::Duration;
const SIZES: [usize; 4] = [1000, 10000, 100000, 1000000];
const MATRIX_SIZES: [usize; 4] = [32, 64, 128, 256];
fn numpy_creation_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_creation");
group.measurement_time(Duration::from_secs(3));
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)))
});
if *size <= 100000 {
group.bench_with_input(BenchmarkId::new("arange", size), size, |b, &size| {
b.iter(|| black_box(arange(0.0f64, size as f64, 1.0f64)))
});
}
if *size <= 100000 {
group.bench_with_input(BenchmarkId::new("linspace", size), size, |b, &size| {
b.iter(|| black_box(linspace(0.0f64, 1.0f64, size)))
});
}
}
for size in MATRIX_SIZES.iter() {
let elements = size * size;
group.throughput(Throughput::Elements(elements as u64));
group.bench_with_input(BenchmarkId::new("eye", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::eye(size, size, 0)))
});
group.bench_with_input(BenchmarkId::new("identity", size), size, |b, &size| {
b.iter(|| black_box(Array::<f64>::identity(size)))
});
}
group.finish();
}
fn numpy_arithmetic_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_arithmetic");
group.measurement_time(Duration::from_secs(3));
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.001 + 1.0).collect();
let b_data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.002 + 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("subtract", size), size, |bench, _| {
bench.iter(|| black_box(&a - &b))
});
group.bench_with_input(BenchmarkId::new("multiply", size), size, |bench, _| {
bench.iter(|| black_box(&a * &b))
});
group.bench_with_input(BenchmarkId::new("divide", size), size, |bench, _| {
bench.iter(|| black_box(&a / &b))
});
group.bench_with_input(BenchmarkId::new("add_scalar", size), size, |bench, _| {
bench.iter(|| black_box(a.add_scalar(2.5)))
});
}
group.finish();
}
fn numpy_ufunc_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_ufuncs");
group.measurement_time(Duration::from_secs(3));
for size in SIZES.iter() {
if *size > 100000 {
continue; }
group.throughput(Throughput::Elements(*size as u64));
let pos_data: Vec<f64> = (1..=*size).map(|x| x as f64).collect();
let pos = Array::from_vec(pos_data);
let small_data: Vec<f64> = (0..*size).map(|x| (x as f64) * 0.0001).collect();
let small = Array::from_vec(small_data);
let angle_data: Vec<f64> = (0..*size)
.map(|x| (x as f64) * 0.001 * std::f64::consts::PI)
.collect();
let angles = Array::from_vec(angle_data);
group.bench_with_input(BenchmarkId::new("sqrt", size), size, |bench, _| {
bench.iter(|| black_box(pos.sqrt()))
});
group.bench_with_input(BenchmarkId::new("exp", size), size, |bench, _| {
bench.iter(|| black_box(small.exp()))
});
group.bench_with_input(BenchmarkId::new("log", size), size, |bench, _| {
bench.iter(|| black_box(pos.log()))
});
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 numpy_reduction_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_reductions");
group.measurement_time(Duration::from_secs(3));
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("std", size), size, |bench, _| {
bench.iter(|| black_box(a.std()))
});
group.bench_with_input(BenchmarkId::new("var", size), size, |bench, _| {
bench.iter(|| black_box(a.var()))
});
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 numpy_manipulation_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_manipulation");
group.measurement_time(Duration::from_secs(3));
for size in SIZES.iter() {
if *size > 100000 {
continue;
}
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 side = (*size as f64).sqrt() as usize;
if side * side == *size && side > 0 {
group.bench_with_input(BenchmarkId::new("reshape", size), size, |bench, _| {
bench.iter(|| black_box(a.reshape(&[side, side])))
});
let matrix = a.reshape(&[side, side]);
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("copy", size), size, |bench, _| {
bench.iter(|| black_box(a.clone()))
});
}
group.finish();
}
fn numpy_linalg_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_linalg");
group.sample_size(20);
group.measurement_time(Duration::from_secs(5));
for size in MATRIX_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.73) % 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 numpy_polynomial_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("np_polynomial");
group.measurement_time(Duration::from_secs(3));
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("polyval_single", degree),
degree,
|bench, _| bench.iter(|| black_box(poly.evaluate(2.5))),
);
group.bench_with_input(BenchmarkId::new("polyder", degree), degree, |bench, _| {
bench.iter(|| black_box(poly.derivative()))
});
group.bench_with_input(BenchmarkId::new("polyint", degree), degree, |bench, _| {
bench.iter(|| black_box(poly.integral()))
});
let p2_coeffs: Vec<f64> = (0..=*degree).map(|i| (i as f64) * 0.5).collect();
let p2 = Polynomial::new(p2_coeffs);
group.bench_with_input(BenchmarkId::new("polymul", degree), degree, |bench, _| {
bench.iter(|| black_box(poly.clone() * p2.clone()))
});
group.bench_with_input(BenchmarkId::new("polyadd", degree), degree, |bench, _| {
bench.iter(|| black_box(poly.clone() + p2.clone()))
});
}
let fit_sizes = [10, 50, 100];
for size in fit_sizes.iter() {
let x_data: Vec<f64> = (0..*size).map(|i| i as f64).collect();
let y_data: Vec<f64> = x_data
.iter()
.map(|x| x * x * 0.5 + x * 2.0 + 1.0 + (x * 0.1).sin())
.collect();
let x = Array::from_vec(x_data);
let y = Array::from_vec(y_data);
group.bench_with_input(BenchmarkId::new("polyfit_deg3", size), size, |bench, _| {
bench.iter(|| black_box(polyfit(&x, &y, 3)))
});
}
group.finish();
}
criterion_group!(
name = numpy_comparison;
config = Criterion::default()
.measurement_time(Duration::from_secs(3))
.warm_up_time(Duration::from_secs(1));
targets =
numpy_creation_benchmarks,
numpy_arithmetic_benchmarks,
numpy_ufunc_benchmarks,
numpy_reduction_benchmarks,
numpy_manipulation_benchmarks,
numpy_linalg_benchmarks,
numpy_polynomial_benchmarks,
);
criterion_main!(numpy_comparison);