diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 753a0462..066e5882 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,22 @@ env: CARGO_TERM_COLOR: always jobs: + lint: + + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install rustfmt and clippy + run: rustup component add rustfmt clippy + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Clippy + run: cargo clippy --all-targets --features sdp-accelerate,faer-sparse,serde -- -D warnings + build: runs-on: macos-latest diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 93f2e793..e9ef2893 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -23,5 +23,24 @@ jobs: steps: - uses: actions/checkout@v4 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + # Cargo.lock is not committed, so every run resolves dependencies afresh and + # picks up releases that have raised their own MSRV past ours: serde_json + # >=1.0.150, proc-macro2 >=1.0.107, unicode-ident >=1.0.23 and syn 3.x all + # now require rustc 1.71. Resolve with a current cargo using MSRV-aware + # resolution, which honours rust-version in Cargo.toml, then build and test + # with the pinned toolchain. + - name: Resolve dependencies compatible with the declared MSRV + if: matrix.toolchain == '1.70.0' + env: + CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback + run: | + rustup toolchain install stable --profile minimal + cargo +stable generate-lockfile + # serde pins serde_derive with an exact `=` requirement, and serde_derive + # 1.0.229 depends on syn 3.x; the fallback resolver cannot see through + # that pin, so step serde back one release explicitly. + cargo +stable update -p serde --precise 1.0.228 + - run: cargo build --verbose - run: cargo test --verbose diff --git a/.github/workflows/pypi.yaml b/.github/workflows/pypi.yaml index abc21779..4275f4f9 100644 --- a/.github/workflows/pypi.yaml +++ b/.github/workflows/pypi.yaml @@ -39,7 +39,9 @@ jobs: test: false # macOS Intel build - - os: macos-13 + # macos-13 was retired on 2025-12-04; macos-15-intel is the + # replacement x86_64 image, available until August 2027. + - os: macos-15-intel target: x86_64 features: "python,pardiso" test: true diff --git a/.github/workflows/testpypi.yaml b/.github/workflows/testpypi.yaml index e5fe2ce2..42aee964 100644 --- a/.github/workflows/testpypi.yaml +++ b/.github/workflows/testpypi.yaml @@ -28,7 +28,9 @@ jobs: test: false # macOS Intel build - - os: macos-13 + # macos-13 was retired on 2025-12-04; macos-15-intel is the + # replacement x86_64 image, available until August 2027. + - os: macos-15-intel target: x86_64 features: "python,pardiso" test: true diff --git a/src/algebra/dense/blas/cholesky.rs b/src/algebra/dense/blas/cholesky.rs index 243b7586..3f9ba8e4 100644 --- a/src/algebra/dense/blas/cholesky.rs +++ b/src/algebra/dense/blas/cholesky.rs @@ -110,8 +110,7 @@ where if A <= T::zero() { // check for positive definite Err(DenseFactorizationError::Cholesky(1)) - } - else { + } else { self.L[(0, 0)] = A.sqrt(); Ok(()) } @@ -307,26 +306,17 @@ mod test { fn test_data_2x2() -> (Matrix, Matrix, Matrix) { // Create a symmetric matrix S - let S = Matrix::::from(&[ - [(4.0).as_T(), (1.0).as_T()], - [(1.0).as_T(), (3.0).as_T()], - ]); - + let S = Matrix::::from(&[[(4.0).as_T(), (1.0).as_T()], [(1.0).as_T(), (3.0).as_T()]]); + // Solution matrix X with 2 columns - let X = Matrix::::from(&[ - [(2.0).as_T(), (3.0).as_T()], - [(1.0).as_T(), (2.0).as_T()], - ]); - + let X = Matrix::::from(&[[(2.0).as_T(), (3.0).as_T()], [(1.0).as_T(), (2.0).as_T()]]); + // Right-hand side B = S*X - let B = Matrix::::from(&[ - [(9.0).as_T(), (14.0).as_T()], - [(5.0).as_T(), (9.0).as_T()], - ]); - + let B = Matrix::::from(&[[(9.0).as_T(), (14.0).as_T()], [(5.0).as_T(), (9.0).as_T()]]); + (S, X, B) } - + #[rustfmt::skip] fn test_data_3x3() -> (Matrix, Matrix, Matrix) { let S = Matrix::::from(&[ @@ -350,7 +340,6 @@ mod test { (S, X, B) } - #[rustfmt::skip] fn test_data_4x4() -> (Matrix, Matrix, Matrix) { // Create a symmetric matrix S @@ -441,9 +430,6 @@ mod test { generate_test_cholesky_logdet!(f64, test_cholesky_logdet_f64, abs); } - - - #[cfg(all(test, feature = "bench"))] mod bench { @@ -454,15 +440,15 @@ mod bench { let v: Vec = (-100..=100).map(|i| i as f64).collect(); - iproduct!(v.clone(), v.clone(), v.clone()).map(move |(b,d,e)| { - // new matrices that are positive definite, - // so choose a,c,e so that the matrix is + iproduct!(v.clone(), v.clone(), v.clone()).map(move |(b, d, e)| { + // new matrices that are positive definite, + // so choose a,c,e so that the matrix is // diagonally dominant let a = b.abs() + d.abs() + 0.1; let c = b.abs() + e.abs() + 0.1; let f = d.abs() + e.abs() + 0.1; - let data = [a,b,d,b,c,e,d,e,f]; - Matrix::new_from_slice((3,3), &data) + let data = [a, b, d, b, c, e, d, e, f]; + Matrix::new_from_slice((3, 3), &data) }) } @@ -478,4 +464,4 @@ mod bench { let _ = eng.factorblas(&mut A); } } -} \ No newline at end of file +} diff --git a/src/algebra/dense/blas/svd.rs b/src/algebra/dense/blas/svd.rs index 5c8fd0e8..ebd56140 100644 --- a/src/algebra/dense/blas/svd.rs +++ b/src/algebra/dense/blas/svd.rs @@ -366,26 +366,17 @@ mod test { fn test_solve_data_2x2() -> (Matrix, Matrix, Matrix) { // Create a symmetric matrix S - let A = Matrix::::from(&[ - [(4.0).as_T(), (1.0).as_T()], - [(1.0).as_T(), (3.0).as_T()], - ]); - + let A = Matrix::::from(&[[(4.0).as_T(), (1.0).as_T()], [(1.0).as_T(), (3.0).as_T()]]); + // Solution matrix X with 2 columns - let X = Matrix::::from(&[ - [(2.0).as_T(), (3.0).as_T()], - [(1.0).as_T(), (2.0).as_T()], - ]); - + let X = Matrix::::from(&[[(2.0).as_T(), (3.0).as_T()], [(1.0).as_T(), (2.0).as_T()]]); + // Right-hand side B = S*X - let B = Matrix::::from(&[ - [(9.0).as_T(), (14.0).as_T()], - [(5.0).as_T(), (9.0).as_T()], - ]); - + let B = Matrix::::from(&[[(9.0).as_T(), (14.0).as_T()], [(5.0).as_T(), (9.0).as_T()]]); + (A, X, B) } - + #[rustfmt::skip] fn test_solve_data_3x3() -> (Matrix, Matrix, Matrix) { let A = Matrix::::from(&[ @@ -409,7 +400,6 @@ mod test { (A, X, B) } - #[rustfmt::skip] fn test_solve_data_4x4() -> (Matrix, Matrix, Matrix) { // Create a symmetric matrix S @@ -451,7 +441,6 @@ mod test { ]; for method in methods.iter() { - // A and B are modified inplace during factor/solve let mut thisA = A.clone(); let mut thisB = B.clone(); @@ -471,13 +460,13 @@ mod test { #[test] fn $test_name() { let (mut A, mut X, mut B) = test_solve_data_2x2::<$fxx>(); - run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); + run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); - let (mut A, mut X, mut B) = test_solve_data_3x3::<$fxx>(); - run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); + let (mut A, mut X, mut B) = test_solve_data_3x3::<$fxx>(); + run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); let (mut A, mut X, mut B) = test_solve_data_4x4::<$fxx>(); - run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); + run_svd_solve_test(&mut A, &mut X, &mut B, |x| x.$tolfn()); } }; } @@ -485,17 +474,16 @@ mod test { generate_test_svd_solve!(f32, test_svd_solve_f32, sqrt); generate_test_svd_solve!(f64, test_svd_solve_f64, abs); - - fn test_factor_data_2x2() ->Matrix { - let (A,_,_) = test_solve_data_2x2::(); + fn test_factor_data_2x2() -> Matrix { + let (A, _, _) = test_solve_data_2x2::(); A } - fn test_factor_data_3x3() ->Matrix { - let (A,_,_) = test_solve_data_3x3::(); + fn test_factor_data_3x3() -> Matrix { + let (A, _, _) = test_solve_data_3x3::(); A } - fn test_factor_data_4x4() ->Matrix { - let (A,_,_) = test_solve_data_4x4::(); + fn test_factor_data_4x4() -> Matrix { + let (A, _, _) = test_solve_data_4x4::(); A } @@ -522,7 +510,6 @@ mod test { s.windows(2).all(|w| w[0] >= w[1]) } - fn run_svd_factor_test(A: &mut Matrix, tolfn: fn(T) -> T) where T: FloatT, @@ -535,7 +522,6 @@ mod test { ]; for method in methods.iter() { - let Acopy = A.clone(); //A is corrupted after factorization let mut eng = SVDEngine::::new(A.size()); @@ -564,57 +550,51 @@ mod test { } } - macro_rules! generate_test_svd_factor { ($fxx:ty, $test_name:ident, $tolfn:ident) => { #[test] fn $test_name() { let mut A = test_factor_data_2x2::<$fxx>(); - run_svd_factor_test(&mut A, |x| x.$tolfn()); + run_svd_factor_test(&mut A, |x| x.$tolfn()); - let mut A = test_factor_data_3x3::<$fxx>(); - run_svd_factor_test(&mut A, |x| x.$tolfn()); + let mut A = test_factor_data_3x3::<$fxx>(); + run_svd_factor_test(&mut A, |x| x.$tolfn()); let mut A = test_factor_data_4x4::<$fxx>(); - run_svd_factor_test(&mut A, |x| x.$tolfn()); + run_svd_factor_test(&mut A, |x| x.$tolfn()); let mut A = test_factor_data_2x4::<$fxx>(); - run_svd_factor_test(&mut A, |x| x.$tolfn()); + run_svd_factor_test(&mut A, |x| x.$tolfn()); let mut A = test_factor_data_4x2::<$fxx>(); - run_svd_factor_test(&mut A, |x| x.$tolfn()); + run_svd_factor_test(&mut A, |x| x.$tolfn()); } }; } generate_test_svd_factor!(f32, test_svd_factor_f32, sqrt); generate_test_svd_factor!(f64, test_svd_factor_f64, abs); - } - - #[cfg(all(test, feature = "bench"))] mod bench { use super::*; fn svd3_bench_iter() -> impl Iterator> { - use itertools::iproduct; let v = [-4., -2., 0., 1., 5.]; iproduct!(v, v, v, v, v, v, v, v, v).map(move |(a, b, c, d, e, f, g, h, i)| { - let data = [a,b,c,d,e,f,g,h,i]; - Matrix::new_from_slice((3,3), &data) + let data = [a, b, c, d, e, f, g, h, i]; + Matrix::new_from_slice((3, 3), &data) }) } #[test] fn bench_svd3_vs_blas() { - - let mut eng = SVDEngine::::new((3,3)); + let mut eng = SVDEngine::::new((3, 3)); for mut A in svd3_bench_iter() { eng.factor3(&mut A).unwrap(); @@ -624,6 +604,4 @@ mod bench { eng.factorblas(&mut A).unwrap(); } } - } - diff --git a/src/algebra/dense/blas/symv.rs b/src/algebra/dense/blas/symv.rs index 4a88328e..b463dbae 100644 --- a/src/algebra/dense/blas/symv.rs +++ b/src/algebra/dense/blas/symv.rs @@ -1,8 +1,6 @@ #![allow(non_snake_case)] -use crate::algebra::{ - DenseMatrix, FloatT, Matrix, MultiplySYMV, ShapedMatrix, Symmetric, -}; +use crate::algebra::{DenseMatrix, FloatT, Matrix, MultiplySYMV, ShapedMatrix, Symmetric}; impl MultiplySYMV for Symmetric<'_, Matrix> where @@ -31,8 +29,8 @@ macro_rules! generate_test_gsymv { fn $test_name() { #[rustfmt::skip] let A = Matrix::<$fxx>::from(&[ - [ 1., 2., 4.], - [ 0., 3., 5.], + [ 1., 2., 4.], + [ 0., 3., 5.], [ 0., 0., 6.], ]); @@ -43,8 +41,8 @@ macro_rules! generate_test_gsymv { #[rustfmt::skip] let A = Matrix::<$fxx>::from(&[ - [ 1., 0., 0.], - [ 2., 3., 0.], + [ 1., 0., 0.], + [ 2., 3., 0.], [ 4., 5., 6.], ]); @@ -52,7 +50,7 @@ macro_rules! generate_test_gsymv { let mut y = vec![-4., -1., 3.]; A.sym_lo().symv(&x, &mut y, 2.0, 3.0); assert_eq!(y, [6.0, 19.0, 33.0]); - } + } }; } diff --git a/src/algebra/dense/blas/syr2k.rs b/src/algebra/dense/blas/syr2k.rs index df3b2747..3c550810 100644 --- a/src/algebra/dense/blas/syr2k.rs +++ b/src/algebra/dense/blas/syr2k.rs @@ -49,30 +49,21 @@ macro_rules! generate_test_syr2k { ($fxx:ty, $test_name:ident) => { #[test] fn $test_name() { - #[rustfmt::skip] - let A = Matrix::<$fxx>::from(&[ - [ 1., -5.], - [-4., 3.], + let A = Matrix::<$fxx>::from(&[ + [ 1., -5.], + [-4., 3.], [ 2., 6.], ]); - let B = Matrix::<$fxx>::from(&[ - [ 4., 5.], - [ 2., -2.], - [-3., -2.], - ]); + let B = Matrix::<$fxx>::from(&[[4., 5.], [2., -2.], [-3., -2.]]); let mut C = Matrix::<$fxx>::identity(3); //NB: modifies upper triangle only C.syr2k(&A, &B, 2., 1.); - let Ctest = Matrix::<$fxx>::from(&[ - [-83., 22., 90.], - [ 0., -55., -4.], - [ 0., 0., -71.], - ]); + let Ctest = Matrix::<$fxx>::from(&[[-83., 22., 90.], [0., -55., -4.], [0., 0., -71.]]); assert_eq!(C, Ctest); } @@ -80,4 +71,4 @@ macro_rules! generate_test_syr2k { } generate_test_syr2k!(f32, test_syr2k_f32); -generate_test_syr2k!(f64, test_syr2k_f64); \ No newline at end of file +generate_test_syr2k!(f64, test_syr2k_f64); diff --git a/src/algebra/dense/core.rs b/src/algebra/dense/core.rs index ecf54c86..fd954e89 100644 --- a/src/algebra/dense/core.rs +++ b/src/algebra/dense/core.rs @@ -6,7 +6,7 @@ use crate::algebra::*; use num_traits::Num; -// The comment below is not a docstring since it relies on the +// The comment below is not a docstring since it relies on the // type Matrix which is not currently visible outside the crate. // It can be restored if the dense Matrix type is made public. @@ -65,12 +65,11 @@ where } } - Self::new((m,n), data) + Self::new((m, n), data) } } - -// Constructors for dense matrices with owned data +// Constructors for dense matrices with owned data impl Matrix where @@ -89,7 +88,11 @@ where pub fn new(size: (usize, usize), data: Vec) -> Self { assert!(size.0 * size.1 == data.len()); - Self{size, data, phantom: std::marker::PhantomData} + Self { + size, + data, + phantom: std::marker::PhantomData, + } } pub fn new_from_slice(size: (usize, usize), src: &[T]) -> Self { @@ -104,11 +107,10 @@ where } } -impl TriangularMatrixChecks for DenseStorageMatrix +impl TriangularMatrixChecks for DenseStorageMatrix where S: AsMut<[T]> + AsRef<[T]>, T: Sized + Num + Copy, - { fn is_triu(&self) -> bool { for c in 0..self.ncols() { @@ -135,7 +137,7 @@ where // Methods that required mutable access to the matrix -impl DenseStorageMatrix +impl DenseStorageMatrix where S: AsMut<[T]> + AsRef<[T]>, T: Sized + Num + Copy, @@ -175,7 +177,7 @@ where where RI: IntoIterator + Copy, CI: IntoIterator, - MAT: DenseMatrix, + MAT: DenseMatrix, { for (j, &col) in cols.into_iter().enumerate() { for (i, &row) in rows.into_iter().enumerate() { @@ -185,15 +187,11 @@ where } /// self.subsref(B,rows,cols) sets self = B[rows,cols] - pub(crate) fn subsref<'a, RI, CI, MAT>( - &mut self, - source: &MAT, - rows: RI, - cols: CI, - ) where + pub(crate) fn subsref<'a, RI, CI, MAT>(&mut self, source: &MAT, rows: RI, cols: CI) + where RI: IntoIterator + Copy, CI: IntoIterator, - MAT: DenseMatrix, + MAT: DenseMatrix, { for (j, &col) in cols.into_iter().enumerate() { for (i, &row) in rows.into_iter().enumerate() { @@ -203,9 +201,6 @@ where } } - - - impl std::fmt::Display for Matrix where T: FloatT, @@ -224,9 +219,6 @@ where } } - - - #[test] #[rustfmt::skip] fn test_matrix_istriu_istril() { diff --git a/src/algebra/dense/fixed/dense2x2/core.rs b/src/algebra/dense/fixed/dense2x2/core.rs index e43dac5d..942712d2 100644 --- a/src/algebra/dense/fixed/dense2x2/core.rs +++ b/src/algebra/dense/fixed/dense2x2/core.rs @@ -6,10 +6,10 @@ use crate::algebra::{DenseMatrixN, DenseMatrixSymN, FloatT}; // NB: Implements special matrix decomposition cases // NB: S = 4 here because the matrix has 2^2 elements -pub (crate) type DenseMatrix2 = DenseMatrixN<4, T>; +pub(crate) type DenseMatrix2 = DenseMatrixN<4, T>; // NB: S = 3 here because the upper triangle has 3 elements -pub (crate) type DenseMatrixSym2 = DenseMatrixSymN<3, T>; +pub(crate) type DenseMatrixSym2 = DenseMatrixSymN<3, T>; // hand implemented DenseMatrixSym2 to make sure // everything is properly unrolled diff --git a/src/algebra/dense/fixed/dense2x2/svd.rs b/src/algebra/dense/fixed/dense2x2/svd.rs index 91d7bf2f..ac2f0d46 100644 --- a/src/algebra/dense/fixed/dense2x2/svd.rs +++ b/src/algebra/dense/fixed/dense2x2/svd.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use crate::algebra::*; use crate::algebra::dense::fixed::dense3x3::svd::compute_two_sided_rotation; +use crate::algebra::*; // 2x2 SVD using a two-sided Jacobi method. @@ -68,24 +68,18 @@ fn set_order_and_signs_2x2( [absa, absb] } - - - #[cfg(test)] mod tests { use super::*; #[test] - fn test_svd_2x2_nice(){ - + fn test_svd_2x2_nice() { #[rustfmt::skip] let A = Matrix::from(&[ [ 1.0, 2.0], [ 3.0, 4.0] ]); - let strue = [ - 5.464985704219043, - 0.3659661906262575]; + let strue = [5.464985704219043, 0.3659661906262575]; let mut A: DenseMatrix2 = A.into(); let mut U = DenseMatrix2::zeros(); @@ -97,14 +91,13 @@ mod tests { assert!((s[i] - strue[i]).abs() < 1e-10); } - for (i,&si) in s.iter().enumerate() { - let mut u = U.col_slice(i).to_vec(); - let v = V.col_slice(i).to_vec(); - let mut Av = vec![0.0; v.len()]; - A.mul(&mut Av, &v); - u.scale(si); - assert!(Av.norm_inf_diff(&u) < 1e-10); + for (i, &si) in s.iter().enumerate() { + let mut u = U.col_slice(i).to_vec(); + let v = V.col_slice(i).to_vec(); + let mut Av = vec![0.0; v.len()]; + A.mul(&mut Av, &v); + u.scale(si); + assert!(Av.norm_inf_diff(&u) < 1e-10); } } } - diff --git a/src/algebra/dense/fixed/dense3x3/svd.rs b/src/algebra/dense/fixed/dense3x3/svd.rs index dd8b6e32..f9c7f11b 100644 --- a/src/algebra/dense/fixed/dense3x3/svd.rs +++ b/src/algebra/dense/fixed/dense3x3/svd.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use crate::algebra::*; use super::eigen::*; +use crate::algebra::*; // 3x3 SVD using a two-sided Jacobi method. @@ -139,25 +139,20 @@ fn apply_two_sided_rotation( #[inline] fn hypot_fast(x: T, y: T) -> T { - - // NB: avoids overflow in x^2 + y^2, and also faster + // NB: avoids overflow in x^2 + y^2, and also faster // bc it reduces the range of the sqrt to [1,2] - // marginally faster than [x,y].norm(), which is - // equivalent and amounts to the same method. Faster - // than hypot(x,y) since it doesn't check nan or inf + // marginally faster than [x,y].norm(), which is + // equivalent and amounts to the same method. Faster + // than hypot(x,y) since it doesn't check nan or inf // edge cases let x = x.abs(); let y = y.abs(); - let (maxval, minval) = if x > y { - (x, y) - } else { - (y, x) - }; + let (maxval, minval) = if x > y { (x, y) } else { (y, x) }; if minval.is_zero() { - if maxval.is_zero() { + if maxval.is_zero() { return T::zero(); } else { return maxval; @@ -166,7 +161,6 @@ fn hypot_fast(x: T, y: T) -> T { let r = minval / maxval; maxval * T::sqrt(T::one() + r * r) - } fn compute_polar_2x2(App: T, Aqp: T, Apq: T, Aqq: T) -> (T, T, T, T, T) { @@ -175,7 +169,7 @@ fn compute_polar_2x2(App: T, Aqp: T, Apq: T, Aqq: T) -> (T, T, T, T, let x = App + Aqq; let y = Aqp - Apq; - let d = hypot_fast(x, y); + let d = hypot_fast(x, y); let (c, s) = { if d.is_zero() { @@ -286,9 +280,10 @@ mod tests { #[test] fn test_svd_3x3_hard() { let mut A = Matrix::zeros((3, 3)); - A.data.copy_from(&[0.0001, 0.01, 1.0, 0.01, 1.0, 0.0001, 1.0, 0.0001, 0.01]); + A.data + .copy_from(&[0.0001, 0.01, 1.0, 0.01, 1.0, 0.0001, 1.0, 0.0001, 0.01]); - let strue = [1.0101,0.9949869396127771, 0.9949869396127768]; + let strue = [1.0101, 0.9949869396127771, 0.9949869396127768]; let mut A: DenseMatrix3 = A.into(); let mut U = DenseMatrix3::zeros(); diff --git a/src/algebra/dense/matrix_math.rs b/src/algebra/dense/matrix_math.rs index 9337b44b..bfb3880e 100644 --- a/src/algebra/dense/matrix_math.rs +++ b/src/algebra/dense/matrix_math.rs @@ -1,16 +1,13 @@ #![allow(non_snake_case)] use crate::algebra::*; - -// PJG : MatrixMath should be implemented for a more -// general type, e.g. the DenseStorageMatrix type +// PJG : MatrixMath should be implemented for a more +// general type, e.g. the DenseStorageMatrix type // or similar. That would provide math functionality -// for more types, e.g. statically size matrices or -// the ones on borrowed data. - +// for more types, e.g. statically size matrices or +// the ones on borrowed data. impl MatrixMath for Matrix { - fn col_sums(&self, sums: &mut [T]) { assert_eq!(self.ncols(), sums.len()); for (col, sum) in sums.iter_mut().enumerate() { @@ -71,7 +68,6 @@ impl MatrixMath for Matrix { } impl MatrixMathMut for Matrix { - //scalar mut operations fn scale(&mut self, c: T) { self.data.scale(c); @@ -100,7 +96,6 @@ impl MatrixMathMut for Matrix { } } } - } impl Matrix @@ -133,16 +128,15 @@ where } } - // additional functions that require floating point operations // allow dead code here since dense matrix and its supporting // functionality could eventually become a public interface. #[allow(dead_code)] -impl DenseStorageMatrix -where +impl DenseStorageMatrix +where T: FloatT, - S: AsRef<[T]> + AsMut<[T]> + S: AsRef<[T]> + AsMut<[T]>, { /// Set A = (A + A') / 2. Assumes A is real pub fn symmetric_part(&mut self) -> &mut Self { @@ -160,9 +154,7 @@ where } } - - -pub(crate) fn svec_to_mat(M: &mut DenseStorageMatrix, x: &[T]) +pub(crate) fn svec_to_mat(M: &mut DenseStorageMatrix, x: &[T]) where T: FloatT, S: AsRef<[T]> + AsMut<[T]>, @@ -182,10 +174,10 @@ where } //PJG : Perhaps implementation for Symmetric type would be faster -pub(crate) fn mat_to_svec(x: &mut [T], M: &MATM) -where -MATM: DenseMatrix, - T: FloatT, +pub(crate) fn mat_to_svec(x: &mut [T], M: &MATM) +where + MATM: DenseMatrix, + T: FloatT, { let mut idx = 0; for col in 0..M.ncols() { @@ -202,7 +194,6 @@ MATM: DenseMatrix, } } - #[test] fn test_row_col_sums_and_norms() { #[rustfmt::skip] @@ -286,39 +277,23 @@ fn test_l_r_scalings() { #[test] fn test_symmetric_part() { + let mut A = Matrix::from(&[[-1., 4., 6.], [2., -8., 8.], [0., 4., 9.]]); - let mut A = Matrix::from(&[ - [-1., 4., 6.], - [ 2., -8., 8.], - [ 0., 4., 9.], - ]); - - let B = Matrix::from(&[ - [-1., 3., 3.], - [ 3., -8., 6.], - [ 3., 6., 9.], - ]); + let B = Matrix::from(&[[-1., 3., 3.], [3., -8., 6.], [3., 6., 9.]]); A.symmetric_part(); - assert_eq!(B,A); + assert_eq!(B, A); } #[test] fn test_col_norms_sym() { - - let A = Matrix::from(&[ - [-1., 4., 6.], - [ 2., -8., 8.], - [ 0., 4., 9.], - ]); + let A = Matrix::from(&[[-1., 4., 6.], [2., -8., 8.], [0., 4., 9.]]); let mut v = vec![0.0; 3]; A.col_norms_sym(&mut v); assert_eq!(v, [6.0, 8.0, 9.0]); } - - #[test] #[rustfmt::skip] fn test_kron() { @@ -384,8 +359,6 @@ fn test_kron() { assert_eq!(K,Ktest); } - - #[test] fn test_svec_conversions() { let n = 3; diff --git a/src/solver/chordal/decomp/augment_compact.rs b/src/solver/chordal/decomp/augment_compact.rs index 9d2e64da..f41b9e44 100644 --- a/src/solver/chordal/decomp/augment_compact.rs +++ b/src/solver/chordal/decomp/augment_compact.rs @@ -561,11 +561,9 @@ where fn extra_columns(total_length: usize, n_start: usize, start_val: usize) -> Vec { let mut v = vec![0; total_length]; - let mut start_val = start_val; - for i in (n_start..(v.len() - 1)).step_by(2) { - v[i] = start_val; - v[i + 1] = start_val; - start_val += 1; + for (offset, i) in (n_start..(v.len() - 1)).step_by(2).enumerate() { + v[i] = start_val + offset; + v[i + 1] = start_val + offset; } v } diff --git a/src/solver/chordal/decomp/reverse_compact.rs b/src/solver/chordal/decomp/reverse_compact.rs index 48f026ea..f9dd5491 100644 --- a/src/solver/chordal/decomp/reverse_compact.rs +++ b/src/solver/chordal/decomp/reverse_compact.rs @@ -45,13 +45,9 @@ where for (cone, cone_map) in zip(old_cones.iter(), cone_maps.iter()) { let row_range = row_ranges[cone_map.orig_index].clone(); - if cone_map.tree_and_clique.is_none() { - row_ptr = - add_blocks_with_cone(new_s, old_s, new_z, old_z, row_range, cone, row_ptr); - } else { + if let Some((tree_index, clique_index)) = cone_map.tree_and_clique { assert!(matches!(cone, SupportedConeT::PSDTriangleConeT(_))); - let (tree_index, clique_index) = cone_map.tree_and_clique.unwrap(); let pattern = &self.spatterns[tree_index]; row_ptr = add_blocks_with_sparsity_pattern( @@ -65,6 +61,9 @@ where &mut clique_buffer, row_ptr, ); + } else { + row_ptr = + add_blocks_with_cone(new_s, old_s, new_z, old_z, row_range, cone, row_ptr); } } } diff --git a/src/solver/core/cones/compositecone.rs b/src/solver/core/cones/compositecone.rs index 164c5bc5..173a5c02 100644 --- a/src/solver/core/cones/compositecone.rs +++ b/src/solver/core/cones/compositecone.rs @@ -329,7 +329,7 @@ where // if we have any nonsymmetric cones, then back off from full steps slightly // so that centrality checks and logarithms don't fail right at the boundaries if !all_symmetric { - let ceil = T::one() - T::sqrt(T::epsilon()); + let ceil = T::one() - T::sqrt(T::epsilon()); α = T::min(α, ceil); } diff --git a/src/solver/core/cones/supportedcone.rs b/src/solver/core/cones/supportedcone.rs index 2eaa02df..3623cec4 100644 --- a/src/solver/core/cones/supportedcone.rs +++ b/src/solver/core/cones/supportedcone.rs @@ -75,7 +75,7 @@ where T: FloatT, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", &self.as_tag().as_str()) + write!(f, "{}", self.as_tag().as_str()) } } diff --git a/src/solver/core/kktsolvers/direct/quasidef/datamaps.rs b/src/solver/core/kktsolvers/direct/quasidef/datamaps.rs index 5d75c5b5..d6192c00 100644 --- a/src/solver/core/kktsolvers/direct/quasidef/datamaps.rs +++ b/src/solver/core/kktsolvers/direct/quasidef/datamaps.rs @@ -23,7 +23,7 @@ impl SupportedCone where T: FloatT, { - pub(crate) fn to_sparse_expansion(&self) -> Option> { + pub(crate) fn to_sparse_expansion(&self) -> Option> { match self { SupportedCone::SecondOrderCone(sc) => Some(SparseExpansionCone::SecondOrderCone(sc)), SupportedCone::GenPowerCone(sc) => Some(SparseExpansionCone::GenPowerCone(sc)),