diff --git a/Cargo.toml b/Cargo.toml index 2f4f8bb0a..d3445e69d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,10 @@ blas-src = { version = "0.2.0", optional = true, default-features = false } matrixmultiply = { version = "0.2.0" } # Use via the `serde-1` crate feature! serde = { version = "1.0", optional = true } +# Conversions from `nalgebra` 0.15 types with `nalgebra-0_15` crate feature! +nalgebra-crate-0_15 = { package = "nalgebra", version = "0.15", optional = true } +# Conversions from `nalgebra` 0.16 types with `nalgebra-0_16` crate feature! +nalgebra-crate-0_16 = { package = "nalgebra", version = "0.16", optional = true } [dev-dependencies] defmac = "0.2" @@ -49,6 +53,8 @@ quickcheck = { version = "0.7.2", default-features = false } rawpointer = "0.1" [features] +default = [] + # Enable blas usage # See README for more instructions blas = ["cblas-sys", "blas-src"] @@ -61,7 +67,11 @@ test-blas-openblas-sys = ["blas"] test = ["test-blas-openblas-sys"] # This feature is used for docs -docs = ["serde-1", "rayon"] +docs = ["serde-1", "rayon", "nalgebra-0_15", "nalgebra-0_16"] + +# Conversions from nalgebra types +nalgebra-0_15 = ["nalgebra-crate-0_15"] +nalgebra-0_16 = ["nalgebra-crate-0_16"] [profile.release] [profile.bench] diff --git a/README.rst b/README.rst index 1fa147a62..0ea5fab22 100644 --- a/README.rst +++ b/README.rst @@ -57,6 +57,16 @@ your `Cargo.toml`. - Optional, compatible with Rust stable - Enables parallel iterators, parallelized methods and ``par_azip!``. +- ``nalgebra-0_15`` + + - Optional, compatible with Rust stable + - Enables conversions from nalgebra 0.15 vectors/matrices + +- ``nalgebra-0_16`` + + - Optional, compatible with Rust stable + - Enables conversions from nalgebra 0.16 vectors/matrices + - ``blas`` - Optional and experimental, compatible with Rust stable diff --git a/src/convert_nalgebra_0_15.rs b/src/convert_nalgebra_0_15.rs new file mode 100644 index 000000000..e7ae7b251 --- /dev/null +++ b/src/convert_nalgebra_0_15.rs @@ -0,0 +1,296 @@ +use crate::dimension; +use crate::imp_prelude::*; +use nalgebra_crate_0_15 as na; +use std::isize; + +/// **Requires crate feature `"nalgebra-0_15"`** +impl From> for ArrayBase +where + A: na::Scalar, + R: na::Dim, + S1: na::storage::Storage, + S2: DataOwned, +{ + /// Converts the `nalgebra::Vector` to `ndarray::ArrayBase`. + /// + /// **Panics** if the number of elements overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::Vector3; + /// use ndarray::{array, Array1}; + /// + /// # fn main() { + /// let vector = Vector3::new(1, 2, 3); + /// let array = Array1::from(vector); + /// assert_eq!(array, array![1, 2, 3]); + /// # } + /// ``` + fn from(vector: na::Matrix) -> ArrayBase { + ArrayBase::from_vec(vector.iter().cloned().collect()) + } +} + +/// **Requires crate feature `"nalgebra-0_15"`** +impl<'a, A, R, RStride, CStride> From> + for ArrayView<'a, A, Ix1> +where + A: na::Scalar, + R: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the 1-D `nalgebra::MatrixSlice` to `ndarray::ArrayView`. + /// + /// **Panics** if the number of elements, row stride, or size in bytes + /// overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSlice3x1; + /// use ndarray::{array, ArrayView1}; + /// + /// # fn main() { + /// let slice = MatrixSlice3x1::from_slice(&[1, 2, 3]); + /// let view = ArrayView1::from(slice); + /// assert_eq!(view, array![1, 2, 3]); + /// # } + /// ``` + fn from(slice: na::MatrixSlice<'a, A, R, na::U1, RStride, CStride>) -> ArrayView<'a, A, Ix1> { + if slice.is_empty() { + ArrayView::from(&[]) + } else { + let dim = Dim(slice.shape().0); + let strides = Dim(slice.strides().0); + ndassert!( + strides[0] <= isize::MAX as usize, + "stride {} must not exceed `isize::MAX`", + strides[0], + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides) + .expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`"); + unsafe { ArrayView::from_shape_ptr(dim.strides(strides), slice.get_unchecked(0, 0)) } + } + } +} + +/// **Requires crate feature `"nalgebra-0_15"`** +impl<'a, A, R, RStride, CStride> From> + for ArrayViewMut<'a, A, Ix1> +where + A: na::Scalar, + R: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the 1-D `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`. + /// + /// **Panics** if the number of elements, row stride, or size in bytes + /// overflows `isize`. Also panics if the row stride is zero when there is + /// more than one row. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSliceMut3x1; + /// use ndarray::{array, ArrayViewMut1}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let mut data = [1, 2, 3]; + /// let slice = MatrixSliceMut3x1::from_slice(&mut data); + /// let view = ArrayViewMut1::from(slice); + /// assert_eq!(view, array![1, 2, 3]); + /// # } + /// ``` + fn from( + mut slice: na::MatrixSliceMut<'a, A, R, na::U1, RStride, CStride>, + ) -> ArrayViewMut<'a, A, Ix1> { + if slice.is_empty() { + ArrayViewMut::from(&mut []) + } else { + let dim = Dim(slice.shape().0); + let strides = Dim(slice.strides().0); + ndassert!( + strides[0] <= isize::MAX as usize, + "stride {} must not exceed `isize::MAX`", + strides[0], + ); + // `nalgebra` should prevent this ever being violated but currently + // doesn't (rustsim/nalgebra#473). + ndassert!( + dim[0] <= 1 || strides[0] != 0, + "stride {} must be nonzero when axis length {} is > 1", + strides[0], + dim[0], + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides).expect( + "overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`", + ); + unsafe { + ArrayViewMut::from_shape_ptr(dim.strides(strides), slice.get_unchecked_mut(0, 0)) + } + } + } +} + +/// **Requires crate feature `"nalgebra-0_15"`** +impl From> for ArrayBase +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + S1: na::storage::Storage, + S2: DataOwned, +{ + /// Converts the `nalgebra::Matrix` to `ndarray::ArrayBase`. + /// + /// **Panics** if the number of rows, columns, or elements overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::Matrix2x3; + /// use ndarray::{array, Array2}; + /// + /// # fn main() { + /// let matrix = Matrix2x3::new(1, 2, 3, 4, 5, 6); + /// let array = Array2::from(matrix); + /// assert_eq!(array, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from(matrix: na::Matrix) -> ArrayBase { + let (rows, cols) = matrix.shape(); + ArrayBase::from_shape_vec((cols, rows), matrix.iter().cloned().collect()) + .expect("convert `nalgebra::Matrix` to `ndarray::ArrayBase`") + .reversed_axes() + } +} + +/// **Requires crate feature `"nalgebra-0_15"`** +impl<'a, A, R, C, RStride, CStride> From> + for ArrayView<'a, A, Ix2> +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the `nalgebra::MatrixSlice` to `ndarray::ArrayView`. + /// + /// **Panics** if the number of rows, number of columns, row stride, column + /// stride, number of elements, or size in bytes overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSlice2x3; + /// use ndarray::{array, ArrayView2}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let slice = MatrixSlice2x3::from_slice(&[1, 4, 2, 5, 3, 6]); + /// let view = ArrayView2::from(slice); + /// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from(slice: na::MatrixSlice<'a, A, R, C, RStride, CStride>) -> ArrayView<'a, A, Ix2> { + if slice.is_empty() { + ArrayView::from_shape(slice.shape(), &[]).unwrap() + } else { + let dim = Dim(slice.shape()); + let strides = Dim(slice.strides()); + ndassert!( + strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize, + "strides {:?} must not exceed `isize::MAX`", + strides, + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides) + .expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`"); + unsafe { ArrayView::from_shape_ptr(dim.strides(strides), slice.get_unchecked(0, 0)) } + } + } +} + +/// **Requires crate feature `"nalgebra-0_15"`** +impl<'a, A, R, C, RStride, CStride> From> + for ArrayViewMut<'a, A, Ix2> +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`. + /// + /// **Panics** if the number of rows, number of columns, row stride, column + /// stride, number of elements, or size in bytes overflows `isize`. Also + /// panics if the row stride or column stride is zero when the length of + /// the corresponding axis is greater than one. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_15 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSliceMut2x3; + /// use ndarray::{array, ArrayViewMut2}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let mut data = [1, 4, 2, 5, 3, 6]; + /// let slice = MatrixSliceMut2x3::from_slice(&mut data); + /// let view = ArrayViewMut2::from(slice); + /// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from( + mut slice: na::MatrixSliceMut<'a, A, R, C, RStride, CStride>, + ) -> ArrayViewMut<'a, A, Ix2> { + if slice.is_empty() { + ArrayViewMut::from_shape(slice.shape(), &mut []).unwrap() + } else { + let dim = Dim(slice.shape()); + let strides = Dim(slice.strides()); + ndassert!( + strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize, + "strides {:?} must not exceed `isize::MAX`", + strides, + ); + // `nalgebra` should prevent this ever being violated but currently + // doesn't (rustsim/nalgebra#473). + ndassert!( + (dim[0] <= 1 || strides[0] != 0) && (dim[1] <= 1 || strides[1] != 0), + "strides {:?} must be nonzero when corresponding lengths {:?} are > 1", + strides, + dim, + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides).expect( + "overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`", + ); + unsafe { + ArrayViewMut::from_shape_ptr(dim.strides(strides), slice.get_unchecked_mut(0, 0)) + } + } + } +} diff --git a/src/convert_nalgebra_0_16.rs b/src/convert_nalgebra_0_16.rs new file mode 100644 index 000000000..112083a46 --- /dev/null +++ b/src/convert_nalgebra_0_16.rs @@ -0,0 +1,296 @@ +use crate::dimension; +use crate::imp_prelude::*; +use nalgebra_crate_0_16 as na; +use std::isize; + +/// **Requires crate feature `"nalgebra-0_16"`** +impl From> for ArrayBase +where + A: na::Scalar, + R: na::Dim, + S1: na::storage::Storage, + S2: DataOwned, +{ + /// Converts the `nalgebra::Vector` to `ndarray::ArrayBase`. + /// + /// **Panics** if the number of elements overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::Vector3; + /// use ndarray::{array, Array1}; + /// + /// # fn main() { + /// let vector = Vector3::new(1, 2, 3); + /// let array = Array1::from(vector); + /// assert_eq!(array, array![1, 2, 3]); + /// # } + /// ``` + fn from(vector: na::Matrix) -> ArrayBase { + ArrayBase::from_vec(vector.iter().cloned().collect()) + } +} + +/// **Requires crate feature `"nalgebra-0_16"`** +impl<'a, A, R, RStride, CStride> From> + for ArrayView<'a, A, Ix1> +where + A: na::Scalar, + R: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the 1-D `nalgebra::MatrixSlice` to `ndarray::ArrayView`. + /// + /// **Panics** if the number of elements, row stride, or size in bytes + /// overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSlice3x1; + /// use ndarray::{array, ArrayView1}; + /// + /// # fn main() { + /// let slice = MatrixSlice3x1::from_slice(&[1, 2, 3]); + /// let view = ArrayView1::from(slice); + /// assert_eq!(view, array![1, 2, 3]); + /// # } + /// ``` + fn from(slice: na::MatrixSlice<'a, A, R, na::U1, RStride, CStride>) -> ArrayView<'a, A, Ix1> { + if slice.is_empty() { + ArrayView::from(&[]) + } else { + let dim = Dim(slice.shape().0); + let strides = Dim(slice.strides().0); + ndassert!( + strides[0] <= isize::MAX as usize, + "stride {} must not exceed `isize::MAX`", + strides[0], + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides) + .expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`"); + unsafe { ArrayView::from_shape_ptr(dim.strides(strides), slice.get_unchecked(0, 0)) } + } + } +} + +/// **Requires crate feature `"nalgebra-0_16"`** +impl<'a, A, R, RStride, CStride> From> + for ArrayViewMut<'a, A, Ix1> +where + A: na::Scalar, + R: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the 1-D `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`. + /// + /// **Panics** if the number of elements, row stride, or size in bytes + /// overflows `isize`. Also panics if the row stride is zero when there is + /// more than one row. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSliceMut3x1; + /// use ndarray::{array, ArrayViewMut1}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let mut data = [1, 2, 3]; + /// let slice = MatrixSliceMut3x1::from_slice(&mut data); + /// let view = ArrayViewMut1::from(slice); + /// assert_eq!(view, array![1, 2, 3]); + /// # } + /// ``` + fn from( + mut slice: na::MatrixSliceMut<'a, A, R, na::U1, RStride, CStride>, + ) -> ArrayViewMut<'a, A, Ix1> { + if slice.is_empty() { + ArrayViewMut::from(&mut []) + } else { + let dim = Dim(slice.shape().0); + let strides = Dim(slice.strides().0); + ndassert!( + strides[0] <= isize::MAX as usize, + "stride {} must not exceed `isize::MAX`", + strides[0], + ); + // `nalgebra` should prevent this ever being violated but currently + // doesn't (rustsim/nalgebra#473). + ndassert!( + dim[0] <= 1 || strides[0] != 0, + "stride {} must be nonzero when axis length {} is > 1", + strides[0], + dim[0], + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides).expect( + "overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`", + ); + unsafe { + ArrayViewMut::from_shape_ptr(dim.strides(strides), slice.get_unchecked_mut(0, 0)) + } + } + } +} + +/// **Requires crate feature `"nalgebra-0_16"`** +impl From> for ArrayBase +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + S1: na::storage::Storage, + S2: DataOwned, +{ + /// Converts the `nalgebra::Matrix` to `ndarray::ArrayBase`. + /// + /// **Panics** if the number of rows, columns, or elements overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::Matrix2x3; + /// use ndarray::{array, Array2}; + /// + /// # fn main() { + /// let matrix = Matrix2x3::new(1, 2, 3, 4, 5, 6); + /// let array = Array2::from(matrix); + /// assert_eq!(array, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from(matrix: na::Matrix) -> ArrayBase { + let (rows, cols) = matrix.shape(); + ArrayBase::from_shape_vec((cols, rows), matrix.iter().cloned().collect()) + .expect("convert `nalgebra::Matrix` to `ndarray::ArrayBase`") + .reversed_axes() + } +} + +/// **Requires crate feature `"nalgebra-0_16"`** +impl<'a, A, R, C, RStride, CStride> From> + for ArrayView<'a, A, Ix2> +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the `nalgebra::MatrixSlice` to `ndarray::ArrayView`. + /// + /// **Panics** if the number of rows, number of columns, row stride, column + /// stride, number of elements, or size in bytes overflows `isize`. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSlice2x3; + /// use ndarray::{array, ArrayView2}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let slice = MatrixSlice2x3::from_slice(&[1, 4, 2, 5, 3, 6]); + /// let view = ArrayView2::from(slice); + /// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from(slice: na::MatrixSlice<'a, A, R, C, RStride, CStride>) -> ArrayView<'a, A, Ix2> { + if slice.is_empty() { + ArrayView::from_shape(slice.shape(), &[]).unwrap() + } else { + let dim = Dim(slice.shape()); + let strides = Dim(slice.strides()); + ndassert!( + strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize, + "strides {:?} must not exceed `isize::MAX`", + strides, + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides) + .expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`"); + unsafe { ArrayView::from_shape_ptr(dim.strides(strides), slice.get_unchecked(0, 0)) } + } + } +} + +/// **Requires crate feature `"nalgebra-0_16"`** +impl<'a, A, R, C, RStride, CStride> From> + for ArrayViewMut<'a, A, Ix2> +where + A: na::Scalar, + R: na::Dim, + C: na::Dim, + RStride: na::Dim, + CStride: na::Dim, +{ + /// Converts the `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`. + /// + /// **Panics** if the number of rows, number of columns, row stride, column + /// stride, number of elements, or size in bytes overflows `isize`. Also + /// panics if the row stride or column stride is zero when the length of + /// the corresponding axis is greater than one. + /// + /// # Example + /// + /// ``` + /// # extern crate nalgebra_crate_0_16 as nalgebra; + /// # extern crate ndarray; + /// + /// use nalgebra::MatrixSliceMut2x3; + /// use ndarray::{array, ArrayViewMut2}; + /// + /// # fn main() { + /// // `from_slice` assumes column-major memory layout. + /// let mut data = [1, 4, 2, 5, 3, 6]; + /// let slice = MatrixSliceMut2x3::from_slice(&mut data); + /// let view = ArrayViewMut2::from(slice); + /// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]); + /// # } + /// ``` + fn from( + mut slice: na::MatrixSliceMut<'a, A, R, C, RStride, CStride>, + ) -> ArrayViewMut<'a, A, Ix2> { + if slice.is_empty() { + ArrayViewMut::from_shape(slice.shape(), &mut []).unwrap() + } else { + let dim = Dim(slice.shape()); + let strides = Dim(slice.strides()); + ndassert!( + strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize, + "strides {:?} must not exceed `isize::MAX`", + strides, + ); + // `nalgebra` should prevent this ever being violated but currently + // doesn't (rustsim/nalgebra#473). + ndassert!( + (dim[0] <= 1 || strides[0] != 0) && (dim[1] <= 1 || strides[1] != 0), + "strides {:?} must be nonzero when corresponding lengths {:?} are > 1", + strides, + dim, + ); + dimension::max_abs_offset_check_overflow::(&dim, &strides).expect( + "overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`", + ); + unsafe { + ArrayViewMut::from_shape_ptr(dim.strides(strides), slice.get_unchecked_mut(0, 0)) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index d998be49f..5b758e6db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,12 @@ extern crate serde; #[cfg(feature="rayon")] extern crate rayon; +#[cfg(feature = "nalgebra-0_15")] +extern crate nalgebra_crate_0_15; + +#[cfg(feature = "nalgebra-0_16")] +extern crate nalgebra_crate_0_16; + #[cfg(feature="blas")] extern crate cblas_sys; #[cfg(feature="blas")] @@ -146,6 +152,10 @@ mod aliases; mod arraytraits; #[cfg(feature = "serde-1")] mod array_serde; +#[cfg(feature = "nalgebra-0_15")] +mod convert_nalgebra_0_15; +#[cfg(feature = "nalgebra-0_16")] +mod convert_nalgebra_0_16; mod arrayformat; mod data_traits;