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] 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); +}