diff --git a/nalgebra-sparse/src/cs.rs b/nalgebra-sparse/src/cs.rs index e79557b2..645df265 100644 --- a/nalgebra-sparse/src/cs.rs +++ b/nalgebra-sparse/src/cs.rs @@ -1,6 +1,5 @@ use std::mem::replace; use std::ops::Range; -use std::sync::Arc; use num_traits::One; @@ -18,7 +17,7 @@ use crate::pattern::SparsityPattern; /// is obtained by associating columns with the major dimension. #[derive(Debug, Clone, PartialEq, Eq)] pub struct CsMatrix { - sparsity_pattern: Arc, + sparsity_pattern: SparsityPattern, values: Vec } @@ -27,13 +26,13 @@ impl CsMatrix { #[inline] pub fn new(major_dim: usize, minor_dim: usize) -> Self { Self { - sparsity_pattern: Arc::new(SparsityPattern::new(major_dim, minor_dim)), + sparsity_pattern: SparsityPattern::new(major_dim, minor_dim), values: vec![], } } #[inline] - pub fn pattern(&self) -> &Arc { + pub fn pattern(&self) -> &SparsityPattern { &self.sparsity_pattern } @@ -50,24 +49,24 @@ impl CsMatrix { /// Returns the raw data represented as a tuple `(major_offsets, minor_indices, values)`. #[inline] pub fn cs_data(&self) -> (&[usize], &[usize], &[T]) { - let pattern = self.pattern().as_ref(); + let pattern = self.pattern(); (pattern.major_offsets(), pattern.minor_indices(), &self.values) } /// Returns the raw data represented as a tuple `(major_offsets, minor_indices, values)`. #[inline] pub fn cs_data_mut(&mut self) -> (&[usize], &[usize], &mut [T]) { - let pattern = self.sparsity_pattern.as_ref(); + let pattern = &mut self.sparsity_pattern; (pattern.major_offsets(), pattern.minor_indices(), &mut self.values) } #[inline] - pub fn pattern_and_values_mut(&mut self) -> (&Arc, &mut [T]) { + pub fn pattern_and_values_mut(&mut self) -> (&SparsityPattern, &mut [T]) { (&self.sparsity_pattern, &mut self.values) } #[inline] - pub fn from_pattern_and_values(pattern: Arc, values: Vec) + pub fn from_pattern_and_values(pattern: SparsityPattern, values: Vec) -> Self { assert_eq!(pattern.nnz(), values.len(), "Internal error: consumers should verify shape compatibility."); Self { @@ -84,25 +83,14 @@ impl CsMatrix { Some(row_begin .. row_end) } - pub fn take_pattern_and_values(self) -> (Arc, Vec) { + pub fn take_pattern_and_values(self) -> (SparsityPattern, Vec) { (self.sparsity_pattern, self.values) } #[inline] pub fn disassemble(self) -> (Vec, Vec, Vec) { - // Take an Arc to the pattern, which might be the sole reference to the data after - // taking the values. This is important, because it might let us avoid cloning the data - // further below. - let pattern = self.sparsity_pattern; - let values = self.values; - - // Try to take the pattern out of the `Arc` if possible, - // otherwise clone the pattern. - let owned_pattern = Arc::try_unwrap(pattern) - .unwrap_or_else(|arc| SparsityPattern::clone(&*arc)); - let (offsets, indices) = owned_pattern.disassemble(); - - (offsets, indices, values) + let (offsets, indices) = self.sparsity_pattern.disassemble(); + (offsets, indices, self.values) } /// Returns an entry for the given major/minor indices, or `None` if the indices are out @@ -151,12 +139,12 @@ impl CsMatrix { #[inline] pub fn lane_iter(&self) -> CsLaneIter { - CsLaneIter::new(self.pattern().as_ref(), self.values()) + CsLaneIter::new(self.pattern(), self.values()) } #[inline] pub fn lane_iter_mut(&mut self) -> CsLaneIterMut { - CsLaneIterMut::new(self.sparsity_pattern.as_ref(), &mut self.values) + CsLaneIterMut::new(&self.sparsity_pattern, &mut self.values) } #[inline] @@ -190,7 +178,7 @@ impl CsMatrix { new_indices) .expect("Internal error: Sparsity pattern must always be valid."); - Self::from_pattern_and_values(Arc::new(new_pattern), new_values) + Self::from_pattern_and_values(new_pattern, new_values) } } @@ -205,7 +193,7 @@ impl CsMatrix { // TODO: We should skip checks here let pattern = SparsityPattern::try_from_offsets_and_indices(n, n, offsets, indices) .unwrap(); - Self::from_pattern_and_values(Arc::new(pattern), values) + Self::from_pattern_and_values(pattern, values) } } diff --git a/nalgebra-sparse/src/csc.rs b/nalgebra-sparse/src/csc.rs index c3d79508..d7883fa3 100644 --- a/nalgebra-sparse/src/csc.rs +++ b/nalgebra-sparse/src/csc.rs @@ -5,7 +5,6 @@ use crate::pattern::{SparsityPattern, SparsityPatternFormatError, SparsityPatter use crate::csr::CsrMatrix; use crate::cs::{CsMatrix, CsLane, CsLaneMut, CsLaneIter, CsLaneIterMut}; -use std::sync::Arc; use std::slice::{IterMut, Iter}; use num_traits::{One}; use nalgebra::Scalar; @@ -95,14 +94,14 @@ impl CscMatrix { let pattern = SparsityPattern::try_from_offsets_and_indices( num_cols, num_rows, col_offsets, row_indices) .map_err(pattern_format_error_to_csc_error)?; - Self::try_from_pattern_and_values(Arc::new(pattern), values) + Self::try_from_pattern_and_values(pattern, values) } /// Try to construct a CSC matrix from a sparsity pattern and associated non-zero values. /// /// Returns an error if the number of values does not match the number of minor indices /// in the pattern. - pub fn try_from_pattern_and_values(pattern: Arc, values: Vec) + pub fn try_from_pattern_and_values(pattern: SparsityPattern, values: Vec) -> Result { if pattern.nnz() == values.len() { Ok(Self { @@ -212,7 +211,7 @@ impl CscMatrix { /// An iterator over columns in the matrix. pub fn col_iter(&self) -> CscColIter { CscColIter { - lane_iter: CsLaneIter::new(self.pattern().as_ref(), self.values()) + lane_iter: CsLaneIter::new(self.pattern(), self.values()) } } @@ -258,7 +257,7 @@ impl CscMatrix { /// The sparsity pattern is stored internally inside an `Arc`. This allows users to re-use /// the same sparsity pattern for multiple matrices without storing the same pattern multiple /// times in memory. - pub fn pattern(&self) -> &Arc { + pub fn pattern(&self) -> &SparsityPattern { self.cs.pattern() } diff --git a/nalgebra-sparse/src/csr.rs b/nalgebra-sparse/src/csr.rs index 81f8191c..dceca614 100644 --- a/nalgebra-sparse/src/csr.rs +++ b/nalgebra-sparse/src/csr.rs @@ -7,7 +7,6 @@ use crate::cs::{CsMatrix, CsLaneIterMut, CsLaneIter, CsLane, CsLaneMut}; use nalgebra::Scalar; use num_traits::{One}; -use std::sync::Arc; use std::slice::{IterMut, Iter}; /// A CSR representation of a sparse matrix. @@ -97,14 +96,14 @@ impl CsrMatrix { let pattern = SparsityPattern::try_from_offsets_and_indices( num_rows, num_cols, row_offsets, col_indices) .map_err(pattern_format_error_to_csr_error)?; - Self::try_from_pattern_and_values(Arc::new(pattern), values) + Self::try_from_pattern_and_values(pattern, values) } /// Try to construct a CSR matrix from a sparsity pattern and associated non-zero values. /// /// Returns an error if the number of values does not match the number of minor indices /// in the pattern. - pub fn try_from_pattern_and_values(pattern: Arc, values: Vec) + pub fn try_from_pattern_and_values(pattern: SparsityPattern, values: Vec) -> Result { if pattern.nnz() == values.len() { Ok(Self { @@ -214,7 +213,7 @@ impl CsrMatrix { /// An iterator over rows in the matrix. pub fn row_iter(&self) -> CsrRowIter { CsrRowIter { - lane_iter: CsLaneIter::new(self.pattern().as_ref(), self.values()) + lane_iter: CsLaneIter::new(self.pattern(), self.values()) } } @@ -260,7 +259,7 @@ impl CsrMatrix { /// The sparsity pattern is stored internally inside an `Arc`. This allows users to re-use /// the same sparsity pattern for multiple matrices without storing the same pattern multiple /// times in memory. - pub fn pattern(&self) -> &Arc { + pub fn pattern(&self) -> &SparsityPattern { self.cs.pattern() } diff --git a/nalgebra-sparse/src/factorization/cholesky.rs b/nalgebra-sparse/src/factorization/cholesky.rs index 2639424c..8ffbbe3d 100644 --- a/nalgebra-sparse/src/factorization/cholesky.rs +++ b/nalgebra-sparse/src/factorization/cholesky.rs @@ -5,26 +5,25 @@ use crate::pattern::SparsityPattern; use crate::csc::CscMatrix; use core::{mem, iter}; use nalgebra::{Scalar, RealField, DMatrixSlice, DMatrixSliceMut, DMatrix}; -use std::sync::Arc; use std::fmt::{Display, Formatter}; use crate::ops::serial::spsolve_csc_lower_triangular; use crate::ops::Op; pub struct CscSymbolicCholesky { // Pattern of the original matrix that was decomposed - m_pattern: Arc, + m_pattern: SparsityPattern, l_pattern: SparsityPattern, // u in this context is L^T, so that M = L L^T u_pattern: SparsityPattern } impl CscSymbolicCholesky { - pub fn factor(pattern: &Arc) -> Self { + pub fn factor(pattern: SparsityPattern) -> Self { assert_eq!(pattern.major_dim(), pattern.minor_dim(), "Major and minor dimensions must be the same (square matrix)."); - let (l_pattern, u_pattern) = nonzero_pattern(&*pattern); + let (l_pattern, u_pattern) = nonzero_pattern(&pattern); Self { - m_pattern: Arc::clone(pattern), + m_pattern: pattern, l_pattern, u_pattern, } @@ -37,7 +36,7 @@ impl CscSymbolicCholesky { pub struct CscCholesky { // Pattern of the original matrix - m_pattern: Arc, + m_pattern: SparsityPattern, l_factor: CscMatrix, u_pattern: SparsityPattern, work_x: Vec, @@ -66,7 +65,7 @@ impl CscCholesky { let l_nnz = symbolic.l_pattern.nnz(); let l_values = vec![T::zero(); l_nnz]; - let l_factor = CscMatrix::try_from_pattern_and_values(Arc::new(symbolic.l_pattern), l_values) + let l_factor = CscMatrix::try_from_pattern_and_values(symbolic.l_pattern, l_values) .unwrap(); let (nrows, ncols) = (l_factor.nrows(), l_factor.ncols()); @@ -86,7 +85,7 @@ impl CscCholesky { } pub fn factor(matrix: &CscMatrix) -> Result { - let symbolic = CscSymbolicCholesky::factor(&*matrix.pattern()); + let symbolic = CscSymbolicCholesky::factor(matrix.pattern().clone()); Self::factor_numerical(symbolic, matrix.values()) } diff --git a/nalgebra-sparse/src/ops/impl_std_ops.rs b/nalgebra-sparse/src/ops/impl_std_ops.rs index 12db5264..1b337397 100644 --- a/nalgebra-sparse/src/ops/impl_std_ops.rs +++ b/nalgebra-sparse/src/ops/impl_std_ops.rs @@ -7,7 +7,6 @@ use crate::ops::serial::{spadd_csr_prealloc, spadd_csc_prealloc, spadd_pattern, use nalgebra::{ClosedAdd, ClosedMul, ClosedSub, ClosedDiv, Scalar, Matrix, Dim, DMatrixSlice, DMatrix, Dynamic}; use num_traits::{Zero, One}; -use std::sync::Arc; use crate::ops::{Op}; use nalgebra::base::storage::Storage; @@ -48,11 +47,7 @@ macro_rules! impl_sp_plus_minus { impl_bin_op!($trait, $method, <'a, T>(a: &'a $matrix_type, b: &'a $matrix_type) -> $matrix_type { // If both matrices have the same pattern, then we can immediately re-use it - let pattern = if Arc::ptr_eq(a.pattern(), b.pattern()) { - Arc::clone(a.pattern()) - } else { - Arc::new(spadd_pattern(a.pattern(), b.pattern())) - }; + let pattern = spadd_pattern(a.pattern(), b.pattern()); let values = vec![T::zero(); pattern.nnz()]; // We are giving data that is valid by definition, so it is safe to unwrap below let mut result = $matrix_type::try_from_pattern_and_values(pattern, values) @@ -64,24 +59,12 @@ macro_rules! impl_sp_plus_minus { impl_bin_op!($trait, $method, <'a, T>(a: $matrix_type, b: &'a $matrix_type) -> $matrix_type { - let mut a = a; - if Arc::ptr_eq(a.pattern(), b.pattern()) { - $spadd_fn(T::one(), &mut a, $factor * T::one(), Op::NoOp(b)).unwrap(); - a - } else { - &a $sign b - } + &a $sign b }); impl_bin_op!($trait, $method, <'a, T>(a: &'a $matrix_type, b: $matrix_type) -> $matrix_type { - let mut b = b; - if Arc::ptr_eq(a.pattern(), b.pattern()) { - $spadd_fn($factor * T::one(), &mut b, T::one(), Op::NoOp(a)).unwrap(); - b - } else { - a $sign &b - } + a $sign &b }); impl_bin_op!($trait, $method, (a: $matrix_type, b: $matrix_type) -> $matrix_type { a $sign &b @@ -107,7 +90,7 @@ macro_rules! impl_spmm { impl_mul!(<'a, T>(a: &'a $matrix_type, b: &'a $matrix_type) -> $matrix_type { let pattern = $pattern_fn(a.pattern(), b.pattern()); let values = vec![T::zero(); pattern.nnz()]; - let mut result = $matrix_type::try_from_pattern_and_values(Arc::new(pattern), values) + let mut result = $matrix_type::try_from_pattern_and_values(pattern, values) .unwrap(); $spmm_fn(T::zero(), &mut result, @@ -154,7 +137,7 @@ macro_rules! impl_scalar_mul { .iter() .map(|v_i| v_i.inlined_clone() * b.inlined_clone()) .collect(); - $matrix_type::try_from_pattern_and_values(Arc::clone(a.pattern()), values).unwrap() + $matrix_type::try_from_pattern_and_values(a.pattern().clone(), values).unwrap() }); impl_mul!(<'a, T>(a: &'a $matrix_type, b: T) -> $matrix_type { a * &b @@ -251,7 +234,7 @@ macro_rules! impl_div { .iter() .map(|v_i| v_i.inlined_clone() / scalar.inlined_clone()) .collect(); - $matrix_type::try_from_pattern_and_values(Arc::clone(matrix.pattern()), new_values) + $matrix_type::try_from_pattern_and_values(matrix.pattern().clone(), new_values) .unwrap() }); impl_bin_op!(Div, div, <'a, T: ClosedDiv>(matrix: &'a $matrix_type, scalar: &'a T) -> $matrix_type { diff --git a/nalgebra-sparse/src/ops/serial/cs.rs b/nalgebra-sparse/src/ops/serial/cs.rs index 22f3b524..9a4f7e34 100644 --- a/nalgebra-sparse/src/ops/serial/cs.rs +++ b/nalgebra-sparse/src/ops/serial/cs.rs @@ -4,7 +4,6 @@ use crate::ops::serial::{OperationErrorType, OperationError}; use nalgebra::{Scalar, ClosedAdd, ClosedMul, DMatrixSliceMut, DMatrixSlice}; use num_traits::{Zero, One}; use crate::SparseEntryMut; -use std::sync::Arc; fn spmm_cs_unexpected_entry() -> OperationError { OperationError::from_type_and_message( @@ -73,64 +72,52 @@ pub fn spadd_cs_prealloc(beta: T, where T: Scalar + ClosedAdd + ClosedMul + Zero + One { - - if Arc::ptr_eq(&c.pattern(), &a.inner_ref().pattern()) { - // Special fast path: The two matrices have *exactly* the same sparsity pattern, - // so we only need to sum the value arrays - // TODO: Test this fast path - for (c_ij, a_ij) in c.values_mut().iter_mut().zip(a.inner_ref().values()) { - let (alpha, beta) = (alpha.inlined_clone(), beta.inlined_clone()); - *c_ij = beta * c_ij.inlined_clone() + alpha * a_ij.inlined_clone(); - } - Ok(()) - } else { - match a { - Op::NoOp(a) => { - for (mut c_lane_i, a_lane_i) in c.lane_iter_mut().zip(a.lane_iter()) { - if beta != T::one() { - for c_ij in c_lane_i.values_mut() { - *c_ij *= beta.inlined_clone(); - } - } - - let (mut c_minors, mut c_vals) = c_lane_i.indices_and_values_mut(); - let (a_minors, a_vals) = (a_lane_i.minor_indices(), a_lane_i.values()); - - for (a_col, a_val) in a_minors.iter().zip(a_vals) { - // TODO: Use exponential search instead of linear search. - // If C has substantially more entries in the row than A, then a line search - // will needlessly visit many entries in C. - let (c_idx, _) = c_minors.iter() - .enumerate() - .find(|(_, c_col)| *c_col == a_col) - .ok_or_else(spadd_cs_unexpected_entry)?; - c_vals[c_idx] += alpha.inlined_clone() * a_val.inlined_clone(); - c_minors = &c_minors[c_idx ..]; - c_vals = &mut c_vals[c_idx ..]; - } - } - } - Op::Transpose(a) => { + match a { + Op::NoOp(a) => { + for (mut c_lane_i, a_lane_i) in c.lane_iter_mut().zip(a.lane_iter()) { if beta != T::one() { - for c_ij in c.values_mut() { + for c_ij in c_lane_i.values_mut() { *c_ij *= beta.inlined_clone(); } } - for (i, a_lane_i) in a.lane_iter().enumerate() { - for (&j, a_val) in a_lane_i.minor_indices().iter().zip(a_lane_i.values()) { - let a_val = a_val.inlined_clone(); - let alpha = alpha.inlined_clone(); - match c.get_entry_mut(j, i).unwrap() { - SparseEntryMut::NonZero(c_ji) => { *c_ji += alpha * a_val } - SparseEntryMut::Zero => return Err(spadd_cs_unexpected_entry()), - } + let (mut c_minors, mut c_vals) = c_lane_i.indices_and_values_mut(); + let (a_minors, a_vals) = (a_lane_i.minor_indices(), a_lane_i.values()); + + for (a_col, a_val) in a_minors.iter().zip(a_vals) { + // TODO: Use exponential search instead of linear search. + // If C has substantially more entries in the row than A, then a line search + // will needlessly visit many entries in C. + let (c_idx, _) = c_minors.iter() + .enumerate() + .find(|(_, c_col)| *c_col == a_col) + .ok_or_else(spadd_cs_unexpected_entry)?; + c_vals[c_idx] += alpha.inlined_clone() * a_val.inlined_clone(); + c_minors = &c_minors[c_idx ..]; + c_vals = &mut c_vals[c_idx ..]; + } + } + } + Op::Transpose(a) => { + if beta != T::one() { + for c_ij in c.values_mut() { + *c_ij *= beta.inlined_clone(); + } + } + + for (i, a_lane_i) in a.lane_iter().enumerate() { + for (&j, a_val) in a_lane_i.minor_indices().iter().zip(a_lane_i.values()) { + let a_val = a_val.inlined_clone(); + let alpha = alpha.inlined_clone(); + match c.get_entry_mut(j, i).unwrap() { + SparseEntryMut::NonZero(c_ji) => { *c_ji += alpha * a_val } + SparseEntryMut::Zero => return Err(spadd_cs_unexpected_entry()), } } } } - Ok(()) } + Ok(()) } /// Helper functionality for implementing CSR/CSC SPMM. diff --git a/nalgebra-sparse/src/proptest.rs b/nalgebra-sparse/src/proptest.rs index 80eb88a6..1115693a 100644 --- a/nalgebra-sparse/src/proptest.rs +++ b/nalgebra-sparse/src/proptest.rs @@ -11,7 +11,6 @@ use std::iter::{repeat}; use proptest::sample::{Index}; use crate::csr::CsrMatrix; use crate::pattern::SparsityPattern; -use std::sync::Arc; use crate::csc::CscMatrix; fn dense_row_major_coord_strategy(nrows: usize, ncols: usize, nnz: usize) @@ -291,7 +290,7 @@ where (Just(pattern), values) }) .prop_map(|(pattern, values)| { - CsrMatrix::try_from_pattern_and_values(Arc::new(pattern), values) + CsrMatrix::try_from_pattern_and_values(pattern, values) .expect("Internal error: Generated CsrMatrix is invalid") }) } @@ -313,7 +312,7 @@ pub fn csc(value_strategy: T, (Just(pattern), values) }) .prop_map(|(pattern, values)| { - CscMatrix::try_from_pattern_and_values(Arc::new(pattern), values) + CscMatrix::try_from_pattern_and_values(pattern, values) .expect("Internal error: Generated CscMatrix is invalid") }) } \ No newline at end of file diff --git a/nalgebra-sparse/tests/unit_tests/ops.rs b/nalgebra-sparse/tests/unit_tests/ops.rs index a814f094..5a9aafe7 100644 --- a/nalgebra-sparse/tests/unit_tests/ops.rs +++ b/nalgebra-sparse/tests/unit_tests/ops.rs @@ -17,12 +17,11 @@ use proptest::prelude::*; use matrixcompare::prop_assert_matrix_eq; use std::panic::catch_unwind; -use std::sync::Arc; /// Represents the sparsity pattern of a CSR matrix as a dense matrix with 0/1 fn dense_csr_pattern(pattern: &SparsityPattern) -> DMatrix { let boolean_csr = CsrMatrix::try_from_pattern_and_values( - Arc::new(pattern.clone()), + pattern.clone(), vec![1; pattern.nnz()]) .unwrap(); DMatrix::from(&boolean_csr) @@ -31,7 +30,7 @@ fn dense_csr_pattern(pattern: &SparsityPattern) -> DMatrix { /// Represents the sparsity pattern of a CSC matrix as a dense matrix with 0/1 fn dense_csc_pattern(pattern: &SparsityPattern) -> DMatrix { let boolean_csc = CscMatrix::try_from_pattern_and_values( - Arc::new(pattern.clone()), + pattern.clone(), vec![1; pattern.nnz()]) .unwrap(); DMatrix::from(&boolean_csc) @@ -137,8 +136,8 @@ fn spadd_csr_prealloc_args_strategy() -> impl Strategy> let beta = value_strategy.clone(); (Just(c_pattern), Just(a_pattern), c_values, a_values, alpha, beta, trans_strategy()) }).prop_map(|(c_pattern, a_pattern, c_values, a_values, alpha, beta, trans_a)| { - let c = CsrMatrix::try_from_pattern_and_values(Arc::new(c_pattern), c_values).unwrap(); - let a = CsrMatrix::try_from_pattern_and_values(Arc::new(a_pattern), a_values).unwrap(); + let c = CsrMatrix::try_from_pattern_and_values(c_pattern, c_values).unwrap(); + let a = CsrMatrix::try_from_pattern_and_values(a_pattern, a_values).unwrap(); let a = if trans_a { Op::Transpose(a.transpose()) } else { Op::NoOp(a) }; SpaddCsrArgs { c, beta, alpha, a } @@ -222,15 +221,12 @@ fn spmm_csr_prealloc_args_strategy() -> impl Strategy> { let b_values = vec![PROPTEST_I32_VALUE_STRATEGY; b_pattern.nnz()]; let c_pattern = spmm_pattern(&a_pattern, &b_pattern); let c_values = vec![PROPTEST_I32_VALUE_STRATEGY; c_pattern.nnz()]; - let a_pattern = Arc::new(a_pattern); - let b_pattern = Arc::new(b_pattern); - let c_pattern = Arc::new(c_pattern); let a = a_values.prop_map(move |values| - CsrMatrix::try_from_pattern_and_values(Arc::clone(&a_pattern), values).unwrap()); + CsrMatrix::try_from_pattern_and_values(a_pattern.clone(), values).unwrap()); let b = b_values.prop_map(move |values| - CsrMatrix::try_from_pattern_and_values(Arc::clone(&b_pattern), values).unwrap()); + CsrMatrix::try_from_pattern_and_values(b_pattern.clone(), values).unwrap()); let c = c_values.prop_map(move |values| - CsrMatrix::try_from_pattern_and_values(Arc::clone(&c_pattern), values).unwrap()); + CsrMatrix::try_from_pattern_and_values(c_pattern.clone(), values).unwrap()); let alpha = PROPTEST_I32_VALUE_STRATEGY; let beta = PROPTEST_I32_VALUE_STRATEGY; (c, beta, alpha, trans_strategy(), a, trans_strategy(), b) @@ -383,16 +379,16 @@ proptest! { // corresponding to a and b, and convert them to dense matrices. // The sum of these dense matrices will then have non-zeros in exactly the same locations // as the result of "adding" the sparsity patterns - let a_csr = CsrMatrix::try_from_pattern_and_values(Arc::new(a.clone()), vec![1; a.nnz()]) + let a_csr = CsrMatrix::try_from_pattern_and_values(a.clone(), vec![1; a.nnz()]) .unwrap(); let a_dense = DMatrix::from(&a_csr); - let b_csr = CsrMatrix::try_from_pattern_and_values(Arc::new(b.clone()), vec![1; b.nnz()]) + let b_csr = CsrMatrix::try_from_pattern_and_values(b.clone(), vec![1; b.nnz()]) .unwrap(); let b_dense = DMatrix::from(&b_csr); let c_dense = a_dense + b_dense; let c_csr = CsrMatrix::from(&c_dense); - prop_assert_eq!(&pattern_result, c_csr.pattern().as_ref()); + prop_assert_eq!(&pattern_result, c_csr.pattern()); } #[test] @@ -492,16 +488,16 @@ proptest! { // corresponding to a and b, and convert them to dense matrices. // The product of these dense matrices will then have non-zeros in exactly the same locations // as the result of "multiplying" the sparsity patterns - let a_csr = CsrMatrix::try_from_pattern_and_values(Arc::new(a.clone()), vec![1; a.nnz()]) + let a_csr = CsrMatrix::try_from_pattern_and_values(a.clone(), vec![1; a.nnz()]) .unwrap(); let a_dense = DMatrix::from(&a_csr); - let b_csr = CsrMatrix::try_from_pattern_and_values(Arc::new(b.clone()), vec![1; b.nnz()]) + let b_csr = CsrMatrix::try_from_pattern_and_values(b.clone(), vec![1; b.nnz()]) .unwrap(); let b_dense = DMatrix::from(&b_csr); let c_dense = a_dense * b_dense; let c_csr = CsrMatrix::from(&c_dense); - prop_assert_eq!(&c_pattern, c_csr.pattern().as_ref()); + prop_assert_eq!(&c_pattern, c_csr.pattern()); } #[test]