use ironlab::Matrix;
use ironlab::ir::IrError;
use ironlab::{linspace, logspace, meshgrid};
#[test]
fn from_fn_fills_row_major() {
let m = Matrix::from_fn(2, 3, |row, col| (10 * row + col) as f64);
assert_eq!((m.rows(), m.cols()), (2, 3));
assert_eq!(m.values(), &[0.0, 1.0, 2.0, 10.0, 11.0, 12.0]);
assert_eq!(m[(0, 2)], 2.0);
assert_eq!(m[(1, 0)], 10.0);
assert_eq!(m.row(1), &[10.0, 11.0, 12.0]);
}
#[test]
fn from_rows_agrees_with_from_fn() {
let m = Matrix::from_rows(&[vec![0.0, 1.0, 2.0], vec![10.0, 11.0, 12.0]]);
assert_eq!(m, Matrix::from_fn(2, 3, |row, col| (10 * row + col) as f64));
}
#[test]
#[should_panic(expected = "matrix rows have different lengths")]
fn from_rows_panics_on_ragged_rows() {
let _ = Matrix::from_rows(&[vec![0.0, 1.0], vec![2.0]]);
}
#[test]
fn from_vec_checks_the_length() {
let m = Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0, 4.0]).unwrap();
assert_eq!(m[(1, 0)], 3.0);
assert!(matches!(
Matrix::from_vec(2, 2, vec![1.0, 2.0, 3.0]),
Err(IrError::InvalidShape { .. })
));
}
#[test]
fn zeros_and_index_mut() {
let mut m = Matrix::zeros(2, 2);
assert_eq!(m.values(), &[0.0; 4]);
m[(0, 1)] = 5.0;
assert_eq!(m.values(), &[0.0, 5.0, 0.0, 0.0]);
}
#[test]
#[should_panic(expected = "out of range")]
fn index_past_the_last_column_panics() {
let m = Matrix::from_fn(2, 2, |_, _| 0.0);
let _ = m[(0, 2)];
}
#[test]
#[should_panic(expected = "out of range")]
fn index_mut_past_the_last_column_panics() {
let mut m = Matrix::zeros(2, 2);
m[(0, 2)] = 1.0;
}
#[test]
#[should_panic(expected = "out of range")]
fn row_past_the_last_row_panics() {
let m = Matrix::zeros(2, 3);
let _ = m.row(2);
}
#[test]
fn map_and_zip_map_preserve_shape_and_pairing() {
let a = Matrix::from_fn(2, 3, |row, col| (row + col) as f64);
let b = Matrix::from_fn(2, 3, |row, _| row as f64 * 100.0);
let doubled = a.map(|v| 2.0 * v);
assert_eq!(
doubled,
Matrix::from_fn(2, 3, |row, col| 2.0 * (row + col) as f64)
);
let sum = a.zip_map(&b, |p, q| p + q);
assert_eq!(
sum,
Matrix::from_fn(2, 3, |row, col| (row + col) as f64 + row as f64 * 100.0)
);
}
#[test]
#[should_panic(expected = "matrices have different shapes")]
fn zip_map_panics_on_shape_mismatch() {
let a = Matrix::zeros(2, 3);
let b = Matrix::zeros(3, 2);
let _ = a.zip_map(&b, |p, q| p + q);
}
#[test]
fn meshgrid_varies_x_along_columns_and_y_along_rows() {
let x = [1.0, 2.0, 3.0];
let y = [-1.0, 1.0];
let (xx, yy) = meshgrid(&x, &y);
assert_eq!((xx.rows(), xx.cols()), (2, 3));
assert_eq!((yy.rows(), yy.cols()), (2, 3));
for row in 0..2 {
for col in 0..3 {
assert_eq!(xx[(row, col)], x[col]);
assert_eq!(yy[(row, col)], y[row]);
}
}
}
#[test]
fn linspace_has_exact_endpoints_and_count() {
let v = linspace(0.1, 0.3, 7);
assert_eq!(v.len(), 7);
assert_eq!(v[0], 0.1);
assert_eq!(v[6], 0.3);
let pi = std::f64::consts::PI;
let w = linspace(-pi, 2.0 * pi, 1001);
assert_eq!(w.len(), 1001);
assert_eq!(w[0], -pi);
assert_eq!(w[1000], 2.0 * pi);
}
#[test]
fn linspace_is_evenly_spaced_including_decreasing_ranges() {
assert_eq!(linspace(0.0, 1.0, 5), vec![0.0, 0.25, 0.5, 0.75, 1.0]);
assert_eq!(linspace(1.0, -1.0, 3), vec![1.0, 0.0, -1.0]);
}
#[test]
fn linspace_degenerate_counts() {
assert_eq!(linspace(2.0, 5.0, 1), vec![5.0]);
assert!(linspace(2.0, 5.0, 0).is_empty());
}
#[test]
fn logspace_is_exact_at_integer_exponents() {
assert_eq!(
logspace(-3.0, 3.0, 7),
vec![0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0]
);
}
#[test]
fn logspace_has_a_constant_ratio_and_follows_linspace_counts() {
let v = logspace(0.0, 1.0, 3);
assert_eq!(v[0], 1.0);
assert!((v[1] - 10f64.sqrt()).abs() < 1e-12, "{}", v[1]);
assert_eq!(v[2], 10.0);
assert_eq!(logspace(0.0, 2.0, 1), vec![100.0]);
assert!(logspace(0.0, 1.0, 0).is_empty());
}