From 0fcd9dd70210a54ce923365d47d3ad3ad1d00914 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Tue, 18 Oct 2022 09:03:52 +0200 Subject: [PATCH 01/34] revert some things and add poc for mut and immut iterators --- Cargo.toml | 2 +- src/base/iter.rs | 165 +++++++++++++++++++++++++++++++++++------- src/base/par_iter.rs | 169 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 29 deletions(-) create mode 100644 src/base/par_iter.rs diff --git a/Cargo.toml b/Cargo.toml index 9d0b1a7c..48262dce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,7 @@ glam020 = { package = "glam", version = "0.20", optional = true } glam021 = { package = "glam", version = "0.21", optional = true } glam022 = { package = "glam", version = "0.22", optional = true } cust_core = { version = "0.1", optional = true } - +rayon = "1.5" # TODO make this feature gated [dev-dependencies] serde_json = "1.0" diff --git a/src/base/iter.rs b/src/base/iter.rs index 991c24dc..cb587589 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -1,12 +1,17 @@ //! Matrix iterators. +use core::fmt::Debug; +use core::ops::Range; use std::iter::FusedIterator; use std::marker::PhantomData; use std::mem; +use rayon::iter::plumbing::Producer; + use crate::base::dimension::{Dim, U1}; use crate::base::storage::{RawStorage, RawStorageMut}; use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar}; +use crate::{DMatrix, DimMax}; macro_rules! iterator { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { @@ -288,7 +293,6 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte } /* - * * Column iterators. * */ @@ -296,12 +300,25 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte /// An iterator through the columns of a matrix. pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage> { mat: &'a Matrix, - curr: usize, + range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, S> { + /// a new column iterator covering all columns of the matrix pub(crate) fn new(mat: &'a Matrix) -> Self { - ColumnIter { mat, curr: 0 } + ColumnIter { + mat, + range: 0..mat.ncols(), + } + } + /// a new column iterator covering column indices [begin,end) + /// where begin is included in the range but index end is not + /// begin must lie in [0,ncols] and end must lie in [0,ncols]. + pub(crate) fn with_range(mat: &'a Matrix, range: Range) -> Self { + debug_assert!(range.end <= mat.ncols()); + debug_assert!(range.start < mat.ncols()); + debug_assert!(range.start <= range.end); + Self { mat, range } } } @@ -310,9 +327,10 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter #[inline] fn next(&mut self) -> Option { - if self.curr < self.mat.ncols() { - let res = self.mat.column(self.curr); - self.curr += 1; + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { + let res = self.mat.column(self.range.start); + self.range.start += 1; Some(res) } else { None @@ -321,15 +339,29 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter #[inline] fn size_hint(&self) -> (usize, Option) { - ( - self.mat.ncols() - self.curr, - Some(self.mat.ncols() - self.curr), - ) + let hint = self.range.len(); + (hint, Some(hint)) } #[inline] fn count(self) -> usize { - self.mat.ncols() - self.curr + self.range.len() + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator + for ColumnIter<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < self.mat.ncols()); + debug_assert!(self.range.end >= self.range.start); + Some(self.mat.column(self.range.end)) + } else { + None + } } } @@ -338,29 +370,53 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat { #[inline] fn len(&self) -> usize { - self.mat.ncols() - self.curr + self.range.end - self.range.start + } +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> +where + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Sync, +{ + type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIter<'a, T, R, Cols, S>; + + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero + let left = Self { + mat: self.mat, + range: self.range.start..(self.range.start + index), + }; + + let right = Self { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + }; + (left, right) + } + + fn into_iter(self) -> Self::IntoIter { + self } } /// An iterator through the mutable columns of a matrix. #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { - mat: *mut Matrix, - curr: usize, - phantom: PhantomData<&'a mut Matrix>, + mat: &'a mut Matrix, + range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { pub(crate) fn new(mat: &'a mut Matrix) -> Self { - ColumnIterMut { - mat, - curr: 0, - phantom: PhantomData, - } + let range = 0..mat.ncols(); + ColumnIterMut { mat, range } } fn ncols(&self) -> usize { - unsafe { (*self.mat).ncols() } + self.mat.ncols() } } @@ -370,10 +426,11 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; #[inline] - fn next(&mut self) -> Option { - if self.curr < self.ncols() { - let res = unsafe { (*self.mat).column_mut(self.curr) }; - self.curr += 1; + fn next(&'_ mut self) -> Option { + if self.range.start < self.ncols() { + let pmat: *mut _ = self.mat; + let res = unsafe { (*pmat).column_mut(self.range.start) }; + self.range.start += 1; Some(res) } else { None @@ -382,12 +439,13 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator #[inline] fn size_hint(&self) -> (usize, Option) { - (self.ncols() - self.curr, Some(self.ncols() - self.curr)) + let hint = self.range.len(); + (hint, Some(hint)) } #[inline] fn count(self) -> usize { - self.ncols() - self.curr + self.range.len() } } @@ -396,6 +454,57 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte { #[inline] fn len(&self) -> usize { - self.ncols() - self.curr + self.range.len() } } + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedIterator + for ColumnIterMut<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < unsafe { (*self.mat).ncols() }); + debug_assert!(self.range.end >= self.range.start); + let pmat: *mut _ = self.mat; + Some(unsafe { (*pmat).column_mut(self.range.end) }) + } else { + None + } + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer for ColumnIterMut<'a,T,R,C,S> +where T : Send + Sync + Debug + PartialEq + Clone, + S: Send + Sync { + type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIterMut<'a,T,R,C,S>; + + fn into_iter(self) -> Self::IntoIter { + self + } + + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero + let pmat : * mut _ = self.mat; + + let left = Self { + mat: unsafe {&mut *pmat}, + range: self.range.start..(self.range.start + index), + }; + + let right = Self { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + }; + (left, right) + } +} + +fn test_send(_: T) {} + +fn something(mut matrix: DMatrix) { + test_send(matrix.column_iter_mut()); +} diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs new file mode 100644 index 00000000..cdc602b5 --- /dev/null +++ b/src/base/par_iter.rs @@ -0,0 +1,169 @@ +//! this module implements parallelators to make matrices work with +//! the rayon crate seamlessly + +use core::{ + fmt::Debug, + iter::{Skip, Take}, + marker::PhantomData, + ops::Range, +}; +use std::os::unix::prelude::AsRawFd; + +use rayon::{ + iter::plumbing::{bridge, Producer}, + prelude::*, +}; + +use crate::{ + iter::{ColumnIter, ColumnIterMut}, Const, DMatrix, Dim, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, + RawStorage, RawStorageMut, U1, SliceStorageMut, +}; + +use super::conversion; + +/// a rayon parallel iterator over the columns of a matrix +pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { + mat: &'a Matrix, +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R, Cols, S> { + fn new(matrix: &'a Matrix) -> Self { + Self { mat: matrix } + } +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Sync + Send + Clone + Debug + PartialEq + 'static, + S: Sync, +{ + type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + + fn drive_unindexed(self, consumer: Consumer) -> Consumer::Result + where + Consumer: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Send + Sync + Clone + Debug + PartialEq + 'static, + S: Sync, +{ + fn len(&self) -> usize { + self.mat.ncols() + } + + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { + let producer = ColumnIter::new(self.mat); + callback.callback(producer) + } +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Matrix +where + T: Send + Sync + Clone + Debug + PartialEq + 'static, + S: Sync, +{ + fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { + ParColumnIter::new(self) + } +} + +/// TODO +pub struct ParColumnIterMut<'a,T,R:Dim ,Cols:Dim, S:RawStorage+RawStorageMut> { + mat : &'a mut Matrix, +} + +impl<'a,T,R,Cols,S> ParColumnIterMut<'a,T,R,Cols,S> +where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut { + /// TODO + pub fn new(mat : &'a mut Matrix) -> Self { + Self { + mat, + } + } +} + +impl<'a,T,R,Cols,S> ParallelIterator for ParColumnIterMut<'a,T,R,Cols,S> +where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut, +T : Send + Sync + Debug + PartialEq + Clone + 'static, +S : Send + Sync { + type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: rayon::iter::plumbing::UnindexedConsumer { + bridge(self,consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + + +impl<'a,T,R,Cols,S> IndexedParallelIterator for ParColumnIterMut<'a,T,R,Cols,S> +where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut, +T : Send + Sync + Debug + PartialEq + Clone + 'static, +S : Send + Sync { + fn drive>(self, consumer: C) -> C::Result { + bridge(self,consumer) + } + + fn len(&self) -> usize { + self.mat.ncols() + } + + fn with_producer>(self, callback: CB) -> CB::Output { + let producer = ColumnIterMut::new(self.mat); + callback.callback(producer) + } +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage + RawStorageMut> Matrix +where + T: Send + Sync + Clone + Debug + PartialEq + 'static, + S: Sync, +{ + fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { + ParColumnIterMut::new(self) + } +} + + +#[test] +fn parallel_iterator() { + let matrix = DMatrix::::zeros(3, 4); + let res: Vec<_> = matrix.par_column_iter().map(|col| col.len()).collect(); + assert_eq!(res, vec![3, 3, 3, 3]); +} + +#[test] +fn test_mut_parallel_iter() { + let mut matrix = DMatrix::::zeros(4, 3); + matrix.par_column_iter_mut().enumerate().for_each(|(idx,mut col)| col[idx]=1f32); + let identity = DMatrix::::identity(4, 3); + assert_eq!(matrix,identity); +} + + +fn try_some_stuff() { + let mut mat = DMatrix::::zeros(3, 4); + let _left = mat.columns_mut(0, 1); + let _right = mat.columns_mut(1, 3); +} From f850ed535e67f29edcea36ad7685a13860df345f Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Wed, 19 Oct 2022 09:51:46 +0200 Subject: [PATCH 02/34] add tests and start cleanup --- src/base/mod.rs | 2 + src/base/par_iter.rs | 12 ++---- tests/core/matrix.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/base/mod.rs b/src/base/mod.rs index 4cbcff93..b828d0a1 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,6 +42,8 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; +pub mod par_iter; + #[cfg(feature = "rkyv-serialize-no-std")] mod rkyv_wrappers; diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index cdc602b5..abe48bb2 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -80,7 +80,8 @@ where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, { - fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { + /// TODO + pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { ParColumnIter::new(self) } } @@ -140,18 +141,13 @@ where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, { - fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { + /// TODO + pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { ParColumnIterMut::new(self) } } -#[test] -fn parallel_iterator() { - let matrix = DMatrix::::zeros(3, 4); - let res: Vec<_> = matrix.par_column_iter().map(|col| col.len()).collect(); - assert_eq!(res, vec![3, 3, 3, 3]); -} #[test] fn test_mut_parallel_iter() { diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 219845d4..aa515e49 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1136,3 +1136,92 @@ fn omatrix_to_string() { (svec.to_string(), smatr.to_string()) ); } + +#[test] +fn column_iteration() { + // dynamic matrix + let dmat = nalgebra::dmatrix![ + 13,14,15; + 23,24,25; + 33,34,35; + ]; + // not using enumerate on purpose + let mut idx = 0; + for col in dmat.column_iter() { + assert_eq!(dmat.column(idx),col); + idx += 1; + } + // statically sized matrix + let smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; + let mut idx = 0; + for col in smat.column_iter() { + assert_eq!(smat.column(idx),col); + idx += 1; + } +} + +#[test] +fn column_iteration_double_ended() { + let dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(),Some(dmat.column(0))); + assert_eq!(col_iter.next(),Some(dmat.column(1))); + assert_eq!(col_iter.next_back(),Some(dmat.column(4))); + assert_eq!(col_iter.next_back(),Some(dmat.column(3))); + assert_eq!(col_iter.next(),Some(dmat.column(2))); + assert_eq!(col_iter.next_back(),None); + assert_eq!(col_iter.next(),None); +} + +#[test] +fn parallel_column_iteration() { + use rayon::prelude::*; + use nalgebra::{dmatrix,dvector}; + let dmat = dmatrix![ + 13.,14.; + 23.,24.; + 33.,34.; + ]; + let cloned = dmat.clone(); + // test that correct columns are iterated over + dmat.par_column_iter().enumerate().for_each(|(idx,col)| { + assert_eq!(col,cloned.column(idx)); + }); + // test that a more complex expression produces the same + // result as the serial equivalent + let par_result :f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); + let ser_result = dmat.column_iter().map(|col| col.norm()).sum(); + assert_eq!(par_result,ser_result); +} + +#[test] +fn column_iteration_mut() { + todo!(); +} + +#[test] +fn colum_iteration_mut_double_ended() { + let dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let cloned = dmat.clone(); + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(),Some(cloned.column(0))); + assert_eq!(col_iter.next(),Some(cloned.column(1))); + assert_eq!(col_iter.next_back(),Some(cloned.column(4))); + assert_eq!(col_iter.next_back(),Some(cloned.column(3))); + assert_eq!(col_iter.next(),Some(cloned.column(2))); + assert_eq!(col_iter.next_back(),None); + assert_eq!(col_iter.next(),None); +} + +#[test] +fn parallel_column_iteration_mut() { + todo!() +} From 7ac536be07b8ef7c44ed096574cf382d5d070700 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Thu, 20 Oct 2022 19:07:22 +0200 Subject: [PATCH 03/34] cleanups and add tests --- src/base/iter.rs | 23 +++++++--------- src/base/par_iter.rs | 29 +++------------------ tests/core/matrix.rs | 62 ++++++++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index cb587589..f4b34f63 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -475,23 +475,26 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI } } -impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer for ColumnIterMut<'a,T,R,C,S> -where T : Send + Sync + Debug + PartialEq + Clone, - S: Send + Sync { +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer + for ColumnIterMut<'a, T, R, C, S> +where + T: Send + Sync + Debug + PartialEq + Clone, + S: Send + Sync, +{ type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; - type IntoIter = ColumnIterMut<'a,T,R,C,S>; + type IntoIter = ColumnIterMut<'a, T, R, C, S>; fn into_iter(self) -> Self::IntoIter { - self + self } fn split_at(self, index: usize) -> (Self, Self) { // the index is relative to the size of this current iterator // it will always start at zero - let pmat : * mut _ = self.mat; + let pmat: *mut _ = self.mat; let left = Self { - mat: unsafe {&mut *pmat}, + mat: unsafe { &mut *pmat }, range: self.range.start..(self.range.start + index), }; @@ -502,9 +505,3 @@ where T : Send + Sync + Debug + PartialEq + Clone, (left, right) } } - -fn test_send(_: T) {} - -fn something(mut matrix: DMatrix) { - test_send(matrix.column_iter_mut()); -} diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index abe48bb2..b53e1f49 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -3,24 +3,18 @@ use core::{ fmt::Debug, - iter::{Skip, Take}, - marker::PhantomData, - ops::Range, }; -use std::os::unix::prelude::AsRawFd; use rayon::{ - iter::plumbing::{bridge, Producer}, + iter::plumbing::{bridge}, prelude::*, }; use crate::{ - iter::{ColumnIter, ColumnIterMut}, Const, DMatrix, Dim, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, - RawStorage, RawStorageMut, U1, SliceStorageMut, + iter::{ColumnIter, ColumnIterMut}, DMatrix, Dim, Matrix, MatrixSlice, MatrixSliceMut, + RawStorage, RawStorageMut, U1, }; -use super::conversion; - /// a rayon parallel iterator over the columns of a matrix pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { mat: &'a Matrix, @@ -146,20 +140,3 @@ where ParColumnIterMut::new(self) } } - - - -#[test] -fn test_mut_parallel_iter() { - let mut matrix = DMatrix::::zeros(4, 3); - matrix.par_column_iter_mut().enumerate().for_each(|(idx,mut col)| col[idx]=1f32); - let identity = DMatrix::::identity(4, 3); - assert_eq!(matrix,identity); -} - - -fn try_some_stuff() { - let mut mat = DMatrix::::zeros(3, 4); - let _left = mat.columns_mut(0, 1); - let _right = mat.columns_mut(1, 3); -} diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index aa515e49..a4ad5057 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1145,19 +1145,41 @@ fn column_iteration() { 23,24,25; 33,34,35; ]; - // not using enumerate on purpose - let mut idx = 0; - for col in dmat.column_iter() { - assert_eq!(dmat.column(idx),col); - idx += 1; - } + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(),Some(dmat.column(0))); + assert_eq!(col_iter.next(),Some(dmat.column(1))); + assert_eq!(col_iter.next(),Some(dmat.column(2))); + assert_eq!(col_iter.next(),None); + // statically sized matrix let smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; - let mut idx = 0; - for col in smat.column_iter() { - assert_eq!(smat.column(idx),col); - idx += 1; - } + let mut col_iter = smat.column_iter(); + assert_eq!(col_iter.next(),Some(smat.column(0))); + assert_eq!(col_iter.next(),Some(smat.column(1))); + assert_eq!(col_iter.next(),None); +} + +#[test] +fn column_iteration_mut() { + let mut dmat = nalgebra::dmatrix![ + 13,14,15; + 23,24,25; + 33,34,35; + ]; + let mut cloned = dmat.clone(); + let mut col_iter = dmat.column_iter_mut(); + assert_eq!(col_iter.next(),Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(),Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(),Some(cloned.column_mut(2))); + assert_eq!(col_iter.next(),None); + + // statically sized matrix + let mut smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; + let mut cloned = smat.clone(); + let mut col_iter = smat.column_iter_mut(); + assert_eq!(col_iter.next(),Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(),Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(),None); } #[test] @@ -1181,7 +1203,7 @@ fn column_iteration_double_ended() { fn parallel_column_iteration() { use rayon::prelude::*; use nalgebra::{dmatrix,dvector}; - let dmat = dmatrix![ + let dmat : DMatrix = dmatrix![ 13.,14.; 23.,24.; 33.,34.; @@ -1193,15 +1215,11 @@ fn parallel_column_iteration() { }); // test that a more complex expression produces the same // result as the serial equivalent - let par_result :f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); - let ser_result = dmat.column_iter().map(|col| col.norm()).sum(); + let par_result : f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); + let ser_result : f64= dmat.column_iter().map(|col| col.norm()).sum(); assert_eq!(par_result,ser_result); } -#[test] -fn column_iteration_mut() { - todo!(); -} #[test] fn colum_iteration_mut_double_ended() { @@ -1223,5 +1241,11 @@ fn colum_iteration_mut_double_ended() { #[test] fn parallel_column_iteration_mut() { - todo!() + use rayon::prelude::*; + let mut first = DMatrix::::zeros(400,300); + let mut second = DMatrix::::zeros(400,300); + first.column_iter_mut().enumerate().for_each(|(idx,mut col)|col[idx]=1.); + second.par_column_iter_mut().enumerate().for_each(|(idx,mut col)| col[idx]=1.); + assert_eq!(first,second); + assert_eq!(second,DMatrix::identity(400,300)); } From daade1cf5e83cc956ef64b6e8e762cc5260f2705 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Fri, 21 Oct 2022 08:44:35 +0200 Subject: [PATCH 04/34] add documentation --- src/base/iter.rs | 15 +++------------ src/base/par_iter.rs | 21 +++++++++------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index f4b34f63..eb3312c0 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -311,15 +311,6 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, range: 0..mat.ncols(), } } - /// a new column iterator covering column indices [begin,end) - /// where begin is included in the range but index end is not - /// begin must lie in [0,ncols] and end must lie in [0,ncols]. - pub(crate) fn with_range(mat: &'a Matrix, range: Range) -> Self { - debug_assert!(range.end <= mat.ncols()); - debug_assert!(range.start < mat.ncols()); - debug_assert!(range.start <= range.end); - Self { mat, range } - } } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter<'a, T, R, C, S> { @@ -384,7 +375,7 @@ where fn split_at(self, index: usize) -> (Self, Self) { // the index is relative to the size of this current iterator - // it will always start at zero + // it will always start at zero so it serves as an offset let left = Self { mat: self.mat, range: self.range.start..(self.range.start + index), @@ -465,7 +456,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI debug_assert!(self.range.start <= self.range.end); if !self.range.is_empty() { self.range.end -= 1; - debug_assert!(self.range.end < unsafe { (*self.mat).ncols() }); + debug_assert!(self.range.end < self.mat.ncols()); debug_assert!(self.range.end >= self.range.start); let pmat: *mut _ = self.mat; Some(unsafe { (*pmat).column_mut(self.range.end) }) @@ -490,7 +481,7 @@ where fn split_at(self, index: usize) -> (Self, Self) { // the index is relative to the size of this current iterator - // it will always start at zero + // it will always start at zero so it serves as an offset let pmat: *mut _ = self.mat; let left = Self { diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index b53e1f49..3854e678 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -1,26 +1,23 @@ //! this module implements parallelators to make matrices work with //! the rayon crate seamlessly -use core::{ - fmt::Debug, -}; - +use core::fmt::Debug; use rayon::{ iter::plumbing::{bridge}, prelude::*, }; - use crate::{ - iter::{ColumnIter, ColumnIterMut}, DMatrix, Dim, Matrix, MatrixSlice, MatrixSliceMut, + iter::{ColumnIter, ColumnIterMut}, Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, U1, }; -/// a rayon parallel iterator over the columns of a matrix +/// A rayon parallel iterator over the colums of a matrix pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { mat: &'a Matrix, } impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R, Cols, S> { + /// create a new parallel iterator for the given matrix fn new(matrix: &'a Matrix) -> Self { Self { mat: matrix } } @@ -74,21 +71,21 @@ where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, { - /// TODO + /// Iterate through the columns of the matrix in parallel using rayon. pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { ParColumnIter::new(self) } } -/// TODO +/// A rayon parallel iterator through the mutable columns of a matrix pub struct ParColumnIterMut<'a,T,R:Dim ,Cols:Dim, S:RawStorage+RawStorageMut> { mat : &'a mut Matrix, } impl<'a,T,R,Cols,S> ParColumnIterMut<'a,T,R,Cols,S> where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut { - /// TODO - pub fn new(mat : &'a mut Matrix) -> Self { + /// create a new parallel iterator for the given matrix + fn new(mat : &'a mut Matrix) -> Self { Self { mat, } @@ -135,7 +132,7 @@ where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, { - /// TODO + /// Mutably iterate through the columns of this matrix in parallel using rayon pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { ParColumnIterMut::new(self) } From a4e28a136e7fd76f0dacea17f755f91d285b1e06 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Fri, 21 Oct 2022 08:51:41 +0200 Subject: [PATCH 05/34] apply fmt --- src/base/par_iter.rs | 77 ++++++++++++++++---------- tests/core/matrix.rs | 129 ++++++++++++++++++++++--------------------- 2 files changed, 114 insertions(+), 92 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 3854e678..3109e1ac 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -1,15 +1,12 @@ //! this module implements parallelators to make matrices work with //! the rayon crate seamlessly -use core::fmt::Debug; -use rayon::{ - iter::plumbing::{bridge}, - prelude::*, -}; use crate::{ - iter::{ColumnIter, ColumnIterMut}, Dim, Matrix, MatrixSlice, MatrixSliceMut, - RawStorage, RawStorageMut, U1, + iter::{ColumnIter, ColumnIterMut}, + Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, U1, }; +use core::fmt::Debug; +use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { @@ -78,29 +75,42 @@ where } /// A rayon parallel iterator through the mutable columns of a matrix -pub struct ParColumnIterMut<'a,T,R:Dim ,Cols:Dim, S:RawStorage+RawStorageMut> { - mat : &'a mut Matrix, +pub struct ParColumnIterMut< + 'a, + T, + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +> { + mat: &'a mut Matrix, } -impl<'a,T,R,Cols,S> ParColumnIterMut<'a,T,R,Cols,S> -where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut { +impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +{ /// create a new parallel iterator for the given matrix - fn new(mat : &'a mut Matrix) -> Self { - Self { - mat, - } + fn new(mat: &'a mut Matrix) -> Self { + Self { mat } } } -impl<'a,T,R,Cols,S> ParallelIterator for ParColumnIterMut<'a,T,R,Cols,S> -where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut, -T : Send + Sync + Debug + PartialEq + Clone + 'static, -S : Send + Sync { +impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Send + Sync, +{ type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; fn drive_unindexed(self, consumer: C) -> C::Result - where - C: rayon::iter::plumbing::UnindexedConsumer { - bridge(self,consumer) + where + C: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) } fn opt_len(&self) -> Option { @@ -108,26 +118,33 @@ S : Send + Sync { } } - -impl<'a,T,R,Cols,S> IndexedParallelIterator for ParColumnIterMut<'a,T,R,Cols,S> -where R: Dim, Cols : Dim, S:RawStorage + RawStorageMut, -T : Send + Sync + Debug + PartialEq + Clone + 'static, -S : Send + Sync { +impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Send + Sync, +{ fn drive>(self, consumer: C) -> C::Result { - bridge(self,consumer) + bridge(self, consumer) } fn len(&self) -> usize { self.mat.ncols() } - fn with_producer>(self, callback: CB) -> CB::Output { + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { let producer = ColumnIterMut::new(self.mat); callback.callback(producer) } } -impl<'a, T, R: Dim, Cols: Dim, S: RawStorage + RawStorageMut> Matrix +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage + RawStorageMut> + Matrix where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index a4ad5057..5021df8b 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1141,111 +1141,116 @@ fn omatrix_to_string() { fn column_iteration() { // dynamic matrix let dmat = nalgebra::dmatrix![ - 13,14,15; - 23,24,25; - 33,34,35; - ]; + 13,14,15; + 23,24,25; + 33,34,35; + ]; let mut col_iter = dmat.column_iter(); - assert_eq!(col_iter.next(),Some(dmat.column(0))); - assert_eq!(col_iter.next(),Some(dmat.column(1))); - assert_eq!(col_iter.next(),Some(dmat.column(2))); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(dmat.column(0))); + assert_eq!(col_iter.next(), Some(dmat.column(1))); + assert_eq!(col_iter.next(), Some(dmat.column(2))); + assert_eq!(col_iter.next(), None); // statically sized matrix let smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; let mut col_iter = smat.column_iter(); - assert_eq!(col_iter.next(),Some(smat.column(0))); - assert_eq!(col_iter.next(),Some(smat.column(1))); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(smat.column(0))); + assert_eq!(col_iter.next(), Some(smat.column(1))); + assert_eq!(col_iter.next(), None); } #[test] fn column_iteration_mut() { let mut dmat = nalgebra::dmatrix![ - 13,14,15; - 23,24,25; - 33,34,35; - ]; + 13,14,15; + 23,24,25; + 33,34,35; + ]; let mut cloned = dmat.clone(); let mut col_iter = dmat.column_iter_mut(); - assert_eq!(col_iter.next(),Some(cloned.column_mut(0))); - assert_eq!(col_iter.next(),Some(cloned.column_mut(1))); - assert_eq!(col_iter.next(),Some(cloned.column_mut(2))); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(2))); + assert_eq!(col_iter.next(), None); // statically sized matrix let mut smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; let mut cloned = smat.clone(); let mut col_iter = smat.column_iter_mut(); - assert_eq!(col_iter.next(),Some(cloned.column_mut(0))); - assert_eq!(col_iter.next(),Some(cloned.column_mut(1))); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(), None); } #[test] fn column_iteration_double_ended() { let dmat = nalgebra::dmatrix![ - 13,14,15,16,17; - 23,24,25,26,27; - 33,34,35,36,37; - ]; + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; let mut col_iter = dmat.column_iter(); - assert_eq!(col_iter.next(),Some(dmat.column(0))); - assert_eq!(col_iter.next(),Some(dmat.column(1))); - assert_eq!(col_iter.next_back(),Some(dmat.column(4))); - assert_eq!(col_iter.next_back(),Some(dmat.column(3))); - assert_eq!(col_iter.next(),Some(dmat.column(2))); - assert_eq!(col_iter.next_back(),None); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(dmat.column(0))); + assert_eq!(col_iter.next(), Some(dmat.column(1))); + assert_eq!(col_iter.next_back(), Some(dmat.column(4))); + assert_eq!(col_iter.next_back(), Some(dmat.column(3))); + assert_eq!(col_iter.next(), Some(dmat.column(2))); + assert_eq!(col_iter.next_back(), None); + assert_eq!(col_iter.next(), None); } #[test] fn parallel_column_iteration() { + use nalgebra::dmatrix; use rayon::prelude::*; - use nalgebra::{dmatrix,dvector}; - let dmat : DMatrix = dmatrix![ - 13.,14.; - 23.,24.; - 33.,34.; - ]; + let dmat: DMatrix = dmatrix![ + 13.,14.; + 23.,24.; + 33.,34.; + ]; let cloned = dmat.clone(); // test that correct columns are iterated over - dmat.par_column_iter().enumerate().for_each(|(idx,col)| { - assert_eq!(col,cloned.column(idx)); + dmat.par_column_iter().enumerate().for_each(|(idx, col)| { + assert_eq!(col, cloned.column(idx)); }); // test that a more complex expression produces the same // result as the serial equivalent - let par_result : f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); - let ser_result : f64= dmat.column_iter().map(|col| col.norm()).sum(); - assert_eq!(par_result,ser_result); + let par_result: f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); + let ser_result: f64 = dmat.column_iter().map(|col| col.norm()).sum(); + assert_eq!(par_result, ser_result); } - #[test] fn colum_iteration_mut_double_ended() { let dmat = nalgebra::dmatrix![ - 13,14,15,16,17; - 23,24,25,26,27; - 33,34,35,36,37; - ]; + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; let cloned = dmat.clone(); let mut col_iter = dmat.column_iter(); - assert_eq!(col_iter.next(),Some(cloned.column(0))); - assert_eq!(col_iter.next(),Some(cloned.column(1))); - assert_eq!(col_iter.next_back(),Some(cloned.column(4))); - assert_eq!(col_iter.next_back(),Some(cloned.column(3))); - assert_eq!(col_iter.next(),Some(cloned.column(2))); - assert_eq!(col_iter.next_back(),None); - assert_eq!(col_iter.next(),None); + assert_eq!(col_iter.next(), Some(cloned.column(0))); + assert_eq!(col_iter.next(), Some(cloned.column(1))); + assert_eq!(col_iter.next_back(), Some(cloned.column(4))); + assert_eq!(col_iter.next_back(), Some(cloned.column(3))); + assert_eq!(col_iter.next(), Some(cloned.column(2))); + assert_eq!(col_iter.next_back(), None); + assert_eq!(col_iter.next(), None); } #[test] fn parallel_column_iteration_mut() { use rayon::prelude::*; - let mut first = DMatrix::::zeros(400,300); - let mut second = DMatrix::::zeros(400,300); - first.column_iter_mut().enumerate().for_each(|(idx,mut col)|col[idx]=1.); - second.par_column_iter_mut().enumerate().for_each(|(idx,mut col)| col[idx]=1.); - assert_eq!(first,second); - assert_eq!(second,DMatrix::identity(400,300)); + let mut first = DMatrix::::zeros(400, 300); + let mut second = DMatrix::::zeros(400, 300); + first + .column_iter_mut() + .enumerate() + .for_each(|(idx, mut col)| col[idx] = 1.); + second + .par_column_iter_mut() + .enumerate() + .for_each(|(idx, mut col)| col[idx] = 1.); + assert_eq!(first, second); + assert_eq!(second, DMatrix::identity(400, 300)); } From 42ab3f69037c8f9165adf8ba5b7a67f6beb648a2 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Fri, 21 Oct 2022 09:02:28 +0200 Subject: [PATCH 06/34] fix clippy lints in my code --- src/base/par_iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 3109e1ac..9beccee9 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -63,7 +63,7 @@ where } } -impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Matrix +impl> Matrix where T: Send + Sync + Clone + Debug + PartialEq + 'static, S: Sync, @@ -143,7 +143,7 @@ where } } -impl<'a, T, R: Dim, Cols: Dim, S: RawStorage + RawStorageMut> +impl + RawStorageMut> Matrix where T: Send + Sync + Clone + Debug + PartialEq + 'static, From f6461d38623aa8cb1643b796054f00f07212d56f Mon Sep 17 00:00:00 2001 From: Geo <54497890+geo-ant@users.noreply.github.com> Date: Sun, 23 Oct 2022 13:40:03 +0200 Subject: [PATCH 07/34] make mut iterator pointer based Change the ColumnIterMut back to the original impl and manually implement Send --- src/base/iter.rs | 53 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index eb3312c0..cbd2bbf6 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -226,7 +226,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for RowIter<'a } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator - for RowIter<'a, T, R, C, S> +for RowIter<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -257,7 +257,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> RowIterMut<'a, T, R, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator - for RowIterMut<'a, T, R, C, S> +for RowIterMut<'a, T, R, C, S> { type Item = MatrixViewMut<'a, T, U1, C, S::RStride, S::CStride>; @@ -284,7 +284,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator - for RowIterMut<'a, T, R, C, S> +for RowIterMut<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -341,7 +341,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator - for ColumnIter<'a, T, R, C, S> +for ColumnIter<'a, T, R, C, S> { fn next_back(&mut self) -> Option { debug_assert!(self.range.start <= self.range.end); @@ -357,7 +357,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator - for ColumnIter<'a, T, R, C, S> +for ColumnIter<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -366,9 +366,9 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat } impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> -where - T: Send + Sync + Debug + PartialEq + Clone + 'static, - S: Sync, + where + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIter<'a, T, R, Cols, S>; @@ -396,31 +396,31 @@ where /// An iterator through the mutable columns of a matrix. #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { - mat: &'a mut Matrix, + mat: *mut Matrix, + phantom: PhantomData<&'a mut Matrix>, range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { pub(crate) fn new(mat: &'a mut Matrix) -> Self { let range = 0..mat.ncols(); - ColumnIterMut { mat, range } + ColumnIterMut { mat, range, phantom: Default::default() } } fn ncols(&self) -> usize { - self.mat.ncols() + unsafe { (*self.mat).ncols() } } } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator - for ColumnIterMut<'a, T, R, C, S> +for ColumnIterMut<'a, T, R, C, S> { type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; #[inline] fn next(&'_ mut self) -> Option { if self.range.start < self.ncols() { - let pmat: *mut _ = self.mat; - let res = unsafe { (*pmat).column_mut(self.range.start) }; + let res = unsafe { (*self.mat).column_mut(self.range.start) }; self.range.start += 1; Some(res) } else { @@ -441,7 +441,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator - for ColumnIterMut<'a, T, R, C, S> +for ColumnIterMut<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -450,16 +450,15 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedIterator - for ColumnIterMut<'a, T, R, C, S> +for ColumnIterMut<'a, T, R, C, S> { fn next_back(&mut self) -> Option { debug_assert!(self.range.start <= self.range.end); if !self.range.is_empty() { self.range.end -= 1; - debug_assert!(self.range.end < self.mat.ncols()); + debug_assert!(self.range.end < self.ncols()); debug_assert!(self.range.end >= self.range.start); - let pmat: *mut _ = self.mat; - Some(unsafe { (*pmat).column_mut(self.range.end) }) + Some(unsafe { (*self.mat).column_mut(self.range.end) }) } else { None } @@ -467,10 +466,10 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer - for ColumnIterMut<'a, T, R, C, S> -where - T: Send + Sync + Debug + PartialEq + Clone, - S: Send + Sync, +for ColumnIterMut<'a, T, R, C, S> + where + T: Send + Sync + Debug + PartialEq + Clone, + S: Send + Sync, { type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIterMut<'a, T, R, C, S>; @@ -482,17 +481,21 @@ where fn split_at(self, index: usize) -> (Self, Self) { // the index is relative to the size of this current iterator // it will always start at zero so it serves as an offset - let pmat: *mut _ = self.mat; let left = Self { - mat: unsafe { &mut *pmat }, + mat: self.mat, range: self.range.start..(self.range.start + index), + phantom: Default::default(), }; let right = Self { mat: self.mat, range: (self.range.start + index)..self.range.end, + phantom: Default::default(), }; (left, right) } } + +unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send +for ColumnIterMut<'a, T, R, C, S> {} \ No newline at end of file From 8638b796ac990e9d8ba83830c6e34e5cf460af37 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Mon, 24 Oct 2022 08:08:20 +0200 Subject: [PATCH 08/34] fix fmt --- src/base/iter.rs | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index cbd2bbf6..925fefbb 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -226,7 +226,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for RowIter<'a } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator -for RowIter<'a, T, R, C, S> + for RowIter<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -257,7 +257,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> RowIterMut<'a, T, R, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator -for RowIterMut<'a, T, R, C, S> + for RowIterMut<'a, T, R, C, S> { type Item = MatrixViewMut<'a, T, U1, C, S::RStride, S::CStride>; @@ -284,7 +284,7 @@ for RowIterMut<'a, T, R, C, S> } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator -for RowIterMut<'a, T, R, C, S> + for RowIterMut<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -341,7 +341,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator -for ColumnIter<'a, T, R, C, S> + for ColumnIter<'a, T, R, C, S> { fn next_back(&mut self) -> Option { debug_assert!(self.range.start <= self.range.end); @@ -357,7 +357,7 @@ for ColumnIter<'a, T, R, C, S> } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator -for ColumnIter<'a, T, R, C, S> + for ColumnIter<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -366,9 +366,9 @@ for ColumnIter<'a, T, R, C, S> } impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> - where - T: Send + Sync + Debug + PartialEq + Clone + 'static, - S: Sync, +where + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIter<'a, T, R, Cols, S>; @@ -404,7 +404,11 @@ pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { pub(crate) fn new(mat: &'a mut Matrix) -> Self { let range = 0..mat.ncols(); - ColumnIterMut { mat, range, phantom: Default::default() } + ColumnIterMut { + mat, + range, + phantom: Default::default(), + } } fn ncols(&self) -> usize { @@ -413,7 +417,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator -for ColumnIterMut<'a, T, R, C, S> + for ColumnIterMut<'a, T, R, C, S> { type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; @@ -441,7 +445,7 @@ for ColumnIterMut<'a, T, R, C, S> } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator -for ColumnIterMut<'a, T, R, C, S> + for ColumnIterMut<'a, T, R, C, S> { #[inline] fn len(&self) -> usize { @@ -450,7 +454,7 @@ for ColumnIterMut<'a, T, R, C, S> } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedIterator -for ColumnIterMut<'a, T, R, C, S> + for ColumnIterMut<'a, T, R, C, S> { fn next_back(&mut self) -> Option { debug_assert!(self.range.start <= self.range.end); @@ -466,10 +470,10 @@ for ColumnIterMut<'a, T, R, C, S> } impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer -for ColumnIterMut<'a, T, R, C, S> - where - T: Send + Sync + Debug + PartialEq + Clone, - S: Send + Sync, + for ColumnIterMut<'a, T, R, C, S> +where + T: Send + Sync + Debug + PartialEq + Clone, + S: Send + Sync, { type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIterMut<'a, T, R, C, S>; @@ -498,4 +502,6 @@ for ColumnIterMut<'a, T, R, C, S> } unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send -for ColumnIterMut<'a, T, R, C, S> {} \ No newline at end of file + for ColumnIterMut<'a, T, R, C, S> +{ +} From 85e7551c817f2c923bf0c902117283689ad66b05 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Mon, 24 Oct 2022 08:39:03 +0200 Subject: [PATCH 09/34] feature gate functionality --- .github/workflows/nalgebra-ci-build.yml | 2 +- Cargo.toml | 3 +- src/base/iter.rs | 125 +++++++++++++----------- src/base/mod.rs | 1 + tests/core/matrix.rs | 3 + tests/lib.rs | 4 + 6 files changed, 77 insertions(+), 61 deletions(-) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index 9e500084..d7027127 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -61,7 +61,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; test-nalgebra-glm: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index 48262dce..b8f25b5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] +rayon = [ "dep:rayon" ] # Conversion convert-mint = [ "mint" ] @@ -101,7 +102,7 @@ glam020 = { package = "glam", version = "0.20", optional = true } glam021 = { package = "glam", version = "0.21", optional = true } glam022 = { package = "glam", version = "0.22", optional = true } cust_core = { version = "0.1", optional = true } -rayon = "1.5" # TODO make this feature gated +rayon = { version = "1.5", optional = true } [dev-dependencies] serde_json = "1.0" diff --git a/src/base/iter.rs b/src/base/iter.rs index 925fefbb..0ecd057c 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -6,8 +6,6 @@ use std::iter::FusedIterator; use std::marker::PhantomData; use std::mem; -use rayon::iter::plumbing::Producer; - use crate::base::dimension::{Dim, U1}; use crate::base::storage::{RawStorage, RawStorageMut}; use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar}; @@ -365,34 +363,6 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat } } -impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> -where - T: Send + Sync + Debug + PartialEq + Clone + 'static, - S: Sync, -{ - type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; - type IntoIter = ColumnIter<'a, T, R, Cols, S>; - - fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset - let left = Self { - mat: self.mat, - range: self.range.start..(self.range.start + index), - }; - - let right = Self { - mat: self.mat, - range: (self.range.start + index)..self.range.end, - }; - (left, right) - } - - fn into_iter(self) -> Self::IntoIter { - self - } -} - /// An iterator through the mutable columns of a matrix. #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { @@ -469,39 +439,76 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI } } -impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer - for ColumnIterMut<'a, T, R, C, S> -where - T: Send + Sync + Debug + PartialEq + Clone, - S: Send + Sync, -{ - type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; - type IntoIter = ColumnIterMut<'a, T, R, C, S>; +/// implementations for parallel iteration with rayon +#[cfg(feature = "rayon")] +mod parallel { + use super::*; + use rayon::iter::plumbing::Producer; - fn into_iter(self) -> Self::IntoIter { - self + impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> + where + T: Send + Sync + Debug + PartialEq + Clone + 'static, + S: Sync, + { + type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIter<'a, T, R, Cols, S>; + + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset + let left = Self { + mat: self.mat, + range: self.range.start..(self.range.start + index), + }; + + let right = Self { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + }; + (left, right) + } + + fn into_iter(self) -> Self::IntoIter { + self + } } - fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset + impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer + for ColumnIterMut<'a, T, R, C, S> + where + T: Send + Sync + Debug + PartialEq + Clone, + S: Send + Sync, + { + type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIterMut<'a, T, R, C, S>; - let left = Self { - mat: self.mat, - range: self.range.start..(self.range.start + index), - phantom: Default::default(), - }; + fn into_iter(self) -> Self::IntoIter { + self + } - let right = Self { - mat: self.mat, - range: (self.range.start + index)..self.range.end, - phantom: Default::default(), - }; - (left, right) + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset + + let left = Self { + mat: self.mat, + range: self.range.start..(self.range.start + index), + phantom: Default::default(), + }; + + let right = Self { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + phantom: Default::default(), + }; + (left, right) + } + } + + /// this implementation is safe because we are enforcing exclusive access + /// to the columns through the active range of the iterator + unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send + for ColumnIterMut<'a, T, R, C, S> + { } } - -unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send - for ColumnIterMut<'a, T, R, C, S> -{ -} diff --git a/src/base/mod.rs b/src/base/mod.rs index b828d0a1..0f09cc33 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,6 +42,7 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; +#[cfg(feature = "rayon")] pub mod par_iter; #[cfg(feature = "rkyv-serialize-no-std")] diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 5021df8b..150eb678 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1200,6 +1200,7 @@ fn column_iteration_double_ended() { } #[test] +#[cfg(feature = "rayon")] fn parallel_column_iteration() { use nalgebra::dmatrix; use rayon::prelude::*; @@ -1221,6 +1222,7 @@ fn parallel_column_iteration() { } #[test] +#[cfg(feature = "rayon")] fn colum_iteration_mut_double_ended() { let dmat = nalgebra::dmatrix![ 13,14,15,16,17; @@ -1239,6 +1241,7 @@ fn colum_iteration_mut_double_ended() { } #[test] +#[cfg(feature = "rayon")] fn parallel_column_iteration_mut() { use rayon::prelude::*; let mut first = DMatrix::::zeros(400, 300); diff --git a/tests/lib.rs b/tests/lib.rs index 546aa8a7..fb13b3ae 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -9,6 +9,10 @@ compile_error!( Example: `cargo test --features debug,compare,rand,macros`" ); +// make sure to test the parallel iterators for all builds that do not require no_std +#[cfg(all(feature = "std", not(feature = "rayon")))] +compile_error!("Please additionally enable the `rayon` feature to compile and run the tests"); + #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] #[macro_use] extern crate approx; From 6591f2819a56af4bb9fd130c22133c887a39f2a5 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Mon, 24 Oct 2022 08:46:25 +0200 Subject: [PATCH 10/34] make rayon feature imply std --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b8f25b5d..7e7df5b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] -rayon = [ "dep:rayon" ] +rayon = [ "std", "dep:rayon" ] # Conversion convert-mint = [ "mint" ] From 701d260fa687698ac56fd625973ef2005eb8a5cd Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Tue, 25 Oct 2022 08:47:57 +0200 Subject: [PATCH 11/34] rayon parallel feature w/o nightly features on old compilers --- .github/workflows/nalgebra-ci-build.yml | 2 +- Cargo.toml | 2 +- tests/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index d7027127..467a3090 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -61,7 +61,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon-par; test-nalgebra-glm: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index 7e7df5b4..ff3407fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] -rayon = [ "std", "dep:rayon" ] +rayon-par = [ "std", "rayon" ] # Conversion convert-mint = [ "mint" ] diff --git a/tests/lib.rs b/tests/lib.rs index fb13b3ae..49384d8a 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -10,8 +10,8 @@ compile_error!( ); // make sure to test the parallel iterators for all builds that do not require no_std -#[cfg(all(feature = "std", not(feature = "rayon")))] -compile_error!("Please additionally enable the `rayon` feature to compile and run the tests"); +#[cfg(all(feature = "std", not(feature = "rayon-par")))] +compile_error!("Please additionally enable the `rayon-par` feature to compile and run the tests"); #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] #[macro_use] From e40687d8e6ddba17a3ea95cea66a1ec4ef819c91 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sat, 12 Nov 2022 17:37:18 +0100 Subject: [PATCH 12/34] replace confusing trait bounds with Scalar --- src/base/iter.rs | 6 +++--- src/base/par_iter.rs | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index 0ecd057c..b3f66d81 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -447,7 +447,7 @@ mod parallel { impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> where - T: Send + Sync + Debug + PartialEq + Clone + 'static, + T: Send + Sync + Scalar, S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; @@ -473,10 +473,10 @@ mod parallel { } } - impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer + impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer for ColumnIterMut<'a, T, R, C, S> where - T: Send + Sync + Debug + PartialEq + Clone, + T: Send + Sync + Scalar, S: Send + Sync, { type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 9beccee9..589f7b81 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -3,9 +3,7 @@ use crate::{ iter::{ColumnIter, ColumnIterMut}, - Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, U1, -}; -use core::fmt::Debug; + Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, U1, Scalar,}; use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix @@ -23,7 +21,7 @@ impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator for ParColumnIter<'a, T, R, Cols, S> where - T: Sync + Send + Clone + Debug + PartialEq + 'static, + T: Sync + Send + Scalar, S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; @@ -43,7 +41,7 @@ where impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where - T: Send + Sync + Clone + Debug + PartialEq + 'static, + T: Send + Sync + Scalar, S: Sync, { fn len(&self) -> usize { @@ -65,7 +63,7 @@ where impl> Matrix where - T: Send + Sync + Clone + Debug + PartialEq + 'static, + T: Send + Sync + Scalar, S: Sync, { /// Iterate through the columns of the matrix in parallel using rayon. @@ -102,7 +100,7 @@ where R: Dim, Cols: Dim, S: RawStorage + RawStorageMut, - T: Send + Sync + Debug + PartialEq + Clone + 'static, + T: Send + Sync + Scalar, S: Send + Sync, { type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; @@ -123,7 +121,7 @@ where R: Dim, Cols: Dim, S: RawStorage + RawStorageMut, - T: Send + Sync + Debug + PartialEq + Clone + 'static, + T: Send + Sync + Scalar, S: Send + Sync, { fn drive>(self, consumer: C) -> C::Result { @@ -146,7 +144,7 @@ where impl + RawStorageMut> Matrix where - T: Send + Sync + Clone + Debug + PartialEq + 'static, + T: Send + Sync + Scalar, S: Sync, { /// Mutably iterate through the columns of this matrix in parallel using rayon From e9a5705e1afdcde2e2734e05184faa9159c5617d Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sat, 12 Nov 2022 17:54:01 +0100 Subject: [PATCH 13/34] address review --- Cargo.toml | 2 +- src/base/iter.rs | 2 +- src/base/par_iter.rs | 6 +++--- tests/core/matrix.rs | 2 +- tests/lib.rs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ff3407fe..7e7df5b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] -rayon-par = [ "std", "rayon" ] +rayon = [ "std", "dep:rayon" ] # Conversion convert-mint = [ "mint" ] diff --git a/src/base/iter.rs b/src/base/iter.rs index b3f66d81..4e1dc21a 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -447,7 +447,7 @@ mod parallel { impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> where - T: Send + Sync + Scalar, + T: Send + Sync + Scalar, S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 589f7b81..8aaad348 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -1,9 +1,9 @@ -//! this module implements parallelators to make matrices work with -//! the rayon crate seamlessly +//! Parallel iterators for matrices compatible with rayon. use crate::{ iter::{ColumnIter, ColumnIterMut}, - Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, U1, Scalar,}; + Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, Scalar, U1, +}; use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 150eb678..12f5308e 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1223,7 +1223,7 @@ fn parallel_column_iteration() { #[test] #[cfg(feature = "rayon")] -fn colum_iteration_mut_double_ended() { +fn column_iteration_mut_double_ended() { let dmat = nalgebra::dmatrix![ 13,14,15,16,17; 23,24,25,26,27; diff --git a/tests/lib.rs b/tests/lib.rs index 49384d8a..fb13b3ae 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -10,8 +10,8 @@ compile_error!( ); // make sure to test the parallel iterators for all builds that do not require no_std -#[cfg(all(feature = "std", not(feature = "rayon-par")))] -compile_error!("Please additionally enable the `rayon-par` feature to compile and run the tests"); +#[cfg(all(feature = "std", not(feature = "rayon")))] +compile_error!("Please additionally enable the `rayon` feature to compile and run the tests"); #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] #[macro_use] From 324e686fe6befecf39e9dec0cb9a8cc52286c4ee Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sat, 12 Nov 2022 17:57:27 +0100 Subject: [PATCH 14/34] update workflow for new feature name --- .github/workflows/nalgebra-ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index 467a3090..d7027127 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -61,7 +61,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon-par; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; test-nalgebra-glm: runs-on: ubuntu-latest steps: From 83c2e27d6d05e69777406852775d5411d8c5d1b3 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sat, 12 Nov 2022 19:01:28 +0100 Subject: [PATCH 15/34] start expanding docs(not done) --- src/base/par_iter.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 8aaad348..93796b6a 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -6,7 +6,12 @@ use crate::{ }; use rayon::{iter::plumbing::bridge, prelude::*}; -/// A rayon parallel iterator over the colums of a matrix +/// A rayon parallel iterator over the colums of a matrix. It is created +/// using the [`par_column_iter`] method of [`Matrix`]. +/// +/// [`par_column_iter`]: crate::Matrix::par_column_iter +/// [`Matrix`]: crate::Matrix +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { mat: &'a Matrix, } @@ -18,6 +23,7 @@ impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -38,6 +44,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -61,6 +68,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl> Matrix where T: Send + Sync + Scalar, @@ -72,6 +80,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] /// A rayon parallel iterator through the mutable columns of a matrix pub struct ParColumnIterMut< 'a, @@ -83,6 +92,7 @@ pub struct ParColumnIterMut< mat: &'a mut Matrix, } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -95,6 +105,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -116,6 +127,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -141,6 +153,7 @@ where } } +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl + RawStorageMut> Matrix where From 97861c8a5e006dbc62572f8e9cc0aa94440a66ea Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 14:54:26 +0100 Subject: [PATCH 16/34] add examples in par_column_iter method --- Cargo.toml | 2 ++ src/base/par_iter.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7e7df5b4..96356547 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,3 +138,5 @@ lto = true [package.metadata.docs.rs] # Enable all the features when building the docs on docs.rs all-features = true +# define the configuration attribute `docsrs` +rustdoc-args = ["--cfg", "docsrs"] diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 93796b6a..a551c0a7 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -1,5 +1,9 @@ //! Parallel iterators for matrices compatible with rayon. +//only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + use crate::{ iter::{ColumnIter, ColumnIterMut}, Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, Scalar, U1, @@ -75,6 +79,32 @@ where S: Sync, { /// Iterate through the columns of the matrix in parallel using rayon. + /// This iterates over *immutable* references ot the columns of the matrix, + /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] + /// instead. + /// + /// **Example** + /// Using parallel column iterators to calculate the sum of the maximum + /// elements in each column: + /// ``` + /// use nalgebra::{dmatrix,DMatrix}; + /// use rayon::prelude::*; + /// + /// let matrix : DMatrix = + /// nalgebra::dmatrix![1.,0.,5.; + /// 2.,4.,1.; + /// 3.,2.,2.;]; + /// let sum_of_max :f64 = + /// matrix + /// .par_column_iter() + /// .map(|col|col.max()) + /// .sum(); + /// + /// assert_eq!(sum_of_max,3.+4.+5.); + /// + /// ``` + /// + /// [`par_column_iter_mut`]: crate::Matrix::par_column_iter_mut pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { ParColumnIter::new(self) } From 8d1f684e45d76ce97b44db940cbb7b1d2d1019ca Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:01:15 +0100 Subject: [PATCH 17/34] change feature name to par-iter and add doc example to par_column_iter_mut --- Cargo.toml | 2 +- src/base/iter.rs | 2 +- src/base/matrix.rs | 2 +- src/base/mod.rs | 3 ++- src/base/par_iter.rs | 44 +++++++++++++++++++++++++++++++++----------- tests/core/matrix.rs | 6 +++--- tests/lib.rs | 4 ++-- 7 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 96356547..cee3130c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] -rayon = [ "std", "dep:rayon" ] +par-iter = [ "std", "rayon" ] # Conversion convert-mint = [ "mint" ] diff --git a/src/base/iter.rs b/src/base/iter.rs index 4e1dc21a..220eadd8 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -440,7 +440,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI } /// implementations for parallel iteration with rayon -#[cfg(feature = "rayon")] +#[cfg(feature = "par-iter")] mod parallel { use super::*; use rayon::iter::plumbing::Producer; diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 700e2f02..2d166d2a 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -100,7 +100,7 @@ pub type MatrixCross = /// - [Find the min and max components (vector-specific methods) `argmin`, `argmax`, `icamin`, `icamax`…](#find-the-min-and-max-components-vector-specific-methods) /// /// #### Iteration, map, and fold -/// - [Iteration on components, rows, and columns `iter`, `column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Iteration on components, rows, and columns `iter`, `column_iter`, `par_column_iter`…](#iteration-on-components-rows-and-columns) /// - [Elementwise mapping and folding `map`, `fold`, `zip_map`…](#elementwise-mapping-and-folding) /// - [Folding or columns and rows `compress_rows`, `compress_columns`…](#folding-on-columns-and-rows) /// diff --git a/src/base/mod.rs b/src/base/mod.rs index 0f09cc33..f22a53bf 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,7 +42,8 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; -#[cfg(feature = "rayon")] + +#[cfg(feature = "par-iter")] pub mod par_iter; #[cfg(feature = "rkyv-serialize-no-std")] diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index a551c0a7..1b106e6e 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -15,7 +15,7 @@ use rayon::{iter::plumbing::bridge, prelude::*}; /// /// [`par_column_iter`]: crate::Matrix::par_column_iter /// [`Matrix`]: crate::Matrix -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { mat: &'a Matrix, } @@ -27,7 +27,7 @@ impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -48,7 +48,7 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -72,7 +72,7 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl> Matrix where T: Send + Sync + Scalar, @@ -83,7 +83,7 @@ where /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] /// instead. /// - /// **Example** + /// # Example /// Using parallel column iterators to calculate the sum of the maximum /// elements in each column: /// ``` @@ -110,7 +110,7 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// A rayon parallel iterator through the mutable columns of a matrix pub struct ParColumnIterMut< 'a, @@ -122,7 +122,7 @@ pub struct ParColumnIterMut< mat: &'a mut Matrix, } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -135,7 +135,7 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -157,7 +157,7 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -183,14 +183,36 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] impl + RawStorageMut> Matrix where T: Send + Sync + Scalar, S: Sync, { - /// Mutably iterate through the columns of this matrix in parallel using rayon + /// Mutably iterate through the columns of this matrix in parallel using rayon. + /// Allows mutable access to the columns in parallel using mutable references. + /// If mutable access to the columns is not required rather use [`par_column_iter`] + /// instead. + /// + /// # Example + /// Normalize each column of a matrix with respect to its own maximum value. + /// + /// ``` + /// use nalgebra::{dmatrix,DMatrix}; + /// use rayon::prelude::*; + /// + /// let mut matrix : DMatrix = + /// dmatrix![2.,4.,6.; + /// 1.,2.,3.]; + /// matrix.par_column_iter_mut().for_each(|mut col| col /= col.max()); + /// + /// assert_eq!(matrix, + /// dmatrix![1. ,1. , 1.; + /// 0.5,0.5,0.5]); + /// ``` + /// + /// [`par_column_iter`]: crate::Matrix::par_column_iter pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { ParColumnIterMut::new(self) } diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 12f5308e..603897af 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1200,7 +1200,7 @@ fn column_iteration_double_ended() { } #[test] -#[cfg(feature = "rayon")] +#[cfg(feature = "par-iter")] fn parallel_column_iteration() { use nalgebra::dmatrix; use rayon::prelude::*; @@ -1222,7 +1222,7 @@ fn parallel_column_iteration() { } #[test] -#[cfg(feature = "rayon")] +#[cfg(feature = "par-iter")] fn column_iteration_mut_double_ended() { let dmat = nalgebra::dmatrix![ 13,14,15,16,17; @@ -1241,7 +1241,7 @@ fn column_iteration_mut_double_ended() { } #[test] -#[cfg(feature = "rayon")] +#[cfg(feature = "par-iter")] fn parallel_column_iteration_mut() { use rayon::prelude::*; let mut first = DMatrix::::zeros(400, 300); diff --git a/tests/lib.rs b/tests/lib.rs index fb13b3ae..6e4238e5 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -10,8 +10,8 @@ compile_error!( ); // make sure to test the parallel iterators for all builds that do not require no_std -#[cfg(all(feature = "std", not(feature = "rayon")))] -compile_error!("Please additionally enable the `rayon` feature to compile and run the tests"); +#[cfg(all(feature = "std", not(feature = "par-iter")))] +compile_error!("Please additionally enable the `par-iter` feature to compile and run the tests"); #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] #[macro_use] From e1305d3d8e626d0d112a30cebbf6aaf17eaa8238 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:01:31 +0100 Subject: [PATCH 18/34] fmt --- src/base/mod.rs | 1 - src/base/par_iter.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/base/mod.rs b/src/base/mod.rs index f22a53bf..73fe18c3 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,7 +42,6 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; - #[cfg(feature = "par-iter")] pub mod par_iter; diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 1b106e6e..6e1eb53a 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -82,7 +82,7 @@ where /// This iterates over *immutable* references ot the columns of the matrix, /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] /// instead. - /// + /// /// # Example /// Using parallel column iterators to calculate the sum of the maximum /// elements in each column: @@ -90,11 +90,11 @@ where /// use nalgebra::{dmatrix,DMatrix}; /// use rayon::prelude::*; /// - /// let matrix : DMatrix = + /// let matrix : DMatrix = /// nalgebra::dmatrix![1.,0.,5.; /// 2.,4.,1.; /// 3.,2.,2.;]; - /// let sum_of_max :f64 = + /// let sum_of_max :f64 = /// matrix /// .par_column_iter() /// .map(|col|col.max()) @@ -194,10 +194,10 @@ where /// Allows mutable access to the columns in parallel using mutable references. /// If mutable access to the columns is not required rather use [`par_column_iter`] /// instead. - /// - /// # Example + /// + /// # Example /// Normalize each column of a matrix with respect to its own maximum value. - /// + /// /// ``` /// use nalgebra::{dmatrix,DMatrix}; /// use rayon::prelude::*; From 85a58ca9391ba3da073ccce58fc473d344798aa5 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:02:19 +0100 Subject: [PATCH 19/34] update CI workflow --- .github/workflows/nalgebra-ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index d7027127..665bd008 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -61,7 +61,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,par-iter; test-nalgebra-glm: runs-on: ubuntu-latest steps: From 6fce1067760d576380872161da0fbf3c4f9ff84d Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:10:57 +0100 Subject: [PATCH 20/34] restructure code for better docs --- src/base/par_iter.rs | 75 +++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 6e1eb53a..6ea3e468 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -72,44 +72,6 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -impl> Matrix -where - T: Send + Sync + Scalar, - S: Sync, -{ - /// Iterate through the columns of the matrix in parallel using rayon. - /// This iterates over *immutable* references ot the columns of the matrix, - /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] - /// instead. - /// - /// # Example - /// Using parallel column iterators to calculate the sum of the maximum - /// elements in each column: - /// ``` - /// use nalgebra::{dmatrix,DMatrix}; - /// use rayon::prelude::*; - /// - /// let matrix : DMatrix = - /// nalgebra::dmatrix![1.,0.,5.; - /// 2.,4.,1.; - /// 3.,2.,2.;]; - /// let sum_of_max :f64 = - /// matrix - /// .par_column_iter() - /// .map(|col|col.max()) - /// .sum(); - /// - /// assert_eq!(sum_of_max,3.+4.+5.); - /// - /// ``` - /// - /// [`par_column_iter_mut`]: crate::Matrix::par_column_iter_mut - pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { - ParColumnIter::new(self) - } -} - #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// A rayon parallel iterator through the mutable columns of a matrix pub struct ParColumnIterMut< @@ -184,12 +146,44 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -impl + RawStorageMut> +/// # Parallel iterators using `rayon` +/// *Only availabe if compiled with the feature `par-iter`* +impl> Matrix where T: Send + Sync + Scalar, S: Sync, { + /// Iterate through the columns of the matrix in parallel using rayon. + /// This iterates over *immutable* references ot the columns of the matrix, + /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] + /// instead. + /// + /// # Example + /// Using parallel column iterators to calculate the sum of the maximum + /// elements in each column: + /// ``` + /// use nalgebra::{dmatrix,DMatrix}; + /// use rayon::prelude::*; + /// + /// let matrix : DMatrix = + /// nalgebra::dmatrix![1.,0.,5.; + /// 2.,4.,1.; + /// 3.,2.,2.;]; + /// let sum_of_max :f64 = + /// matrix + /// .par_column_iter() + /// .map(|col|col.max()) + /// .sum(); + /// + /// assert_eq!(sum_of_max,3.+4.+5.); + /// + /// ``` + /// + /// [`par_column_iter_mut`]: crate::Matrix::par_column_iter_mut + pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { + ParColumnIter::new(self) + } /// Mutably iterate through the columns of this matrix in parallel using rayon. /// Allows mutable access to the columns in parallel using mutable references. /// If mutable access to the columns is not required rather use [`par_column_iter`] @@ -213,7 +207,8 @@ where /// ``` /// /// [`par_column_iter`]: crate::Matrix::par_column_iter - pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> { + pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> + where S: RawStorageMut{ ParColumnIterMut::new(self) } } From ae5bca75f7a840cfc2fcc2930b37f2654cd31cde Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:15:15 +0100 Subject: [PATCH 21/34] advertize the feature on the matrix front doc page --- src/base/matrix.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 2d166d2a..f0fa8d81 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -100,7 +100,8 @@ pub type MatrixCross = /// - [Find the min and max components (vector-specific methods) `argmin`, `argmax`, `icamin`, `icamax`…](#find-the-min-and-max-components-vector-specific-methods) /// /// #### Iteration, map, and fold -/// - [Iteration on components, rows, and columns `iter`, `column_iter`, `par_column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Iteration on components, rows, and columns `iter`, `column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Parallel iterators using rayon `par_column_iter`, `par_column_iter_mut`…](#parallel-iterators-using-rayon) /// - [Elementwise mapping and folding `map`, `fold`, `zip_map`…](#elementwise-mapping-and-folding) /// - [Folding or columns and rows `compress_rows`, `compress_columns`…](#folding-on-columns-and-rows) /// From 66dfaf824adec8784e0213ca99829452dd54bec5 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:18:02 +0100 Subject: [PATCH 22/34] formatting --- src/base/par_iter.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 6ea3e468..a0ba5ebb 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -148,8 +148,7 @@ where #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// # Parallel iterators using `rayon` /// *Only availabe if compiled with the feature `par-iter`* -impl> - Matrix +impl> Matrix where T: Send + Sync + Scalar, S: Sync, @@ -207,8 +206,10 @@ where /// ``` /// /// [`par_column_iter`]: crate::Matrix::par_column_iter - pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> - where S: RawStorageMut{ + pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> + where + S: RawStorageMut, + { ParColumnIterMut::new(self) } } From 296320bb74be806a797b3e3a0f01f189c2361957 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:20:21 +0100 Subject: [PATCH 23/34] indicate feature gating --- src/base/par_iter.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index a0ba5ebb..19700c92 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -1,6 +1,6 @@ //! Parallel iterators for matrices compatible with rayon. -//only enables the `doc_cfg` feature when +// only enables the `doc_cfg` feature when // the `docsrs` configuration attribute is defined #![cfg_attr(docsrs, feature(doc_cfg))] @@ -12,7 +12,8 @@ use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. -/// +/// +/// *only availabe if compiled with the feature `par-iter`* /// [`par_column_iter`]: crate::Matrix::par_column_iter /// [`Matrix`]: crate::Matrix #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] @@ -49,6 +50,7 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +/// *only availabe if compiled with the feature `par-iter`* impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -74,6 +76,7 @@ where #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// A rayon parallel iterator through the mutable columns of a matrix +/// *only availabe if compiled with the feature `par-iter`* pub struct ParColumnIterMut< 'a, T, @@ -85,6 +88,7 @@ pub struct ParColumnIterMut< } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +/// *only availabe if compiled with the feature `par-iter`* impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -98,6 +102,7 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +/// *only availabe if compiled with the feature `par-iter`* impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -120,6 +125,7 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +/// *only availabe if compiled with the feature `par-iter`* impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, From 9cc7cc121f0c03c525c08fe171cd6de8f09ee2c8 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:23:43 +0100 Subject: [PATCH 24/34] mention feature gating --- src/base/iter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/base/iter.rs b/src/base/iter.rs index 220eadd8..8f34dbc9 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -1,5 +1,9 @@ //! Matrix iterators. +// only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + use core::fmt::Debug; use core::ops::Range; use std::iter::FusedIterator; @@ -445,6 +449,8 @@ mod parallel { use super::*; use rayon::iter::plumbing::Producer; + #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] + /// *only available if compiled with the feature `par-iter`* impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> where T: Send + Sync + Scalar, @@ -473,6 +479,8 @@ mod parallel { } } + #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] + /// *only available if compiled with the feature `par-iter`* impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer for ColumnIterMut<'a, T, R, C, S> where From 93f2c6c125a58f80199999c54722ae93e6d502ad Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Thu, 24 Nov 2022 08:29:30 +0100 Subject: [PATCH 25/34] fix format --- src/base/par_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 19700c92..7d943e40 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -12,7 +12,7 @@ use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. -/// +/// /// *only availabe if compiled with the feature `par-iter`* /// [`par_column_iter`]: crate::Matrix::par_column_iter /// [`Matrix`]: crate::Matrix From 7b9b123301da855b0776338e0c0d8c18cfa0e761 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 27 Nov 2022 15:37:17 +0100 Subject: [PATCH 26/34] add test, find bug, add another test --- src/base/iter.rs | 3 ++- tests/core/matrix.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index 8f34dbc9..90a1607f 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -397,7 +397,8 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator #[inline] fn next(&'_ mut self) -> Option { - if self.range.start < self.ncols() { + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { let res = unsafe { (*self.mat).column_mut(self.range.start) }; self.range.start += 1; Some(res) diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 603897af..29da1188 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1199,6 +1199,24 @@ fn column_iteration_double_ended() { assert_eq!(col_iter.next(), None); } +#[test] +fn column_iterator_double_ended_mut() { + let mut dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let mut cloned = dmat.clone(); + let mut col_iter_mut = dmat.column_iter_mut(); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter_mut.next_back(), Some(cloned.column_mut(4))); + assert_eq!(col_iter_mut.next_back(), Some(cloned.column_mut(3))); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(2))); + assert_eq!(col_iter_mut.next_back(), None); + assert_eq!(col_iter_mut.next(), None); +} + #[test] #[cfg(feature = "par-iter")] fn parallel_column_iteration() { @@ -1219,6 +1237,15 @@ fn parallel_column_iteration() { let par_result: f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); let ser_result: f64 = dmat.column_iter().map(|col| col.norm()).sum(); assert_eq!(par_result, ser_result); + + // repeat this test using mutable iterators + let mut dmat = dmat; + dmat.par_column_iter_mut().enumerate().for_each(|(idx, col)| { + assert_eq!(col, cloned.column(idx)); + }); + + let par_mut_result: f64 = dmat.par_column_iter_mut().map(|col| col.norm()).sum(); + assert_eq!(par_mut_result,ser_result); } #[test] From 61abece7af1cd02fabd40258e3347d54a80ab29c Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:51:25 +0100 Subject: [PATCH 27/34] create separate newtype for producer trait --- src/base/iter.rs | 88 +++----------------------------------------- src/base/par_iter.rs | 86 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 85 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index 90a1607f..fc6bd664 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -301,8 +301,8 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte #[derive(Clone, Debug)] /// An iterator through the columns of a matrix. pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage> { - mat: &'a Matrix, - range: Range, + pub(crate) mat: &'a Matrix, + pub(crate) range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, S> { @@ -370,9 +370,9 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat /// An iterator through the mutable columns of a matrix. #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { - mat: *mut Matrix, - phantom: PhantomData<&'a mut Matrix>, - range: Range, + pub(crate) mat: *mut Matrix, + pub(crate) range: Range, + pub(crate) phantom: PhantomData<&'a mut Matrix>, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { @@ -443,81 +443,3 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedI } } } - -/// implementations for parallel iteration with rayon -#[cfg(feature = "par-iter")] -mod parallel { - use super::*; - use rayon::iter::plumbing::Producer; - - #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] - /// *only available if compiled with the feature `par-iter`* - impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnIter<'a, T, R, Cols, S> - where - T: Send + Sync + Scalar, - S: Sync, - { - type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; - type IntoIter = ColumnIter<'a, T, R, Cols, S>; - - fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset - let left = Self { - mat: self.mat, - range: self.range.start..(self.range.start + index), - }; - - let right = Self { - mat: self.mat, - range: (self.range.start + index)..self.range.end, - }; - (left, right) - } - - fn into_iter(self) -> Self::IntoIter { - self - } - } - - #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] - /// *only available if compiled with the feature `par-iter`* - impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer - for ColumnIterMut<'a, T, R, C, S> - where - T: Send + Sync + Scalar, - S: Send + Sync, - { - type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; - type IntoIter = ColumnIterMut<'a, T, R, C, S>; - - fn into_iter(self) -> Self::IntoIter { - self - } - - fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset - - let left = Self { - mat: self.mat, - range: self.range.start..(self.range.start + index), - phantom: Default::default(), - }; - - let right = Self { - mat: self.mat, - range: (self.range.start + index)..self.range.end, - phantom: Default::default(), - }; - (left, right) - } - } - - /// this implementation is safe because we are enforcing exclusive access - /// to the columns through the active range of the iterator - unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send - for ColumnIterMut<'a, T, R, C, S> - { - } -} diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 7d943e40..46e3c607 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -9,6 +9,7 @@ use crate::{ Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, Scalar, U1, }; use rayon::{iter::plumbing::bridge, prelude::*}; +use rayon::iter::plumbing::Producer; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. @@ -69,7 +70,7 @@ where self, callback: CB, ) -> CB::Output { - let producer = ColumnIter::new(self.mat); + let producer = ColumnProducer(ColumnIter::new(self.mat)); callback.callback(producer) } } @@ -146,7 +147,7 @@ where self, callback: CB, ) -> CB::Output { - let producer = ColumnIterMut::new(self.mat); + let producer = ColumnProducerMut(ColumnIterMut::new(self.mat)); callback.callback(producer) } } @@ -219,3 +220,84 @@ where ParColumnIterMut::new(self) } } + +/// a private helper newtype that wraps the `ColumnIter` and implements +/// the rayon `Producer` trait. It's just here so we don't have to make the +/// rayon trait part of the public interface of the `ColumnIter` +struct ColumnProducer<'a,T,R:Dim,C:Dim,S:RawStorage>(ColumnIter<'a,T,R,C,S>); + +#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +/// *only available if compiled with the feature `par-iter`* +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnProducer<'a, T, R, Cols, S> +where +T: Send + Sync + Scalar, +S: Sync, +{ + type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIter<'a, T, R, Cols, S>; + + #[inline] + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset + let left_iter = ColumnIter { + mat: self.0.mat, + range: self.0.range.start..(self.0.range.start + index), + }; + + let right_iter = ColumnIter { + mat: self.0.mat, + range: (self.0.range.start + index)..self.0.range.end, + }; + (Self(left_iter), Self(right_iter)) + } + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0 + } +} + +/// See `ColumnProducer`. A private wrapper newtype that keeps the Producer +/// implementation private +struct ColumnProducerMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>(ColumnIterMut<'a,T,R,C,S>); + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer +for ColumnProducerMut<'a, T, R, C, S> +where +T: Send + Sync + Scalar, +S: Send + Sync, +{ + type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIterMut<'a, T, R, C, S>; + + fn into_iter(self) -> Self::IntoIter { + self.0 + } + + fn split_at(self, index: usize) -> (Self, Self) { + // the index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset + + let left_iter = ColumnIterMut { + mat: self.0.mat, + range: self.0.range.start..(self.0.range.start + index), + phantom: Default::default(), + }; + + let right_iter = ColumnIterMut { + mat: self.0.mat, + range: (self.0.range.start + index)..self.0.range.end, + phantom: Default::default(), + }; + (Self(left_iter), Self(right_iter)) + } +} + + +/// this implementation is safe because we are enforcing exclusive access +/// to the columns through the active range of the iterator +unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send +for ColumnIterMut<'a, T, R, C, S> +{ +} From 50e25c57f7c82745cba061a95cbbbb527a1dc4e8 Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:51:45 +0100 Subject: [PATCH 28/34] fmt --- src/base/par_iter.rs | 28 +++++++++++++++------------- tests/core/matrix.rs | 12 +++++++----- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 46e3c607..c50ba53f 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -8,8 +8,8 @@ use crate::{ iter::{ColumnIter, ColumnIterMut}, Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, Scalar, U1, }; -use rayon::{iter::plumbing::bridge, prelude::*}; use rayon::iter::plumbing::Producer; +use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. @@ -224,18 +224,19 @@ where /// a private helper newtype that wraps the `ColumnIter` and implements /// the rayon `Producer` trait. It's just here so we don't have to make the /// rayon trait part of the public interface of the `ColumnIter` -struct ColumnProducer<'a,T,R:Dim,C:Dim,S:RawStorage>(ColumnIter<'a,T,R,C,S>); +struct ColumnProducer<'a, T, R: Dim, C: Dim, S: RawStorage>(ColumnIter<'a, T, R, C, S>); #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// *only available if compiled with the feature `par-iter`* -impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnProducer<'a, T, R, Cols, S> +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer + for ColumnProducer<'a, T, R, Cols, S> where -T: Send + Sync + Scalar, -S: Sync, + T: Send + Sync + Scalar, + S: Sync, { type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIter<'a, T, R, Cols, S>; - + #[inline] fn split_at(self, index: usize) -> (Self, Self) { // the index is relative to the size of this current iterator @@ -252,7 +253,7 @@ S: Sync, (Self(left_iter), Self(right_iter)) } - #[inline] + #[inline] fn into_iter(self) -> Self::IntoIter { self.0 } @@ -260,13 +261,15 @@ S: Sync, /// See `ColumnProducer`. A private wrapper newtype that keeps the Producer /// implementation private -struct ColumnProducerMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>(ColumnIterMut<'a,T,R,C,S>); +struct ColumnProducerMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>( + ColumnIterMut<'a, T, R, C, S>, +); impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer -for ColumnProducerMut<'a, T, R, C, S> + for ColumnProducerMut<'a, T, R, C, S> where -T: Send + Sync + Scalar, -S: Send + Sync, + T: Send + Sync + Scalar, + S: Send + Sync, { type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIterMut<'a, T, R, C, S>; @@ -294,10 +297,9 @@ S: Send + Sync, } } - /// this implementation is safe because we are enforcing exclusive access /// to the columns through the active range of the iterator unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send -for ColumnIterMut<'a, T, R, C, S> + for ColumnIterMut<'a, T, R, C, S> { } diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 29da1188..41972347 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1237,15 +1237,17 @@ fn parallel_column_iteration() { let par_result: f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); let ser_result: f64 = dmat.column_iter().map(|col| col.norm()).sum(); assert_eq!(par_result, ser_result); - + // repeat this test using mutable iterators let mut dmat = dmat; - dmat.par_column_iter_mut().enumerate().for_each(|(idx, col)| { - assert_eq!(col, cloned.column(idx)); - }); + dmat.par_column_iter_mut() + .enumerate() + .for_each(|(idx, col)| { + assert_eq!(col, cloned.column(idx)); + }); let par_mut_result: f64 = dmat.par_column_iter_mut().map(|col| col.norm()).sum(); - assert_eq!(par_mut_result,ser_result); + assert_eq!(par_mut_result, ser_result); } #[test] From 997c707be9a75f6fd5c25ee1a4f3d853951f395e Mon Sep 17 00:00:00 2001 From: geo-ant <54497890+geo-ant@users.noreply.github.com> Date: Sun, 27 Nov 2022 17:05:46 +0100 Subject: [PATCH 29/34] upgrade rayon dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cee3130c..e7c6ba1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,7 @@ glam020 = { package = "glam", version = "0.20", optional = true } glam021 = { package = "glam", version = "0.21", optional = true } glam022 = { package = "glam", version = "0.22", optional = true } cust_core = { version = "0.1", optional = true } -rayon = { version = "1.5", optional = true } +rayon = { version = "1.6", optional = true } [dev-dependencies] serde_json = "1.0" From 5e26b8e121d201e13a7e8969567e16c84cf39b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 14 Jan 2023 12:19:36 +0100 Subject: [PATCH 30/34] Remove unused import --- src/base/iter.rs | 1 - src/base/par_iter.rs | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index fc6bd664..4b9536ed 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -13,7 +13,6 @@ use std::mem; use crate::base::dimension::{Dim, U1}; use crate::base::storage::{RawStorage, RawStorageMut}; use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar}; -use crate::{DMatrix, DimMax}; macro_rules! iterator { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index c50ba53f..2a8ca268 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -6,7 +6,7 @@ use crate::{ iter::{ColumnIter, ColumnIterMut}, - Dim, Matrix, MatrixSlice, MatrixSliceMut, RawStorage, RawStorageMut, Scalar, U1, + Dim, Matrix, MatrixView, MatrixViewMut, RawStorage, RawStorageMut, Scalar, U1, }; use rayon::iter::plumbing::Producer; use rayon::{iter::plumbing::bridge, prelude::*}; @@ -36,7 +36,7 @@ where T: Sync + Send + Scalar, S: Sync, { - type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; fn drive_unindexed(self, consumer: Consumer) -> Consumer::Result where @@ -112,7 +112,7 @@ where T: Send + Sync + Scalar, S: Send + Sync, { - type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; fn drive_unindexed(self, consumer: C) -> C::Result where C: rayon::iter::plumbing::UnindexedConsumer, @@ -234,7 +234,7 @@ where T: Send + Sync + Scalar, S: Sync, { - type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIter<'a, T, R, Cols, S>; #[inline] @@ -271,7 +271,7 @@ where T: Send + Sync + Scalar, S: Send + Sync, { - type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; type IntoIter = ColumnIterMut<'a, T, R, C, S>; fn into_iter(self) -> Self::IntoIter { From 1f4ded0c504941603c3a2243c1c06c192a5993c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 14 Jan 2023 15:30:00 +0100 Subject: [PATCH 31/34] =?UTF-8?q?Don=E2=80=99t=20make=20the=20ColumnIter[M?= =?UTF-8?q?ut]=20fields=20pub(crate)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/iter.rs | 46 ++++++++++++++++++++++++++++---- src/base/par_iter.rs | 62 ++++++++++++++++---------------------------- tests/lib.rs | 4 --- 3 files changed, 63 insertions(+), 49 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index 4b9536ed..f213f096 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -300,8 +300,8 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte #[derive(Clone, Debug)] /// An iterator through the columns of a matrix. pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage> { - pub(crate) mat: &'a Matrix, - pub(crate) range: Range, + mat: &'a Matrix, + range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, S> { @@ -312,6 +312,22 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, range: 0..mat.ncols(), } } + + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: it’s OK even if index > self.range.len() because + // the iterations will yield None in this case. + let left_iter = ColumnIter { + mat: self.mat, + range: self.range.start..(self.range.start + index), + }; + + let right_iter = ColumnIter { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + }; + + (left_iter, right_iter) + } } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter<'a, T, R, C, S> { @@ -369,9 +385,9 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat /// An iterator through the mutable columns of a matrix. #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { - pub(crate) mat: *mut Matrix, - pub(crate) range: Range, - pub(crate) phantom: PhantomData<&'a mut Matrix>, + mat: *mut Matrix, + range: Range, + phantom: PhantomData<&'a mut Matrix>, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { @@ -384,6 +400,26 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, } } + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: it’s OK even if index > self.range.len() because + // the iterations will yield None in this case. + assert!(index <= self.range.len()); + + let left_iter = ColumnIterMut { + mat: self.mat, + range: self.range.start..(self.range.start + index), + phantom: Default::default(), + }; + + let right_iter = ColumnIterMut { + mat: self.mat, + range: (self.range.start + index)..self.range.end, + phantom: Default::default(), + }; + + (left_iter, right_iter) + } + fn ncols(&self) -> usize { unsafe { (*self.mat).ncols() } } diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 2a8ca268..820c408a 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -14,7 +14,7 @@ use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. /// -/// *only availabe if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `par-iter`.* /// [`par_column_iter`]: crate::Matrix::par_column_iter /// [`Matrix`]: crate::Matrix #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] @@ -23,7 +23,7 @@ pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { } impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R, Cols, S> { - /// create a new parallel iterator for the given matrix + /// Create a new parallel iterator for the given matrix. fn new(matrix: &'a Matrix) -> Self { Self { mat: matrix } } @@ -51,7 +51,7 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *only availabe if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `par-iter`.* impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -76,8 +76,8 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// A rayon parallel iterator through the mutable columns of a matrix -/// *only availabe if compiled with the feature `par-iter`* +/// A rayon parallel iterator through the mutable columns of a matrix. +/// *Only available if compiled with the feature `par-iter`.* pub struct ParColumnIterMut< 'a, T, @@ -96,14 +96,14 @@ where Cols: Dim, S: RawStorage + RawStorageMut, { - /// create a new parallel iterator for the given matrix + /// create a new parallel iterator for the given matrix. fn new(mat: &'a mut Matrix) -> Self { Self { mat } } } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *only availabe if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `par-iter`* impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -126,7 +126,7 @@ where } #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *only availabe if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `par-iter`* impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -154,7 +154,7 @@ where #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] /// # Parallel iterators using `rayon` -/// *Only availabe if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `par-iter`* impl> Matrix where T: Send + Sync + Scalar, @@ -190,6 +190,7 @@ where pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { ParColumnIter::new(self) } + /// Mutably iterate through the columns of this matrix in parallel using rayon. /// Allows mutable access to the columns in parallel using mutable references. /// If mutable access to the columns is not required rather use [`par_column_iter`] @@ -221,9 +222,9 @@ where } } -/// a private helper newtype that wraps the `ColumnIter` and implements +/// A private helper newtype that wraps the `ColumnIter` and implements /// the rayon `Producer` trait. It's just here so we don't have to make the -/// rayon trait part of the public interface of the `ColumnIter` +/// rayon trait part of the public interface of the `ColumnIter`. struct ColumnProducer<'a, T, R: Dim, C: Dim, S: RawStorage>(ColumnIter<'a, T, R, C, S>); #[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] @@ -238,24 +239,16 @@ where type IntoIter = ColumnIter<'a, T, R, Cols, S>; #[inline] - fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset - let left_iter = ColumnIter { - mat: self.0.mat, - range: self.0.range.start..(self.0.range.start + index), - }; - - let right_iter = ColumnIter { - mat: self.0.mat, - range: (self.0.range.start + index)..self.0.range.end, - }; - (Self(left_iter), Self(right_iter)) + fn into_iter(self) -> Self::IntoIter { + self.0 } #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0 + fn split_at(self, index: usize) -> (Self, Self) { + // The index is relative to the size of this current iterator. + // It will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); + (Self(left_iter), Self(right_iter)) } } @@ -279,20 +272,9 @@ where } fn split_at(self, index: usize) -> (Self, Self) { - // the index is relative to the size of this current iterator - // it will always start at zero so it serves as an offset - - let left_iter = ColumnIterMut { - mat: self.0.mat, - range: self.0.range.start..(self.0.range.start + index), - phantom: Default::default(), - }; - - let right_iter = ColumnIterMut { - mat: self.0.mat, - range: (self.0.range.start + index)..self.0.range.end, - phantom: Default::default(), - }; + // The index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); (Self(left_iter), Self(right_iter)) } } diff --git a/tests/lib.rs b/tests/lib.rs index 6e4238e5..546aa8a7 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -9,10 +9,6 @@ compile_error!( Example: `cargo test --features debug,compare,rand,macros`" ); -// make sure to test the parallel iterators for all builds that do not require no_std -#[cfg(all(feature = "std", not(feature = "par-iter")))] -compile_error!("Please additionally enable the `par-iter` feature to compile and run the tests"); - #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] #[macro_use] extern crate approx; From d54c56fd4320f9e459435ec1ea24db6c0736ada2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 14 Jan 2023 15:37:12 +0100 Subject: [PATCH 32/34] Fix potential unsoundness in ColumnIter::split_at --- src/base/iter.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/base/iter.rs b/src/base/iter.rs index f213f096..0e4aa8d4 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -314,16 +314,17 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, } pub(crate) fn split_at(self, index: usize) -> (Self, Self) { - // SAFETY: it’s OK even if index > self.range.len() because - // the iterations will yield None in this case. + // SAFETY: this makes sur the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); + let left_iter = ColumnIter { mat: self.mat, - range: self.range.start..(self.range.start + index), + range: self.range.start..split_pos, }; let right_iter = ColumnIter { mat: self.mat, - range: (self.range.start + index)..self.range.end, + range: split_pos..self.range.end, }; (left_iter, right_iter) @@ -401,19 +402,18 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, } pub(crate) fn split_at(self, index: usize) -> (Self, Self) { - // SAFETY: it’s OK even if index > self.range.len() because - // the iterations will yield None in this case. - assert!(index <= self.range.len()); + // SAFETY: this makes sur the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); let left_iter = ColumnIterMut { mat: self.mat, - range: self.range.start..(self.range.start + index), + range: self.range.start..split_pos, phantom: Default::default(), }; let right_iter = ColumnIterMut { mat: self.mat, - range: (self.range.start + index)..self.range.end, + range: split_pos..self.range.end, phantom: Default::default(), }; From 82b496074068f25b59ecc8098bb42eab13bc9a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 14 Jan 2023 15:48:42 +0100 Subject: [PATCH 33/34] Better coding-style in the doc-tests. --- src/base/par_iter.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 820c408a..0f1202c9 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -169,20 +169,19 @@ where /// Using parallel column iterators to calculate the sum of the maximum /// elements in each column: /// ``` - /// use nalgebra::{dmatrix,DMatrix}; + /// use nalgebra::{dmatrix, DMatrix}; /// use rayon::prelude::*; /// - /// let matrix : DMatrix = - /// nalgebra::dmatrix![1.,0.,5.; - /// 2.,4.,1.; - /// 3.,2.,2.;]; - /// let sum_of_max :f64 = - /// matrix - /// .par_column_iter() - /// .map(|col|col.max()) - /// .sum(); + /// let matrix : DMatrix = dmatrix![1.0, 0.0, 5.0; + /// 2.0, 4.0, 1.0; + /// 3.0, 2.0, 2.0; + /// ]; + /// let sum_of_max :f64 = matrix + /// .par_column_iter() + /// .map(|col| col.max()) + /// .sum(); /// - /// assert_eq!(sum_of_max,3.+4.+5.); + /// assert_eq!(sum_of_max,3.0 + 4.0 + 5.0); /// /// ``` /// @@ -200,17 +199,16 @@ where /// Normalize each column of a matrix with respect to its own maximum value. /// /// ``` - /// use nalgebra::{dmatrix,DMatrix}; + /// use nalgebra::{dmatrix, DMatrix}; /// use rayon::prelude::*; /// - /// let mut matrix : DMatrix = - /// dmatrix![2.,4.,6.; - /// 1.,2.,3.]; + /// let mut matrix : DMatrix = dmatrix![ + /// 2.0, 4.0, 6.0; + /// 1.0, 2.0, 3.0; + /// ]; /// matrix.par_column_iter_mut().for_each(|mut col| col /= col.max()); /// - /// assert_eq!(matrix, - /// dmatrix![1. ,1. , 1.; - /// 0.5,0.5,0.5]); + /// assert_eq!(matrix, dmatrix![1.0, 1.0, 1.0; 0.5, 0.5, 0.5]); /// ``` /// /// [`par_column_iter`]: crate::Matrix::par_column_iter From 3a8c1bf81e56e37421f7f17cfeb5c48d69fe316c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 14 Jan 2023 15:59:11 +0100 Subject: [PATCH 34/34] Use rayon as the feature name instead of par-iter --- .github/workflows/nalgebra-ci-build.yml | 2 +- Cargo.toml | 2 +- src/base/mod.rs | 2 +- src/base/par_iter.rs | 34 ++++++++++++------------- tests/core/matrix.rs | 6 ++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index 665bd008..d7027127 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -61,7 +61,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,par-iter; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; test-nalgebra-glm: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index e7c6ba1e..82528ed4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] cuda = [ "cust_core", "simba/cuda" ] -par-iter = [ "std", "rayon" ] + # Conversion convert-mint = [ "mint" ] diff --git a/src/base/mod.rs b/src/base/mod.rs index 73fe18c3..0f09cc33 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,7 +42,7 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; -#[cfg(feature = "par-iter")] +#[cfg(feature = "rayon")] pub mod par_iter; #[cfg(feature = "rkyv-serialize-no-std")] diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs index 0f1202c9..af5e1cb7 100644 --- a/src/base/par_iter.rs +++ b/src/base/par_iter.rs @@ -14,10 +14,10 @@ use rayon::{iter::plumbing::bridge, prelude::*}; /// A rayon parallel iterator over the colums of a matrix. It is created /// using the [`par_column_iter`] method of [`Matrix`]. /// -/// *Only available if compiled with the feature `par-iter`.* +/// *Only available if compiled with the feature `rayon`.* /// [`par_column_iter`]: crate::Matrix::par_column_iter /// [`Matrix`]: crate::Matrix -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { mat: &'a Matrix, } @@ -29,7 +29,7 @@ impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -50,8 +50,8 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *Only available if compiled with the feature `par-iter`.* +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`.* impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator for ParColumnIter<'a, T, R, Cols, S> where @@ -75,9 +75,9 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] /// A rayon parallel iterator through the mutable columns of a matrix. -/// *Only available if compiled with the feature `par-iter`.* +/// *Only available if compiled with the feature `rayon`.* pub struct ParColumnIterMut< 'a, T, @@ -88,8 +88,8 @@ pub struct ParColumnIterMut< mat: &'a mut Matrix, } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *only availabe if compiled with the feature `par-iter`* +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only availabe if compiled with the feature `rayon`* impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -102,8 +102,8 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *Only available if compiled with the feature `par-iter`* +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -125,8 +125,8 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *Only available if compiled with the feature `par-iter`* +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> where R: Dim, @@ -152,9 +152,9 @@ where } } -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] /// # Parallel iterators using `rayon` -/// *Only available if compiled with the feature `par-iter`* +/// *Only available if compiled with the feature `rayon`* impl> Matrix where T: Send + Sync + Scalar, @@ -225,8 +225,8 @@ where /// rayon trait part of the public interface of the `ColumnIter`. struct ColumnProducer<'a, T, R: Dim, C: Dim, S: RawStorage>(ColumnIter<'a, T, R, C, S>); -#[cfg_attr(doc_cfg, doc(cfg(feature = "par-iter")))] -/// *only available if compiled with the feature `par-iter`* +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only available if compiled with the feature `rayon`* impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer for ColumnProducer<'a, T, R, Cols, S> where diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 41972347..27926a27 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1218,7 +1218,7 @@ fn column_iterator_double_ended_mut() { } #[test] -#[cfg(feature = "par-iter")] +#[cfg(feature = "rayon")] fn parallel_column_iteration() { use nalgebra::dmatrix; use rayon::prelude::*; @@ -1251,7 +1251,7 @@ fn parallel_column_iteration() { } #[test] -#[cfg(feature = "par-iter")] +#[cfg(feature = "rayon")] fn column_iteration_mut_double_ended() { let dmat = nalgebra::dmatrix![ 13,14,15,16,17; @@ -1270,7 +1270,7 @@ fn column_iteration_mut_double_ended() { } #[test] -#[cfg(feature = "par-iter")] +#[cfg(feature = "rayon")] fn parallel_column_iteration_mut() { use rayon::prelude::*; let mut first = DMatrix::::zeros(400, 300);