Patch to version 0.4.0 (#257)

* uncomment test

* Add random test for logistic regression

* linting

* Bump version

* Add test for logistic regression

* linting

* initial commit

* final

* final-clean

* Bump to 0.4.0

* Fix linter

* cleanup

* Update CHANDELOG with breaking changes

* Update CHANDELOG date

* Add functional methods to DenseMatrix implementation

* linting

* add type declaration in test

* Fix Wasm tests failing

* linting

* fix tests

* linting

* Add type annotations on BBDTree constructor

* fix clippy

* fix clippy

* fix tests

* bump version

* run fmt. fix changelog

---------

Co-authored-by: Edmund Cape <edmund@Edmunds-MacBook-Pro.local>
This commit is contained in:
Lorenzo
2024-03-04 13:51:27 +00:00
committed by GitHub
parent 80a93c1a0e
commit 239c00428f
45 changed files with 759 additions and 406 deletions
+122 -84
View File
@@ -1775,7 +1775,7 @@ mod tests {
#[test]
fn test_xa() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(vec![7, 8].xa(false, &a), vec![39, 54, 69]);
assert_eq!(vec![7, 8, 9].xa(true, &a), vec![50, 122]);
}
@@ -1783,19 +1783,27 @@ mod tests {
#[test]
fn test_min_max() {
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).max(0),
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]])
.unwrap()
.max(0),
vec!(4, 5, 6)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).max(1),
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]])
.unwrap()
.max(1),
vec!(3, 6)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).min(0),
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]])
.unwrap()
.min(0),
vec!(1., 2., 3.)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).min(1),
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]])
.unwrap()
.min(1),
vec!(1., 4.)
);
}
@@ -1803,11 +1811,15 @@ mod tests {
#[test]
fn test_argmax() {
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 5, 3], &[4, 2, 6]]).argmax(0),
DenseMatrix::from_2d_array(&[&[1, 5, 3], &[4, 2, 6]])
.unwrap()
.argmax(0),
vec!(1, 0, 1)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[4, 2, 3], &[1, 5, 6]]).argmax(1),
DenseMatrix::from_2d_array(&[&[4, 2, 3], &[1, 5, 6]])
.unwrap()
.argmax(1),
vec!(0, 2)
);
}
@@ -1815,168 +1827,181 @@ mod tests {
#[test]
fn test_sum() {
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).sum(0),
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]])
.unwrap()
.sum(0),
vec!(5, 7, 9)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).sum(1),
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]])
.unwrap()
.sum(1),
vec!(6., 15.)
);
}
#[test]
fn test_abs() {
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]);
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]).unwrap();
x.abs_mut();
assert_eq!(x, DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]));
assert_eq!(
x,
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap()
);
}
#[test]
fn test_neg() {
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]);
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]).unwrap();
x.neg_mut();
assert_eq!(x, DenseMatrix::from_2d_array(&[&[1, -2, 3], &[-4, 5, -6]]));
assert_eq!(
x,
DenseMatrix::from_2d_array(&[&[1, -2, 3], &[-4, 5, -6]]).unwrap()
);
}
#[test]
fn test_copy_from() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let mut y = DenseMatrix::<i32>::zeros(2, 3);
y.copy_from(&x);
assert_eq!(y, DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]));
assert_eq!(
y,
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap()
);
}
#[test]
fn test_init() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(
DenseMatrix::<i32>::zeros(2, 2),
DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]])
DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]]).unwrap()
);
assert_eq!(
DenseMatrix::<i32>::ones(2, 2),
DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]])
DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]]).unwrap()
);
assert_eq!(
DenseMatrix::<i32>::eye(3),
DenseMatrix::from_2d_array(&[&[1, 0, 0], &[0, 1, 0], &[0, 0, 1]])
DenseMatrix::from_2d_array(&[&[1, 0, 0], &[0, 1, 0], &[0, 0, 1]]).unwrap()
);
assert_eq!(
DenseMatrix::from_slice(x.slice(0..2, 0..2).as_ref()),
DenseMatrix::from_2d_array(&[&[1, 2], &[4, 5]])
DenseMatrix::from_slice(x.slice(0..2, 0..2).as_ref()), // internal only?
DenseMatrix::from_2d_array(&[&[1, 2], &[4, 5]]).unwrap()
);
assert_eq!(
DenseMatrix::from_row(x.get_row(0).as_ref()),
DenseMatrix::from_2d_array(&[&[1, 2, 3]])
DenseMatrix::from_row(x.get_row(0).as_ref()), // internal only?
DenseMatrix::from_2d_array(&[&[1, 2, 3]]).unwrap()
);
assert_eq!(
DenseMatrix::from_column(x.get_col(0).as_ref()),
DenseMatrix::from_2d_array(&[&[1], &[4]])
DenseMatrix::from_column(x.get_col(0).as_ref()), // internal only?
DenseMatrix::from_2d_array(&[&[1], &[4]]).unwrap()
);
}
#[test]
fn test_transpose() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(
x.transpose(),
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]])
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]]).unwrap()
);
}
#[test]
fn test_reshape() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(
x.reshape(3, 2, 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap()
);
assert_eq!(
x.reshape(3, 2, 1),
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]])
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]]).unwrap()
);
}
#[test]
#[should_panic]
fn test_failed_reshape() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(
x.reshape(4, 2, 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap()
);
}
#[test]
fn test_matmul() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap();
assert_eq!(
a.matmul(&(*b.slice(0..3, 0..2))),
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]])
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]]).unwrap()
);
assert_eq!(
a.matmul(&b),
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]])
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]]).unwrap()
);
}
#[test]
fn test_concat() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]).unwrap();
assert_eq!(
DenseMatrix::concatenate_1d(&[&vec!(1, 2, 3), &vec!(4, 5, 6)], 0),
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]])
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap()
);
assert_eq!(
DenseMatrix::concatenate_1d(&[&vec!(1, 2), &vec!(3, 4)], 1),
DenseMatrix::from_2d_array(&[&[1, 3], &[2, 4]])
DenseMatrix::from_2d_array(&[&[1, 3], &[2, 4]]).unwrap()
);
assert_eq!(
DenseMatrix::concatenate_2d(&[&a, &b], 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]).unwrap()
);
assert_eq!(
DenseMatrix::concatenate_2d(&[&a, &b], 1),
DenseMatrix::from_2d_array(&[&[1, 2, 5, 6], &[3, 4, 7, 8]])
DenseMatrix::from_2d_array(&[&[1, 2, 5, 6], &[3, 4, 7, 8]]).unwrap()
);
}
#[test]
fn test_take() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap();
assert_eq!(
a.take(&[0, 2], 1),
DenseMatrix::from_2d_array(&[&[1, 3], &[4, 6]])
DenseMatrix::from_2d_array(&[&[1, 3], &[4, 6]]).unwrap()
);
assert_eq!(
b.take(&[0, 2], 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[5, 6]])
DenseMatrix::from_2d_array(&[&[1, 2], &[5, 6]]).unwrap()
);
}
#[test]
fn test_merge() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap();
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]).unwrap(),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, true)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8], &[1, 2], &[3, 4]]),
DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8], &[1, 2], &[3, 4]]).unwrap(),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, false)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 5, 7], &[3, 4, 6, 8]]),
DenseMatrix::from_2d_array(&[&[1, 2, 5, 7], &[3, 4, 6, 8]]).unwrap(),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, true)
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[5, 7, 1, 2], &[6, 8, 3, 4]]),
DenseMatrix::from_2d_array(&[&[5, 7, 1, 2], &[6, 8, 3, 4]]).unwrap(),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, false)
);
}
@@ -1984,20 +2009,28 @@ mod tests {
#[test]
fn test_ops() {
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).mul_scalar(2),
DenseMatrix::from_2d_array(&[&[2, 4], &[6, 8]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]])
.unwrap()
.mul_scalar(2),
DenseMatrix::from_2d_array(&[&[2, 4], &[6, 8]]).unwrap()
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).add_scalar(2),
DenseMatrix::from_2d_array(&[&[3, 4], &[5, 6]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]])
.unwrap()
.add_scalar(2),
DenseMatrix::from_2d_array(&[&[3, 4], &[5, 6]]).unwrap()
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).sub_scalar(1),
DenseMatrix::from_2d_array(&[&[0, 1], &[2, 3]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]])
.unwrap()
.sub_scalar(1),
DenseMatrix::from_2d_array(&[&[0, 1], &[2, 3]]).unwrap()
);
assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).div_scalar(2),
DenseMatrix::from_2d_array(&[&[0, 1], &[1, 2]])
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]])
.unwrap()
.div_scalar(2),
DenseMatrix::from_2d_array(&[&[0, 1], &[1, 2]]).unwrap()
);
}
@@ -2011,42 +2044,45 @@ mod tests {
#[test]
fn test_vstack() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let expected = DenseMatrix::from_2d_array(&[
&[1, 2, 3],
&[4, 5, 6],
&[7, 8, 9],
&[1, 2, 3],
&[4, 5, 6],
]);
])
.unwrap();
let result = a.v_stack(&b);
assert_eq!(result, expected);
}
#[test]
fn test_hstack() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap();
let expected =
DenseMatrix::from_2d_array(&[&[1, 2, 3, 1, 2], &[4, 5, 6, 3, 4], &[7, 8, 9, 5, 6]]);
DenseMatrix::from_2d_array(&[&[1, 2, 3, 1, 2], &[4, 5, 6, 3, 4], &[7, 8, 9, 5, 6]])
.unwrap();
let result = a.h_stack(&b);
assert_eq!(result, expected);
}
#[test]
fn test_map() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]).unwrap();
let result: DenseMatrix<f64> = a.map(|&v| v as f64);
assert_eq!(result, expected);
}
#[test]
fn scale() {
let mut m = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]);
let expected_0 = DenseMatrix::from_2d_array(&[&[-1., -1., -1.], &[1., 1., 1.]]);
let expected_1 = DenseMatrix::from_2d_array(&[&[-1.22, 0.0, 1.22], &[-1.22, 0.0, 1.22]]);
let mut m = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).unwrap();
let expected_0 = DenseMatrix::from_2d_array(&[&[-1., -1., -1.], &[1., 1., 1.]]).unwrap();
let expected_1 =
DenseMatrix::from_2d_array(&[&[-1.22, 0.0, 1.22], &[-1.22, 0.0, 1.22]]).unwrap();
{
let mut m = m.clone();
@@ -2060,52 +2096,52 @@ mod tests {
#[test]
fn test_pow_mut() {
let mut a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]);
let mut a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]).unwrap();
a.pow_mut(2.0);
assert_eq!(
a,
DenseMatrix::from_2d_array(&[&[1.0, 4.0, 9.0], &[16.0, 25.0, 36.0]])
DenseMatrix::from_2d_array(&[&[1.0, 4.0, 9.0], &[16.0, 25.0, 36.0]]).unwrap()
);
}
#[test]
fn test_ab() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]).unwrap();
assert_eq!(
a.ab(false, &b, false),
DenseMatrix::from_2d_array(&[&[19, 22], &[43, 50]])
DenseMatrix::from_2d_array(&[&[19, 22], &[43, 50]]).unwrap()
);
assert_eq!(
a.ab(true, &b, false),
DenseMatrix::from_2d_array(&[&[26, 30], &[38, 44]])
DenseMatrix::from_2d_array(&[&[26, 30], &[38, 44]]).unwrap()
);
assert_eq!(
a.ab(false, &b, true),
DenseMatrix::from_2d_array(&[&[17, 23], &[39, 53]])
DenseMatrix::from_2d_array(&[&[17, 23], &[39, 53]]).unwrap()
);
assert_eq!(
a.ab(true, &b, true),
DenseMatrix::from_2d_array(&[&[23, 31], &[34, 46]])
DenseMatrix::from_2d_array(&[&[23, 31], &[34, 46]]).unwrap()
);
}
#[test]
fn test_ax() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
assert_eq!(
a.ax(false, &vec![7, 8, 9]).transpose(),
DenseMatrix::from_2d_array(&[&[50, 122]])
DenseMatrix::from_2d_array(&[&[50, 122]]).unwrap()
);
assert_eq!(
a.ax(true, &vec![7, 8]).transpose(),
DenseMatrix::from_2d_array(&[&[39, 54, 69]])
DenseMatrix::from_2d_array(&[&[39, 54, 69]]).unwrap()
);
}
#[test]
fn diag() {
let x = DenseMatrix::from_2d_array(&[&[0, 1, 2], &[3, 4, 5], &[6, 7, 8]]);
let x = DenseMatrix::from_2d_array(&[&[0, 1, 2], &[3, 4, 5], &[6, 7, 8]]).unwrap();
assert_eq!(x.diag(), vec![0, 4, 8]);
}
@@ -2117,13 +2153,15 @@ mod tests {
&[68, 590, 37],
&[69, 660, 46],
&[73, 600, 55],
]);
])
.unwrap();
let mut result = DenseMatrix::zeros(3, 3);
let expected = DenseMatrix::from_2d_array(&[
&[11.5, 50.0, 34.75],
&[50.0, 1250.0, 205.0],
&[34.75, 205.0, 110.0],
]);
])
.unwrap();
a.cov(&mut result);
+208 -79
View File
@@ -19,6 +19,8 @@ use crate::linalg::traits::svd::SVDDecomposable;
use crate::numbers::basenum::Number;
use crate::numbers::realnum::RealNumber;
use crate::error::Failed;
/// Dense matrix
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
@@ -50,26 +52,26 @@ pub struct DenseMatrixMutView<'a, T: Debug + Display + Copy + Sized> {
}
impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> {
fn new(m: &'a DenseMatrix<T>, rows: Range<usize>, cols: Range<usize>) -> Self {
let (start, end, stride) = if m.column_major {
(
rows.start + cols.start * m.nrows,
rows.end + (cols.end - 1) * m.nrows,
m.nrows,
)
fn new(
m: &'a DenseMatrix<T>,
vrows: Range<usize>,
vcols: Range<usize>,
) -> Result<Self, Failed> {
if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) {
Err(Failed::input(
"The specified view is outside of the matrix range",
))
} else {
(
rows.start * m.ncols + cols.start,
(rows.end - 1) * m.ncols + cols.end,
m.ncols,
)
};
DenseMatrixView {
values: &m.values[start..end],
stride,
nrows: rows.end - rows.start,
ncols: cols.end - cols.start,
column_major: m.column_major,
let (start, end, stride) =
m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major);
Ok(DenseMatrixView {
values: &m.values[start..end],
stride,
nrows: vrows.end - vrows.start,
ncols: vcols.end - vcols.start,
column_major: m.column_major,
})
}
}
@@ -102,26 +104,26 @@ impl<'a, T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrixView<'a,
}
impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> {
fn new(m: &'a mut DenseMatrix<T>, rows: Range<usize>, cols: Range<usize>) -> Self {
let (start, end, stride) = if m.column_major {
(
rows.start + cols.start * m.nrows,
rows.end + (cols.end - 1) * m.nrows,
m.nrows,
)
fn new(
m: &'a mut DenseMatrix<T>,
vrows: Range<usize>,
vcols: Range<usize>,
) -> Result<Self, Failed> {
if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) {
Err(Failed::input(
"The specified view is outside of the matrix range",
))
} else {
(
rows.start * m.ncols + cols.start,
(rows.end - 1) * m.ncols + cols.end,
m.ncols,
)
};
DenseMatrixMutView {
values: &mut m.values[start..end],
stride,
nrows: rows.end - rows.start,
ncols: cols.end - cols.start,
column_major: m.column_major,
let (start, end, stride) =
m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major);
Ok(DenseMatrixMutView {
values: &mut m.values[start..end],
stride,
nrows: vrows.end - vrows.start,
ncols: vcols.end - vcols.start,
column_major: m.column_major,
})
}
}
@@ -182,42 +184,102 @@ impl<'a, T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrixMutView<
impl<T: Debug + Display + Copy + Sized> DenseMatrix<T> {
/// Create new instance of `DenseMatrix` without copying data.
/// `values` should be in column-major order.
pub fn new(nrows: usize, ncols: usize, values: Vec<T>, column_major: bool) -> Self {
DenseMatrix {
ncols,
nrows,
values,
column_major,
pub fn new(
nrows: usize,
ncols: usize,
values: Vec<T>,
column_major: bool,
) -> Result<Self, Failed> {
let data_len = values.len();
if nrows * ncols != values.len() {
Err(Failed::input(&format!(
"The specified shape: (cols: {ncols}, rows: {nrows}) does not align with data len: {data_len}"
)))
} else {
Ok(DenseMatrix {
ncols,
nrows,
values,
column_major,
})
}
}
/// New instance of `DenseMatrix` from 2d array.
pub fn from_2d_array(values: &[&[T]]) -> Self {
DenseMatrix::from_2d_vec(&values.iter().map(|row| Vec::from(*row)).collect::<Vec<_>>())
pub fn from_2d_array(values: &[&[T]]) -> Result<Self, Failed> {
DenseMatrix::from_2d_vec(&values.iter().map(|row| Vec::from(*row)).collect())
}
/// New instance of `DenseMatrix` from 2d vector.
pub fn from_2d_vec(values: &[Vec<T>]) -> Self {
let nrows = values.len();
let ncols = values
.first()
.unwrap_or_else(|| panic!("Cannot create 2d matrix from an empty vector"))
.len();
let mut m_values = Vec::with_capacity(nrows * ncols);
#[allow(clippy::ptr_arg)]
pub fn from_2d_vec(values: &Vec<Vec<T>>) -> Result<Self, Failed> {
if values.is_empty() || values[0].is_empty() {
Err(Failed::input(
"The 2d vec provided is empty; cannot instantiate the matrix",
))
} else {
let nrows = values.len();
let ncols = values
.first()
.unwrap_or_else(|| {
panic!("Invalid state: Cannot create 2d matrix from an empty vector")
})
.len();
let mut m_values = Vec::with_capacity(nrows * ncols);
for c in 0..ncols {
for r in values.iter().take(nrows) {
m_values.push(r[c])
for c in 0..ncols {
for r in values.iter().take(nrows) {
m_values.push(r[c])
}
}
}
DenseMatrix::new(nrows, ncols, m_values, true)
DenseMatrix::new(nrows, ncols, m_values, true)
}
}
/// Iterate over values of matrix
pub fn iter(&self) -> Iter<'_, T> {
self.values.iter()
}
/// Check if the size of the requested view is bounded to matrix rows/cols count
fn is_valid_view(
&self,
n_rows: usize,
n_cols: usize,
vrows: &Range<usize>,
vcols: &Range<usize>,
) -> bool {
!(vrows.end <= n_rows
&& vcols.end <= n_cols
&& vrows.start <= n_rows
&& vcols.start <= n_cols)
}
/// Compute the range of the requested view: start, end, size of the slice
fn stride_range(
&self,
n_rows: usize,
n_cols: usize,
vrows: &Range<usize>,
vcols: &Range<usize>,
column_major: bool,
) -> (usize, usize, usize) {
let (start, end, stride) = if column_major {
(
vrows.start + vcols.start * n_rows,
vrows.end + (vcols.end - 1) * n_rows,
n_rows,
)
} else {
(
vrows.start * n_cols + vcols.start,
(vrows.end - 1) * n_cols + vcols.end,
n_cols,
)
};
(start, end, stride)
}
}
impl<T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrix<T> {
@@ -304,6 +366,7 @@ where
impl<T: Debug + Display + Copy + Sized> Array<T, (usize, usize)> for DenseMatrix<T> {
fn get(&self, pos: (usize, usize)) -> &T {
let (row, col) = pos;
if row >= self.nrows || col >= self.ncols {
panic!(
"Invalid index ({},{}) for {}x{} matrix",
@@ -383,15 +446,15 @@ impl<T: Debug + Display + Copy + Sized> MutArrayView2<T> for DenseMatrix<T> {}
impl<T: Debug + Display + Copy + Sized> Array2<T> for DenseMatrix<T> {
fn get_row<'a>(&'a self, row: usize) -> Box<dyn ArrayView1<T> + 'a> {
Box::new(DenseMatrixView::new(self, row..row + 1, 0..self.ncols))
Box::new(DenseMatrixView::new(self, row..row + 1, 0..self.ncols).unwrap())
}
fn get_col<'a>(&'a self, col: usize) -> Box<dyn ArrayView1<T> + 'a> {
Box::new(DenseMatrixView::new(self, 0..self.nrows, col..col + 1))
Box::new(DenseMatrixView::new(self, 0..self.nrows, col..col + 1).unwrap())
}
fn slice<'a>(&'a self, rows: Range<usize>, cols: Range<usize>) -> Box<dyn ArrayView2<T> + 'a> {
Box::new(DenseMatrixView::new(self, rows, cols))
Box::new(DenseMatrixView::new(self, rows, cols).unwrap())
}
fn slice_mut<'a>(
@@ -402,15 +465,17 @@ impl<T: Debug + Display + Copy + Sized> Array2<T> for DenseMatrix<T> {
where
Self: Sized,
{
Box::new(DenseMatrixMutView::new(self, rows, cols))
Box::new(DenseMatrixMutView::new(self, rows, cols).unwrap())
}
// private function so for now assume infalible
fn fill(nrows: usize, ncols: usize, value: T) -> Self {
DenseMatrix::new(nrows, ncols, vec![value; nrows * ncols], true)
DenseMatrix::new(nrows, ncols, vec![value; nrows * ncols], true).unwrap()
}
// private function so for now assume infalible
fn from_iterator<I: Iterator<Item = T>>(iter: I, nrows: usize, ncols: usize, axis: u8) -> Self {
DenseMatrix::new(nrows, ncols, iter.collect(), axis != 0)
DenseMatrix::new(nrows, ncols, iter.collect(), axis != 0).unwrap()
}
fn transpose(&self) -> Self {
@@ -544,15 +609,74 @@ mod tests {
use approx::relative_eq;
#[test]
fn test_display() {
fn test_instantiate_from_2d() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
assert!(x.is_ok());
}
#[test]
fn test_instantiate_from_2d_empty() {
let input: &[&[f64]] = &[&[]];
let x = DenseMatrix::from_2d_array(input);
assert!(x.is_err());
}
#[test]
fn test_instantiate_from_2d_empty2() {
let input: &[&[f64]] = &[&[], &[]];
let x = DenseMatrix::from_2d_array(input);
assert!(x.is_err());
}
#[test]
fn test_instantiate_ok_view1() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..2, 0..2);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view2() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view3() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 2..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view4() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 3..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_err_view1() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 3..4, 0..3);
assert!(v.is_err());
}
#[test]
fn test_instantiate_err_view2() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 3..4);
assert!(v.is_err());
}
#[test]
fn test_instantiate_err_view3() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 4..3);
assert!(v.is_err());
}
#[test]
fn test_display() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
println!("{}", &x);
}
#[test]
fn test_get_row_col() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
assert_eq!(15.0, x.get_col(1).sum());
assert_eq!(15.0, x.get_row(1).sum());
@@ -561,7 +685,7 @@ mod tests {
#[test]
fn test_row_major() {
let mut x = DenseMatrix::new(2, 3, vec![1, 2, 3, 4, 5, 6], false);
let mut x = DenseMatrix::new(2, 3, vec![1, 2, 3, 4, 5, 6], false).unwrap();
assert_eq!(5, *x.get_col(1).get(1));
assert_eq!(7, x.get_col(1).sum());
@@ -575,7 +699,8 @@ mod tests {
#[test]
fn test_get_slice() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]);
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]])
.unwrap();
assert_eq!(
vec![4, 5, 6],
@@ -589,7 +714,7 @@ mod tests {
#[test]
fn test_iter_mut() {
let mut x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
let mut x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap();
assert_eq!(vec![1, 4, 7, 2, 5, 8, 3, 6, 9], x.values);
// add +2 to some elements
@@ -625,7 +750,8 @@ mod tests {
#[test]
fn test_str_array() {
let mut x =
DenseMatrix::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"], &["7", "8", "9"]]);
DenseMatrix::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"], &["7", "8", "9"]])
.unwrap();
assert_eq!(vec!["1", "4", "7", "2", "5", "8", "3", "6", "9"], x.values);
x.iterator_mut(0).for_each(|v| *v = "str");
@@ -637,7 +763,7 @@ mod tests {
#[test]
fn test_transpose() {
let x = DenseMatrix::<&str>::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"]]);
let x = DenseMatrix::<&str>::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"]]).unwrap();
assert_eq!(vec!["1", "4", "2", "5", "3", "6"], x.values);
assert!(x.column_major);
@@ -664,8 +790,8 @@ mod tests {
#[test]
fn test_take() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap();
println!("{a}");
// take column 0 and 2
@@ -677,7 +803,7 @@ mod tests {
#[test]
fn test_mut() {
let a = DenseMatrix::from_2d_array(&[&[1.3, -2.1, 3.4], &[-4., -5.3, 6.1]]);
let a = DenseMatrix::from_2d_array(&[&[1.3, -2.1, 3.4], &[-4., -5.3, 6.1]]).unwrap();
let a = a.abs();
assert_eq!(vec![1.3, 4.0, 2.1, 5.3, 3.4, 6.1], a.values);
@@ -688,7 +814,8 @@ mod tests {
#[test]
fn test_reshape() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]);
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]])
.unwrap();
let a = a.reshape(2, 6, 0);
assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], a.values);
@@ -701,13 +828,15 @@ mod tests {
#[test]
fn test_eq() {
let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]);
let b = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).unwrap();
let b = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let c = DenseMatrix::from_2d_array(&[
&[1. + f32::EPSILON, 2., 3.],
&[4., 5., 6. + f32::EPSILON],
]);
let d = DenseMatrix::from_2d_array(&[&[1. + 0.5, 2., 3.], &[4., 5., 6. + f32::EPSILON]]);
])
.unwrap();
let d = DenseMatrix::from_2d_array(&[&[1. + 0.5, 2., 3.], &[4., 5., 6. + f32::EPSILON]])
.unwrap();
assert!(!relative_eq!(a, b));
assert!(!relative_eq!(a, d));
+1
View File
@@ -55,6 +55,7 @@ impl<T: Debug + Display + Copy + Sized> Array<T, usize> for Vec<T> {
impl<T: Debug + Display + Copy + Sized> MutArray<T, usize> for Vec<T> {
fn set(&mut self, i: usize, x: T) {
// NOTE: this panics in case of out of bounds index
self[i] = x
}