diff --git a/src/classification/logistic_regression.rs b/src/classification/logistic_regression.rs index faacb2d..919a637 100644 --- a/src/classification/logistic_regression.rs +++ b/src/classification/logistic_regression.rs @@ -139,8 +139,7 @@ impl LogisticRegression { let mut yi: Vec = vec![0; y_nrows]; for i in 0..y_nrows { - let yc = y_m.get(0, i); - let j = classes.iter().position(|c| yc == *c).unwrap(); + let yc = y_m.get(0, i); yi[i] = classes.iter().position(|c| yc == *c).unwrap(); } @@ -244,7 +243,7 @@ impl LogisticRegression { mod tests { use super::*; use crate::linalg::naive::dense_matrix::*; - use ndarray::{arr1, arr2, Array}; + use ndarray::{arr1, arr2}; #[test] fn multiclass_objective_f() { diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 42f7632..0000000 --- a/src/error.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::fmt; - -#[derive(Debug)] -pub struct IllegalArgumentError { - pub message: String, -} - -impl fmt::Display for IllegalArgumentError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.message) - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 63eeea7..a340717 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ pub mod cluster; pub mod decomposition; pub mod linalg; pub mod math; -pub mod error; pub mod algorithm; pub mod common; pub mod optimization; \ No newline at end of file diff --git a/src/linalg/evd.rs b/src/linalg/evd.rs index f4467f5..d7b993a 100644 --- a/src/linalg/evd.rs +++ b/src/linalg/evd.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use num::complex::Complex; use crate::linalg::BaseMatrix; diff --git a/src/linalg/mod.rs b/src/linalg/mod.rs index 3565815..0f1a5f1 100644 --- a/src/linalg/mod.rs +++ b/src/linalg/mod.rs @@ -122,9 +122,7 @@ pub trait BaseMatrix: Clone + Debug { r } - fn transpose(&self) -> Self; - - fn generate_positive_definite(nrows: usize, ncols: usize) -> Self; + fn transpose(&self) -> Self; fn rand(nrows: usize, ncols: usize) -> Self; diff --git a/src/linalg/naive/dense_matrix.rs b/src/linalg/naive/dense_matrix.rs index ace051d..ba50298 100644 --- a/src/linalg/naive/dense_matrix.rs +++ b/src/linalg/naive/dense_matrix.rs @@ -366,12 +366,7 @@ impl BaseMatrix for DenseMatrix { fn sub_element_mut(&mut self, row: usize, col: usize, x: f64) { self.values[col*self.nrows + row] -= x; - } - - fn generate_positive_definite(nrows: usize, ncols: usize) -> Self { - let m = DenseMatrix::rand(nrows, ncols); - m.dot(&m.transpose()) - } + } fn transpose(&self) -> Self { let mut m = DenseMatrix { @@ -723,11 +718,6 @@ mod tests { } } - #[test] - fn generate_positive_definite() { - let m = DenseMatrix::generate_positive_definite(3, 3); - } - #[test] fn reshape() { let m_orig = DenseMatrix::vector_from_array(&[1., 2., 3., 4., 5., 6.]); diff --git a/src/linalg/ndarray_bindings.rs b/src/linalg/ndarray_bindings.rs index 111a2f3..fe883e5 100644 --- a/src/linalg/ndarray_bindings.rs +++ b/src/linalg/ndarray_bindings.rs @@ -5,6 +5,7 @@ use crate::linalg::svd::SVDDecomposableMatrix; use crate::linalg::evd::EVDDecomposableMatrix; use crate::linalg::qr::QRDecomposableMatrix; use ndarray::{Array, ArrayBase, OwnedRepr, Ix2, Ix1, Axis, stack, s}; +use rand::prelude::*; impl BaseMatrix for ArrayBase, Ix2> { @@ -81,7 +82,7 @@ impl BaseMatrix for ArrayBase, Ix2> } fn approximate_eq(&self, other: &Self, error: f64) -> bool { - false + (self - other).iter().all(|v| v.abs() <= error) } fn add_mut(&mut self, other: &Self) -> &Self { @@ -128,12 +129,12 @@ impl BaseMatrix for ArrayBase, Ix2> self.clone().reversed_axes() } - fn generate_positive_definite(nrows: usize, ncols: usize) -> Self{ - panic!("generate_positive_definite method is not implemented for ndarray"); - } - fn rand(nrows: usize, ncols: usize) -> Self{ - panic!("rand method is not implemented for ndarray"); + let mut rng = rand::thread_rng(); + let values: Vec = (0..nrows*ncols).map(|_| { + rng.gen() + }).collect(); + Array::from_shape_vec((nrows, ncols), values).unwrap() } fn norm2(&self) -> f64{ @@ -600,4 +601,26 @@ mod tests { let res: Array2 = BaseMatrix::eye(3); assert_eq!(res, a); } + + #[test] + fn rand() { + let m: Array2 = BaseMatrix::rand(3, 3); + for c in 0..3 { + for r in 0..3 { + assert!(m[[r, c]] != 0f64); + } + } + } + + #[test] + fn approximate_eq() { + let a = arr2(&[[1., 2., 3.], + [4., 5., 6.], + [7., 8., 9.]]); + let noise = arr2(&[[1e-5, 2e-5, 3e-5], + [4e-5, 5e-5, 6e-5], + [7e-5, 8e-5, 9e-5]]); + assert!(a.approximate_eq(&(&noise + &a), 1e-4)); + assert!(!a.approximate_eq(&(&noise + &a), 1e-5)); + } } \ No newline at end of file diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index e99be6a..bffeec2 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use crate::linalg::BaseMatrix; #[derive(Debug, Clone)] diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index 0f1ff21..665f394 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use crate::linalg::BaseMatrix; #[derive(Debug, Clone)] @@ -504,7 +506,7 @@ mod tests { #[test] fn solve() { - let mut a = DenseMatrix::from_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]); + let a = DenseMatrix::from_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]); let b = DenseMatrix::from_array(&[&[0.5, 0.2],&[0.5, 0.8], &[0.5, 0.3]]); let expected_w = DenseMatrix::from_array(&[ &[-0.20, -1.28], diff --git a/src/math/distance/euclidian.rs b/src/math/distance/euclidian.rs index a449f74..2d5b88a 100644 --- a/src/math/distance/euclidian.rs +++ b/src/math/distance/euclidian.rs @@ -21,7 +21,7 @@ mod tests { use super::*; #[test] - fn measure_simple_euclidian_distance() { + fn squared_distance() { let a = vec![1., 2., 3.]; let b = vec![4., 5., 6.]; diff --git a/src/math/mod.rs b/src/math/mod.rs index 0946afb..f091f7a 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -9,9 +9,7 @@ pub trait NumericExt { impl NumericExt for f64 { - fn ln_1pe(&self) -> f64{ - let y = 0.; - + fn ln_1pe(&self) -> f64{ if *self > 15. { return *self; } else { diff --git a/src/optimization/first_order/lbfgs.rs b/src/optimization/first_order/lbfgs.rs index cf8aa76..d1bd8f9 100644 --- a/src/optimization/first_order/lbfgs.rs +++ b/src/optimization/first_order/lbfgs.rs @@ -154,7 +154,7 @@ impl LBFGS { g_converged || x_converged || state.counter_f_tol > self.successive_f_tol } - fn update_hessian<'a, X: Matrix>(&self, df: &'a DF, state: &mut LBFGSState) { + fn update_hessian<'a, X: Matrix>(&self, _: &'a DF, state: &mut LBFGSState) { state.dg = state.x_df.sub(&state.x_df_prev); let rho_iteration = 1. / state.dx.vector_dot(&state.dg); if !rho_iteration.is_infinite() { diff --git a/src/optimization/mod.rs b/src/optimization/mod.rs index 157a6ca..8d97662 100644 --- a/src/optimization/mod.rs +++ b/src/optimization/mod.rs @@ -1,10 +1,8 @@ pub mod first_order; pub mod line_search; -use crate::linalg::Matrix; - -pub type F<'a, X: Matrix> = dyn for<'b> Fn(&'b X) -> f64 + 'a; -pub type DF<'a, X: Matrix> = dyn for<'b> Fn(&'b mut X, &'b X) + 'a; +pub type F<'a, X> = dyn for<'b> Fn(&'b X) -> f64 + 'a; +pub type DF<'a, X> = dyn for<'b> Fn(&'b mut X, &'b X) + 'a; #[derive(Debug, PartialEq)] pub enum FunctionOrder { diff --git a/src/regression/linear_regression.rs b/src/regression/linear_regression.rs index db522b3..adf2d38 100644 --- a/src/regression/linear_regression.rs +++ b/src/regression/linear_regression.rs @@ -1,5 +1,4 @@ use crate::linalg::Matrix; -use crate::regression::Regression; use std::fmt::Debug; #[derive(Debug)] @@ -27,7 +26,7 @@ impl LinearRegression { panic!("Number of rows of X doesn't match number of rows of Y"); } - let mut a = x.v_stack(&M::ones(x_nrows, 1)); + let a = x.v_stack(&M::ones(x_nrows, 1)); let w = match solver { LinearRegressionSolver::QR => a.qr_solve_mut(b), @@ -43,16 +42,11 @@ impl LinearRegression { } } -} - -impl Regression for LinearRegression { - - - fn predict(&self, x: &M) -> M { + pub fn predict(&self, x: &M) -> M::RowVector { let (nrows, _) = x.shape(); let mut y_hat = x.dot(&self.coefficients); y_hat.add_mut(&M::fill(nrows, 1, self.intercept)); - y_hat.transpose() + y_hat.transpose().to_row_vector() } } @@ -85,9 +79,9 @@ mod tests { let y = DenseMatrix::from_array(&[&[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]]); - let y_hat_qr = LinearRegression::fit(&x, &y, LinearRegressionSolver::QR).predict(&x); + let y_hat_qr = DenseMatrix::from_row_vector(LinearRegression::fit(&x, &y, LinearRegressionSolver::QR).predict(&x)); - let y_hat_svd = LinearRegression::fit(&x, &y, LinearRegressionSolver::SVD).predict(&x); + let y_hat_svd = DenseMatrix::from_row_vector(LinearRegression::fit(&x, &y, LinearRegressionSolver::SVD).predict(&x)); assert!(y.approximate_eq(&y_hat_qr, 5.)); assert!(y.approximate_eq(&y_hat_svd, 5.)); diff --git a/src/regression/mod.rs b/src/regression/mod.rs index c4bc5a4..d765146 100644 --- a/src/regression/mod.rs +++ b/src/regression/mod.rs @@ -1,9 +1 @@ -pub mod linear_regression; - -use crate::linalg::Matrix; - -pub trait Regression { - - fn predict(&self, x: &M) -> M; - -} \ No newline at end of file +pub mod linear_regression; \ No newline at end of file