diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 8d2b3cd3a..95a78312e 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1884,10 +1884,84 @@ where } } + /// Transform the array into `shape`; any shape with the same number of + /// elements is accepted, but the source array must be contiguous. + /// + /// If an index ordering is not specified, the default is `RowMajor`. + /// The operation will only succeed if the array's memory layout is compatible with + /// the index ordering. + /// + /// Use `.to_shape()` instead for more flexible reshaping of arrays, which + /// allows copying elements if required. + /// + /// **Errors** if the shapes don't have the same number of elements.
+ /// **Errors** if order RowMajor is given but input is not c-contiguous. + /// **Errors** if order ColumnMajor is given but input is not f-contiguous. + /// + /// If shape is not given: use memory layout of incoming array. Row major arrays are + /// reshaped using row major index ordering, column major arrays with column major index + /// ordering. + /// + /// ``` + /// use ndarray::{aview1, aview2}; + /// use ndarray::Order; + /// + /// assert!( + /// aview1(&[1., 2., 3., 4.]).into_shape_with_order((2, 2)).unwrap() + /// == aview2(&[[1., 2.], + /// [3., 4.]]) + /// ); + /// + /// assert!( + /// aview1(&[1., 2., 3., 4.]).into_shape_with_order(((2, 2), Order::ColumnMajor)).unwrap() + /// == aview2(&[[1., 3.], + /// [2., 4.]]) + /// ); + /// ``` + pub fn into_shape_with_order(self, shape: E) -> Result, ShapeError> + where + E: ShapeArg, + { + let (shape, order) = shape.into_shape_and_order(); + self.into_shape_with_order_impl(shape, order.unwrap_or(Order::RowMajor)) + } + + fn into_shape_with_order_impl(self, shape: E, order: Order) + -> Result, ShapeError> + where + E: Dimension, + { + let shape = shape.into_dimension(); + if size_of_shape_checked(&shape) != Ok(self.dim.size()) { + return Err(error::incompatible_shapes(&self.dim, &shape)); + } + + // Check if contiguous, then we can change shape + unsafe { + // safe because arrays are contiguous and len is unchanged + match order { + Order::RowMajor if self.is_standard_layout() => { + Ok(self.with_strides_dim(shape.default_strides(), shape)) + } + Order::ColumnMajor if self.raw_view().reversed_axes().is_standard_layout() => { + Ok(self.with_strides_dim(shape.fortran_strides(), shape)) + } + _otherwise => Err(error::from_kind(error::ErrorKind::IncompatibleLayout)) + } + } + } + /// Transform the array into `shape`; any shape with the same number of /// elements is accepted, but the source array or view must be in standard /// or column-major (Fortran) layout. /// + /// **Note** that `.into_shape()` "moves" elements differently depending on if the input array + /// is C-contig or F-contig, it follows the index order that corresponds to the memory order. + /// Prefer to use `.to_shape()` or `.into_shape_with_order()`. + /// + /// Because of this, the method is deprecated. That reshapes depend on memory order is not + /// intuitive. + /// /// **Errors** if the shapes don't have the same number of elements.
/// **Errors** if the input array is not c- or f-contiguous. /// @@ -1900,6 +1974,7 @@ where /// [3., 4.]]) /// ); /// ``` + #[deprecated = "Use `.into_shape_with_order()` or `.to_shape()`"] pub fn into_shape(self, shape: E) -> Result, ShapeError> where E: IntoDimension, @@ -1932,7 +2007,7 @@ where self.into_shape_clone_order(shape, order) } - pub fn into_shape_clone_order(self, shape: E, order: Order) + fn into_shape_clone_order(self, shape: E, order: Order) -> Result, ShapeError> where S: DataOwned, @@ -2004,7 +2079,7 @@ where A: Clone, E: IntoDimension, { - return self.clone().into_shape_clone(shape).unwrap(); + //return self.clone().into_shape_clone(shape).unwrap(); let shape = shape.into_dimension(); if size_of_shape_checked(&shape) != Ok(self.dim.size()) { panic!( diff --git a/tests/reshape.rs b/tests/reshape.rs index 21fe407ea..52bb6e908 100644 --- a/tests/reshape.rs +++ b/tests/reshape.rs @@ -230,3 +230,41 @@ fn to_shape_broadcast() { } } } + + +#[test] +fn into_shape_with_order() { + // 1D -> C -> C + let data = [1, 2, 3, 4, 5, 6, 7, 8]; + let v = aview1(&data); + let u = v.into_shape_with_order(((3, 3), Order::RowMajor)); + assert!(u.is_err()); + + let u = v.into_shape_with_order(((2, 2, 2), Order::C)); + assert!(u.is_ok()); + + let u = u.unwrap(); + assert_eq!(u.shape(), &[2, 2, 2]); + assert_eq!(u, array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]]); + + let s = u.into_shape_with_order((4, 2)).unwrap(); + assert_eq!(s.shape(), &[4, 2]); + assert_eq!(s, aview2(&[[1, 2], [3, 4], [5, 6], [7, 8]])); + + // 1D -> F -> F + let data = [1, 2, 3, 4, 5, 6, 7, 8]; + let v = aview1(&data); + let u = v.into_shape_with_order(((3, 3), Order::ColumnMajor)); + assert!(u.is_err()); + + let u = v.into_shape_with_order(((2, 2, 2), Order::ColumnMajor)); + assert!(u.is_ok()); + + let u = u.unwrap(); + assert_eq!(u.shape(), &[2, 2, 2]); + assert_eq!(u, array![[[1, 5], [3, 7]], [[2, 6], [4, 8]]]); + + let s = u.into_shape_with_order(((4, 2), Order::ColumnMajor)).unwrap(); + assert_eq!(s.shape(), &[4, 2]); + assert_eq!(s, array![[1, 5], [2, 6], [3, 7], [4, 8]]); +}