From c79d3e8924558d16c328d75efc50248087561709 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 3 Apr 2023 11:14:09 +0900 Subject: [PATCH 01/27] uncomment test --- src/linalg/basic/vector.rs | 1 + src/linear/logistic_regression.rs | 62 +++++++++++++++---------------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/linalg/basic/vector.rs b/src/linalg/basic/vector.rs index 99da9819..3fb25847 100644 --- a/src/linalg/basic/vector.rs +++ b/src/linalg/basic/vector.rs @@ -36,6 +36,7 @@ impl Array for Vec { impl MutArray for Vec { fn set(&mut self, i: usize, x: T) { + // NOTE: this panics in case of out of bounds index self[i] = x } diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 4a4041bc..c8240050 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -818,37 +818,37 @@ mod tests { assert!(reg_coeff_sum < coeff); } - // TODO: serialization for the new DenseMatrix needs to be implemented - // #[cfg_attr(all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test::wasm_bindgen_test)] - // #[test] - // #[cfg(feature = "serde")] - // fn serde() { - // let x = DenseMatrix::from_2d_array(&[ - // &[1., -5.], - // &[2., 5.], - // &[3., -2.], - // &[1., 2.], - // &[2., 0.], - // &[6., -5.], - // &[7., 5.], - // &[6., -2.], - // &[7., 2.], - // &[6., 0.], - // &[8., -5.], - // &[9., 5.], - // &[10., -2.], - // &[8., 2.], - // &[9., 0.], - // ]); - // let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; - - // let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); - - // let deserialized_lr: LogisticRegression, Vec> = - // serde_json::from_str(&serde_json::to_string(&lr).unwrap()).unwrap(); - - // assert_eq!(lr, deserialized_lr); - // } + //TODO: serialization for the new DenseMatrix needs to be implemented + #[cfg_attr(all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test::wasm_bindgen_test)] + #[test] + #[cfg(feature = "serde")] + fn serde() { + let x = DenseMatrix::from_2d_array(&[ + &[1., -5.], + &[2., 5.], + &[3., -2.], + &[1., 2.], + &[2., 0.], + &[6., -5.], + &[7., 5.], + &[6., -2.], + &[7., 2.], + &[6., 0.], + &[8., -5.], + &[9., 5.], + &[10., -2.], + &[8., 2.], + &[9., 0.], + ]); + let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; + + let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); + + let deserialized_lr: LogisticRegression, Vec> = + serde_json::from_str(&serde_json::to_string(&lr).unwrap()).unwrap(); + + assert_eq!(lr, deserialized_lr); + } #[cfg_attr( all(target_arch = "wasm32", not(target_os = "wasi")), From e5250def2ff04c725e56e631ab51c5864effc103 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 3 Apr 2023 11:29:58 +0900 Subject: [PATCH 02/27] Add random test for logistic regression --- src/linear/logistic_regression.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index c8240050..579adea3 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -903,4 +903,29 @@ mod tests { assert!(reg_coeff_sum < coeff); } + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test::wasm_bindgen_test + )] + #[test] + fn lr_fit_predict_random() { + let x: DenseMatrix = DenseMatrix::rand(52181, 94); + let y1: Vec = vec![1; 2181]; + let y2: Vec = vec![0; 50000]; + let y: Vec = y1.into_iter().chain(y2.into_iter()).collect(); + + let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); + let lr_reg = LogisticRegression::fit( + &x, + &y, + LogisticRegressionParameters::default().with_alpha(1.0), + ) + .unwrap(); + + let y_hat = lr.predict(&x).unwrap(); + let y_hat_reg = lr_reg.predict(&x).unwrap(); + + assert_eq!(y.len(), y_hat.len()); + assert_eq!(y.len(), y_hat_reg.len()); + } } From 28f8b06a638b9715b6ef4bef9623a3452180b4c3 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 3 Apr 2023 12:14:31 +0900 Subject: [PATCH 03/27] linting --- src/linear/logistic_regression.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 579adea3..0ef23805 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -819,7 +819,10 @@ mod tests { } //TODO: serialization for the new DenseMatrix needs to be implemented - #[cfg_attr(all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test::wasm_bindgen_test + )] #[test] #[cfg(feature = "serde")] fn serde() { From b734e8cbabb1f55db532d5fccbac0a793291af18 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 3 Apr 2023 12:15:05 +0900 Subject: [PATCH 04/27] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a30db160..48d91804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "smartcore" description = "Machine Learning in Rust." homepage = "https://smartcorelib.org" -version = "0.3.1" +version = "0.3.2" authors = ["smartcore Developers"] edition = "2021" license = "Apache-2.0" From 63322c15a2f6fc9402fc7843d50bade16f862c19 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Tue, 4 Apr 2023 19:14:03 +0900 Subject: [PATCH 05/27] Add test for logistic regression --- src/linear/logistic_regression.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 0ef23805..bf87967c 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -931,4 +931,22 @@ mod tests { assert_eq!(y.len(), y_hat.len()); assert_eq!(y.len(), y_hat_reg.len()); } + + #[test] + fn test_logit() { + let x: &DenseMatrix = &DenseMatrix::rand(52181, 94); + let y1: Vec = vec![1; 2181]; + let y2: Vec = vec![0; 50000]; + let y: &Vec = &(y1.into_iter().chain(y2.into_iter()).collect()); + println!("y vec height: {:?}", y.len()); + println!("x matrix shape: {:?}", x.shape()); + + let lr = LogisticRegression::fit(x, y, Default::default()).unwrap(); + let y_hat = lr.predict(&x).unwrap(); + + println!("y_hat shape: {:?}", y_hat.shape()); + + assert_eq!(y_hat.shape(), 52181); + + } } From 5aed7f5444f6fb0afc48f2d01a06889b7e158316 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Tue, 4 Apr 2023 19:16:46 +0900 Subject: [PATCH 06/27] linting --- src/linear/logistic_regression.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index bf87967c..f7f10fcb 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -940,13 +940,12 @@ mod tests { let y: &Vec = &(y1.into_iter().chain(y2.into_iter()).collect()); println!("y vec height: {:?}", y.len()); println!("x matrix shape: {:?}", x.shape()); - - let lr = LogisticRegression::fit(x, y, Default::default()).unwrap(); + + let lr = LogisticRegression::fit(x, y, Default::default()).unwrap(); let y_hat = lr.predict(&x).unwrap(); println!("y_hat shape: {:?}", y_hat.shape()); assert_eq!(y_hat.shape(), 52181); - } } From 2c781ec56672dce995562a9750f4c8b4c29c7765 Mon Sep 17 00:00:00 2001 From: Edmund Cape Date: Tue, 4 Apr 2023 15:58:42 -0400 Subject: [PATCH 07/27] initial commit --- src/algorithm/neighbour/bbd_tree.rs | 3 +- src/algorithm/neighbour/fastpair.rs | 18 +- src/cluster/dbscan.rs | 6 +- src/cluster/kmeans.rs | 12 +- src/decomposition/pca.rs | 20 +- src/decomposition/svd.rs | 10 +- src/ensemble/random_forest_classifier.rs | 11 +- src/ensemble/random_forest_regressor.rs | 11 +- src/error/mod.rs | 19 ++ src/lib.rs | 2 +- src/linalg/basic/arrays.rs | 206 +++++++++------ src/linalg/basic/matrix.rs | 311 +++++++++++++++++------ src/linalg/traits/cholesky.rs | 18 +- src/linalg/traits/evd.rs | 20 +- src/linalg/traits/high_order.rs | 6 +- src/linalg/traits/lu.rs | 15 +- src/linalg/traits/qr.rs | 19 +- src/linalg/traits/stats.rs | 26 +- src/linalg/traits/svd.rs | 30 ++- src/linear/bg_solver.rs | 6 +- src/linear/elastic_net.rs | 10 +- src/linear/lasso.rs | 3 +- src/linear/linear_regression.rs | 7 +- src/linear/logistic_regression.rs | 20 +- src/linear/ridge_regression.rs | 7 +- src/metrics/distance/mahalanobis.rs | 5 +- src/metrics/mod.rs | 2 +- src/model_selection/mod.rs | 16 +- src/naive_bayes/bernoulli.rs | 15 +- src/naive_bayes/categorical.rs | 13 +- src/naive_bayes/gaussian.rs | 11 +- src/naive_bayes/multinomial.rs | 15 +- src/neighbors/knn_classifier.rs | 16 +- src/neighbors/knn_regressor.rs | 13 +- src/optimization/first_order/lbfgs.rs | 1 + src/preprocessing/categorical.rs | 17 +- src/preprocessing/numerical.rs | 85 ++++--- src/svm/svc.rs | 17 +- src/svm/svr.rs | 8 +- src/tree/decision_tree_classifier.rs | 11 +- src/tree/decision_tree_regressor.rs | 8 +- 41 files changed, 697 insertions(+), 372 deletions(-) diff --git a/src/algorithm/neighbour/bbd_tree.rs b/src/algorithm/neighbour/bbd_tree.rs index 44cef506..1cc92c4a 100644 --- a/src/algorithm/neighbour/bbd_tree.rs +++ b/src/algorithm/neighbour/bbd_tree.rs @@ -343,7 +343,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let tree = BBDTree::new(&data); diff --git a/src/algorithm/neighbour/fastpair.rs b/src/algorithm/neighbour/fastpair.rs index eca73ed6..759d018c 100644 --- a/src/algorithm/neighbour/fastpair.rs +++ b/src/algorithm/neighbour/fastpair.rs @@ -17,7 +17,7 @@ /// &[4.6, 3.1, 1.5, 0.2], /// &[5.0, 3.6, 1.4, 0.2], /// &[5.4, 3.9, 1.7, 0.4], -/// ]); +/// ]).unwrap(); /// let fastpair = FastPair::new(&x); /// let closest_pair: PairwiseDistance = fastpair.unwrap().closest_pair(); /// ``` @@ -271,7 +271,7 @@ mod tests_fastpair { fn dataset_has_at_least_three_points() { // Create a dataset which consists of only two points: // A(0.0, 0.0) and B(1.0, 1.0). - let dataset = DenseMatrix::::from_2d_array(&[&[0.0, 0.0], &[1.0, 1.0]]); + let dataset = DenseMatrix::::from_2d_array(&[&[0.0, 0.0], &[1.0, 1.0]]).unwrap(); // We expect an error when we run `FastPair` on this dataset, // becuase `FastPair` currently only works on a minimum of 3 @@ -288,7 +288,7 @@ mod tests_fastpair { #[test] fn one_dimensional_dataset_minimal() { - let dataset = DenseMatrix::::from_2d_array(&[&[0.0], &[2.0], &[9.0]]); + let dataset = DenseMatrix::::from_2d_array(&[&[0.0], &[2.0], &[9.0]]).unwrap(); let result = FastPair::new(&dataset); assert!(result.is_ok()); @@ -308,7 +308,8 @@ mod tests_fastpair { #[test] fn one_dimensional_dataset_2() { - let dataset = DenseMatrix::::from_2d_array(&[&[27.0], &[0.0], &[9.0], &[2.0]]); + let dataset = + DenseMatrix::::from_2d_array(&[&[27.0], &[0.0], &[9.0], &[2.0]]).unwrap(); let result = FastPair::new(&dataset); assert!(result.is_ok()); @@ -343,7 +344,8 @@ mod tests_fastpair { &[6.9, 3.1, 4.9, 1.5], &[5.5, 2.3, 4.0, 1.3], &[6.5, 2.8, 4.6, 1.5], - ]); + ]) + .unwrap(); let fastpair = FastPair::new(&x); assert!(fastpair.is_ok()); @@ -516,7 +518,8 @@ mod tests_fastpair { &[6.9, 3.1, 4.9, 1.5], &[5.5, 2.3, 4.0, 1.3], &[6.5, 2.8, 4.6, 1.5], - ]); + ]) + .unwrap(); // compute let fastpair = FastPair::new(&x); assert!(fastpair.is_ok()); @@ -564,7 +567,8 @@ mod tests_fastpair { &[6.9, 3.1, 4.9, 1.5], &[5.5, 2.3, 4.0, 1.3], &[6.5, 2.8, 4.6, 1.5], - ]); + ]) + .unwrap(); // compute let fastpair = FastPair::new(&x); assert!(fastpair.is_ok()); diff --git a/src/cluster/dbscan.rs b/src/cluster/dbscan.rs index 0d84a613..3ff6b07b 100644 --- a/src/cluster/dbscan.rs +++ b/src/cluster/dbscan.rs @@ -443,7 +443,8 @@ mod tests { &[2.2, 1.2], &[1.8, 0.8], &[3.0, 5.0], - ]); + ]) + .unwrap(); let expected_labels = vec![1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0]; @@ -488,7 +489,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let dbscan = DBSCAN::fit(&x, Default::default()).unwrap(); diff --git a/src/cluster/kmeans.rs b/src/cluster/kmeans.rs index c2470abb..6609ace4 100644 --- a/src/cluster/kmeans.rs +++ b/src/cluster/kmeans.rs @@ -41,7 +41,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! //! let kmeans = KMeans::fit(&x, KMeansParameters::default().with_k(2)).unwrap(); // Fit to data, 2 clusters //! let y_hat: Vec = kmeans.predict(&x).unwrap(); // use the same points for prediction @@ -249,7 +249,7 @@ impl, Y: Array1> Predictor impl, Y: Array1> KMeans { /// Fit algorithm to _NxM_ matrix where _N_ is number of samples and _M_ is number of features. - /// * `data` - training instances to cluster + /// * `data` - training instances to cluster /// * `parameters` - cluster parameters pub fn fit(data: &X, parameters: KMeansParameters) -> Result, Failed> { let bbd = BBDTree::new(data); @@ -424,7 +424,7 @@ mod tests { )] #[test] fn invalid_k() { - 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!(KMeans::, Vec>::fit( &x, @@ -492,7 +492,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let kmeans = KMeans::fit(&x, Default::default()).unwrap(); @@ -531,7 +532,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let kmeans: KMeans, Vec> = KMeans::fit(&x, Default::default()).unwrap(); diff --git a/src/decomposition/pca.rs b/src/decomposition/pca.rs index d4116ed5..11853648 100644 --- a/src/decomposition/pca.rs +++ b/src/decomposition/pca.rs @@ -35,7 +35,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! //! let pca = PCA::fit(&iris, PCAParameters::default().with_n_components(2)).unwrap(); // Reduce number of features to 2 //! @@ -443,6 +443,7 @@ mod tests { &[2.6, 53.0, 66.0, 10.8], &[6.8, 161.0, 60.0, 15.6], ]) + .unwrap() } #[cfg_attr( all(target_arch = "wasm32", not(target_os = "wasi")), @@ -457,7 +458,8 @@ mod tests { &[0.9952, 0.0588], &[0.0463, 0.9769], &[0.0752, 0.2007], - ]); + ]) + .unwrap(); let pca = PCA::fit(&us_arrests, Default::default()).unwrap(); @@ -500,7 +502,8 @@ mod tests { -0.974080592182491, 0.0723250196376097, ], - ]); + ]) + .unwrap(); let expected_projection = DenseMatrix::from_2d_array(&[ &[-64.8022, -11.448, 2.4949, -2.4079], @@ -553,7 +556,8 @@ mod tests { &[91.5446, -22.9529, 0.402, -0.7369], &[118.1763, 5.5076, 2.7113, -0.205], &[10.4345, -5.9245, 3.7944, 0.5179], - ]); + ]) + .unwrap(); let expected_eigenvalues: Vec = vec![ 343544.6277001563, @@ -616,7 +620,8 @@ mod tests { -0.0881962972508558, -0.0096011588898465, ], - ]); + ]) + .unwrap(); let expected_projection = DenseMatrix::from_2d_array(&[ &[0.9856, -1.1334, 0.4443, -0.1563], @@ -669,7 +674,8 @@ mod tests { &[-2.1086, -1.4248, -0.1048, -0.1319], &[-2.0797, 0.6113, 0.1389, -0.1841], &[-0.6294, -0.321, 0.2407, 0.1667], - ]); + ]) + .unwrap(); let expected_eigenvalues: Vec = vec![ 2.480241579149493, @@ -732,7 +738,7 @@ mod tests { // &[4.9, 2.4, 3.3, 1.0], // &[6.6, 2.9, 4.6, 1.3], // &[5.2, 2.7, 3.9, 1.4], - // ]); + // ]).unwrap(); // let pca = PCA::fit(&iris, Default::default()).unwrap(); diff --git a/src/decomposition/svd.rs b/src/decomposition/svd.rs index a82dfbd0..259bfbc0 100644 --- a/src/decomposition/svd.rs +++ b/src/decomposition/svd.rs @@ -32,7 +32,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! //! let svd = SVD::fit(&iris, SVDParameters::default(). //! with_n_components(2)).unwrap(); // Reduce number of features to 2 @@ -292,7 +292,8 @@ mod tests { &[5.7, 81.0, 39.0, 9.3], &[2.6, 53.0, 66.0, 10.8], &[6.8, 161.0, 60.0, 15.6], - ]); + ]) + .unwrap(); let expected = DenseMatrix::from_2d_array(&[ &[243.54655757, -18.76673788], @@ -300,7 +301,8 @@ mod tests { &[305.93972467, -15.39087376], &[197.28420365, -11.66808306], &[293.43187394, 1.91163633], - ]); + ]) + .unwrap(); let svd = SVD::fit(&x, Default::default()).unwrap(); let x_transformed = svd.transform(&x).unwrap(); @@ -341,7 +343,7 @@ mod tests { // &[4.9, 2.4, 3.3, 1.0], // &[6.6, 2.9, 4.6, 1.3], // &[5.2, 2.7, 3.9, 1.4], - // ]); + // ]).unwrap(); // let svd = SVD::fit(&iris, Default::default()).unwrap(); diff --git a/src/ensemble/random_forest_classifier.rs b/src/ensemble/random_forest_classifier.rs index 6448b52e..dabb2480 100644 --- a/src/ensemble/random_forest_classifier.rs +++ b/src/ensemble/random_forest_classifier.rs @@ -33,7 +33,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y = vec![ //! 0, 0, 0, 0, 0, 0, 0, 0, //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -660,7 +660,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let classifier = RandomForestClassifier::fit( @@ -733,7 +734,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let classifier = RandomForestClassifier::fit( @@ -786,7 +788,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let forest = RandomForestClassifier::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/ensemble/random_forest_regressor.rs b/src/ensemble/random_forest_regressor.rs index 926327e1..efc63d3d 100644 --- a/src/ensemble/random_forest_regressor.rs +++ b/src/ensemble/random_forest_regressor.rs @@ -29,7 +29,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! let y = vec![ //! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, //! 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9 @@ -574,7 +574,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -648,7 +649,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -702,7 +704,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, diff --git a/src/error/mod.rs b/src/error/mod.rs index 838df085..b6b1d982 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -32,6 +32,8 @@ pub enum FailedError { SolutionFailed, /// Error in input parameters ParametersError, + /// Invalid state error (should never happen) + InvalidStateError, } impl Failed { @@ -64,6 +66,22 @@ impl Failed { } } + /// new instance of `FailedError::ParametersError` + pub fn input(msg: &str) -> Self { + Failed { + err: FailedError::ParametersError, + msg: msg.to_string(), + } + } + + /// new instance of `FailedError::InvalidStateError` + pub fn invalid_state(msg: &str) -> Self { + Failed { + err: FailedError::InvalidStateError, + msg: msg.to_string(), + } + } + /// new instance of `err` pub fn because(err: FailedError, msg: &str) -> Self { Failed { @@ -97,6 +115,7 @@ impl fmt::Display for FailedError { FailedError::DecompositionFailed => "Decomposition failed", FailedError::SolutionFailed => "Can't find solution", FailedError::ParametersError => "Error in input, check parameters", + FailedError::InvalidStateError => "Invalid state, this should never happen", // useful in development phase of lib }; write!(f, "{failed_err_str}") } diff --git a/src/lib.rs b/src/lib.rs index 136584ee..539acf89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ //! &[3., 4.], //! &[5., 6.], //! &[7., 8.], -//! &[9., 10.]]); +//! &[9., 10.]]).unwrap(); //! // Our classes are defined as a vector //! let y = vec![2, 2, 2, 3, 3]; //! diff --git a/src/linalg/basic/arrays.rs b/src/linalg/basic/arrays.rs index 7d0c77a6..a3bbe038 100644 --- a/src/linalg/basic/arrays.rs +++ b/src/linalg/basic/arrays.rs @@ -1777,7 +1777,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]); } @@ -1785,19 +1785,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.) ); } @@ -1805,11 +1813,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) ); } @@ -1817,168 +1829,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::::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::::zeros(2, 2), - DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]]) + DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]]).unwrap() ); assert_eq!( DenseMatrix::::ones(2, 2), - DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]]) + DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]]).unwrap() ); assert_eq!( DenseMatrix::::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) ); } @@ -1986,20 +2011,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() ); } @@ -2013,42 +2046,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 = 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(); @@ -2062,52 +2098,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]); } @@ -2119,13 +2155,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); diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index f21e04fe..de3c28f6 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -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)] @@ -49,27 +51,75 @@ pub struct DenseMatrixMutView<'a, T: Debug + Display + Copy + Sized> { column_major: bool, } +// functional utility functions used across types +fn is_valid_matrix_window( + mrows: usize, + mcols: usize, + vrows: &Range, + vcols: &Range, +) -> bool { + debug_assert!( + vrows.end <= mrows && vcols.end <= mcols, + "The window end is outside of the matrix range" + ); + debug_assert!( + vrows.start <= mrows && vcols.start <= mcols, + "The window start is outside of the matrix range" + ); + debug_assert!( + // depends on a properly formed range + vrows.start <= vrows.end && vcols.start <= vcols.end, + "Invalid range: start <= end failed" + ); + + !(vrows.end <= mrows && vcols.end <= mcols && vrows.start <= mrows && vcols.start <= mcols) +} +fn start_end_stride( + mrows: usize, + mcols: usize, + vrows: &Range, + vcols: &Range, + column_major: bool, +) -> (usize, usize, usize) { + let (start, end, stride) = if column_major { + ( + vrows.start + vcols.start * mrows, + vrows.end + (vcols.end - 1) * mrows, + mrows, + ) + } else { + ( + vrows.start * mcols + vcols.start, + (vrows.end - 1) * mcols + vcols.end, + mcols, + ) + }; + (start, end, stride) +} + impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { - fn new(m: &'a DenseMatrix, rows: Range, cols: Range) -> 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, + vrows: Range, + vcols: Range, + ) -> Result { + let (mrows, mcols) = m.shape(); + + if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { + Err(Failed::input(&format!( + "The specified window 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) = + start_end_stride(mrows, mcols, &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 +152,27 @@ 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, rows: Range, cols: Range) -> 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, + vrows: Range, + vcols: Range, + ) -> Result { + let (mrows, mcols) = m.shape(); + if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { + Err(Failed::input(&format!( + "The specified window 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) = + start_end_stride(mrows, mcols, &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,36 +233,65 @@ impl<'a, T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrixMutView< impl DenseMatrix { /// Create new instance of `DenseMatrix` without copying data. /// `values` should be in column-major order. - pub fn new(nrows: usize, ncols: usize, values: Vec, column_major: bool) -> Self { - DenseMatrix { - ncols, - nrows, - values, - column_major, + pub fn new( + nrows: usize, + ncols: usize, + values: Vec, + column_major: bool, + ) -> Result { + debug_assert!( + nrows * ncols == values.len(), + "Instantiatint DenseMatrix requires nrows * ncols == values.len()" + ); + 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 { + pub fn from_2d_array(values: &[&[T]]) -> Result { 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>) -> 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); - - for c in 0..ncols { - for r in values.iter().take(nrows) { - m_values.push(r[c]) + pub fn from_2d_vec(values: &Vec>) -> Result { + debug_assert!( + !(values.is_empty() || values[0].is_empty()), + "Instantiating DenseMatrix requires a non-empty 2d_vec" + ); + + if values.is_empty() || values[0].is_empty() { + Err(Failed::input(&format!( + "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]) + } } - } - DenseMatrix::new(nrows, ncols, m_values, true) + DenseMatrix::new(nrows, ncols, m_values, true) + } } /// Iterate over values of matrix @@ -304,6 +384,13 @@ where impl Array for DenseMatrix { fn get(&self, pos: (usize, usize)) -> &T { let (row, col) = pos; + let idx_target = col * self.nrows + row; + + println!("------ 🦀 ----- 📋 target: {}", self.values.len()); + println!("------ 🦀 ----- 📋 nrows: {}", &self.nrows); + println!("row: {} col: {}", &row, &col); + println!("DenseMatrix get target: {}", idx_target); + if row >= self.nrows || col >= self.ncols { panic!( "Invalid index ({},{}) for {}x{} matrix", @@ -383,15 +470,15 @@ impl MutArrayView2 for DenseMatrix {} impl Array2 for DenseMatrix { fn get_row<'a>(&'a self, row: usize) -> Box + '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 + '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, cols: Range) -> Box + 'a> { - Box::new(DenseMatrixView::new(self, rows, cols)) + Box::new(DenseMatrixView::new(self, rows, cols).unwrap()) } fn slice_mut<'a>( @@ -402,15 +489,17 @@ impl Array2 for DenseMatrix { 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>(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 +633,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 +709,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 +723,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 +738,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 +774,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 +787,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 +814,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 +827,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 +838,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 +852,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)); diff --git a/src/linalg/traits/cholesky.rs b/src/linalg/traits/cholesky.rs index 1394270f..baec8f87 100644 --- a/src/linalg/traits/cholesky.rs +++ b/src/linalg/traits/cholesky.rs @@ -15,7 +15,7 @@ //! &[25., 15., -5.], //! &[15., 18., 0.], //! &[-5., 0., 11.] -//! ]); +//! ]).unwrap(); //! //! let cholesky = A.cholesky().unwrap(); //! let lower_triangular: DenseMatrix = cholesky.L(); @@ -175,11 +175,14 @@ mod tests { )] #[test] fn cholesky_decompose() { - let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]); + let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) + .unwrap(); let l = - DenseMatrix::from_2d_array(&[&[5.0, 0.0, 0.0], &[3.0, 3.0, 0.0], &[-1.0, 1.0, 3.0]]); + DenseMatrix::from_2d_array(&[&[5.0, 0.0, 0.0], &[3.0, 3.0, 0.0], &[-1.0, 1.0, 3.0]]) + .unwrap(); let u = - DenseMatrix::from_2d_array(&[&[5.0, 3.0, -1.0], &[0.0, 3.0, 1.0], &[0.0, 0.0, 3.0]]); + DenseMatrix::from_2d_array(&[&[5.0, 3.0, -1.0], &[0.0, 3.0, 1.0], &[0.0, 0.0, 3.0]]) + .unwrap(); let cholesky = a.cholesky().unwrap(); assert!(relative_eq!(cholesky.L().abs(), l.abs(), epsilon = 1e-4)); @@ -197,9 +200,10 @@ mod tests { )] #[test] fn cholesky_solve_mut() { - let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]); - let b = DenseMatrix::from_2d_array(&[&[40., 51., 28.]]); - let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0]]); + let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) + .unwrap(); + let b = DenseMatrix::from_2d_array(&[&[40., 51., 28.]]).unwrap(); + let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0]]).unwrap(); let cholesky = a.cholesky().unwrap(); diff --git a/src/linalg/traits/evd.rs b/src/linalg/traits/evd.rs index ccbdded6..4db766b0 100644 --- a/src/linalg/traits/evd.rs +++ b/src/linalg/traits/evd.rs @@ -19,7 +19,7 @@ //! &[0.9000, 0.4000, 0.7000], //! &[0.4000, 0.5000, 0.3000], //! &[0.7000, 0.3000, 0.8000], -//! ]); +//! ]).unwrap(); //! //! let evd = A.evd(true).unwrap(); //! let eigenvectors: DenseMatrix = evd.V; @@ -820,7 +820,8 @@ mod tests { &[0.9000, 0.4000, 0.7000], &[0.4000, 0.5000, 0.3000], &[0.7000, 0.3000, 0.8000], - ]); + ]) + .unwrap(); let eigen_values: Vec = vec![1.7498382, 0.3165784, 0.1335834]; @@ -828,7 +829,8 @@ mod tests { &[0.6881997, -0.07121225, 0.7220180], &[0.3700456, 0.89044952, -0.2648886], &[0.6240573, -0.44947578, -0.6391588], - ]); + ]) + .unwrap(); let evd = A.evd(true).unwrap(); @@ -852,7 +854,8 @@ mod tests { &[0.9000, 0.4000, 0.7000], &[0.4000, 0.5000, 0.3000], &[0.8000, 0.3000, 0.8000], - ]); + ]) + .unwrap(); let eigen_values: Vec = vec![1.79171122, 0.31908143, 0.08920735]; @@ -860,7 +863,8 @@ mod tests { &[0.7178958, 0.05322098, 0.6812010], &[0.3837711, -0.84702111, -0.1494582], &[0.6952105, 0.43984484, -0.7036135], - ]); + ]) + .unwrap(); let evd = A.evd(false).unwrap(); @@ -885,7 +889,8 @@ mod tests { &[4.0, -1.0, 1.0, 1.0], &[1.0, 1.0, 3.0, -2.0], &[1.0, 1.0, 4.0, -1.0], - ]); + ]) + .unwrap(); let eigen_values_d: Vec = vec![0.0, 2.0, 2.0, 0.0]; let eigen_values_e: Vec = vec![2.2361, 0.9999, -0.9999, -2.2361]; @@ -895,7 +900,8 @@ mod tests { &[-0.6707, 0.1059, 0.901, 0.6289], &[0.9159, -0.1378, 0.3816, 0.0806], &[0.6707, 0.1059, 0.901, -0.6289], - ]); + ]) + .unwrap(); let evd = A.evd(false).unwrap(); diff --git a/src/linalg/traits/high_order.rs b/src/linalg/traits/high_order.rs index f1f86672..d3466e20 100644 --- a/src/linalg/traits/high_order.rs +++ b/src/linalg/traits/high_order.rs @@ -12,9 +12,9 @@ pub trait HighOrderOperations: Array2 { /// use smartcore::linalg::traits::high_order::HighOrderOperations; /// use smartcore::linalg::basic::arrays::Array2; /// - /// let a = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.]]); - /// let b = DenseMatrix::from_2d_array(&[&[5., 6.], &[7., 8.], &[9., 10.]]); - /// let expected = DenseMatrix::from_2d_array(&[&[71., 80.], &[92., 104.]]); + /// let a = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.]]).unwrap(); + /// let b = DenseMatrix::from_2d_array(&[&[5., 6.], &[7., 8.], &[9., 10.]]).unwrap(); + /// let expected = DenseMatrix::from_2d_array(&[&[71., 80.], &[92., 104.]]).unwrap(); /// /// assert_eq!(a.ab(true, &b, false), expected); /// ``` diff --git a/src/linalg/traits/lu.rs b/src/linalg/traits/lu.rs index 1f0d5f47..7a1d0439 100644 --- a/src/linalg/traits/lu.rs +++ b/src/linalg/traits/lu.rs @@ -18,7 +18,7 @@ //! &[1., 2., 3.], //! &[0., 1., 5.], //! &[5., 6., 0.] -//! ]); +//! ]).unwrap(); //! //! let lu = A.lu().unwrap(); //! let lower: DenseMatrix = lu.L(); @@ -263,13 +263,13 @@ mod tests { )] #[test] fn decompose() { - let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]); + let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]).unwrap(); let expected_L = - DenseMatrix::from_2d_array(&[&[1., 0., 0.], &[0., 1., 0.], &[0.2, 0.8, 1.]]); + DenseMatrix::from_2d_array(&[&[1., 0., 0.], &[0., 1., 0.], &[0.2, 0.8, 1.]]).unwrap(); let expected_U = - DenseMatrix::from_2d_array(&[&[5., 6., 0.], &[0., 1., 5.], &[0., 0., -1.]]); + DenseMatrix::from_2d_array(&[&[5., 6., 0.], &[0., 1., 5.], &[0., 0., -1.]]).unwrap(); let expected_pivot = - DenseMatrix::from_2d_array(&[&[0., 0., 1.], &[0., 1., 0.], &[1., 0., 0.]]); + DenseMatrix::from_2d_array(&[&[0., 0., 1.], &[0., 1., 0.], &[1., 0., 0.]]).unwrap(); let lu = a.lu().unwrap(); assert!(relative_eq!(lu.L(), expected_L, epsilon = 1e-4)); assert!(relative_eq!(lu.U(), expected_U, epsilon = 1e-4)); @@ -281,9 +281,10 @@ mod tests { )] #[test] fn inverse() { - let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]); + let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]).unwrap(); let expected = - DenseMatrix::from_2d_array(&[&[-6.0, 3.6, 1.4], &[5.0, -3.0, -1.0], &[-1.0, 0.8, 0.2]]); + DenseMatrix::from_2d_array(&[&[-6.0, 3.6, 1.4], &[5.0, -3.0, -1.0], &[-1.0, 0.8, 0.2]]) + .unwrap(); let a_inv = a.lu().and_then(|lu| lu.inverse()).unwrap(); assert!(relative_eq!(a_inv, expected, epsilon = 1e-4)); } diff --git a/src/linalg/traits/qr.rs b/src/linalg/traits/qr.rs index eb452e13..2c70efcb 100644 --- a/src/linalg/traits/qr.rs +++ b/src/linalg/traits/qr.rs @@ -13,7 +13,7 @@ //! &[0.9, 0.4, 0.7], //! &[0.4, 0.5, 0.3], //! &[0.7, 0.3, 0.8] -//! ]); +//! ]).unwrap(); //! //! let qr = A.qr().unwrap(); //! let orthogonal: DenseMatrix = qr.Q(); @@ -201,17 +201,20 @@ mod tests { )] #[test] fn decompose() { - let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]); + let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) + .unwrap(); let q = DenseMatrix::from_2d_array(&[ &[-0.7448, 0.2436, 0.6212], &[-0.331, -0.9432, -0.027], &[-0.5793, 0.2257, -0.7832], - ]); + ]) + .unwrap(); let r = DenseMatrix::from_2d_array(&[ &[-1.2083, -0.6373, -1.0842], &[0.0, -0.3064, 0.0682], &[0.0, 0.0, -0.1999], - ]); + ]) + .unwrap(); let qr = a.qr().unwrap(); assert!(relative_eq!(qr.Q().abs(), q.abs(), epsilon = 1e-4)); assert!(relative_eq!(qr.R().abs(), r.abs(), epsilon = 1e-4)); @@ -223,13 +226,15 @@ mod tests { )] #[test] fn qr_solve_mut() { - let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]); - let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]); + let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) + .unwrap(); + let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]).unwrap(); let expected_w = DenseMatrix::from_2d_array(&[ &[-0.2027027, -1.2837838], &[0.8783784, 2.2297297], &[0.4729730, 0.6621622], - ]); + ]) + .unwrap(); let w = a.qr_solve_mut(b).unwrap(); assert!(relative_eq!(w, expected_w, epsilon = 1e-2)); } diff --git a/src/linalg/traits/stats.rs b/src/linalg/traits/stats.rs index 052da476..43c23dce 100644 --- a/src/linalg/traits/stats.rs +++ b/src/linalg/traits/stats.rs @@ -136,8 +136,8 @@ pub trait MatrixPreprocessing: MutArrayView2 + Clone { /// ```rust /// use smartcore::linalg::basic::matrix::DenseMatrix; /// use smartcore::linalg::traits::stats::MatrixPreprocessing; - /// let mut a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]); - /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]); + /// let mut a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]).unwrap(); + /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]).unwrap(); /// a.binarize_mut(0.); /// /// assert_eq!(a, expected); @@ -159,8 +159,8 @@ pub trait MatrixPreprocessing: MutArrayView2 + Clone { /// ```rust /// use smartcore::linalg::basic::matrix::DenseMatrix; /// use smartcore::linalg::traits::stats::MatrixPreprocessing; - /// let a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]); - /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]); + /// let a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]).unwrap(); + /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]).unwrap(); /// /// assert_eq!(a.binarize(0.), expected); /// ``` @@ -186,7 +186,8 @@ mod tests { &[1., 2., 3., 1., 2.], &[4., 5., 6., 3., 4.], &[7., 8., 9., 5., 6.], - ]); + ]) + .unwrap(); let expected_0 = vec![4., 5., 6., 3., 4.]; let expected_1 = vec![1.8, 4.4, 7.]; @@ -196,7 +197,7 @@ mod tests { #[test] fn test_var() { - let m = DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]); + let m = DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]).unwrap(); let expected_0 = vec![4., 4., 4., 4.]; let expected_1 = vec![1.25, 1.25]; @@ -211,7 +212,8 @@ mod tests { let m = DenseMatrix::from_2d_array(&[ &[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25], &[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25], - ]); + ]) + .unwrap(); let expected_0 = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; let expected_1 = vec![1.25, 1.25]; @@ -230,7 +232,8 @@ mod tests { &[1., 2., 3., 1., 2.], &[4., 5., 6., 3., 4.], &[7., 8., 9., 5., 6.], - ]); + ]) + .unwrap(); let expected_0 = vec![ 2.449489742783178, 2.449489742783178, @@ -251,10 +254,10 @@ mod tests { #[test] fn test_scale() { let m: DenseMatrix = - 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(); let expected_0: DenseMatrix = - DenseMatrix::from_2d_array(&[&[-1., -1., -1., -1.], &[1., 1., 1., 1.]]); + DenseMatrix::from_2d_array(&[&[-1., -1., -1., -1.], &[1., 1., 1., 1.]]).unwrap(); let expected_1: DenseMatrix = DenseMatrix::from_2d_array(&[ &[ -1.3416407864998738, @@ -268,7 +271,8 @@ mod tests { 0.4472135954999579, 1.3416407864998738, ], - ]); + ]) + .unwrap(); assert_eq!(m.mean(0), vec![3.0, 4.0, 5.0, 6.0]); assert_eq!(m.mean(1), vec![2.5, 6.5]); diff --git a/src/linalg/traits/svd.rs b/src/linalg/traits/svd.rs index 8608942d..75c303ae 100644 --- a/src/linalg/traits/svd.rs +++ b/src/linalg/traits/svd.rs @@ -17,7 +17,7 @@ //! &[0.9, 0.4, 0.7], //! &[0.4, 0.5, 0.3], //! &[0.7, 0.3, 0.8] -//! ]); +//! ]).unwrap(); //! //! let svd = A.svd().unwrap(); //! let u: DenseMatrix = svd.U; @@ -489,7 +489,8 @@ mod tests { &[0.9000, 0.4000, 0.7000], &[0.4000, 0.5000, 0.3000], &[0.7000, 0.3000, 0.8000], - ]); + ]) + .unwrap(); let s: Vec = vec![1.7498382, 0.3165784, 0.1335834]; @@ -497,13 +498,15 @@ mod tests { &[0.6881997, -0.07121225, 0.7220180], &[0.3700456, 0.89044952, -0.2648886], &[0.6240573, -0.44947578, -0.639158], - ]); + ]) + .unwrap(); let V = DenseMatrix::from_2d_array(&[ &[0.6881997, -0.07121225, 0.7220180], &[0.3700456, 0.89044952, -0.2648886], &[0.6240573, -0.44947578, -0.6391588], - ]); + ]) + .unwrap(); let svd = A.svd().unwrap(); @@ -577,7 +580,8 @@ mod tests { -0.2158704, -0.27529472, ], - ]); + ]) + .unwrap(); let s: Vec = vec![ 3.8589375, 3.4396766, 2.6487176, 2.2317399, 1.5165054, 0.8109055, 0.2706515, @@ -647,7 +651,8 @@ mod tests { 0.73034065, -0.43965505, ], - ]); + ]) + .unwrap(); let V = DenseMatrix::from_2d_array(&[ &[ @@ -707,7 +712,8 @@ mod tests { 0.1654796, -0.32346758, ], - ]); + ]) + .unwrap(); let svd = A.svd().unwrap(); @@ -723,10 +729,11 @@ mod tests { )] #[test] fn solve() { - let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]); - let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]); + let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) + .unwrap(); + let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]).unwrap(); let expected_w = - DenseMatrix::from_2d_array(&[&[-0.20, -1.28], &[0.87, 2.22], &[0.47, 0.66]]); + DenseMatrix::from_2d_array(&[&[-0.20, -1.28], &[0.87, 2.22], &[0.47, 0.66]]).unwrap(); let w = a.svd_solve_mut(b).unwrap(); assert!(relative_eq!(w, expected_w, epsilon = 1e-2)); } @@ -737,7 +744,8 @@ mod tests { )] #[test] fn decompose_restore() { - let a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0, 4.0], &[5.0, 6.0, 7.0, 8.0]]); + let a = + DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0, 4.0], &[5.0, 6.0, 7.0, 8.0]]).unwrap(); let svd = a.svd().unwrap(); let u: &DenseMatrix = &svd.U; //U let v: &DenseMatrix = &svd.V; // V diff --git a/src/linear/bg_solver.rs b/src/linear/bg_solver.rs index d1ad29f2..6ac9b3e4 100644 --- a/src/linear/bg_solver.rs +++ b/src/linear/bg_solver.rs @@ -12,7 +12,8 @@ //! pub struct BGSolver {} //! impl<'a, T: FloatNumber, X: Array2> BiconjugateGradientSolver<'a, T, X> for BGSolver {} //! -//! let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]); +//! let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., +//! 11.]]).unwrap(); //! let b = vec![40., 51., 28.]; //! let expected = vec![1.0, 2.0, 3.0]; //! let mut x = Vec::zeros(3); @@ -158,7 +159,8 @@ mod tests { #[test] fn bg_solver() { - let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]); + let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) + .unwrap(); let b = vec![40., 51., 28.]; let expected = vec![1.0, 2.0, 3.0]; diff --git a/src/linear/elastic_net.rs b/src/linear/elastic_net.rs index 87deddca..643ab14e 100644 --- a/src/linear/elastic_net.rs +++ b/src/linear/elastic_net.rs @@ -38,7 +38,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! //! let y: Vec = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; @@ -511,7 +511,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, @@ -562,7 +563,8 @@ mod tests { &[17.0, 1918.0, 1.4054969025700674], &[18.0, 1929.0, 1.3271699396384906], &[19.0, 1915.0, 1.1373332337674806], - ]); + ]) + .unwrap(); let y: Vec = vec![ 1.48, 2.72, 4.52, 5.72, 5.25, 4.07, 3.75, 4.75, 6.77, 4.72, 6.78, 6.79, 8.3, 7.42, @@ -627,7 +629,7 @@ mod tests { // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - // ]); + // ]).unwrap(); // let y = vec![ // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, diff --git a/src/linear/lasso.rs b/src/linear/lasso.rs index 8de391fc..2919b025 100644 --- a/src/linear/lasso.rs +++ b/src/linear/lasso.rs @@ -418,7 +418,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, diff --git a/src/linear/linear_regression.rs b/src/linear/linear_regression.rs index a5c76999..43410bbb 100644 --- a/src/linear/linear_regression.rs +++ b/src/linear/linear_regression.rs @@ -40,7 +40,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! //! let y: Vec = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; @@ -341,7 +341,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, @@ -393,7 +394,7 @@ mod tests { // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - // ]); + // ]).unwrap(); // let y = vec![ // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 4a4041bc..648367e3 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -35,7 +35,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![ //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! ]; @@ -416,7 +416,7 @@ impl, Y: /// Fits Logistic Regression to your data. /// * `x` - _NxM_ matrix with _N_ observations and _M_ features in each observation. /// * `y` - target class values - /// * `parameters` - other parameters, use `Default::default()` to set parameters to default values. + /// * `parameters` - other parameters, use `Default::default()` to set parameters to default values. pub fn fit( x: &X, y: &Y, @@ -448,6 +448,7 @@ impl, Y: ))), Ordering::Equal => { let x0 = Vec::zeros(num_attributes + 1); + dbg!(&x.shape()); let objective = BinaryObjectiveFunction { x, @@ -561,6 +562,7 @@ impl, Y: }; let optimizer: LBFGS = Default::default(); + println!("------ optimizer 🦀 ------"); optimizer.optimize(&f, &df, &x0, &ls) } } @@ -611,7 +613,8 @@ mod tests { &[10., -2.], &[8., 2.], &[9., 0.], - ]); + ]) + .unwrap(); let y = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; @@ -671,7 +674,8 @@ mod tests { &[10., -2.], &[8., 2.], &[9., 0.], - ]); + ]) + .unwrap(); let y = vec![0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1]; @@ -733,7 +737,8 @@ mod tests { &[10., -2.], &[8., 2.], &[9., 0.], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); @@ -839,7 +844,7 @@ mod tests { // &[10., -2.], // &[8., 2.], // &[9., 0.], - // ]); + // ]).unwrap(); // let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; // let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); @@ -877,7 +882,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/linear/ridge_regression.rs b/src/linear/ridge_regression.rs index 2c354299..be2f3d41 100644 --- a/src/linear/ridge_regression.rs +++ b/src/linear/ridge_regression.rs @@ -40,7 +40,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! //! let y: Vec = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; @@ -455,7 +455,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, @@ -513,7 +514,7 @@ mod tests { // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - // ]); + // ]).unwrap(); // let y = vec![ // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, diff --git a/src/metrics/distance/mahalanobis.rs b/src/metrics/distance/mahalanobis.rs index e526c20e..a9347a58 100644 --- a/src/metrics/distance/mahalanobis.rs +++ b/src/metrics/distance/mahalanobis.rs @@ -25,7 +25,7 @@ //! &[68., 590., 37.], //! &[69., 660., 46.], //! &[73., 600., 55.], -//! ]); +//! ]).unwrap(); //! //! let a = data.mean_by(0); //! let b = vec![66., 640., 44.]; @@ -151,7 +151,8 @@ mod tests { &[68., 590., 37.], &[69., 660., 46.], &[73., 600., 55.], - ]); + ]) + .unwrap(); let a = data.mean_by(0); let b = vec![66., 640., 44.]; diff --git a/src/metrics/mod.rs b/src/metrics/mod.rs index c7e1be3d..a7184293 100644 --- a/src/metrics/mod.rs +++ b/src/metrics/mod.rs @@ -37,7 +37,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![ //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! ]; diff --git a/src/model_selection/mod.rs b/src/model_selection/mod.rs index 27571fdb..e72787b7 100644 --- a/src/model_selection/mod.rs +++ b/src/model_selection/mod.rs @@ -36,7 +36,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![ //! 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., //! ]; @@ -84,7 +84,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![ //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! ]; @@ -396,7 +396,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let cv = KFold { @@ -441,7 +442,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -489,7 +491,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -539,7 +542,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let cv = KFold::default().with_n_splits(3); diff --git a/src/naive_bayes/bernoulli.rs b/src/naive_bayes/bernoulli.rs index 52a3c52e..33f00bd4 100644 --- a/src/naive_bayes/bernoulli.rs +++ b/src/naive_bayes/bernoulli.rs @@ -19,14 +19,14 @@ //! &[0, 1, 0, 0, 1, 0], //! &[0, 1, 0, 1, 0, 0], //! &[0, 1, 1, 0, 0, 1], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![0, 0, 0, 1]; //! //! let nb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); //! //! // Testing data point is: //! // Chinese Chinese Chinese Tokyo Japan -//! let x_test = DenseMatrix::from_2d_array(&[&[0, 1, 1, 0, 0, 1]]); +//! let x_test = DenseMatrix::from_2d_array(&[&[0, 1, 1, 0, 0, 1]]).unwrap(); //! let y_hat = nb.predict(&x_test).unwrap(); //! ``` //! @@ -527,7 +527,8 @@ mod tests { &[0.0, 1.0, 0.0, 0.0, 1.0, 0.0], &[0.0, 1.0, 0.0, 1.0, 0.0, 0.0], &[0.0, 1.0, 1.0, 0.0, 0.0, 1.0], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 1]; let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); @@ -558,7 +559,7 @@ mod tests { // Testing data point is: // Chinese Chinese Chinese Tokyo Japan - let x_test = DenseMatrix::from_2d_array(&[&[0.0, 1.0, 1.0, 0.0, 0.0, 1.0]]); + let x_test = DenseMatrix::from_2d_array(&[&[0.0, 1.0, 1.0, 0.0, 0.0, 1.0]]).unwrap(); let y_hat = bnb.predict(&x_test).unwrap(); assert_eq!(y_hat, &[1]); @@ -586,7 +587,8 @@ mod tests { &[2, 0, 3, 3, 1, 2, 0, 2, 4, 1], &[2, 4, 0, 4, 2, 4, 1, 3, 1, 4], &[0, 2, 2, 3, 4, 0, 4, 4, 4, 4], - ]); + ]) + .unwrap(); let y: Vec = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2]; let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); @@ -643,7 +645,8 @@ mod tests { &[0, 1, 0, 0, 1, 0], &[0, 1, 0, 1, 0, 0], &[0, 1, 1, 0, 0, 1], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 1]; let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/naive_bayes/categorical.rs b/src/naive_bayes/categorical.rs index 2c0c7a4a..71a7487a 100644 --- a/src/naive_bayes/categorical.rs +++ b/src/naive_bayes/categorical.rs @@ -24,7 +24,7 @@ //! &[3, 4, 2, 4], //! &[0, 3, 1, 2], //! &[0, 4, 1, 2], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; //! //! let nb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); @@ -455,7 +455,8 @@ mod tests { &[1, 1, 1, 1], &[1, 2, 0, 0], &[2, 1, 1, 1], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); @@ -513,7 +514,7 @@ mod tests { ] ); - let x_test = DenseMatrix::from_2d_array(&[&[0, 2, 1, 0], &[2, 2, 0, 0]]); + let x_test = DenseMatrix::from_2d_array(&[&[0, 2, 1, 0], &[2, 2, 0, 0]]).unwrap(); let y_hat = cnb.predict(&x_test).unwrap(); assert_eq!(y_hat, vec![0, 1]); } @@ -539,7 +540,8 @@ mod tests { &[3, 4, 2, 4], &[0, 3, 1, 2], &[0, 4, 1, 2], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); @@ -571,7 +573,8 @@ mod tests { &[3, 4, 2, 4], &[0, 3, 1, 2], &[0, 4, 1, 2], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/naive_bayes/gaussian.rs b/src/naive_bayes/gaussian.rs index d72d27de..aff996be 100644 --- a/src/naive_bayes/gaussian.rs +++ b/src/naive_bayes/gaussian.rs @@ -16,7 +16,7 @@ //! &[ 1., 1.], //! &[ 2., 1.], //! &[ 3., 2.], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![1, 1, 1, 2, 2, 2]; //! //! let nb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); @@ -395,7 +395,8 @@ mod tests { &[1., 1.], &[2., 1.], &[3., 2.], - ]); + ]) + .unwrap(); let y: Vec = vec![1, 1, 1, 2, 2, 2]; let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); @@ -435,7 +436,8 @@ mod tests { &[1., 1.], &[2., 1.], &[3., 2.], - ]); + ]) + .unwrap(); let y: Vec = vec![1, 1, 1, 2, 2, 2]; let priors = vec![0.3, 0.7]; @@ -462,7 +464,8 @@ mod tests { &[1., 1.], &[2., 1.], &[3., 2.], - ]); + ]) + .unwrap(); let y: Vec = vec![1, 1, 1, 2, 2, 2]; let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/naive_bayes/multinomial.rs b/src/naive_bayes/multinomial.rs index a340c40d..2d6c437c 100644 --- a/src/naive_bayes/multinomial.rs +++ b/src/naive_bayes/multinomial.rs @@ -20,13 +20,13 @@ //! &[0, 2, 0, 0, 1, 0], //! &[0, 1, 0, 1, 0, 0], //! &[0, 1, 1, 0, 0, 1], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![0, 0, 0, 1]; //! let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); //! //! // Testing data point is: //! // Chinese Chinese Chinese Tokyo Japan -//! let x_test = DenseMatrix::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]); +//! let x_test = DenseMatrix::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]).unwrap(); //! let y_hat = nb.predict(&x_test).unwrap(); //! ``` //! @@ -433,7 +433,8 @@ mod tests { &[0, 2, 0, 0, 1, 0], &[0, 1, 0, 1, 0, 0], &[0, 1, 1, 0, 0, 1], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 1]; let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); @@ -467,7 +468,7 @@ mod tests { // Testing data point is: // Chinese Chinese Chinese Tokyo Japan - let x_test = DenseMatrix::::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]); + let x_test = DenseMatrix::::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]).unwrap(); let y_hat = mnb.predict(&x_test).unwrap(); assert_eq!(y_hat, &[0]); @@ -495,7 +496,8 @@ mod tests { &[2, 0, 3, 3, 1, 2, 0, 2, 4, 1], &[2, 4, 0, 4, 2, 4, 1, 3, 1, 4], &[0, 2, 2, 3, 4, 0, 4, 4, 4, 4], - ]); + ]) + .unwrap(); let y: Vec = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2]; let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); @@ -554,7 +556,8 @@ mod tests { &[0, 1, 0, 0, 1, 0], &[0, 1, 0, 1, 0, 0], &[0, 1, 1, 0, 0, 1], - ]); + ]) + .unwrap(); let y = vec![0, 0, 0, 1]; let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/neighbors/knn_classifier.rs b/src/neighbors/knn_classifier.rs index a70a12ec..d18620c9 100644 --- a/src/neighbors/knn_classifier.rs +++ b/src/neighbors/knn_classifier.rs @@ -22,7 +22,7 @@ //! &[3., 4.], //! &[5., 6.], //! &[7., 8.], -//! &[9., 10.]]); +//! &[9., 10.]]).unwrap(); //! let y = vec![2, 2, 2, 3, 3]; //your class labels //! //! let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap(); @@ -211,7 +211,7 @@ impl, Y: Array1, D: Distance, Y: Array1, D: Distance>> { /// Fits KNN regressor to a NxM matrix where N is number of samples and M is number of features. /// * `x` - training data - /// * `y` - vector with real values + /// * `y` - vector with real values /// * `parameters` - additional parameters like search algorithm and k pub fn fit( x: &X, @@ -295,7 +295,8 @@ mod tests { #[test] fn knn_fit_predict_weighted() { let x = - DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]); + DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) + .unwrap(); let y: Vec = vec![1., 2., 3., 4., 5.]; let y_exp = vec![1., 2., 3., 4., 5.]; let knn = KNNRegressor::fit( @@ -322,7 +323,8 @@ mod tests { #[test] fn knn_fit_predict_uniform() { let x = - DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]); + DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) + .unwrap(); let y: Vec = vec![1., 2., 3., 4., 5.]; let y_exp = vec![2., 2., 3., 4., 4.]; let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap(); @@ -341,7 +343,8 @@ mod tests { #[cfg(feature = "serde")] fn serde() { let x = - DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]); + DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) + .unwrap(); let y = vec![1., 2., 3., 4., 5.]; let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/optimization/first_order/lbfgs.rs b/src/optimization/first_order/lbfgs.rs index 81e7b640..f27c14b1 100644 --- a/src/optimization/first_order/lbfgs.rs +++ b/src/optimization/first_order/lbfgs.rs @@ -246,6 +246,7 @@ impl FirstOrderOptimizer for LBFGS { ) -> OptimizerResult { let mut state = self.init_state(x0); + println!("---- 🦀 ------"); df(&mut state.x_df, x0); let g_converged = state.x_df.norm(std::f64::INFINITY) < self.g_atol; diff --git a/src/preprocessing/categorical.rs b/src/preprocessing/categorical.rs index 933d7c2b..feafd2d9 100644 --- a/src/preprocessing/categorical.rs +++ b/src/preprocessing/categorical.rs @@ -12,7 +12,7 @@ //! &[1.5, 2.0, 1.5, 4.0], //! &[1.5, 1.0, 1.5, 5.0], //! &[1.5, 2.0, 1.5, 6.0], -//! ]); +//! ]).unwrap(); //! let encoder_params = OneHotEncoderParams::from_cat_idx(&[1, 3]); //! // Infer number of categories from data and return a reusable encoder //! let encoder = OneHotEncoder::fit(&data, encoder_params).unwrap(); @@ -240,14 +240,16 @@ mod tests { &[2.0, 1.5, 4.0], &[1.0, 1.5, 5.0], &[2.0, 1.5, 6.0], - ]); + ]) + .unwrap(); let oh_enc = DenseMatrix::from_2d_array(&[ &[1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0], &[0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0], &[1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0], &[0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0], - ]); + ]) + .unwrap(); (orig, oh_enc) } @@ -259,14 +261,16 @@ mod tests { &[1.5, 2.0, 1.5, 4.0], &[1.5, 1.0, 1.5, 5.0], &[1.5, 2.0, 1.5, 6.0], - ]); + ]) + .unwrap(); let oh_enc = DenseMatrix::from_2d_array(&[ &[1.5, 1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0], &[1.5, 0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0], &[1.5, 1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0], &[1.5, 0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0], - ]); + ]) + .unwrap(); (orig, oh_enc) } @@ -334,7 +338,8 @@ mod tests { &[2.0, 1.5, 4.0], &[1.0, 1.5, 5.0], &[2.0, 1.5, 6.0], - ]); + ]) + .unwrap(); let params = OneHotEncoderParams::from_cat_idx(&[1]); let result = OneHotEncoder::fit(&m, params); diff --git a/src/preprocessing/numerical.rs b/src/preprocessing/numerical.rs index c673731b..ddb74a45 100644 --- a/src/preprocessing/numerical.rs +++ b/src/preprocessing/numerical.rs @@ -11,7 +11,7 @@ //! vec![0.0, 0.0], //! vec![1.0, 1.0], //! vec![1.0, 1.0], -//! ]); +//! ]).unwrap(); //! //! let standard_scaler = //! numerical::StandardScaler::fit(&data, numerical::StandardScalerParameters::default()) @@ -24,7 +24,7 @@ //! vec![-1.0, -1.0], //! vec![1.0, 1.0], //! vec![1.0, 1.0], -//! ]) +//! ]).unwrap() //! ); //! ``` use std::marker::PhantomData; @@ -197,15 +197,18 @@ mod tests { fn combine_three_columns() { assert_eq!( build_matrix_from_columns(vec![ - DenseMatrix::from_2d_vec(&vec![vec![1.0], vec![1.0], vec![1.0],]), - DenseMatrix::from_2d_vec(&vec![vec![2.0], vec![2.0], vec![2.0],]), - DenseMatrix::from_2d_vec(&vec![vec![3.0], vec![3.0], vec![3.0],]) + DenseMatrix::from_2d_vec(&vec![vec![1.0], vec![1.0], vec![1.0],]).unwrap(), + DenseMatrix::from_2d_vec(&vec![vec![2.0], vec![2.0], vec![2.0],]).unwrap(), + DenseMatrix::from_2d_vec(&vec![vec![3.0], vec![3.0], vec![3.0],]).unwrap() ]), - Some(DenseMatrix::from_2d_vec(&vec![ - vec![1.0, 2.0, 3.0], - vec![1.0, 2.0, 3.0], - vec![1.0, 2.0, 3.0] - ])) + Some( + DenseMatrix::from_2d_vec(&vec![ + vec![1.0, 2.0, 3.0], + vec![1.0, 2.0, 3.0], + vec![1.0, 2.0, 3.0] + ]) + .unwrap() + ) ) } @@ -287,13 +290,15 @@ mod tests { /// sklearn. #[test] fn fit_transform_random_values() { - let transformed_values = - fit_transform_with_default_standard_scaler(&DenseMatrix::from_2d_array(&[ + let transformed_values = fit_transform_with_default_standard_scaler( + &DenseMatrix::from_2d_array(&[ &[0.1004222429, 0.2194113576, 0.9310663354, 0.3313593793], &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], - ])); + ]) + .unwrap(), + ); println!("{transformed_values}"); assert!(transformed_values.approximate_eq( &DenseMatrix::from_2d_array(&[ @@ -301,7 +306,8 @@ mod tests { &[-0.7615464283, -0.7076698384, -1.1075452562, 1.2632979631], &[0.4832504303, -0.6106747444, 1.0630075435, 0.5494084257], &[1.3936980634, 1.7215431158, -0.8839228078, -1.3855590021], - ]), + ]) + .unwrap(), 1.0 )) } @@ -310,13 +316,10 @@ mod tests { #[test] fn fit_transform_with_zero_variance() { assert_eq!( - fit_transform_with_default_standard_scaler(&DenseMatrix::from_2d_array(&[ - &[1.0], - &[1.0], - &[1.0], - &[1.0] - ])), - DenseMatrix::from_2d_array(&[&[0.0], &[0.0], &[0.0], &[0.0]]), + fit_transform_with_default_standard_scaler( + &DenseMatrix::from_2d_array(&[&[1.0], &[1.0], &[1.0], &[1.0]]).unwrap() + ), + DenseMatrix::from_2d_array(&[&[0.0], &[0.0], &[0.0], &[0.0]]).unwrap(), "When scaling values with zero variance, zero is expected as return value" ) } @@ -331,7 +334,8 @@ mod tests { &[1.0, 2.0, 5.0], &[1.0, 1.0, 1.0], &[1.0, 2.0, 5.0] - ]), + ]) + .unwrap(), StandardScalerParameters::default(), ), Ok(StandardScaler { @@ -354,7 +358,8 @@ mod tests { &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], - ]), + ]) + .unwrap(), StandardScalerParameters::default(), ) .unwrap(); @@ -364,17 +369,18 @@ mod tests { vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625], ); - assert!( - &DenseMatrix::::from_2d_vec(&vec![fitted_scaler.stds]).approximate_eq( + assert!(&DenseMatrix::::from_2d_vec(&vec![fitted_scaler.stds]) + .unwrap() + .approximate_eq( &DenseMatrix::from_2d_array(&[&[ 0.29426447500954, 0.16758497615485, 0.20820945786863, 0.23329718831165 - ],]), + ],]) + .unwrap(), 0.00000000000001 - ) - ) + )) } /// If `with_std` is set to `false` the values should not be @@ -392,8 +398,9 @@ mod tests { }; assert_eq!( - standard_scaler.transform(&DenseMatrix::from_2d_array(&[&[0.0, 2.0], &[2.0, 4.0]])), - Ok(DenseMatrix::from_2d_array(&[&[-1.0, -1.0], &[1.0, 1.0]])) + standard_scaler + .transform(&DenseMatrix::from_2d_array(&[&[0.0, 2.0], &[2.0, 4.0]]).unwrap()), + Ok(DenseMatrix::from_2d_array(&[&[-1.0, -1.0], &[1.0, 1.0]]).unwrap()) ) } @@ -413,8 +420,8 @@ mod tests { assert_eq!( standard_scaler - .transform(&DenseMatrix::from_2d_array(&[&[0.0, 9.0], &[4.0, 12.0]])), - Ok(DenseMatrix::from_2d_array(&[&[0.0, 3.0], &[2.0, 4.0]])) + .transform(&DenseMatrix::from_2d_array(&[&[0.0, 9.0], &[4.0, 12.0]]).unwrap()), + Ok(DenseMatrix::from_2d_array(&[&[0.0, 3.0], &[2.0, 4.0]]).unwrap()) ) } @@ -433,7 +440,8 @@ mod tests { &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], - ]), + ]) + .unwrap(), StandardScalerParameters::default(), ) .unwrap(); @@ -446,17 +454,18 @@ mod tests { vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625], ); - assert!( - &DenseMatrix::from_2d_vec(&vec![deserialized_scaler.stds]).approximate_eq( + assert!(&DenseMatrix::from_2d_vec(&vec![deserialized_scaler.stds]) + .unwrap() + .approximate_eq( &DenseMatrix::from_2d_array(&[&[ 0.29426447500954, 0.16758497615485, 0.20820945786863, 0.23329718831165 - ],]), + ],]) + .unwrap(), 0.00000000000001 - ) - ) + )) } } } diff --git a/src/svm/svc.rs b/src/svm/svc.rs index 131f44c2..9833ac82 100644 --- a/src/svm/svc.rs +++ b/src/svm/svc.rs @@ -53,7 +53,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y = vec![ -1, -1, -1, -1, -1, -1, -1, -1, //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; //! @@ -966,7 +966,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![ -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -992,7 +993,8 @@ mod tests { )] #[test] fn svc_fit_decision_function() { - let x = DenseMatrix::from_2d_array(&[&[4.0, 0.0], &[0.0, 4.0], &[8.0, 0.0], &[0.0, 8.0]]); + let x = DenseMatrix::from_2d_array(&[&[4.0, 0.0], &[0.0, 4.0], &[8.0, 0.0], &[0.0, 8.0]]) + .unwrap(); let x2 = DenseMatrix::from_2d_array(&[ &[3.0, 3.0], @@ -1001,7 +1003,8 @@ mod tests { &[10.0, 10.0], &[1.0, 1.0], &[0.0, 0.0], - ]); + ]) + .unwrap(); let y: Vec = vec![-1, -1, 1, 1]; @@ -1054,7 +1057,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1103,7 +1107,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![ -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, diff --git a/src/svm/svr.rs b/src/svm/svr.rs index 6fbd15be..fb2d8aa0 100644 --- a/src/svm/svr.rs +++ b/src/svm/svr.rs @@ -44,7 +44,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! //! let y: Vec = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; @@ -642,7 +642,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, @@ -690,7 +691,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, diff --git a/src/tree/decision_tree_classifier.rs b/src/tree/decision_tree_classifier.rs index 4f36e5b9..abda96ed 100644 --- a/src/tree/decision_tree_classifier.rs +++ b/src/tree/decision_tree_classifier.rs @@ -48,7 +48,7 @@ //! &[4.9, 2.4, 3.3, 1.0], //! &[6.6, 2.9, 4.6, 1.3], //! &[5.2, 2.7, 3.9, 1.4], -//! ]); +//! ]).unwrap(); //! let y = vec![ 0, 0, 0, 0, 0, 0, 0, 0, //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; //! @@ -938,7 +938,8 @@ mod tests { &[4.9, 2.4, 3.3, 1.0], &[6.6, 2.9, 4.6, 1.3], &[5.2, 2.7, 3.9, 1.4], - ]); + ]) + .unwrap(); let y: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; assert_eq!( @@ -1005,7 +1006,8 @@ mod tests { &[0., 0., 1., 1.], &[0., 0., 0., 0.], &[0., 0., 0., 1.], - ]); + ]) + .unwrap(); let y: Vec = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; assert_eq!( @@ -1044,7 +1046,8 @@ mod tests { &[0., 0., 1., 1.], &[0., 0., 0., 0.], &[0., 0., 0., 1.], - ]); + ]) + .unwrap(); let y = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/tree/decision_tree_regressor.rs b/src/tree/decision_tree_regressor.rs index d21c7490..dca4acaf 100644 --- a/src/tree/decision_tree_regressor.rs +++ b/src/tree/decision_tree_regressor.rs @@ -39,7 +39,7 @@ //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], -//! ]); +//! ]).unwrap(); //! let y: Vec = vec![ //! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, //! 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -753,7 +753,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, @@ -834,7 +835,8 @@ mod tests { &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], - ]); + ]) + .unwrap(); let y: Vec = vec![ 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, From 4c9a6500c088e72eb21bb85f6c62343c363cc532 Mon Sep 17 00:00:00 2001 From: Edmund Cape Date: Tue, 4 Apr 2023 16:01:23 -0400 Subject: [PATCH 08/27] final --- src/linear/logistic_regression.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 648367e3..ee2eb98a 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -448,7 +448,6 @@ impl, Y: ))), Ordering::Equal => { let x0 = Vec::zeros(num_attributes + 1); - dbg!(&x.shape()); let objective = BinaryObjectiveFunction { x, From de1a43a3958a1abdcfc0fedbe70d827de4441391 Mon Sep 17 00:00:00 2001 From: Edmund Cape Date: Tue, 4 Apr 2023 16:41:50 -0400 Subject: [PATCH 09/27] final-clean --- src/linalg/basic/matrix.rs | 5 ----- src/linear/logistic_regression.rs | 1 - src/optimization/first_order/lbfgs.rs | 1 - 3 files changed, 7 deletions(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index de3c28f6..ac9a7872 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -386,11 +386,6 @@ impl Array for DenseMatrix let (row, col) = pos; let idx_target = col * self.nrows + row; - println!("------ 🦀 ----- 📋 target: {}", self.values.len()); - println!("------ 🦀 ----- 📋 nrows: {}", &self.nrows); - println!("row: {} col: {}", &row, &col); - println!("DenseMatrix get target: {}", idx_target); - if row >= self.nrows || col >= self.ncols { panic!( "Invalid index ({},{}) for {}x{} matrix", diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index ee2eb98a..7e82314f 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -561,7 +561,6 @@ impl, Y: }; let optimizer: LBFGS = Default::default(); - println!("------ optimizer 🦀 ------"); optimizer.optimize(&f, &df, &x0, &ls) } } diff --git a/src/optimization/first_order/lbfgs.rs b/src/optimization/first_order/lbfgs.rs index f27c14b1..81e7b640 100644 --- a/src/optimization/first_order/lbfgs.rs +++ b/src/optimization/first_order/lbfgs.rs @@ -246,7 +246,6 @@ impl FirstOrderOptimizer for LBFGS { ) -> OptimizerResult { let mut state = self.init_state(x0); - println!("---- 🦀 ------"); df(&mut state.x_df, x0); let g_converged = state.x_df.norm(std::f64::INFINITY) < self.g_atol; From 4c120d38474049eb0ab4fbe25c55646a033e5198 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Wed, 5 Apr 2023 17:14:10 +0900 Subject: [PATCH 10/27] Bump to 0.4.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 48d91804..4f7a6ddb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "smartcore" description = "Machine Learning in Rust." homepage = "https://smartcorelib.org" -version = "0.3.2" +version = "0.4.0" authors = ["smartcore Developers"] edition = "2021" license = "Apache-2.0" From c1b36772c21dff0ab97c9cf54afb7c4050555282 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Wed, 5 Apr 2023 17:17:04 +0900 Subject: [PATCH 11/27] Fix linter --- src/linalg/basic/matrix.rs | 13 ++++++------- src/linear/logistic_regression.rs | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index ac9a7872..b8a914bf 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -106,9 +106,9 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { let (mrows, mcols) = m.shape(); if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { - Err(Failed::input(&format!( + Err(Failed::input( "The specified window is outside of the matrix range" - ))) + )) } else { let (start, end, stride) = start_end_stride(mrows, mcols, &vrows, &vcols, m.column_major); @@ -159,9 +159,9 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> { ) -> Result { let (mrows, mcols) = m.shape(); if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { - Err(Failed::input(&format!( + Err(Failed::input( "The specified window is outside of the matrix range" - ))) + )) } else { let (start, end, stride) = start_end_stride(mrows, mcols, &vrows, &vcols, m.column_major); @@ -271,9 +271,9 @@ impl DenseMatrix { ); if values.is_empty() || values[0].is_empty() { - Err(Failed::input(&format!( + Err(Failed::input( "The 2d vec provided is empty; cannot instantiate the matrix" - ))) + )) } else { let nrows = values.len(); let ncols = values @@ -384,7 +384,6 @@ where impl Array for DenseMatrix { fn get(&self, pos: (usize, usize)) -> &T { let (row, col) = pos; - let idx_target = col * self.nrows + row; if row >= self.nrows || col >= self.ncols { panic!( diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 99e787f2..65f1cc7f 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -821,7 +821,6 @@ mod tests { assert!(reg_coeff_sum < coeff); } - //TODO: serialization for the new DenseMatrix needs to be implemented #[cfg_attr( all(target_arch = "wasm32", not(target_os = "wasi")), From 5feab831e7cccc26b157e220a2f7da5f408dd04b Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Wed, 5 Apr 2023 17:19:10 +0900 Subject: [PATCH 12/27] cleanup --- src/linalg/basic/matrix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index b8a914bf..6a0fa13a 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -107,7 +107,7 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { Err(Failed::input( - "The specified window is outside of the matrix range" + "The specified window is outside of the matrix range", )) } else { let (start, end, stride) = @@ -160,7 +160,7 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> { let (mrows, mcols) = m.shape(); if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { Err(Failed::input( - "The specified window is outside of the matrix range" + "The specified window is outside of the matrix range", )) } else { let (start, end, stride) = @@ -272,7 +272,7 @@ impl DenseMatrix { if values.is_empty() || values[0].is_empty() { Err(Failed::input( - "The 2d vec provided is empty; cannot instantiate the matrix" + "The 2d vec provided is empty; cannot instantiate the matrix", )) } else { let nrows = values.len(); From 574b7feba1665a904b49dcc5b875d79458844efd Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Wed, 5 Apr 2023 17:27:05 +0900 Subject: [PATCH 13/27] Update CHANDELOG with breaking changes --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1054327..61c46ec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - 2022-11-09 + +## Added +- WARNING: Breaking changes! +- `DenseMatrix` constructor now returns `Result` to avoid user instantiating inconsistent rows/cols count +- Every call to `DenseMatrix::new` and `DenseMatrix::from_2d_array` needs to be unwrapped with `unwrap()`, see tests + ## [0.3.0] - 2022-11-09 ## Added From 724268b093615c14a40a06e8b72a3e322dd60d45 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Wed, 5 Apr 2023 17:28:41 +0900 Subject: [PATCH 14/27] Update CHANDELOG date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c46ec3..6f317d9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.4.0] - 2022-11-09 +## [0.4.0] - 2023-04-05 ## Added - WARNING: Breaking changes! From d4e9669353f06d9382fd57c83a5c5c80454fdeb2 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 10:56:52 +0900 Subject: [PATCH 15/27] Add functional methods to DenseMatrix implementation --- src/linalg/basic/matrix.rs | 108 +++++++++++++++---------------------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index 6a0fa13a..d1a0ded2 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -51,51 +51,6 @@ pub struct DenseMatrixMutView<'a, T: Debug + Display + Copy + Sized> { column_major: bool, } -// functional utility functions used across types -fn is_valid_matrix_window( - mrows: usize, - mcols: usize, - vrows: &Range, - vcols: &Range, -) -> bool { - debug_assert!( - vrows.end <= mrows && vcols.end <= mcols, - "The window end is outside of the matrix range" - ); - debug_assert!( - vrows.start <= mrows && vcols.start <= mcols, - "The window start is outside of the matrix range" - ); - debug_assert!( - // depends on a properly formed range - vrows.start <= vrows.end && vcols.start <= vcols.end, - "Invalid range: start <= end failed" - ); - - !(vrows.end <= mrows && vcols.end <= mcols && vrows.start <= mrows && vcols.start <= mcols) -} -fn start_end_stride( - mrows: usize, - mcols: usize, - vrows: &Range, - vcols: &Range, - column_major: bool, -) -> (usize, usize, usize) { - let (start, end, stride) = if column_major { - ( - vrows.start + vcols.start * mrows, - vrows.end + (vcols.end - 1) * mrows, - mrows, - ) - } else { - ( - vrows.start * mcols + vcols.start, - (vrows.end - 1) * mcols + vcols.end, - mcols, - ) - }; - (start, end, stride) -} impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { fn new( @@ -103,15 +58,13 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { vrows: Range, vcols: Range, ) -> Result { - let (mrows, mcols) = m.shape(); - - if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { + if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) { Err(Failed::input( - "The specified window is outside of the matrix range", + "The specified view is outside of the matrix range" )) } else { let (start, end, stride) = - start_end_stride(mrows, mcols, &vrows, &vcols, m.column_major); + m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major); Ok(DenseMatrixView { values: &m.values[start..end], @@ -157,14 +110,13 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> { vrows: Range, vcols: Range, ) -> Result { - let (mrows, mcols) = m.shape(); - if is_valid_matrix_window(mrows, mcols, &vrows, &vcols) { + if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) { Err(Failed::input( - "The specified window is outside of the matrix range", + "The specified view is outside of the matrix range" )) } else { let (start, end, stride) = - start_end_stride(mrows, mcols, &vrows, &vcols, m.column_major); + m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major); Ok(DenseMatrixMutView { values: &mut m.values[start..end], @@ -239,10 +191,6 @@ impl DenseMatrix { values: Vec, column_major: bool, ) -> Result { - debug_assert!( - nrows * ncols == values.len(), - "Instantiatint DenseMatrix requires nrows * ncols == values.len()" - ); let data_len = values.len(); if nrows * ncols != values.len() { Err(Failed::input(&format!( @@ -265,14 +213,9 @@ impl DenseMatrix { /// New instance of `DenseMatrix` from 2d vector. pub fn from_2d_vec(values: &Vec>) -> Result { - debug_assert!( - !(values.is_empty() || values[0].is_empty()), - "Instantiating DenseMatrix requires a non-empty 2d_vec" - ); - if values.is_empty() || values[0].is_empty() { Err(Failed::input( - "The 2d vec provided is empty; cannot instantiate the matrix", + "The 2d vec provided is empty; cannot instantiate the matrix" )) } else { let nrows = values.len(); @@ -298,6 +241,43 @@ impl DenseMatrix { 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, + vcols: &Range, + ) -> 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, + vcols: &Range, + 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 fmt::Display for DenseMatrix { From 0a377d52072555993e2f452ddbc748891e06dbe7 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:05:11 +0900 Subject: [PATCH 16/27] linting --- src/linalg/basic/matrix.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index d1a0ded2..0c2e8696 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -51,7 +51,6 @@ pub struct DenseMatrixMutView<'a, T: Debug + Display + Copy + Sized> { column_major: bool, } - impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { fn new( m: &'a DenseMatrix, @@ -60,7 +59,7 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { ) -> Result { 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" + "The specified view is outside of the matrix range", )) } else { let (start, end, stride) = @@ -112,7 +111,7 @@ impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> { ) -> Result { 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" + "The specified view is outside of the matrix range", )) } else { let (start, end, stride) = @@ -215,7 +214,7 @@ impl DenseMatrix { pub fn from_2d_vec(values: &Vec>) -> Result { if values.is_empty() || values[0].is_empty() { Err(Failed::input( - "The 2d vec provided is empty; cannot instantiate the matrix" + "The 2d vec provided is empty; cannot instantiate the matrix", )) } else { let nrows = values.len(); @@ -250,10 +249,13 @@ impl DenseMatrix { vrows: &Range, vcols: &Range, ) -> bool { - !(vrows.end <= n_rows && vcols.end <= n_cols && vrows.start <= n_rows && vcols.start <= n_cols) + !(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 + /// Compute the range of the requested view: start, end, size of the slice fn stride_range( &self, n_rows: usize, @@ -277,7 +279,6 @@ impl DenseMatrix { }; (start, end, stride) } - } impl fmt::Display for DenseMatrix { From 4e5534613ab671768f8029b717635bad5c3f1fa5 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:10:01 +0900 Subject: [PATCH 17/27] add type declaration in test --- src/linear/logistic_regression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 65f1cc7f..195fa40d 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -829,7 +829,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn serde() { - let x = DenseMatrix::from_2d_array(&[ + let x: DenseMatrix = DenseMatrix::from_2d_array(&[ &[1., -5.], &[2., 5.], &[3., -2.], From c987a803e1b956afd19154c2679d92bb040459d4 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:16:07 +0900 Subject: [PATCH 18/27] Fix Wasm tests failing --- src/linear/logistic_regression.rs | 4 ++-- src/readers/csv.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 195fa40d..82c9d829 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -829,7 +829,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn serde() { - let x: DenseMatrix = DenseMatrix::from_2d_array(&[ + let x: DenseMatrix = DenseMatrix::from_2d_array(&[ &[1., -5.], &[2., 5.], &[3., -2.], @@ -845,7 +845,7 @@ mod tests { &[10., -2.], &[8., 2.], &[9., 0.], - ]); + ]).unwrap(); let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); diff --git a/src/readers/csv.rs b/src/readers/csv.rs index 730f2932..ef00955b 100644 --- a/src/readers/csv.rs +++ b/src/readers/csv.rs @@ -266,7 +266,7 @@ mod tests { &[5.1, 3.5, 1.4, 0.2], &[4.9, 3.0, 1.4, 0.2], &[4.7, 3.2, 1.3, 0.2], - ])) + ]).unwrap()) ) } #[test] From c2592fd44db76fe3881e1d52d3973b9d2160aae7 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:28:05 +0900 Subject: [PATCH 19/27] linting --- src/linear/logistic_regression.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 82c9d829..d07b54f1 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -845,7 +845,8 @@ mod tests { &[10., -2.], &[8., 2.], &[9., 0.], - ]).unwrap(); + ]) + .unwrap(); let y: Vec = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); From e7f76a6f2f6425b173fc39c510c64455a4e0d5ad Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:30:09 +0900 Subject: [PATCH 20/27] fix tests --- src/readers/csv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/readers/csv.rs b/src/readers/csv.rs index ef00955b..4fe7464e 100644 --- a/src/readers/csv.rs +++ b/src/readers/csv.rs @@ -243,7 +243,7 @@ mod tests { &[5.1, 3.5, 1.4, 0.2], &[4.9, 3.0, 1.4, 0.2], &[4.7, 3.2, 1.3, 0.2], - ])) + ]).unwrap()) ) } #[test] From 7c39ace244d71cad2d888d734433792928b8fb36 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 11:39:08 +0900 Subject: [PATCH 21/27] linting --- src/readers/csv.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/readers/csv.rs b/src/readers/csv.rs index 4fe7464e..7f902ff1 100644 --- a/src/readers/csv.rs +++ b/src/readers/csv.rs @@ -243,7 +243,8 @@ mod tests { &[5.1, 3.5, 1.4, 0.2], &[4.9, 3.0, 1.4, 0.2], &[4.7, 3.2, 1.3, 0.2], - ]).unwrap()) + ]) + .unwrap()) ) } #[test] From af5033bd2cb91d47f2ac78d656ceed7c12fb7fc6 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Thu, 6 Apr 2023 18:04:54 +0900 Subject: [PATCH 22/27] Add type annotations on BBDTree constructor --- src/algorithm/neighbour/bbd_tree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithm/neighbour/bbd_tree.rs b/src/algorithm/neighbour/bbd_tree.rs index 1cc92c4a..790f6d39 100644 --- a/src/algorithm/neighbour/bbd_tree.rs +++ b/src/algorithm/neighbour/bbd_tree.rs @@ -40,11 +40,11 @@ impl BBDTreeNode { impl BBDTree { pub fn new>(data: &M) -> BBDTree { - let nodes = Vec::new(); + let nodes: Vec = Vec::new(); let (n, _) = data.shape(); - let index = (0..n).collect::>(); + let index = (0..n).collect::>(); let mut tree = BBDTree { nodes, From 5667847029f624e50bfc89efc38974604f7922d4 Mon Sep 17 00:00:00 2001 From: Lorenzo Moriondo Date: Mon, 4 Mar 2024 08:32:47 +0000 Subject: [PATCH 23/27] fix clippy --- src/linalg/basic/matrix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index 49833b70..6dcad4ca 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -211,7 +211,7 @@ impl DenseMatrix { } /// New instance of `DenseMatrix` from 2d vector. - pub fn from_2d_vec(values: &Vec>) -> Result { + pub fn from_2d_vec(values: &[Vec]) -> Result { if values.is_empty() || values[0].is_empty() { Err(Failed::input( "The 2d vec provided is empty; cannot instantiate the matrix", From 32d7e456124d39c6ed780b806a033617efac9491 Mon Sep 17 00:00:00 2001 From: Lorenzo Moriondo Date: Mon, 4 Mar 2024 08:36:40 +0000 Subject: [PATCH 24/27] fix clippy --- src/linalg/basic/matrix.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/linalg/basic/matrix.rs b/src/linalg/basic/matrix.rs index 6dcad4ca..47c5e9d2 100644 --- a/src/linalg/basic/matrix.rs +++ b/src/linalg/basic/matrix.rs @@ -211,7 +211,8 @@ impl DenseMatrix { } /// New instance of `DenseMatrix` from 2d vector. - pub fn from_2d_vec(values: &[Vec]) -> Result { + #[allow(clippy::ptr_arg)] + pub fn from_2d_vec(values: &Vec>) -> Result { if values.is_empty() || values[0].is_empty() { Err(Failed::input( "The 2d vec provided is empty; cannot instantiate the matrix", From 92cb6973ef82d6187bea47ccb23f6f7a31532aca Mon Sep 17 00:00:00 2001 From: Lorenzo Moriondo Date: Mon, 4 Mar 2024 08:40:45 +0000 Subject: [PATCH 25/27] fix tests --- src/naive_bayes/mod.rs | 2 +- src/tree/decision_tree_classifier.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/naive_bayes/mod.rs b/src/naive_bayes/mod.rs index 11614d14..1d74a315 100644 --- a/src/naive_bayes/mod.rs +++ b/src/naive_bayes/mod.rs @@ -169,7 +169,7 @@ mod tests { #[test] fn test_predict() { - let matrix = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]); + let matrix = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap(); let val = vec![]; match Model::fit(TestDistribution(&val)).unwrap().predict(&matrix) { diff --git a/src/tree/decision_tree_classifier.rs b/src/tree/decision_tree_classifier.rs index 495e07dc..6e7c17d3 100644 --- a/src/tree/decision_tree_classifier.rs +++ b/src/tree/decision_tree_classifier.rs @@ -1067,7 +1067,7 @@ mod tests { &[0., 0., 1., 1.], &[0., 0., 0., 0.], &[0., 0., 0., 1.], - ]); + ]).unwrap(); let y: Vec = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap(); assert_eq!( From c1b0b534e1c10dc8dc095c8aed8afa32197d4328 Mon Sep 17 00:00:00 2001 From: Lorenzo Moriondo Date: Mon, 4 Mar 2024 13:24:35 +0000 Subject: [PATCH 26/27] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 76d3e998..a3fea09b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "smartcore" description = "Machine Learning in Rust." homepage = "https://smartcorelib.org" -version = "0.3.3" +version = "0.4.0" authors = ["smartcore Developers"] edition = "2021" license = "Apache-2.0" From 3fcd72224d7a56b13c2528c2fdbd524167587122 Mon Sep 17 00:00:00 2001 From: Lorenzo Moriondo Date: Mon, 4 Mar 2024 13:28:37 +0000 Subject: [PATCH 27/27] run fmt. fix changelog --- CHANGELOG.md | 3 +-- src/tree/decision_tree_classifier.rs | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f317d9f..6df73a6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Added - WARNING: Breaking changes! -- `DenseMatrix` constructor now returns `Result` to avoid user instantiating inconsistent rows/cols count -- Every call to `DenseMatrix::new` and `DenseMatrix::from_2d_array` needs to be unwrapped with `unwrap()`, see tests +- `DenseMatrix` constructor now returns `Result` to avoid user instantiating inconsistent rows/cols count. Their return values need to be unwrapped with `unwrap()`, see tests ## [0.3.0] - 2022-11-09 diff --git a/src/tree/decision_tree_classifier.rs b/src/tree/decision_tree_classifier.rs index 6e7c17d3..4da9f443 100644 --- a/src/tree/decision_tree_classifier.rs +++ b/src/tree/decision_tree_classifier.rs @@ -1067,7 +1067,8 @@ mod tests { &[0., 0., 1., 1.], &[0., 0., 0., 0.], &[0., 0., 0., 1.], - ]).unwrap(); + ]) + .unwrap(); let y: Vec = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap(); assert_eq!(