From 97a1adf4755b52e40de75d71ebaee8b9269fccb6 Mon Sep 17 00:00:00 2001 From: L <457124+liborty@users.noreply.github.com> Date: Thu, 18 Jul 2024 09:31:49 +1000 Subject: [PATCH] 2.1.11 --- Cargo.toml | 2 +- README.md | 2 ++ src/triangmat.rs | 36 ++++++++++++++++-------------------- src/vecvec.rs | 17 +++++++++-------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c1c64c0..6a40060 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rstats" -version = "2.1.10" +version = "2.1.11" authors = ["Libor Spacek"] edition = "2021" description = "Statistics, Information Measures, Data Analysis, Linear Algebra, Clifford Algebra, Machine Learning, Geometric Median, Matrix Decompositions, Mahalanobis Distance, Hulls, Multithreading.." diff --git a/README.md b/README.md index 44796b4..037e483 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,8 @@ Methods which take an additional generic vector argument, such as a vector of we ## Appendix: Recent Releases +* **Version 2.1.11** - Some minor tidying up of code. + * **Version 2.1.10** - Added `project` of a `TriangMat` to a subspace given by a subspace index. * **Version 2.1.9** - Added multiplications and more tests for `TriangMat`. diff --git a/src/triangmat.rs b/src/triangmat.rs index 8b3d682..ffafa8a 100644 --- a/src/triangmat.rs +++ b/src/triangmat.rs @@ -310,11 +310,11 @@ impl TriangMat { } /// Efficient Cholesky-Banachiewicz matrix decomposition into `LL'`, /// where L is the returned lower triangular matrix and L' its upper triangular transpose. - /// Expects as input a positive definite matrix - /// in TriangMat compact form, such as a covariance matrix produced by `covar`. - /// The computations are all done on the compact form, + /// Takes a positive definite TriangMat matrix, + /// such as a covariance matrix produced by `covar`. + /// The computations are all done in the compact form, /// making this implementation memory efficient for large (symmetric) matrices. - /// Reports errors if the above conditions are not satisfied. + /// Reports errors if the input expectations are not satisfied. pub fn cholesky(&self) -> Result { let sl = self.data.len(); // input not long enough to compute anything @@ -322,10 +322,9 @@ impl TriangMat { return nodata_error("cholesky needs at least 3x3 TriangMat"); }; // n is the dimension of the implied square matrix. - // Not needed as an extra argument. We compute it - // by solving a quadratic equation in seqtosubs() + // It is obtained by solving a quadratic equation in rowcol() let (n, c) = rowcol(sl); - // input is not a triangular number, is of wrong size + // if the input is not a triangular number, then it is of the wrong size if c != 0 { return data_error("cholesky needs a triangular matrix"); }; @@ -386,27 +385,24 @@ impl TriangMat { if self.kind != 0 { return data_error("forward-substitute expects plain lower kind"); }; let data = &self.data; if data.len() < 3 { - return Err(RError::NoDataError( - "forward-substitute needs at least three items".to_owned(), - )); + return nodata_error("forward-substitute needs at least three items"); }; // 2d matrix dimension let n = self.dim(); // dimensions/lengths mismatch if n != b.len() { - return Err(RError::DataError( - "forward_substitute mismatch of self and b dimension".to_owned(), - )); + return data_error("forward_substitute mismatch of self and b dimension"); }; - let mut res: Vec = Vec::with_capacity(n); // result of the same size and shape as b - res.push(f64::from(b[0]) / self.data[0]); + let mut res: Vec = Vec::with_capacity(n); // result of the same size as b + if self.data[0].is_normal() { res.push( f64::from(b[0])/self.data[0] ) } + else { return arith_error("forward-substitute given underconstrained system"); }; for (row, &b_component) in b.iter().enumerate().take(n).skip(1) { let rowoffset = sumn(row); - let mut sumtodiag = 0_f64; - for (column, res_component) in res.iter().enumerate() { - sumtodiag += self.data[rowoffset + column] * res_component; - } - res.push((f64::from(b_component) - sumtodiag) / self.data[rowoffset + row]); + let sumtodiag = res.iter().enumerate().map(|(column, res_component)| + self.data[rowoffset + column] * res_component).sum::(); + if self.data[rowoffset + row].is_normal() { + res.push((f64::from(b_component) - sumtodiag) / self.data[rowoffset + row]); } + else { return arith_error("forward-substitute given underconstrained system"); }; } // println!("Forward substitution: {}",res.gr()); Ok(res) diff --git a/src/vecvec.rs b/src/vecvec.rs index ab9e4ac..036d9fa 100644 --- a/src/vecvec.rs +++ b/src/vecvec.rs @@ -434,19 +434,20 @@ where .map(|(vi, gi)| (vi.clone().into() - gi).powi(2)) .sum(); if mag > eps { - let rec = 1.0_f64 / (mag.sqrt()); // reciprocal of distance (scalar) - // vsum increment by components + // reciprocal of distance (scalar) + let rec = 1.0_f64 / (mag.sqrt()); + // vsum increment by components for (vi, gi) in p.iter().zip(&mut nextg) { *gi += vi.clone().into() * rec } - nextrecsum += rec // add separately the reciprocals for final scaling - } // else simply ignore this point v, should its distance from g be <= eps + // add the scaling reciprocal + nextrecsum += rec + } // ignore point p when |p-g| <= eps } - nextg.iter_mut().for_each(|gi| *gi /= nextrecsum); - // eprintln!("recsum {}, nextrecsum {} diff {}",recsum,nextrecsum,nextrecsum-recsum); + nextg.iter_mut().for_each(|gi| *gi /= nextrecsum); if nextrecsum - recsum < eps { return nextg; - }; // termination test + }; // termination g = nextg; recsum = nextrecsum; } @@ -605,7 +606,7 @@ where Ok(TriangMat{ kind:2,data:covsums }) // kind 2 = symmetric, non transposed } - /// Projects self onto a given basis, e.g. PCA dimensional reduction + /// Projects self onto a given basis, e.g. dimensional reduction /// The returned vectors will have lengths equal to the number of supplied basis vectors. fn projection(self, basis: &[Vec]) -> Result>, RE> {