kn0sys_ndarray/impl_methods.rs
1// Copyright 2014-2016 bluss and ndarray developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use alloc::slice;
10use alloc::vec;
11#[cfg(not(feature = "std"))]
12use alloc::vec::Vec;
13#[allow(unused_imports)]
14use rawpointer::PointerExt;
15use std::mem::{size_of, ManuallyDrop};
16
17use crate::imp_prelude::*;
18
19use crate::argument_traits::AssignElem;
20use crate::dimension;
21use crate::dimension::broadcast::co_broadcast;
22use crate::dimension::reshape_dim;
23use crate::dimension::IntoDimension;
24use crate::dimension::{
25 abs_index,
26 axes_of,
27 do_slice,
28 merge_axes,
29 move_min_stride_axis_to_last,
30 offset_from_low_addr_ptr_to_logical_ptr,
31 size_of_shape_checked,
32 stride_offset,
33 Axes,
34};
35use crate::error::{self, from_kind, ErrorKind, ShapeError};
36use crate::itertools::zip;
37use crate::math_cell::MathCell;
38use crate::order::Order;
39use crate::shape_builder::ShapeArg;
40use crate::zip::{IntoNdProducer, Zip};
41use crate::AxisDescription;
42use crate::{arraytraits, DimMax};
43
44use crate::iter::{
45 AxisChunksIter,
46 AxisChunksIterMut,
47 AxisIter,
48 AxisIterMut,
49 AxisWindows,
50 ExactChunks,
51 ExactChunksMut,
52 IndexedIter,
53 IndexedIterMut,
54 Iter,
55 IterMut,
56 Lanes,
57 LanesMut,
58 Windows,
59};
60use crate::slice::{MultiSliceArg, SliceArg};
61use crate::stacking::concatenate;
62use crate::{NdIndex, Slice, SliceInfoElem};
63
64/// # Methods For All Array Types
65impl<A, S, D> ArrayBase<S, D>
66where
67 S: RawData<Elem = A>,
68 D: Dimension,
69{
70 /// Return the total number of elements in the array.
71 pub fn len(&self) -> usize
72 {
73 self.dim.size()
74 }
75
76 /// Return the length of `axis`.
77 ///
78 /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
79 /// number of dimensions (axes) of the array.
80 ///
81 /// ***Panics*** if the axis is out of bounds.
82 #[track_caller]
83 pub fn len_of(&self, axis: Axis) -> usize
84 {
85 self.dim[axis.index()]
86 }
87
88 /// Return whether the array has any elements
89 pub fn is_empty(&self) -> bool
90 {
91 self.len() == 0
92 }
93
94 /// Return the number of dimensions (axes) in the array
95 pub fn ndim(&self) -> usize
96 {
97 self.dim.ndim()
98 }
99
100 /// Return the shape of the array in its “pattern” form,
101 /// an integer in the one-dimensional case, tuple in the n-dimensional cases
102 /// and so on.
103 pub fn dim(&self) -> D::Pattern
104 {
105 self.dim.clone().into_pattern()
106 }
107
108 /// Return the shape of the array as it's stored in the array.
109 ///
110 /// This is primarily useful for passing to other `ArrayBase`
111 /// functions, such as when creating another array of the same
112 /// shape and dimensionality.
113 ///
114 /// ```
115 /// use kn0sys_ndarray::Array;
116 ///
117 /// let a = Array::from_elem((2, 3), 5.);
118 ///
119 /// // Create an array of zeros that's the same shape and dimensionality as `a`.
120 /// let b = Array::<f64, _>::zeros(a.raw_dim());
121 /// ```
122 pub fn raw_dim(&self) -> D
123 {
124 self.dim.clone()
125 }
126
127 /// Return the shape of the array as a slice.
128 ///
129 /// Note that you probably don't want to use this to create an array of the
130 /// same shape as another array because creating an array with e.g.
131 /// [`Array::zeros()`](ArrayBase::zeros) using a shape of type `&[usize]`
132 /// results in a dynamic-dimensional array. If you want to create an array
133 /// that has the same shape and dimensionality as another array, use
134 /// [`.raw_dim()`](ArrayBase::raw_dim) instead:
135 ///
136 /// ```rust
137 /// use kn0sys_ndarray::{Array, Array2};
138 ///
139 /// let a = Array2::<i32>::zeros((3, 4));
140 /// let shape = a.shape();
141 /// assert_eq!(shape, &[3, 4]);
142 ///
143 /// // Since `a.shape()` returned `&[usize]`, we get an `ArrayD` instance:
144 /// let b = Array::zeros(shape);
145 /// assert_eq!(a.clone().into_dyn(), b);
146 ///
147 /// // To get the same dimension type, use `.raw_dim()` instead:
148 /// let c = Array::zeros(a.raw_dim());
149 /// assert_eq!(a, c);
150 /// ```
151 pub fn shape(&self) -> &[usize]
152 {
153 self.dim.slice()
154 }
155
156 /// Return the strides of the array as a slice.
157 pub fn strides(&self) -> &[isize]
158 {
159 let s = self.strides.slice();
160 // reinterpret unsigned integer as signed
161 unsafe { slice::from_raw_parts(s.as_ptr() as *const _, s.len()) }
162 }
163
164 /// Return the stride of `axis`.
165 ///
166 /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
167 /// number of dimensions (axes) of the array.
168 ///
169 /// ***Panics*** if the axis is out of bounds.
170 #[track_caller]
171 pub fn stride_of(&self, axis: Axis) -> isize
172 {
173 // strides are reinterpreted as isize
174 self.strides[axis.index()] as isize
175 }
176
177 /// Return a read-only view of the array
178 pub fn view(&self) -> ArrayView<'_, A, D>
179 where S: Data
180 {
181 debug_assert!(self.pointer_is_inbounds());
182 unsafe { ArrayView::new(self.ptr, self.dim.clone(), self.strides.clone()) }
183 }
184
185 /// Return a read-write view of the array
186 pub fn view_mut(&mut self) -> ArrayViewMut<'_, A, D>
187 where S: DataMut
188 {
189 self.ensure_unique();
190 unsafe { ArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) }
191 }
192
193 /// Return a shared view of the array with elements as if they were embedded in cells.
194 ///
195 /// The cell view requires a mutable borrow of the array. Once borrowed the
196 /// cell view itself can be copied and accessed without exclusivity.
197 ///
198 /// The view acts "as if" the elements are temporarily in cells, and elements
199 /// can be changed through shared references using the regular cell methods.
200 pub fn cell_view(&mut self) -> ArrayView<'_, MathCell<A>, D>
201 where S: DataMut
202 {
203 self.view_mut().into_cell_view()
204 }
205
206 /// Return an uniquely owned copy of the array.
207 ///
208 /// If the input array is contiguous, then the output array will have the same
209 /// memory layout. Otherwise, the layout of the output array is unspecified.
210 /// If you need a particular layout, you can allocate a new array with the
211 /// desired memory layout and [`.assign()`](Self::assign) the data.
212 /// Alternatively, you can collectan iterator, like this for a result in
213 /// standard layout:
214 ///
215 /// ```
216 /// # use kn0sys_ndarray::prelude::*;
217 /// # let arr = Array::from_shape_vec((2, 2).f(), vec![1, 2, 3, 4]).unwrap();
218 /// # let owned = {
219 /// Array::from_shape_vec(arr.raw_dim(), arr.iter().cloned().collect()).unwrap()
220 /// # };
221 /// # assert!(owned.is_standard_layout());
222 /// # assert_eq!(arr, owned);
223 /// ```
224 ///
225 /// or this for a result in column-major (Fortran) layout:
226 ///
227 /// ```
228 /// # use kn0sys_ndarray::prelude::*;
229 /// # let arr = Array::from_shape_vec((2, 2), vec![1, 2, 3, 4]).unwrap();
230 /// # let owned = {
231 /// Array::from_shape_vec(arr.raw_dim().f(), arr.t().iter().cloned().collect()).unwrap()
232 /// # };
233 /// # assert!(owned.t().is_standard_layout());
234 /// # assert_eq!(arr, owned);
235 /// ```
236 pub fn to_owned(&self) -> Array<A, D>
237 where
238 A: Clone,
239 S: Data,
240 {
241 if let Some(slc) = self.as_slice_memory_order() {
242 unsafe { Array::from_shape_vec_unchecked(self.dim.clone().strides(self.strides.clone()), slc.to_vec()) }
243 } else {
244 self.map(A::clone)
245 }
246 }
247
248 /// Return a shared ownership (copy on write) array, cloning the array
249 /// elements if necessary.
250 pub fn to_shared(&self) -> ArcArray<A, D>
251 where
252 A: Clone,
253 S: Data,
254 {
255 S::to_shared(self)
256 }
257
258 /// Turn the array into a uniquely owned array, cloning the array elements
259 /// if necessary.
260 pub fn into_owned(self) -> Array<A, D>
261 where
262 A: Clone,
263 S: Data,
264 {
265 S::into_owned(self)
266 }
267
268 /// Converts the array into `Array<A, D>` if this is possible without
269 /// cloning the array elements. Otherwise, returns `self` unchanged.
270 ///
271 /// ```
272 /// use kn0sys_ndarray::{array, rcarr2, ArcArray2, Array2};
273 ///
274 /// // Reference-counted, clone-on-write `ArcArray`.
275 /// let a: ArcArray2<_> = rcarr2(&[[1., 2.], [3., 4.]]);
276 /// {
277 /// // Another reference to the same data.
278 /// let b: ArcArray2<_> = a.clone();
279 /// // Since there are two references to the same data, `.into_owned()`
280 /// // would require cloning the data, so `.try_into_owned_nocopy()`
281 /// // returns `Err`.
282 /// assert!(b.try_into_owned_nocopy().is_err());
283 /// }
284 /// // Here, since the second reference has been dropped, the `ArcArray`
285 /// // can be converted into an `Array` without cloning the data.
286 /// let unique: Array2<_> = a.try_into_owned_nocopy().unwrap();
287 /// assert_eq!(unique, array![[1., 2.], [3., 4.]]);
288 /// ```
289 pub fn try_into_owned_nocopy(self) -> Result<Array<A, D>, Self>
290 where S: Data
291 {
292 S::try_into_owned_nocopy(self)
293 }
294
295 /// Turn the array into a shared ownership (copy on write) array,
296 /// cloning the array elements if necessary.
297 ///
298 /// If you want to generalize over `Array` and `ArcArray` inputs but avoid
299 /// an `A: Clone` bound, use `Into::<ArcArray<A, D>>::into` instead of this
300 /// method.
301 pub fn into_shared(self) -> ArcArray<A, D>
302 where
303 A: Clone,
304 S: DataOwned,
305 {
306 S::into_shared(self)
307 }
308
309 /// Returns a reference to the first element of the array, or `None` if it
310 /// is empty.
311 ///
312 /// # Example
313 ///
314 /// ```rust
315 /// use kn0sys_ndarray::Array3;
316 ///
317 /// let mut a = Array3::<f64>::zeros([3, 4, 2]);
318 /// a[[0, 0, 0]] = 42.;
319 /// assert_eq!(a.first(), Some(&42.));
320 ///
321 /// let b = Array3::<f64>::zeros([3, 0, 5]);
322 /// assert_eq!(b.first(), None);
323 /// ```
324 pub fn first(&self) -> Option<&A>
325 where S: Data
326 {
327 if self.is_empty() {
328 None
329 } else {
330 Some(unsafe { &*self.as_ptr() })
331 }
332 }
333
334 /// Returns a mutable reference to the first element of the array, or
335 /// `None` if it is empty.
336 ///
337 /// # Example
338 ///
339 /// ```rust
340 /// use kn0sys_ndarray::Array3;
341 ///
342 /// let mut a = Array3::<f64>::zeros([3, 4, 2]);
343 /// *a.first_mut().unwrap() = 42.;
344 /// assert_eq!(a[[0, 0, 0]], 42.);
345 ///
346 /// let mut b = Array3::<f64>::zeros([3, 0, 5]);
347 /// assert_eq!(b.first_mut(), None);
348 /// ```
349 pub fn first_mut(&mut self) -> Option<&mut A>
350 where S: DataMut
351 {
352 if self.is_empty() {
353 None
354 } else {
355 Some(unsafe { &mut *self.as_mut_ptr() })
356 }
357 }
358
359 /// Returns a reference to the last element of the array, or `None` if it
360 /// is empty.
361 ///
362 /// # Example
363 ///
364 /// ```rust
365 /// use kn0sys_ndarray::Array3;
366 ///
367 /// let mut a = Array3::<f64>::zeros([3, 4, 2]);
368 /// a[[2, 3, 1]] = 42.;
369 /// assert_eq!(a.last(), Some(&42.));
370 ///
371 /// let b = Array3::<f64>::zeros([3, 0, 5]);
372 /// assert_eq!(b.last(), None);
373 /// ```
374 pub fn last(&self) -> Option<&A>
375 where S: Data
376 {
377 if self.is_empty() {
378 None
379 } else {
380 let mut index = self.raw_dim();
381 for ax in 0..index.ndim() {
382 index[ax] -= 1;
383 }
384 Some(unsafe { self.uget(index) })
385 }
386 }
387
388 /// Returns a mutable reference to the last element of the array, or `None`
389 /// if it is empty.
390 ///
391 /// # Example
392 ///
393 /// ```rust
394 /// use kn0sys_ndarray::Array3;
395 ///
396 /// let mut a = Array3::<f64>::zeros([3, 4, 2]);
397 /// *a.last_mut().unwrap() = 42.;
398 /// assert_eq!(a[[2, 3, 1]], 42.);
399 ///
400 /// let mut b = Array3::<f64>::zeros([3, 0, 5]);
401 /// assert_eq!(b.last_mut(), None);
402 /// ```
403 pub fn last_mut(&mut self) -> Option<&mut A>
404 where S: DataMut
405 {
406 if self.is_empty() {
407 None
408 } else {
409 self.ensure_unique();
410 let mut index = self.raw_dim();
411 for ax in 0..index.ndim() {
412 index[ax] -= 1;
413 }
414 Some(unsafe { self.uget_mut(index) })
415 }
416 }
417
418 /// Return an iterator of references to the elements of the array.
419 ///
420 /// Elements are visited in the *logical order* of the array, which
421 /// is where the rightmost index is varying the fastest.
422 ///
423 /// Iterator element type is `&A`.
424 pub fn iter(&self) -> Iter<'_, A, D>
425 where S: Data
426 {
427 debug_assert!(self.pointer_is_inbounds());
428 self.view().into_iter_()
429 }
430
431 /// Return an iterator of mutable references to the elements of the array.
432 ///
433 /// Elements are visited in the *logical order* of the array, which
434 /// is where the rightmost index is varying the fastest.
435 ///
436 /// Iterator element type is `&mut A`.
437 pub fn iter_mut(&mut self) -> IterMut<'_, A, D>
438 where S: DataMut
439 {
440 self.view_mut().into_iter_()
441 }
442
443 /// Return an iterator of indexes and references to the elements of the array.
444 ///
445 /// Elements are visited in the *logical order* of the array, which
446 /// is where the rightmost index is varying the fastest.
447 ///
448 /// Iterator element type is `(D::Pattern, &A)`.
449 ///
450 /// See also [`Zip::indexed`]
451 pub fn indexed_iter(&self) -> IndexedIter<'_, A, D>
452 where S: Data
453 {
454 IndexedIter::new(self.view().into_elements_base())
455 }
456
457 /// Return an iterator of indexes and mutable references to the elements of the array.
458 ///
459 /// Elements are visited in the *logical order* of the array, which
460 /// is where the rightmost index is varying the fastest.
461 ///
462 /// Iterator element type is `(D::Pattern, &mut A)`.
463 pub fn indexed_iter_mut(&mut self) -> IndexedIterMut<'_, A, D>
464 where S: DataMut
465 {
466 IndexedIterMut::new(self.view_mut().into_elements_base())
467 }
468
469 /// Return a sliced view of the array.
470 ///
471 /// See [*Slicing*](#slicing) for full documentation.
472 /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo).
473 ///
474 /// **Panics** if an index is out of bounds or step size is zero.<br>
475 /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.)
476 #[track_caller]
477 pub fn slice<I>(&self, info: I) -> ArrayView<'_, A, I::OutDim>
478 where
479 I: SliceArg<D>,
480 S: Data,
481 {
482 self.view().slice_move(info)
483 }
484
485 /// Return a sliced read-write view of the array.
486 ///
487 /// See [*Slicing*](#slicing) for full documentation.
488 /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo).
489 ///
490 /// **Panics** if an index is out of bounds or step size is zero.<br>
491 /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.)
492 #[track_caller]
493 pub fn slice_mut<I>(&mut self, info: I) -> ArrayViewMut<'_, A, I::OutDim>
494 where
495 I: SliceArg<D>,
496 S: DataMut,
497 {
498 self.view_mut().slice_move(info)
499 }
500
501 /// Return multiple disjoint, sliced, mutable views of the array.
502 ///
503 /// See [*Slicing*](#slicing) for full documentation. See also
504 /// [`MultiSliceArg`], [`s!`], [`SliceArg`], and
505 /// [`SliceInfo`](crate::SliceInfo).
506 ///
507 /// **Panics** if any of the following occur:
508 ///
509 /// * if any of the views would intersect (i.e. if any element would appear in multiple slices)
510 /// * if an index is out of bounds or step size is zero
511 /// * if `D` is `IxDyn` and `info` does not match the number of array axes
512 ///
513 /// # Example
514 ///
515 /// ```
516 /// use kn0sys_ndarray::{arr2, s};
517 ///
518 /// let mut a = arr2(&[[1, 2, 3], [4, 5, 6]]);
519 /// let (mut edges, mut middle) = a.multi_slice_mut((s![.., ..;2], s![.., 1]));
520 /// edges.fill(1);
521 /// middle.fill(0);
522 /// assert_eq!(a, arr2(&[[1, 0, 1], [1, 0, 1]]));
523 /// ```
524 #[track_caller]
525 pub fn multi_slice_mut<'a, M>(&'a mut self, info: M) -> M::Output
526 where
527 M: MultiSliceArg<'a, A, D>,
528 S: DataMut,
529 {
530 info.multi_slice_move(self.view_mut())
531 }
532
533 /// Slice the array, possibly changing the number of dimensions.
534 ///
535 /// See [*Slicing*](#slicing) for full documentation.
536 /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo).
537 ///
538 /// **Panics** if an index is out of bounds or step size is zero.<br>
539 /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.)
540 #[track_caller]
541 pub fn slice_move<I>(mut self, info: I) -> ArrayBase<S, I::OutDim>
542 where I: SliceArg<D>
543 {
544 assert_eq!(
545 info.in_ndim(),
546 self.ndim(),
547 "The input dimension of `info` must match the array to be sliced.",
548 );
549 let out_ndim = info.out_ndim();
550 let mut new_dim = I::OutDim::zeros(out_ndim);
551 let mut new_strides = I::OutDim::zeros(out_ndim);
552
553 let mut old_axis = 0;
554 let mut new_axis = 0;
555 info.as_ref().iter().for_each(|&ax_info| match ax_info {
556 SliceInfoElem::Slice { start, end, step } => {
557 // Slice the axis in-place to update the `dim`, `strides`, and `ptr`.
558 self.slice_axis_inplace(Axis(old_axis), Slice { start, end, step });
559 // Copy the sliced dim and stride to corresponding axis.
560 new_dim[new_axis] = self.dim[old_axis];
561 new_strides[new_axis] = self.strides[old_axis];
562 old_axis += 1;
563 new_axis += 1;
564 }
565 SliceInfoElem::Index(index) => {
566 // Collapse the axis in-place to update the `ptr`.
567 let i_usize = abs_index(self.len_of(Axis(old_axis)), index);
568 self.collapse_axis(Axis(old_axis), i_usize);
569 // Skip copying the axis since it should be removed. Note that
570 // removing this axis is safe because `.collapse_axis()` panics
571 // if the index is out-of-bounds, so it will panic if the axis
572 // is zero length.
573 old_axis += 1;
574 }
575 SliceInfoElem::NewAxis => {
576 // Set the dim and stride of the new axis.
577 new_dim[new_axis] = 1;
578 new_strides[new_axis] = 0;
579 new_axis += 1;
580 }
581 });
582 debug_assert_eq!(old_axis, self.ndim());
583 debug_assert_eq!(new_axis, out_ndim);
584
585 // safe because new dimension, strides allow access to a subset of old data
586 unsafe { self.with_strides_dim(new_strides, new_dim) }
587 }
588
589 /// Slice the array in place without changing the number of dimensions.
590 ///
591 /// In particular, if an axis is sliced with an index, the axis is
592 /// collapsed, as in [`.collapse_axis()`], rather than removed, as in
593 /// [`.slice_move()`] or [`.index_axis_move()`].
594 ///
595 /// [`.collapse_axis()`]: Self::collapse_axis
596 /// [`.slice_move()`]: Self::slice_move
597 /// [`.index_axis_move()`]: Self::index_axis_move
598 ///
599 /// See [*Slicing*](#slicing) for full documentation.
600 /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo).
601 ///
602 /// **Panics** in the following cases:
603 ///
604 /// - if an index is out of bounds
605 /// - if a step size is zero
606 /// - if [`SliceInfoElem::NewAxis`] is in `info`, e.g. if [`NewAxis`] was
607 /// used in the [`s!`] macro
608 /// - if `D` is `IxDyn` and `info` does not match the number of array axes
609 #[track_caller]
610 pub fn slice_collapse<I>(&mut self, info: I)
611 where I: SliceArg<D>
612 {
613 assert_eq!(
614 info.in_ndim(),
615 self.ndim(),
616 "The input dimension of `info` must match the array to be sliced.",
617 );
618 let mut axis = 0;
619 info.as_ref().iter().for_each(|&ax_info| match ax_info {
620 SliceInfoElem::Slice { start, end, step } => {
621 self.slice_axis_inplace(Axis(axis), Slice { start, end, step });
622 axis += 1;
623 }
624 SliceInfoElem::Index(index) => {
625 let i_usize = abs_index(self.len_of(Axis(axis)), index);
626 self.collapse_axis(Axis(axis), i_usize);
627 axis += 1;
628 }
629 SliceInfoElem::NewAxis => panic!("`slice_collapse` does not support `NewAxis`."),
630 });
631 debug_assert_eq!(axis, self.ndim());
632 }
633
634 /// Return a view of the array, sliced along the specified axis.
635 ///
636 /// **Panics** if an index is out of bounds or step size is zero.<br>
637 /// **Panics** if `axis` is out of bounds.
638 #[track_caller]
639 #[must_use = "slice_axis returns an array view with the sliced result"]
640 pub fn slice_axis(&self, axis: Axis, indices: Slice) -> ArrayView<'_, A, D>
641 where S: Data
642 {
643 let mut view = self.view();
644 view.slice_axis_inplace(axis, indices);
645 view
646 }
647
648 /// Return a mutable view of the array, sliced along the specified axis.
649 ///
650 /// **Panics** if an index is out of bounds or step size is zero.<br>
651 /// **Panics** if `axis` is out of bounds.
652 #[track_caller]
653 #[must_use = "slice_axis_mut returns an array view with the sliced result"]
654 pub fn slice_axis_mut(&mut self, axis: Axis, indices: Slice) -> ArrayViewMut<'_, A, D>
655 where S: DataMut
656 {
657 let mut view_mut = self.view_mut();
658 view_mut.slice_axis_inplace(axis, indices);
659 view_mut
660 }
661
662 /// Slice the array in place along the specified axis.
663 ///
664 /// **Panics** if an index is out of bounds or step size is zero.<br>
665 /// **Panics** if `axis` is out of bounds.
666 #[track_caller]
667 pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice)
668 {
669 let offset =
670 do_slice(&mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], indices);
671 unsafe {
672 self.ptr = self.ptr.offset(offset);
673 }
674 debug_assert!(self.pointer_is_inbounds());
675 }
676
677 /// Slice the array in place along the specified axis, then return the sliced array.
678 ///
679 /// **Panics** if an index is out of bounds or step size is zero.<br>
680 /// **Panics** if `axis` is out of bounds.
681 #[must_use = "slice_axis_move returns an array with the sliced result"]
682 pub fn slice_axis_move(mut self, axis: Axis, indices: Slice) -> Self
683 {
684 self.slice_axis_inplace(axis, indices);
685 self
686 }
687
688 /// Return a view of a slice of the array, with a closure specifying the
689 /// slice for each axis.
690 ///
691 /// This is especially useful for code which is generic over the
692 /// dimensionality of the array.
693 ///
694 /// **Panics** if an index is out of bounds or step size is zero.
695 #[track_caller]
696 pub fn slice_each_axis<F>(&self, f: F) -> ArrayView<'_, A, D>
697 where
698 F: FnMut(AxisDescription) -> Slice,
699 S: Data,
700 {
701 let mut view = self.view();
702 view.slice_each_axis_inplace(f);
703 view
704 }
705
706 /// Return a mutable view of a slice of the array, with a closure
707 /// specifying the slice for each axis.
708 ///
709 /// This is especially useful for code which is generic over the
710 /// dimensionality of the array.
711 ///
712 /// **Panics** if an index is out of bounds or step size is zero.
713 #[track_caller]
714 pub fn slice_each_axis_mut<F>(&mut self, f: F) -> ArrayViewMut<'_, A, D>
715 where
716 F: FnMut(AxisDescription) -> Slice,
717 S: DataMut,
718 {
719 let mut view = self.view_mut();
720 view.slice_each_axis_inplace(f);
721 view
722 }
723
724 /// Slice the array in place, with a closure specifying the slice for each
725 /// axis.
726 ///
727 /// This is especially useful for code which is generic over the
728 /// dimensionality of the array.
729 ///
730 /// **Panics** if an index is out of bounds or step size is zero.
731 #[track_caller]
732 pub fn slice_each_axis_inplace<F>(&mut self, mut f: F)
733 where F: FnMut(AxisDescription) -> Slice
734 {
735 for ax in 0..self.ndim() {
736 self.slice_axis_inplace(
737 Axis(ax),
738 f(AxisDescription {
739 axis: Axis(ax),
740 len: self.dim[ax],
741 stride: self.strides[ax] as isize,
742 }),
743 )
744 }
745 }
746
747 /// Return a reference to the element at `index`, or return `None`
748 /// if the index is out of bounds.
749 ///
750 /// Arrays also support indexing syntax: `array[index]`.
751 ///
752 /// ```
753 /// use kn0sys_ndarray::arr2;
754 ///
755 /// let a = arr2(&[[1., 2.],
756 /// [3., 4.]]);
757 ///
758 /// assert!(
759 /// a.get((0, 1)) == Some(&2.) &&
760 /// a.get((0, 2)) == None &&
761 /// a[(0, 1)] == 2. &&
762 /// a[[0, 1]] == 2.
763 /// );
764 /// ```
765 pub fn get<I>(&self, index: I) -> Option<&A>
766 where
767 S: Data,
768 I: NdIndex<D>,
769 {
770 unsafe { self.get_ptr(index).map(|ptr| &*ptr) }
771 }
772
773 /// Return a raw pointer to the element at `index`, or return `None`
774 /// if the index is out of bounds.
775 ///
776 /// ```
777 /// use kn0sys_ndarray::arr2;
778 ///
779 /// let a = arr2(&[[1., 2.], [3., 4.]]);
780 ///
781 /// let v = a.raw_view();
782 /// let p = a.get_ptr((0, 1)).unwrap();
783 ///
784 /// assert_eq!(unsafe { *p }, 2.);
785 /// ```
786 pub fn get_ptr<I>(&self, index: I) -> Option<*const A>
787 where I: NdIndex<D>
788 {
789 let ptr = self.ptr;
790 index
791 .index_checked(&self.dim, &self.strides)
792 .map(move |offset| unsafe { ptr.as_ptr().offset(offset) as *const _ })
793 }
794
795 /// Return a mutable reference to the element at `index`, or return `None`
796 /// if the index is out of bounds.
797 pub fn get_mut<I>(&mut self, index: I) -> Option<&mut A>
798 where
799 S: DataMut,
800 I: NdIndex<D>,
801 {
802 unsafe { self.get_mut_ptr(index).map(|ptr| &mut *ptr) }
803 }
804
805 /// Return a raw pointer to the element at `index`, or return `None`
806 /// if the index is out of bounds.
807 ///
808 /// ```
809 /// use kn0sys_ndarray::arr2;
810 ///
811 /// let mut a = arr2(&[[1., 2.], [3., 4.]]);
812 ///
813 /// let v = a.raw_view_mut();
814 /// let p = a.get_mut_ptr((0, 1)).unwrap();
815 ///
816 /// unsafe {
817 /// *p = 5.;
818 /// }
819 ///
820 /// assert_eq!(a.get((0, 1)), Some(&5.));
821 /// ```
822 pub fn get_mut_ptr<I>(&mut self, index: I) -> Option<*mut A>
823 where
824 S: RawDataMut,
825 I: NdIndex<D>,
826 {
827 // const and mut are separate to enforce &mutness as well as the
828 // extra code in as_mut_ptr
829 let ptr = self.as_mut_ptr();
830 index
831 .index_checked(&self.dim, &self.strides)
832 .map(move |offset| unsafe { ptr.offset(offset) })
833 }
834
835 /// Perform *unchecked* array indexing.
836 ///
837 /// Return a reference to the element at `index`.
838 ///
839 /// **Note:** only unchecked for non-debug builds of ndarray.
840 ///
841 /// # Safety
842 ///
843 /// The caller must ensure that the index is in-bounds.
844 #[inline]
845 pub unsafe fn uget<I>(&self, index: I) -> &A
846 where
847 S: Data,
848 I: NdIndex<D>,
849 {
850 arraytraits::debug_bounds_check(self, &index);
851 let off = index.index_unchecked(&self.strides);
852 &*self.ptr.as_ptr().offset(off)
853 }
854
855 /// Perform *unchecked* array indexing.
856 ///
857 /// Return a mutable reference to the element at `index`.
858 ///
859 /// **Note:** Only unchecked for non-debug builds of ndarray.
860 ///
861 /// # Safety
862 ///
863 /// The caller must ensure that:
864 ///
865 /// 1. the index is in-bounds and
866 ///
867 /// 2. the data is uniquely held by the array. (This property is guaranteed
868 /// for `Array` and `ArrayViewMut`, but not for `ArcArray` or `CowArray`.)
869 #[inline]
870 pub unsafe fn uget_mut<I>(&mut self, index: I) -> &mut A
871 where
872 S: DataMut,
873 I: NdIndex<D>,
874 {
875 debug_assert!(self.data.is_unique());
876 arraytraits::debug_bounds_check(self, &index);
877 let off = index.index_unchecked(&self.strides);
878 &mut *self.ptr.as_ptr().offset(off)
879 }
880
881 /// Swap elements at indices `index1` and `index2`.
882 ///
883 /// Indices may be equal.
884 ///
885 /// ***Panics*** if an index is out of bounds.
886 #[track_caller]
887 pub fn swap<I>(&mut self, index1: I, index2: I)
888 where
889 S: DataMut,
890 I: NdIndex<D>,
891 {
892 let ptr = self.as_mut_ptr();
893 let offset1 = index1.index_checked(&self.dim, &self.strides);
894 let offset2 = index2.index_checked(&self.dim, &self.strides);
895 if let Some(offset1) = offset1 {
896 if let Some(offset2) = offset2 {
897 unsafe {
898 std::ptr::swap(ptr.offset(offset1), ptr.offset(offset2));
899 }
900 return;
901 }
902 }
903 panic!("swap: index out of bounds for indices {:?} {:?}", index1, index2);
904 }
905
906 /// Swap elements *unchecked* at indices `index1` and `index2`.
907 ///
908 /// Indices may be equal.
909 ///
910 /// **Note:** only unchecked for non-debug builds of ndarray.
911 ///
912 /// # Safety
913 ///
914 /// The caller must ensure that:
915 ///
916 /// 1. both `index1` and `index2` are in-bounds and
917 ///
918 /// 2. the data is uniquely held by the array. (This property is guaranteed
919 /// for `Array` and `ArrayViewMut`, but not for `ArcArray` or `CowArray`.)
920 pub unsafe fn uswap<I>(&mut self, index1: I, index2: I)
921 where
922 S: DataMut,
923 I: NdIndex<D>,
924 {
925 debug_assert!(self.data.is_unique());
926 arraytraits::debug_bounds_check(self, &index1);
927 arraytraits::debug_bounds_check(self, &index2);
928 let off1 = index1.index_unchecked(&self.strides);
929 let off2 = index2.index_unchecked(&self.strides);
930 std::ptr::swap(self.ptr.as_ptr().offset(off1), self.ptr.as_ptr().offset(off2));
931 }
932
933 // `get` for zero-dimensional arrays
934 // panics if dimension is not zero. otherwise an element is always present.
935 fn get_0d(&self) -> &A
936 where S: Data
937 {
938 assert!(self.ndim() == 0);
939 unsafe { &*self.as_ptr() }
940 }
941
942 /// Returns a view restricted to `index` along the axis, with the axis
943 /// removed.
944 ///
945 /// See [*Subviews*](#subviews) for full documentation.
946 ///
947 /// **Panics** if `axis` or `index` is out of bounds.
948 ///
949 /// ```
950 /// use kn0sys_ndarray::{arr2, ArrayView, Axis};
951 ///
952 /// let a = arr2(&[[1., 2. ], // ... axis 0, row 0
953 /// [3., 4. ], // --- axis 0, row 1
954 /// [5., 6. ]]); // ... axis 0, row 2
955 /// // . \
956 /// // . axis 1, column 1
957 /// // axis 1, column 0
958 /// assert!(
959 /// a.index_axis(Axis(0), 1) == ArrayView::from(&[3., 4.]) &&
960 /// a.index_axis(Axis(1), 1) == ArrayView::from(&[2., 4., 6.])
961 /// );
962 /// ```
963 #[track_caller]
964 pub fn index_axis(&self, axis: Axis, index: usize) -> ArrayView<'_, A, D::Smaller>
965 where
966 S: Data,
967 D: RemoveAxis,
968 {
969 self.view().index_axis_move(axis, index)
970 }
971
972 /// Returns a mutable view restricted to `index` along the axis, with the
973 /// axis removed.
974 ///
975 /// **Panics** if `axis` or `index` is out of bounds.
976 ///
977 /// ```
978 /// use kn0sys_ndarray::{arr2, aview2, Axis};
979 ///
980 /// let mut a = arr2(&[[1., 2. ],
981 /// [3., 4. ]]);
982 /// // . \
983 /// // . axis 1, column 1
984 /// // axis 1, column 0
985 ///
986 /// {
987 /// let mut column1 = a.index_axis_mut(Axis(1), 1);
988 /// column1 += 10.;
989 /// }
990 ///
991 /// assert!(
992 /// a == aview2(&[[1., 12.],
993 /// [3., 14.]])
994 /// );
995 /// ```
996 #[track_caller]
997 pub fn index_axis_mut(&mut self, axis: Axis, index: usize) -> ArrayViewMut<'_, A, D::Smaller>
998 where
999 S: DataMut,
1000 D: RemoveAxis,
1001 {
1002 self.view_mut().index_axis_move(axis, index)
1003 }
1004
1005 /// Collapses the array to `index` along the axis and removes the axis.
1006 ///
1007 /// See [`.index_axis()`](Self::index_axis) and [*Subviews*](#subviews) for full documentation.
1008 ///
1009 /// **Panics** if `axis` or `index` is out of bounds.
1010 #[track_caller]
1011 pub fn index_axis_move(mut self, axis: Axis, index: usize) -> ArrayBase<S, D::Smaller>
1012 where D: RemoveAxis
1013 {
1014 self.collapse_axis(axis, index);
1015 let dim = self.dim.remove_axis(axis);
1016 let strides = self.strides.remove_axis(axis);
1017 // safe because new dimension, strides allow access to a subset of old data
1018 unsafe { self.with_strides_dim(strides, dim) }
1019 }
1020
1021 /// Selects `index` along the axis, collapsing the axis into length one.
1022 ///
1023 /// **Panics** if `axis` or `index` is out of bounds.
1024 #[track_caller]
1025 pub fn collapse_axis(&mut self, axis: Axis, index: usize)
1026 {
1027 let offset = dimension::do_collapse_axis(&mut self.dim, &self.strides, axis.index(), index);
1028 self.ptr = unsafe { self.ptr.offset(offset) };
1029 debug_assert!(self.pointer_is_inbounds());
1030 }
1031
1032 /// Along `axis`, select arbitrary subviews corresponding to `indices`
1033 /// and copy them into a new array.
1034 ///
1035 /// **Panics** if `axis` or an element of `indices` is out of bounds.
1036 ///
1037 /// ```
1038 /// use kn0sys_ndarray::{arr2, Axis};
1039 ///
1040 /// let x = arr2(&[[0., 1.],
1041 /// [2., 3.],
1042 /// [4., 5.],
1043 /// [6., 7.],
1044 /// [8., 9.]]);
1045 ///
1046 /// let r = x.select(Axis(0), &[0, 4, 3]);
1047 /// assert!(
1048 /// r == arr2(&[[0., 1.],
1049 /// [8., 9.],
1050 /// [6., 7.]])
1051 ///);
1052 /// ```
1053 #[track_caller]
1054 pub fn select(&self, axis: Axis, indices: &[Ix]) -> Array<A, D>
1055 where
1056 A: Clone,
1057 S: Data,
1058 D: RemoveAxis,
1059 {
1060 if self.ndim() == 1 {
1061 // using .len_of(axis) means that we check if `axis` is in bounds too.
1062 let axis_len = self.len_of(axis);
1063 // bounds check the indices first
1064 if let Some(max_index) = indices.iter().cloned().max() {
1065 if max_index >= axis_len {
1066 panic!("ndarray: index {} is out of bounds in array of len {}",
1067 max_index, self.len_of(axis));
1068 }
1069 } // else: indices empty is ok
1070 let view = self.view().into_dimensionality::<Ix1>().unwrap();
1071 Array::from_iter(indices.iter().map(move |&index| {
1072 // Safety: bounds checked indexes
1073 unsafe { view.uget(index).clone() }
1074 }))
1075 .into_dimensionality::<D>()
1076 .unwrap()
1077 } else {
1078 let mut subs = vec![self.view(); indices.len()];
1079 for (&i, sub) in zip(indices, &mut subs[..]) {
1080 sub.collapse_axis(axis, i);
1081 }
1082 if subs.is_empty() {
1083 let mut dim = self.raw_dim();
1084 dim.set_axis(axis, 0);
1085 unsafe { Array::from_shape_vec_unchecked(dim, vec![]) }
1086 } else {
1087 concatenate(axis, &subs).unwrap()
1088 }
1089 }
1090 }
1091
1092 /// Return a producer and iterable that traverses over the *generalized*
1093 /// rows of the array. For a 2D array these are the regular rows.
1094 ///
1095 /// This is equivalent to `.lanes(Axis(n - 1))` where *n* is `self.ndim()`.
1096 ///
1097 /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m*
1098 /// it has *a* × *b* × *c* × ... × *l* rows each of length *m*.
1099 ///
1100 /// For example, in a 2 × 2 × 3 array, each row is 3 elements long
1101 /// and there are 2 × 2 = 4 rows in total.
1102 ///
1103 /// Iterator element is `ArrayView1<A>` (1D array view).
1104 ///
1105 /// ```
1106 /// use kn0sys_ndarray::arr3;
1107 ///
1108 /// let a = arr3(&[[[ 0, 1, 2], // -- row 0, 0
1109 /// [ 3, 4, 5]], // -- row 0, 1
1110 /// [[ 6, 7, 8], // -- row 1, 0
1111 /// [ 9, 10, 11]]]); // -- row 1, 1
1112 ///
1113 /// // `rows` will yield the four generalized rows of the array.
1114 /// for row in a.rows() {
1115 /// /* loop body */
1116 /// }
1117 /// ```
1118 pub fn rows(&self) -> Lanes<'_, A, D::Smaller>
1119 where S: Data
1120 {
1121 let mut n = self.ndim();
1122 if n == 0 {
1123 n += 1;
1124 }
1125 Lanes::new(self.view(), Axis(n - 1))
1126 }
1127
1128 /// Return a producer and iterable that traverses over the *generalized*
1129 /// rows of the array and yields mutable array views.
1130 ///
1131 /// Iterator element is `ArrayView1<A>` (1D read-write array view).
1132 pub fn rows_mut(&mut self) -> LanesMut<'_, A, D::Smaller>
1133 where S: DataMut
1134 {
1135 let mut n = self.ndim();
1136 if n == 0 {
1137 n += 1;
1138 }
1139 LanesMut::new(self.view_mut(), Axis(n - 1))
1140 }
1141
1142 /// Return a producer and iterable that traverses over the *generalized*
1143 /// columns of the array. For a 2D array these are the regular columns.
1144 ///
1145 /// This is equivalent to `.lanes(Axis(0))`.
1146 ///
1147 /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m*
1148 /// it has *b* × *c* × ... × *l* × *m* columns each of length *a*.
1149 ///
1150 /// For example, in a 2 × 2 × 3 array, each column is 2 elements long
1151 /// and there are 2 × 3 = 6 columns in total.
1152 ///
1153 /// Iterator element is `ArrayView1<A>` (1D array view).
1154 ///
1155 /// ```
1156 /// use kn0sys_ndarray::arr3;
1157 ///
1158 /// // The generalized columns of a 3D array:
1159 /// // are directed along the 0th axis: 0 and 6, 1 and 7 and so on...
1160 /// let a = arr3(&[[[ 0, 1, 2], [ 3, 4, 5]],
1161 /// [[ 6, 7, 8], [ 9, 10, 11]]]);
1162 ///
1163 /// // Here `columns` will yield the six generalized columns of the array.
1164 /// for column in a.columns() {
1165 /// /* loop body */
1166 /// }
1167 /// ```
1168 pub fn columns(&self) -> Lanes<'_, A, D::Smaller>
1169 where S: Data
1170 {
1171 Lanes::new(self.view(), Axis(0))
1172 }
1173
1174 /// Return a producer and iterable that traverses over the *generalized*
1175 /// columns of the array and yields mutable array views.
1176 ///
1177 /// Iterator element is `ArrayView1<A>` (1D read-write array view).
1178 pub fn columns_mut(&mut self) -> LanesMut<'_, A, D::Smaller>
1179 where S: DataMut
1180 {
1181 LanesMut::new(self.view_mut(), Axis(0))
1182 }
1183
1184 /// Return a producer and iterable that traverses over all 1D lanes
1185 /// pointing in the direction of `axis`.
1186 ///
1187 /// When pointing in the direction of the first axis, they are *columns*,
1188 /// in the direction of the last axis *rows*; in general they are all
1189 /// *lanes* and are one dimensional.
1190 ///
1191 /// Iterator element is `ArrayView1<A>` (1D array view).
1192 ///
1193 /// ```
1194 /// use kn0sys_ndarray::{arr3, aview1, Axis};
1195 ///
1196 /// let a = arr3(&[[[ 0, 1, 2],
1197 /// [ 3, 4, 5]],
1198 /// [[ 6, 7, 8],
1199 /// [ 9, 10, 11]]]);
1200 ///
1201 /// let inner0 = a.lanes(Axis(0));
1202 /// let inner1 = a.lanes(Axis(1));
1203 /// let inner2 = a.lanes(Axis(2));
1204 ///
1205 /// // The first lane for axis 0 is [0, 6]
1206 /// assert_eq!(inner0.into_iter().next().unwrap(), aview1(&[0, 6]));
1207 /// // The first lane for axis 1 is [0, 3]
1208 /// assert_eq!(inner1.into_iter().next().unwrap(), aview1(&[0, 3]));
1209 /// // The first lane for axis 2 is [0, 1, 2]
1210 /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2]));
1211 /// ```
1212 pub fn lanes(&self, axis: Axis) -> Lanes<'_, A, D::Smaller>
1213 where S: Data
1214 {
1215 Lanes::new(self.view(), axis)
1216 }
1217
1218 /// Return a producer and iterable that traverses over all 1D lanes
1219 /// pointing in the direction of `axis`.
1220 ///
1221 /// Iterator element is `ArrayViewMut1<A>` (1D read-write array view).
1222 pub fn lanes_mut(&mut self, axis: Axis) -> LanesMut<'_, A, D::Smaller>
1223 where S: DataMut
1224 {
1225 LanesMut::new(self.view_mut(), axis)
1226 }
1227
1228 /// Return an iterator that traverses over the outermost dimension
1229 /// and yields each subview.
1230 ///
1231 /// This is equivalent to `.axis_iter(Axis(0))`.
1232 ///
1233 /// Iterator element is `ArrayView<A, D::Smaller>` (read-only array view).
1234 #[allow(deprecated)]
1235 pub fn outer_iter(&self) -> AxisIter<'_, A, D::Smaller>
1236 where
1237 S: Data,
1238 D: RemoveAxis,
1239 {
1240 self.view().into_outer_iter()
1241 }
1242
1243 /// Return an iterator that traverses over the outermost dimension
1244 /// and yields each subview.
1245 ///
1246 /// This is equivalent to `.axis_iter_mut(Axis(0))`.
1247 ///
1248 /// Iterator element is `ArrayViewMut<A, D::Smaller>` (read-write array view).
1249 #[allow(deprecated)]
1250 pub fn outer_iter_mut(&mut self) -> AxisIterMut<'_, A, D::Smaller>
1251 where
1252 S: DataMut,
1253 D: RemoveAxis,
1254 {
1255 self.view_mut().into_outer_iter()
1256 }
1257
1258 /// Return an iterator that traverses over `axis`
1259 /// and yields each subview along it.
1260 ///
1261 /// For example, in a 3 × 4 × 5 array, with `axis` equal to `Axis(2)`,
1262 /// the iterator element
1263 /// is a 3 × 4 subview (and there are 5 in total), as shown
1264 /// in the picture below.
1265 ///
1266 /// Iterator element is `ArrayView<A, D::Smaller>` (read-only array view).
1267 ///
1268 /// See [*Subviews*](#subviews) for full documentation.
1269 ///
1270 /// **Panics** if `axis` is out of bounds.
1271 ///
1272 /// <img src="https://rust-ndarray.github.io/ndarray/images/axis_iter_3_4_5.svg" height="250px">
1273 #[track_caller]
1274 pub fn axis_iter(&self, axis: Axis) -> AxisIter<'_, A, D::Smaller>
1275 where
1276 S: Data,
1277 D: RemoveAxis,
1278 {
1279 AxisIter::new(self.view(), axis)
1280 }
1281
1282 /// Return an iterator that traverses over `axis`
1283 /// and yields each mutable subview along it.
1284 ///
1285 /// Iterator element is `ArrayViewMut<A, D::Smaller>`
1286 /// (read-write array view).
1287 ///
1288 /// **Panics** if `axis` is out of bounds.
1289 #[track_caller]
1290 pub fn axis_iter_mut(&mut self, axis: Axis) -> AxisIterMut<'_, A, D::Smaller>
1291 where
1292 S: DataMut,
1293 D: RemoveAxis,
1294 {
1295 AxisIterMut::new(self.view_mut(), axis)
1296 }
1297
1298 /// Return an iterator that traverses over `axis` by chunks of `size`,
1299 /// yielding non-overlapping views along that axis.
1300 ///
1301 /// Iterator element is `ArrayView<A, D>`
1302 ///
1303 /// The last view may have less elements if `size` does not divide
1304 /// the axis' dimension.
1305 ///
1306 /// **Panics** if `axis` is out of bounds or if `size` is zero.
1307 ///
1308 /// ```
1309 /// use kn0sys_ndarray::Array;
1310 /// use kn0sys_ndarray::{arr3, Axis};
1311 ///
1312 /// let a = Array::from_iter(0..28).into_shape_with_order((2, 7, 2)).unwrap();
1313 /// let mut iter = a.axis_chunks_iter(Axis(1), 2);
1314 ///
1315 /// // first iteration yields a 2 × 2 × 2 view
1316 /// assert_eq!(iter.next().unwrap(),
1317 /// arr3(&[[[ 0, 1], [ 2, 3]],
1318 /// [[14, 15], [16, 17]]]));
1319 ///
1320 /// // however the last element is a 2 × 1 × 2 view since 7 % 2 == 1
1321 /// assert_eq!(iter.next_back().unwrap(), arr3(&[[[12, 13]],
1322 /// [[26, 27]]]));
1323 /// ```
1324 #[track_caller]
1325 pub fn axis_chunks_iter(&self, axis: Axis, size: usize) -> AxisChunksIter<'_, A, D>
1326 where S: Data
1327 {
1328 AxisChunksIter::new(self.view(), axis, size)
1329 }
1330
1331 /// Return an iterator that traverses over `axis` by chunks of `size`,
1332 /// yielding non-overlapping read-write views along that axis.
1333 ///
1334 /// Iterator element is `ArrayViewMut<A, D>`
1335 ///
1336 /// **Panics** if `axis` is out of bounds or if `size` is zero.
1337 #[track_caller]
1338 pub fn axis_chunks_iter_mut(&mut self, axis: Axis, size: usize) -> AxisChunksIterMut<'_, A, D>
1339 where S: DataMut
1340 {
1341 AxisChunksIterMut::new(self.view_mut(), axis, size)
1342 }
1343
1344 /// Return an exact chunks producer (and iterable).
1345 ///
1346 /// It produces the whole chunks of a given n-dimensional chunk size,
1347 /// skipping the remainder along each dimension that doesn't fit evenly.
1348 ///
1349 /// The produced element is a `ArrayView<A, D>` with exactly the dimension
1350 /// `chunk_size`.
1351 ///
1352 /// **Panics** if any dimension of `chunk_size` is zero<br>
1353 /// (**Panics** if `D` is `IxDyn` and `chunk_size` does not match the
1354 /// number of array axes.)
1355 #[track_caller]
1356 pub fn exact_chunks<E>(&self, chunk_size: E) -> ExactChunks<'_, A, D>
1357 where
1358 E: IntoDimension<Dim = D>,
1359 S: Data,
1360 {
1361 ExactChunks::new(self.view(), chunk_size)
1362 }
1363
1364 /// Return an exact chunks producer (and iterable).
1365 ///
1366 /// It produces the whole chunks of a given n-dimensional chunk size,
1367 /// skipping the remainder along each dimension that doesn't fit evenly.
1368 ///
1369 /// The produced element is a `ArrayViewMut<A, D>` with exactly
1370 /// the dimension `chunk_size`.
1371 ///
1372 /// **Panics** if any dimension of `chunk_size` is zero<br>
1373 /// (**Panics** if `D` is `IxDyn` and `chunk_size` does not match the
1374 /// number of array axes.)
1375 ///
1376 /// ```rust
1377 /// use kn0sys_ndarray::Array;
1378 /// use kn0sys_ndarray::arr2;
1379 /// let mut a = Array::zeros((6, 7));
1380 ///
1381 /// // Fill each 2 × 2 chunk with the index of where it appeared in iteration
1382 /// for (i, mut chunk) in a.exact_chunks_mut((2, 2)).into_iter().enumerate() {
1383 /// chunk.fill(i);
1384 /// }
1385 ///
1386 /// // The resulting array is:
1387 /// assert_eq!(
1388 /// a,
1389 /// arr2(&[[0, 0, 1, 1, 2, 2, 0],
1390 /// [0, 0, 1, 1, 2, 2, 0],
1391 /// [3, 3, 4, 4, 5, 5, 0],
1392 /// [3, 3, 4, 4, 5, 5, 0],
1393 /// [6, 6, 7, 7, 8, 8, 0],
1394 /// [6, 6, 7, 7, 8, 8, 0]]));
1395 /// ```
1396 #[track_caller]
1397 pub fn exact_chunks_mut<E>(&mut self, chunk_size: E) -> ExactChunksMut<'_, A, D>
1398 where
1399 E: IntoDimension<Dim = D>,
1400 S: DataMut,
1401 {
1402 ExactChunksMut::new(self.view_mut(), chunk_size)
1403 }
1404
1405 /// Return a window producer and iterable.
1406 ///
1407 /// The windows are all distinct overlapping views of size `window_size`
1408 /// that fit into the array's shape.
1409 ///
1410 /// This is essentially equivalent to [`.windows_with_stride()`] with unit stride.
1411 #[track_caller]
1412 pub fn windows<E>(&self, window_size: E) -> Windows<'_, A, D>
1413 where
1414 E: IntoDimension<Dim = D>,
1415 S: Data,
1416 {
1417 Windows::new(self.view(), window_size)
1418 }
1419
1420 /// Return a window producer and iterable.
1421 ///
1422 /// The windows are all distinct views of size `window_size`
1423 /// that fit into the array's shape.
1424 ///
1425 /// The stride is ordered by the outermost axis.<br>
1426 /// Hence, a (x₀, x₁, ..., xₙ) stride will be applied to
1427 /// (A₀, A₁, ..., Aₙ) where Aₓ stands for `Axis(x)`.
1428 ///
1429 /// This produces all windows that fit within the array for the given stride,
1430 /// assuming the window size is not larger than the array size.
1431 ///
1432 /// The produced element is an `ArrayView<A, D>` with exactly the dimension
1433 /// `window_size`.
1434 ///
1435 /// Note that passing a stride of only ones is similar to
1436 /// calling [`ArrayBase::windows()`].
1437 ///
1438 /// **Panics** if any dimension of `window_size` or `stride` is zero.<br>
1439 /// (**Panics** if `D` is `IxDyn` and `window_size` or `stride` does not match the
1440 /// number of array axes.)
1441 ///
1442 /// This is the same illustration found in [`ArrayBase::windows()`],
1443 /// 2×2 windows in a 3×4 array, but now with a (1, 2) stride:
1444 ///
1445 /// ```text
1446 /// ──▶ Axis(1)
1447 ///
1448 /// │ ┏━━━━━┳━━━━━┱─────┬─────┐ ┌─────┬─────┲━━━━━┳━━━━━┓
1449 /// ▼ ┃ a₀₀ ┃ a₀₁ ┃ │ │ │ │ ┃ a₀₂ ┃ a₀₃ ┃
1450 /// Axis(0) ┣━━━━━╋━━━━━╉─────┼─────┤ ├─────┼─────╊━━━━━╋━━━━━┫
1451 /// ┃ a₁₀ ┃ a₁₁ ┃ │ │ │ │ ┃ a₁₂ ┃ a₁₃ ┃
1452 /// ┡━━━━━╇━━━━━╃─────┼─────┤ ├─────┼─────╄━━━━━╇━━━━━┩
1453 /// │ │ │ │ │ │ │ │ │ │
1454 /// └─────┴─────┴─────┴─────┘ └─────┴─────┴─────┴─────┘
1455 ///
1456 /// ┌─────┬─────┬─────┬─────┐ ┌─────┬─────┬─────┬─────┐
1457 /// │ │ │ │ │ │ │ │ │ │
1458 /// ┢━━━━━╈━━━━━╅─────┼─────┤ ├─────┼─────╆━━━━━╈━━━━━┪
1459 /// ┃ a₁₀ ┃ a₁₁ ┃ │ │ │ │ ┃ a₁₂ ┃ a₁₃ ┃
1460 /// ┣━━━━━╋━━━━━╉─────┼─────┤ ├─────┼─────╊━━━━━╋━━━━━┫
1461 /// ┃ a₂₀ ┃ a₂₁ ┃ │ │ │ │ ┃ a₂₂ ┃ a₂₃ ┃
1462 /// ┗━━━━━┻━━━━━┹─────┴─────┘ └─────┴─────┺━━━━━┻━━━━━┛
1463 /// ```
1464 #[track_caller]
1465 pub fn windows_with_stride<E>(&self, window_size: E, stride: E) -> Windows<'_, A, D>
1466 where
1467 E: IntoDimension<Dim = D>,
1468 S: Data,
1469 {
1470 Windows::new_with_stride(self.view(), window_size, stride)
1471 }
1472
1473 /// Returns a producer which traverses over all windows of a given length along an axis.
1474 ///
1475 /// The windows are all distinct, possibly-overlapping views. The shape of each window
1476 /// is the shape of `self`, with the length of `axis` replaced with `window_size`.
1477 ///
1478 /// **Panics** if `axis` is out-of-bounds or if `window_size` is zero.
1479 ///
1480 /// ```
1481 /// use kn0sys_ndarray::{Array3, Axis, s};
1482 ///
1483 /// let arr = Array3::from_shape_fn([4, 5, 2], |(i, j, k)| i * 100 + j * 10 + k);
1484 /// let correct = vec![
1485 /// arr.slice(s![.., 0..3, ..]),
1486 /// arr.slice(s![.., 1..4, ..]),
1487 /// arr.slice(s![.., 2..5, ..]),
1488 /// ];
1489 /// for (window, correct) in arr.axis_windows(Axis(1), 3).into_iter().zip(&correct) {
1490 /// assert_eq!(window, correct);
1491 /// assert_eq!(window.shape(), &[4, 3, 2]);
1492 /// }
1493 /// ```
1494 pub fn axis_windows(&self, axis: Axis, window_size: usize) -> AxisWindows<'_, A, D>
1495 where S: Data
1496 {
1497 let axis_index = axis.index();
1498
1499 ndassert!(
1500 axis_index < self.ndim(),
1501 concat!(
1502 "Window axis {} does not match array dimension {} ",
1503 "(with array of shape {:?})"
1504 ),
1505 axis_index,
1506 self.ndim(),
1507 self.shape()
1508 );
1509
1510 AxisWindows::new(self.view(), axis, window_size)
1511 }
1512
1513 // Return (length, stride) for diagonal
1514 fn diag_params(&self) -> (Ix, Ixs)
1515 {
1516 /* empty shape has len 1 */
1517 let len = self.dim.slice().iter().cloned().min().unwrap_or(1);
1518 let stride = self.strides().iter().sum();
1519 (len, stride)
1520 }
1521
1522 /// Return a view of the diagonal elements of the array.
1523 ///
1524 /// The diagonal is simply the sequence indexed by *(0, 0, .., 0)*,
1525 /// *(1, 1, ..., 1)* etc as long as all axes have elements.
1526 pub fn diag(&self) -> ArrayView1<'_, A>
1527 where S: Data
1528 {
1529 self.view().into_diag()
1530 }
1531
1532 /// Return a read-write view over the diagonal elements of the array.
1533 pub fn diag_mut(&mut self) -> ArrayViewMut1<'_, A>
1534 where S: DataMut
1535 {
1536 self.view_mut().into_diag()
1537 }
1538
1539 /// Return the diagonal as a one-dimensional array.
1540 pub fn into_diag(self) -> ArrayBase<S, Ix1>
1541 {
1542 let (len, stride) = self.diag_params();
1543 // safe because new len stride allows access to a subset of the current elements
1544 unsafe { self.with_strides_dim(Ix1(stride as Ix), Ix1(len)) }
1545 }
1546
1547 /// Try to make the array unshared.
1548 ///
1549 /// This is equivalent to `.ensure_unique()` if `S: DataMut`.
1550 ///
1551 /// This method is mostly only useful with unsafe code.
1552 fn try_ensure_unique(&mut self)
1553 where S: RawDataMut
1554 {
1555 debug_assert!(self.pointer_is_inbounds());
1556 S::try_ensure_unique(self);
1557 debug_assert!(self.pointer_is_inbounds());
1558 }
1559
1560 /// Make the array unshared.
1561 ///
1562 /// This method is mostly only useful with unsafe code.
1563 fn ensure_unique(&mut self)
1564 where S: DataMut
1565 {
1566 debug_assert!(self.pointer_is_inbounds());
1567 S::ensure_unique(self);
1568 debug_assert!(self.pointer_is_inbounds());
1569 }
1570
1571 /// Return `true` if the array data is laid out in contiguous “C order” in
1572 /// memory (where the last index is the most rapidly varying).
1573 ///
1574 /// Return `false` otherwise, i.e. the array is possibly not
1575 /// contiguous in memory, it has custom strides, etc.
1576 pub fn is_standard_layout(&self) -> bool
1577 {
1578 dimension::is_layout_c(&self.dim, &self.strides)
1579 }
1580
1581 /// Return true if the array is known to be contiguous.
1582 pub(crate) fn is_contiguous(&self) -> bool
1583 {
1584 D::is_contiguous(&self.dim, &self.strides)
1585 }
1586
1587 /// Return a standard-layout array containing the data, cloning if
1588 /// necessary.
1589 ///
1590 /// If `self` is in standard layout, a COW view of the data is returned
1591 /// without cloning. Otherwise, the data is cloned, and the returned array
1592 /// owns the cloned data.
1593 ///
1594 /// ```
1595 /// use kn0sys_ndarray::Array2;
1596 ///
1597 /// let standard = Array2::<f64>::zeros((3, 4));
1598 /// assert!(standard.is_standard_layout());
1599 /// let cow_view = standard.as_standard_layout();
1600 /// assert!(cow_view.is_view());
1601 /// assert!(cow_view.is_standard_layout());
1602 ///
1603 /// let fortran = standard.reversed_axes();
1604 /// assert!(!fortran.is_standard_layout());
1605 /// let cow_owned = fortran.as_standard_layout();
1606 /// assert!(cow_owned.is_owned());
1607 /// assert!(cow_owned.is_standard_layout());
1608 /// ```
1609 pub fn as_standard_layout(&self) -> CowArray<'_, A, D>
1610 where
1611 S: Data<Elem = A>,
1612 A: Clone,
1613 {
1614 if self.is_standard_layout() {
1615 CowArray::from(self.view())
1616 } else {
1617 let v = crate::iterators::to_vec_mapped(self.iter(), A::clone);
1618 let dim = self.dim.clone();
1619 debug_assert_eq!(v.len(), dim.size());
1620
1621 unsafe {
1622 // Safe because the shape and element type are from the existing array
1623 // and the strides are the default strides.
1624 CowArray::from(Array::from_shape_vec_unchecked(dim, v))
1625 }
1626 }
1627 }
1628
1629 /// Return a pointer to the first element in the array.
1630 ///
1631 /// Raw access to array elements needs to follow the strided indexing
1632 /// scheme: an element at multi-index *I* in an array with strides *S* is
1633 /// located at offset
1634 ///
1635 /// *Σ<sub>0 ≤ k < d</sub> I<sub>k</sub> × S<sub>k</sub>*
1636 ///
1637 /// where *d* is `self.ndim()`.
1638 #[inline(always)]
1639 pub fn as_ptr(&self) -> *const A
1640 {
1641 self.ptr.as_ptr() as *const A
1642 }
1643
1644 /// Return a mutable pointer to the first element in the array.
1645 ///
1646 /// This method attempts to unshare the data. If `S: DataMut`, then the
1647 /// data is guaranteed to be uniquely held on return.
1648 ///
1649 /// # Warning
1650 ///
1651 /// When accessing elements through this pointer, make sure to use strides
1652 /// obtained *after* calling this method, since the process of unsharing
1653 /// the data may change the strides.
1654 #[inline(always)]
1655 pub fn as_mut_ptr(&mut self) -> *mut A
1656 where S: RawDataMut
1657 {
1658 self.try_ensure_unique(); // for ArcArray
1659 self.ptr.as_ptr()
1660 }
1661
1662 /// Return a raw view of the array.
1663 #[inline]
1664 pub fn raw_view(&self) -> RawArrayView<A, D>
1665 {
1666 unsafe { RawArrayView::new(self.ptr, self.dim.clone(), self.strides.clone()) }
1667 }
1668
1669 /// Return a raw mutable view of the array.
1670 ///
1671 /// This method attempts to unshare the data. If `S: DataMut`, then the
1672 /// data is guaranteed to be uniquely held on return.
1673 #[inline]
1674 pub fn raw_view_mut(&mut self) -> RawArrayViewMut<A, D>
1675 where S: RawDataMut
1676 {
1677 self.try_ensure_unique(); // for ArcArray
1678 unsafe { RawArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone()) }
1679 }
1680
1681 /// Return a raw mutable view of the array.
1682 ///
1683 /// Safety: The caller must ensure that the owned array is unshared when this is called
1684 #[inline]
1685 pub(crate) unsafe fn raw_view_mut_unchecked(&mut self) -> RawArrayViewMut<A, D>
1686 where S: DataOwned
1687 {
1688 RawArrayViewMut::new(self.ptr, self.dim.clone(), self.strides.clone())
1689 }
1690
1691 /// Return the array’s data as a slice, if it is contiguous and in standard order.
1692 /// Return `None` otherwise.
1693 ///
1694 /// If this function returns `Some(_)`, then the element order in the slice
1695 /// corresponds to the logical order of the array’s elements.
1696 pub fn as_slice(&self) -> Option<&[A]>
1697 where S: Data
1698 {
1699 if self.is_standard_layout() {
1700 unsafe { Some(slice::from_raw_parts(self.ptr.as_ptr(), self.len())) }
1701 } else {
1702 None
1703 }
1704 }
1705
1706 /// Return the array’s data as a slice, if it is contiguous and in standard order.
1707 /// Return `None` otherwise.
1708 pub fn as_slice_mut(&mut self) -> Option<&mut [A]>
1709 where S: DataMut
1710 {
1711 if self.is_standard_layout() {
1712 self.ensure_unique();
1713 unsafe { Some(slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len())) }
1714 } else {
1715 None
1716 }
1717 }
1718
1719 /// Return the array’s data as a slice if it is contiguous,
1720 /// return `None` otherwise.
1721 ///
1722 /// If this function returns `Some(_)`, then the elements in the slice
1723 /// have whatever order the elements have in memory.
1724 pub fn as_slice_memory_order(&self) -> Option<&[A]>
1725 where S: Data
1726 {
1727 if self.is_contiguous() {
1728 let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides);
1729 unsafe { Some(slice::from_raw_parts(self.ptr.sub(offset).as_ptr(), self.len())) }
1730 } else {
1731 None
1732 }
1733 }
1734
1735 /// Return the array’s data as a slice if it is contiguous,
1736 /// return `None` otherwise.
1737 ///
1738 /// In the contiguous case, in order to return a unique reference, this
1739 /// method unshares the data if necessary, but it preserves the existing
1740 /// strides.
1741 pub fn as_slice_memory_order_mut(&mut self) -> Option<&mut [A]>
1742 where S: DataMut
1743 {
1744 self.try_as_slice_memory_order_mut().ok()
1745 }
1746
1747 /// Return the array’s data as a slice if it is contiguous, otherwise
1748 /// return `self` in the `Err` variant.
1749 pub(crate) fn try_as_slice_memory_order_mut(&mut self) -> Result<&mut [A], &mut Self>
1750 where S: DataMut
1751 {
1752 if self.is_contiguous() {
1753 self.ensure_unique();
1754 let offset = offset_from_low_addr_ptr_to_logical_ptr(&self.dim, &self.strides);
1755 unsafe { Ok(slice::from_raw_parts_mut(self.ptr.sub(offset).as_ptr(), self.len())) }
1756 } else {
1757 Err(self)
1758 }
1759 }
1760
1761 /// Transform the array into `new_shape`; any shape with the same number of elements is
1762 /// accepted.
1763 ///
1764 /// `order` specifies the *logical* order in which the array is to be read and reshaped.
1765 /// The array is returned as a `CowArray`; a view if possible, otherwise an owned array.
1766 ///
1767 /// For example, when starting from the one-dimensional sequence 1 2 3 4 5 6, it would be
1768 /// understood as a 2 x 3 array in row major ("C") order this way:
1769 ///
1770 /// ```text
1771 /// 1 2 3
1772 /// 4 5 6
1773 /// ```
1774 ///
1775 /// and as 2 x 3 in column major ("F") order this way:
1776 ///
1777 /// ```text
1778 /// 1 3 5
1779 /// 2 4 6
1780 /// ```
1781 ///
1782 /// This example should show that any time we "reflow" the elements in the array to a different
1783 /// number of rows and columns (or more axes if applicable), it is important to pick an index
1784 /// ordering, and that's the reason for the function parameter for `order`.
1785 ///
1786 /// The `new_shape` parameter should be a dimension and an optional order like these examples:
1787 ///
1788 /// ```text
1789 /// (3, 4) // Shape 3 x 4 with default order (RowMajor)
1790 /// ((3, 4), Order::RowMajor)) // use specific order
1791 /// ((3, 4), Order::ColumnMajor)) // use specific order
1792 /// ((3, 4), Order::C)) // use shorthand for order - shorthands C and F
1793 /// ```
1794 ///
1795 /// **Errors** if the new shape doesn't have the same number of elements as the array's current
1796 /// shape.
1797 ///
1798 /// # Example
1799 ///
1800 /// ```
1801 /// use kn0sys_ndarray::array;
1802 /// use kn0sys_ndarray::Order;
1803 ///
1804 /// assert!(
1805 /// array![1., 2., 3., 4., 5., 6.].to_shape(((2, 3), Order::RowMajor)).unwrap()
1806 /// == array![[1., 2., 3.],
1807 /// [4., 5., 6.]]
1808 /// );
1809 ///
1810 /// assert!(
1811 /// array![1., 2., 3., 4., 5., 6.].to_shape(((2, 3), Order::ColumnMajor)).unwrap()
1812 /// == array![[1., 3., 5.],
1813 /// [2., 4., 6.]]
1814 /// );
1815 /// ```
1816 pub fn to_shape<E>(&self, new_shape: E) -> Result<CowArray<'_, A, E::Dim>, ShapeError>
1817 where
1818 E: ShapeArg,
1819 A: Clone,
1820 S: Data,
1821 {
1822 let (shape, order) = new_shape.into_shape_and_order();
1823 self.to_shape_order(shape, order.unwrap_or(Order::RowMajor))
1824 }
1825
1826 fn to_shape_order<E>(&self, shape: E, order: Order) -> Result<CowArray<'_, A, E>, ShapeError>
1827 where
1828 E: Dimension,
1829 A: Clone,
1830 S: Data,
1831 {
1832 let len = self.dim.size();
1833 if size_of_shape_checked(&shape) != Ok(len) {
1834 return Err(error::incompatible_shapes(&self.dim, &shape));
1835 }
1836
1837 // Create a view if the length is 0, safe because the array and new shape is empty.
1838 if len == 0 {
1839 unsafe {
1840 return Ok(CowArray::from(ArrayView::from_shape_ptr(shape, self.as_ptr())));
1841 }
1842 }
1843
1844 // Try to reshape the array as a view into the existing data
1845 match reshape_dim(&self.dim, &self.strides, &shape, order) {
1846 Ok(to_strides) => unsafe {
1847 return Ok(CowArray::from(ArrayView::new(self.ptr, shape, to_strides)));
1848 },
1849 Err(err) if err.kind() == ErrorKind::IncompatibleShape => {
1850 return Err(error::incompatible_shapes(&self.dim, &shape));
1851 }
1852 _otherwise => {}
1853 }
1854
1855 // otherwise create a new array and copy the elements
1856 unsafe {
1857 let (shape, view) = match order {
1858 Order::RowMajor => (shape.set_f(false), self.view()),
1859 Order::ColumnMajor => (shape.set_f(true), self.t()),
1860 };
1861 Ok(CowArray::from(Array::from_shape_trusted_iter_unchecked(shape, view.into_iter(), A::clone)))
1862 }
1863 }
1864
1865 /// Transform the array into `shape`; any shape with the same number of
1866 /// elements is accepted, but the source array must be contiguous.
1867 ///
1868 /// If an index ordering is not specified, the default is `RowMajor`.
1869 /// The operation will only succeed if the array's memory layout is compatible with
1870 /// the index ordering, so that the array elements can be rearranged in place.
1871 ///
1872 /// If required use `.to_shape()` or `.into_shape_clone` instead for more flexible reshaping of
1873 /// arrays, which allows copying elements if required.
1874 ///
1875 /// **Errors** if the shapes don't have the same number of elements.<br>
1876 /// **Errors** if order RowMajor is given but input is not c-contiguous.
1877 /// **Errors** if order ColumnMajor is given but input is not f-contiguous.
1878 ///
1879 /// If shape is not given: use memory layout of incoming array. Row major arrays are
1880 /// reshaped using row major index ordering, column major arrays with column major index
1881 /// ordering.
1882 ///
1883 /// The `new_shape` parameter should be a dimension and an optional order like these examples:
1884 ///
1885 /// ```text
1886 /// (3, 4) // Shape 3 x 4 with default order (RowMajor)
1887 /// ((3, 4), Order::RowMajor)) // use specific order
1888 /// ((3, 4), Order::ColumnMajor)) // use specific order
1889 /// ((3, 4), Order::C)) // use shorthand for order - shorthands C and F
1890 /// ```
1891 ///
1892 /// # Example
1893 ///
1894 /// ```
1895 /// use kn0sys_ndarray::{aview1, aview2};
1896 /// use kn0sys_ndarray::Order;
1897 ///
1898 /// assert!(
1899 /// aview1(&[1., 2., 3., 4.]).into_shape_with_order((2, 2)).unwrap()
1900 /// == aview2(&[[1., 2.],
1901 /// [3., 4.]])
1902 /// );
1903 ///
1904 /// assert!(
1905 /// aview1(&[1., 2., 3., 4.]).into_shape_with_order(((2, 2), Order::ColumnMajor)).unwrap()
1906 /// == aview2(&[[1., 3.],
1907 /// [2., 4.]])
1908 /// );
1909 /// ```
1910 pub fn into_shape_with_order<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1911 where E: ShapeArg
1912 {
1913 let (shape, order) = shape.into_shape_and_order();
1914 self.into_shape_with_order_impl(shape, order.unwrap_or(Order::RowMajor))
1915 }
1916
1917 fn into_shape_with_order_impl<E>(self, shape: E, order: Order) -> Result<ArrayBase<S, E>, ShapeError>
1918 where E: Dimension
1919 {
1920 let shape = shape.into_dimension();
1921 if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
1922 return Err(error::incompatible_shapes(&self.dim, &shape));
1923 }
1924
1925 // Check if contiguous, then we can change shape
1926 unsafe {
1927 // safe because arrays are contiguous and len is unchanged
1928 match order {
1929 Order::RowMajor if self.is_standard_layout() =>
1930 Ok(self.with_strides_dim(shape.default_strides(), shape)),
1931 Order::ColumnMajor if self.raw_view().reversed_axes().is_standard_layout() =>
1932 Ok(self.with_strides_dim(shape.fortran_strides(), shape)),
1933 _otherwise => Err(error::from_kind(error::ErrorKind::IncompatibleLayout)),
1934 }
1935 }
1936 }
1937
1938 /// Transform the array into `shape`; any shape with the same number of
1939 /// elements is accepted, but the source array or view must be in standard
1940 /// or column-major (Fortran) layout.
1941 ///
1942 /// **Note** that `.into_shape()` "moves" elements differently depending on if the input array
1943 /// is C-contig or F-contig, it follows the index order that corresponds to the memory order.
1944 /// Prefer to use `.to_shape()` or `.into_shape_with_order()`.
1945 ///
1946 /// Because of this, the method **is deprecated**. That reshapes depend on memory order is not
1947 /// intuitive.
1948 ///
1949 /// **Errors** if the shapes don't have the same number of elements.<br>
1950 /// **Errors** if the input array is not c- or f-contiguous.
1951 ///
1952 /// ```
1953 /// use kn0sys_ndarray::{aview1, aview2};
1954 ///
1955 /// assert!(
1956 /// aview1(&[1., 2., 3., 4.]).into_shape((2, 2)).unwrap()
1957 /// == aview2(&[[1., 2.],
1958 /// [3., 4.]])
1959 /// );
1960 /// ```
1961 #[deprecated(note = "Use `.into_shape_with_order()` or `.to_shape()`", since = "0.16.0")]
1962 pub fn into_shape<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1963 where E: IntoDimension
1964 {
1965 let shape = shape.into_dimension();
1966 if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
1967 return Err(error::incompatible_shapes(&self.dim, &shape));
1968 }
1969 // Check if contiguous, if not => copy all, else just adapt strides
1970 unsafe {
1971 // safe because arrays are contiguous and len is unchanged
1972 if self.is_standard_layout() {
1973 Ok(self.with_strides_dim(shape.default_strides(), shape))
1974 } else if self.ndim() > 1 && self.raw_view().reversed_axes().is_standard_layout() {
1975 Ok(self.with_strides_dim(shape.fortran_strides(), shape))
1976 } else {
1977 Err(error::from_kind(error::ErrorKind::IncompatibleLayout))
1978 }
1979 }
1980 }
1981
1982 /// Transform the array into `shape`; any shape with the same number of
1983 /// elements is accepted. Array elements are reordered in place if
1984 /// possible, otherwise they are copied to create a new array.
1985 ///
1986 /// If an index ordering is not specified, the default is `RowMajor`.
1987 ///
1988 /// # `.to_shape` vs `.into_shape_clone`
1989 ///
1990 /// - `to_shape` supports views and outputting views
1991 /// - `to_shape` borrows the original array, `into_shape_clone` consumes the original
1992 /// - `into_shape_clone` preserves array type (Array vs ArcArray), but does not support views.
1993 ///
1994 /// **Errors** if the shapes don't have the same number of elements.<br>
1995 pub fn into_shape_clone<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
1996 where
1997 S: DataOwned,
1998 A: Clone,
1999 E: ShapeArg,
2000 {
2001 let (shape, order) = shape.into_shape_and_order();
2002 let order = order.unwrap_or(Order::RowMajor);
2003 self.into_shape_clone_order(shape, order)
2004 }
2005
2006 fn into_shape_clone_order<E>(self, shape: E, order: Order) -> Result<ArrayBase<S, E>, ShapeError>
2007 where
2008 S: DataOwned,
2009 A: Clone,
2010 E: Dimension,
2011 {
2012 let len = self.dim.size();
2013 if size_of_shape_checked(&shape) != Ok(len) {
2014 return Err(error::incompatible_shapes(&self.dim, &shape));
2015 }
2016
2017 // Safe because the array and new shape is empty.
2018 if len == 0 {
2019 unsafe {
2020 return Ok(self.with_strides_dim(shape.default_strides(), shape));
2021 }
2022 }
2023
2024 // Try to reshape the array's current data
2025 match reshape_dim(&self.dim, &self.strides, &shape, order) {
2026 Ok(to_strides) => unsafe {
2027 return Ok(self.with_strides_dim(to_strides, shape));
2028 },
2029 Err(err) if err.kind() == ErrorKind::IncompatibleShape => {
2030 return Err(error::incompatible_shapes(&self.dim, &shape));
2031 }
2032 _otherwise => {}
2033 }
2034
2035 // otherwise, clone and allocate a new array
2036 unsafe {
2037 let (shape, view) = match order {
2038 Order::RowMajor => (shape.set_f(false), self.view()),
2039 Order::ColumnMajor => (shape.set_f(true), self.t()),
2040 };
2041
2042 Ok(ArrayBase::from_shape_trusted_iter_unchecked(shape, view.into_iter(), A::clone))
2043 }
2044 }
2045
2046 /// *Note: Reshape is for `ArcArray` only. Use `.into_shape_with_order()` for
2047 /// other arrays and array views.*
2048 ///
2049 /// Transform the array into `shape`; any shape with the same number of
2050 /// elements is accepted.
2051 ///
2052 /// May clone all elements if needed to arrange elements in standard
2053 /// layout (and break sharing).
2054 ///
2055 /// **Panics** if shapes are incompatible.
2056 ///
2057 /// *This method is obsolete, because it is inflexible in how logical order
2058 /// of the array is handled. See [`.to_shape()`].*
2059 ///
2060 /// ```
2061 /// use kn0sys_ndarray::{rcarr1, rcarr2};
2062 ///
2063 /// assert!(
2064 /// rcarr1(&[1., 2., 3., 4.]).reshape((2, 2))
2065 /// == rcarr2(&[[1., 2.],
2066 /// [3., 4.]])
2067 /// );
2068 /// ```
2069 #[track_caller]
2070 #[deprecated(note = "Use `.into_shape_with_order()` or `.to_shape()`", since = "0.16.0")]
2071 pub fn reshape<E>(&self, shape: E) -> ArrayBase<S, E::Dim>
2072 where
2073 S: DataShared + DataOwned,
2074 A: Clone,
2075 E: IntoDimension,
2076 {
2077 let shape = shape.into_dimension();
2078 if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
2079 panic!(
2080 "ndarray: incompatible shapes in reshape, attempted from: {:?}, to: {:?}",
2081 self.dim.slice(),
2082 shape.slice()
2083 )
2084 }
2085 // Check if contiguous, if not => copy all, else just adapt strides
2086 if self.is_standard_layout() {
2087 let cl = self.clone();
2088 // safe because array is contiguous and shape has equal number of elements
2089 unsafe { cl.with_strides_dim(shape.default_strides(), shape) }
2090 } else {
2091 let v = self.iter().cloned().collect::<Vec<A>>();
2092 unsafe { ArrayBase::from_shape_vec_unchecked(shape, v) }
2093 }
2094 }
2095
2096 /// Flatten the array to a one-dimensional array.
2097 ///
2098 /// The array is returned as a `CowArray`; a view if possible, otherwise an owned array.
2099 ///
2100 /// ```
2101 /// use kn0sys_ndarray::{arr1, arr3};
2102 ///
2103 /// let array = arr3(&[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
2104 /// let flattened = array.flatten();
2105 /// assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
2106 /// ```
2107 pub fn flatten(&self) -> CowArray<'_, A, Ix1>
2108 where
2109 A: Clone,
2110 S: Data,
2111 {
2112 self.flatten_with_order(Order::RowMajor)
2113 }
2114
2115 /// Flatten the array to a one-dimensional array.
2116 ///
2117 /// `order` specifies the *logical* order in which the array is to be read and reshaped.
2118 /// The array is returned as a `CowArray`; a view if possible, otherwise an owned array.
2119 ///
2120 /// ```
2121 /// use kn0sys_ndarray::{arr1, arr2};
2122 /// use kn0sys_ndarray::Order;
2123 ///
2124 /// let array = arr2(&[[1, 2], [3, 4], [5, 6], [7, 8]]);
2125 /// let flattened = array.flatten_with_order(Order::RowMajor);
2126 /// assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
2127 /// let flattened = array.flatten_with_order(Order::ColumnMajor);
2128 /// assert_eq!(flattened, arr1(&[1, 3, 5, 7, 2, 4, 6, 8]));
2129 /// ```
2130 pub fn flatten_with_order(&self, order: Order) -> CowArray<'_, A, Ix1>
2131 where
2132 A: Clone,
2133 S: Data,
2134 {
2135 self.to_shape((self.len(), order)).unwrap()
2136 }
2137
2138 /// Flatten the array to a one-dimensional array, consuming the array.
2139 ///
2140 /// If possible, no copy is made, and the new array use the same memory as the original array.
2141 /// Otherwise, a new array is allocated and the elements are copied.
2142 ///
2143 /// ```
2144 /// use kn0sys_ndarray::{arr1, arr3};
2145 ///
2146 /// let array = arr3(&[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
2147 /// let flattened = array.into_flat();
2148 /// assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
2149 /// ```
2150 pub fn into_flat(self) -> ArrayBase<S, Ix1>
2151 where
2152 A: Clone,
2153 S: DataOwned,
2154 {
2155 let len = self.len();
2156 self.into_shape_clone(Ix1(len)).unwrap()
2157 }
2158
2159 /// Convert any array or array view to a dynamic dimensional array or
2160 /// array view (respectively).
2161 ///
2162 /// ```
2163 /// use kn0sys_ndarray::{arr2, ArrayD};
2164 ///
2165 /// let array: ArrayD<i32> = arr2(&[[1, 2],
2166 /// [3, 4]]).into_dyn();
2167 /// ```
2168 pub fn into_dyn(self) -> ArrayBase<S, IxDyn>
2169 {
2170 // safe because new dims equivalent
2171 unsafe {
2172 ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(self.strides.into_dyn(), self.dim.into_dyn())
2173 }
2174 }
2175
2176 /// Convert an array or array view to another with the same type, but different dimensionality
2177 /// type. Errors if the dimensions don't agree (the number of axes must match).
2178 ///
2179 /// Note that conversion to a dynamic dimensional array will never fail (and is equivalent to
2180 /// the `into_dyn` method).
2181 ///
2182 /// ```
2183 /// use kn0sys_ndarray::{ArrayD, Ix2, IxDyn};
2184 ///
2185 /// // Create a dynamic dimensionality array and convert it to an Array2
2186 /// // (Ix2 dimension type).
2187 ///
2188 /// let array = ArrayD::<f64>::zeros(IxDyn(&[10, 10]));
2189 ///
2190 /// assert!(array.into_dimensionality::<Ix2>().is_ok());
2191 /// ```
2192 pub fn into_dimensionality<D2>(self) -> Result<ArrayBase<S, D2>, ShapeError>
2193 where D2: Dimension
2194 {
2195 unsafe {
2196 if D::NDIM == D2::NDIM {
2197 // safe because D == D2
2198 let dim = unlimited_transmute::<D, D2>(self.dim);
2199 let strides = unlimited_transmute::<D, D2>(self.strides);
2200 return Ok(ArrayBase::from_data_ptr(self.data, self.ptr).with_strides_dim(strides, dim));
2201 } else if D::NDIM.is_none() || D2::NDIM.is_none() {
2202 // one is dynamic dim
2203 // safe because dim, strides are equivalent under a different type
2204 if let Some(dim) = D2::from_dimension(&self.dim) {
2205 if let Some(strides) = D2::from_dimension(&self.strides) {
2206 return Ok(self.with_strides_dim(strides, dim));
2207 }
2208 }
2209 }
2210 }
2211 Err(ShapeError::from_kind(ErrorKind::IncompatibleShape))
2212 }
2213
2214 /// Act like a larger size and/or shape array by *broadcasting*
2215 /// into a larger shape, if possible.
2216 ///
2217 /// Return `None` if shapes can not be broadcast together.
2218 ///
2219 /// ***Background***
2220 ///
2221 /// * Two axes are compatible if they are equal, or one of them is 1.
2222 /// * In this instance, only the axes of the smaller side (self) can be 1.
2223 ///
2224 /// Compare axes beginning with the *last* axis of each shape.
2225 ///
2226 /// For example (1, 2, 4) can be broadcast into (7, 6, 2, 4)
2227 /// because its axes are either equal or 1 (or missing);
2228 /// while (2, 2) can *not* be broadcast into (2, 4).
2229 ///
2230 /// The implementation creates a view with strides set to zero for the
2231 /// axes that are to be repeated.
2232 ///
2233 /// The broadcasting documentation for Numpy has more information.
2234 ///
2235 /// ```
2236 /// use kn0sys_ndarray::{aview1, aview2};
2237 ///
2238 /// assert!(
2239 /// aview1(&[1., 0.]).broadcast((10, 2)).unwrap()
2240 /// == aview2(&[[1., 0.]; 10])
2241 /// );
2242 /// ```
2243 pub fn broadcast<E>(&self, dim: E) -> Option<ArrayView<'_, A, E::Dim>>
2244 where
2245 E: IntoDimension,
2246 S: Data,
2247 {
2248 /// Return new stride when trying to grow `from` into shape `to`
2249 ///
2250 /// Broadcasting works by returning a "fake stride" where elements
2251 /// to repeat are in axes with 0 stride, so that several indexes point
2252 /// to the same element.
2253 ///
2254 /// **Note:** Cannot be used for mutable iterators, since repeating
2255 /// elements would create aliasing pointers.
2256 fn upcast<D: Dimension, E: Dimension>(to: &D, from: &E, stride: &E) -> Option<D>
2257 {
2258 // Make sure the product of non-zero axis lengths does not exceed
2259 // `isize::MAX`. This is the only safety check we need to perform
2260 // because all the other constraints of `ArrayBase` are guaranteed
2261 // to be met since we're starting from a valid `ArrayBase`.
2262 let _ = size_of_shape_checked(to).ok()?;
2263
2264 let mut new_stride = to.clone();
2265 // begin at the back (the least significant dimension)
2266 // size of the axis has to either agree or `from` has to be 1
2267 if to.ndim() < from.ndim() {
2268 return None;
2269 }
2270
2271 {
2272 let mut new_stride_iter = new_stride.slice_mut().iter_mut().rev();
2273 for ((er, es), dr) in from
2274 .slice()
2275 .iter()
2276 .rev()
2277 .zip(stride.slice().iter().rev())
2278 .zip(new_stride_iter.by_ref())
2279 {
2280 /* update strides */
2281 if *dr == *er {
2282 /* keep stride */
2283 *dr = *es;
2284 } else if *er == 1 {
2285 /* dead dimension, zero stride */
2286 *dr = 0
2287 } else {
2288 return None;
2289 }
2290 }
2291
2292 /* set remaining strides to zero */
2293 for dr in new_stride_iter {
2294 *dr = 0;
2295 }
2296 }
2297 Some(new_stride)
2298 }
2299 let dim = dim.into_dimension();
2300
2301 // Note: zero strides are safe precisely because we return an read-only view
2302 let broadcast_strides = upcast(&dim, &self.dim, &self.strides)?;
2303 unsafe { Some(ArrayView::new(self.ptr, dim, broadcast_strides)) }
2304 }
2305
2306 /// For two arrays or views, find their common shape if possible and
2307 /// broadcast them as array views into that shape.
2308 ///
2309 /// Return `ShapeError` if their shapes can not be broadcast together.
2310 #[allow(clippy::type_complexity)]
2311 pub(crate) fn broadcast_with<'a, 'b, B, S2, E>(
2312 &'a self, other: &'b ArrayBase<S2, E>,
2313 ) -> Result<(ArrayView<'a, A, DimMaxOf<D, E>>, ArrayView<'b, B, DimMaxOf<D, E>>), ShapeError>
2314 where
2315 S: Data<Elem = A>,
2316 S2: Data<Elem = B>,
2317 D: Dimension + DimMax<E>,
2318 E: Dimension,
2319 {
2320 let shape = co_broadcast::<D, E, <D as DimMax<E>>::Output>(&self.dim, &other.dim)?;
2321 let view1 = if shape.slice() == self.dim.slice() {
2322 self.view()
2323 .into_dimensionality::<<D as DimMax<E>>::Output>()
2324 .unwrap()
2325 } else if let Some(view1) = self.broadcast(shape.clone()) {
2326 view1
2327 } else {
2328 return Err(from_kind(ErrorKind::IncompatibleShape));
2329 };
2330 let view2 = if shape.slice() == other.dim.slice() {
2331 other
2332 .view()
2333 .into_dimensionality::<<D as DimMax<E>>::Output>()
2334 .unwrap()
2335 } else if let Some(view2) = other.broadcast(shape) {
2336 view2
2337 } else {
2338 return Err(from_kind(ErrorKind::IncompatibleShape));
2339 };
2340 Ok((view1, view2))
2341 }
2342
2343 /// Swap axes `ax` and `bx`.
2344 ///
2345 /// This does not move any data, it just adjusts the array’s dimensions
2346 /// and strides.
2347 ///
2348 /// **Panics** if the axes are out of bounds.
2349 ///
2350 /// ```
2351 /// use kn0sys_ndarray::arr2;
2352 ///
2353 /// let mut a = arr2(&[[1., 2., 3.]]);
2354 /// a.swap_axes(0, 1);
2355 /// assert!(
2356 /// a == arr2(&[[1.], [2.], [3.]])
2357 /// );
2358 /// ```
2359 #[track_caller]
2360 pub fn swap_axes(&mut self, ax: usize, bx: usize)
2361 {
2362 self.dim.slice_mut().swap(ax, bx);
2363 self.strides.slice_mut().swap(ax, bx);
2364 }
2365
2366 /// Permute the axes.
2367 ///
2368 /// This does not move any data, it just adjusts the array’s dimensions
2369 /// and strides.
2370 ///
2371 /// *i* in the *j*-th place in the axes sequence means `self`'s *i*-th axis
2372 /// becomes `self.permuted_axes()`'s *j*-th axis
2373 ///
2374 /// **Panics** if any of the axes are out of bounds, if an axis is missing,
2375 /// or if an axis is repeated more than once.
2376 ///
2377 /// # Examples
2378 ///
2379 /// ```
2380 /// use kn0sys_ndarray::{arr2, Array3};
2381 ///
2382 /// let a = arr2(&[[0, 1], [2, 3]]);
2383 /// assert_eq!(a.view().permuted_axes([1, 0]), a.t());
2384 ///
2385 /// let b = Array3::<u8>::zeros((1, 2, 3));
2386 /// assert_eq!(b.permuted_axes([1, 0, 2]).shape(), &[2, 1, 3]);
2387 /// ```
2388 #[track_caller]
2389 pub fn permuted_axes<T>(self, axes: T) -> ArrayBase<S, D>
2390 where T: IntoDimension<Dim = D>
2391 {
2392 let axes = axes.into_dimension();
2393 // Ensure that each axis is used exactly once.
2394 let mut usage_counts = D::zeros(self.ndim());
2395 for axis in axes.slice() {
2396 usage_counts[*axis] += 1;
2397 }
2398 for count in usage_counts.slice() {
2399 assert_eq!(*count, 1, "each axis must be listed exactly once");
2400 }
2401 // Determine the new shape and strides.
2402 let mut new_dim = usage_counts; // reuse to avoid an allocation
2403 let mut new_strides = D::zeros(self.ndim());
2404 {
2405 let dim = self.dim.slice();
2406 let strides = self.strides.slice();
2407 for (new_axis, &axis) in axes.slice().iter().enumerate() {
2408 new_dim[new_axis] = dim[axis];
2409 new_strides[new_axis] = strides[axis];
2410 }
2411 }
2412 // safe because axis invariants are checked above; they are a permutation of the old
2413 unsafe { self.with_strides_dim(new_strides, new_dim) }
2414 }
2415
2416 /// Transpose the array by reversing axes.
2417 ///
2418 /// Transposition reverses the order of the axes (dimensions and strides)
2419 /// while retaining the same data.
2420 pub fn reversed_axes(mut self) -> ArrayBase<S, D>
2421 {
2422 self.dim.slice_mut().reverse();
2423 self.strides.slice_mut().reverse();
2424 self
2425 }
2426
2427 /// Return a transposed view of the array.
2428 ///
2429 /// This is a shorthand for `self.view().reversed_axes()`.
2430 ///
2431 /// See also the more general methods `.reversed_axes()` and `.swap_axes()`.
2432 pub fn t(&self) -> ArrayView<'_, A, D>
2433 where S: Data
2434 {
2435 self.view().reversed_axes()
2436 }
2437
2438 /// Return an iterator over the length and stride of each axis.
2439 pub fn axes(&self) -> Axes<'_, D>
2440 {
2441 axes_of(&self.dim, &self.strides)
2442 }
2443
2444 /*
2445 /// Return the axis with the least stride (by absolute value)
2446 pub fn min_stride_axis(&self) -> Axis {
2447 self.dim.min_stride_axis(&self.strides)
2448 }
2449 */
2450
2451 /// Return the axis with the greatest stride (by absolute value),
2452 /// preferring axes with len > 1.
2453 pub fn max_stride_axis(&self) -> Axis
2454 {
2455 self.dim.max_stride_axis(&self.strides)
2456 }
2457
2458 /// Reverse the stride of `axis`.
2459 ///
2460 /// ***Panics*** if the axis is out of bounds.
2461 #[track_caller]
2462 pub fn invert_axis(&mut self, axis: Axis)
2463 {
2464 unsafe {
2465 let s = self.strides.axis(axis) as Ixs;
2466 let m = self.dim.axis(axis);
2467 if m != 0 {
2468 self.ptr = self.ptr.offset(stride_offset(m - 1, s as Ix));
2469 }
2470 self.strides.set_axis(axis, (-s) as Ix);
2471 }
2472 }
2473
2474 /// If possible, merge in the axis `take` to `into`.
2475 ///
2476 /// Returns `true` iff the axes are now merged.
2477 ///
2478 /// This method merges the axes if movement along the two original axes
2479 /// (moving fastest along the `into` axis) can be equivalently represented
2480 /// as movement along one (merged) axis. Merging the axes preserves this
2481 /// order in the merged axis. If `take` and `into` are the same axis, then
2482 /// the axis is "merged" if its length is ≤ 1.
2483 ///
2484 /// If the return value is `true`, then the following hold:
2485 ///
2486 /// * The new length of the `into` axis is the product of the original
2487 /// lengths of the two axes.
2488 ///
2489 /// * The new length of the `take` axis is 0 if the product of the original
2490 /// lengths of the two axes is 0, and 1 otherwise.
2491 ///
2492 /// If the return value is `false`, then merging is not possible, and the
2493 /// original shape and strides have been preserved.
2494 ///
2495 /// Note that the ordering constraint means that if it's possible to merge
2496 /// `take` into `into`, it's usually not possible to merge `into` into
2497 /// `take`, and vice versa.
2498 ///
2499 /// ```
2500 /// use kn0sys_ndarray::Array3;
2501 /// use kn0sys_ndarray::Axis;
2502 ///
2503 /// let mut a = Array3::<f64>::zeros((2, 3, 4));
2504 /// assert!(a.merge_axes(Axis(1), Axis(2)));
2505 /// assert_eq!(a.shape(), &[2, 1, 12]);
2506 /// ```
2507 ///
2508 /// ***Panics*** if an axis is out of bounds.
2509 #[track_caller]
2510 pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool
2511 {
2512 merge_axes(&mut self.dim, &mut self.strides, take, into)
2513 }
2514
2515 /// Insert new array axis at `axis` and return the result.
2516 ///
2517 /// ```
2518 /// use kn0sys_ndarray::{Array3, Axis, arr1, arr2};
2519 ///
2520 /// // Convert a 1-D array into a row vector (2-D).
2521 /// let a = arr1(&[1, 2, 3]);
2522 /// let row = a.insert_axis(Axis(0));
2523 /// assert_eq!(row, arr2(&[[1, 2, 3]]));
2524 ///
2525 /// // Convert a 1-D array into a column vector (2-D).
2526 /// let b = arr1(&[1, 2, 3]);
2527 /// let col = b.insert_axis(Axis(1));
2528 /// assert_eq!(col, arr2(&[[1], [2], [3]]));
2529 ///
2530 /// // The new axis always has length 1.
2531 /// let b = Array3::<f64>::zeros((3, 4, 5));
2532 /// assert_eq!(b.insert_axis(Axis(2)).shape(), &[3, 4, 1, 5]);
2533 /// ```
2534 ///
2535 /// ***Panics*** if the axis is out of bounds.
2536 #[track_caller]
2537 pub fn insert_axis(self, axis: Axis) -> ArrayBase<S, D::Larger>
2538 {
2539 assert!(axis.index() <= self.ndim());
2540 // safe because a new axis of length one does not affect memory layout
2541 unsafe {
2542 let strides = self.strides.insert_axis(axis);
2543 let dim = self.dim.insert_axis(axis);
2544 self.with_strides_dim(strides, dim)
2545 }
2546 }
2547
2548 /// Remove array axis `axis` and return the result.
2549 ///
2550 /// This is equivalent to `.index_axis_move(axis, 0)` and makes most sense to use if the
2551 /// axis to remove is of length 1.
2552 ///
2553 /// **Panics** if the axis is out of bounds or its length is zero.
2554 #[track_caller]
2555 pub fn remove_axis(self, axis: Axis) -> ArrayBase<S, D::Smaller>
2556 where D: RemoveAxis
2557 {
2558 self.index_axis_move(axis, 0)
2559 }
2560
2561 pub(crate) fn pointer_is_inbounds(&self) -> bool
2562 {
2563 self.data._is_pointer_inbounds(self.as_ptr())
2564 }
2565
2566 /// Perform an elementwise assigment to `self` from `rhs`.
2567 ///
2568 /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
2569 ///
2570 /// **Panics** if broadcasting isn’t possible.
2571 #[track_caller]
2572 pub fn assign<E: Dimension, S2>(&mut self, rhs: &ArrayBase<S2, E>)
2573 where
2574 S: DataMut,
2575 A: Clone,
2576 S2: Data<Elem = A>,
2577 {
2578 self.zip_mut_with(rhs, |x, y| x.clone_from(y));
2579 }
2580
2581 /// Perform an elementwise assigment of values cloned from `self` into array or producer `to`.
2582 ///
2583 /// The destination `to` can be another array or a producer of assignable elements.
2584 /// [`AssignElem`] determines how elements are assigned.
2585 ///
2586 /// **Panics** if shapes disagree.
2587 #[track_caller]
2588 pub fn assign_to<P>(&self, to: P)
2589 where
2590 S: Data,
2591 P: IntoNdProducer<Dim = D>,
2592 P::Item: AssignElem<A>,
2593 A: Clone,
2594 {
2595 Zip::from(self).map_assign_into(to, A::clone);
2596 }
2597
2598 /// Perform an elementwise assigment to `self` from element `x`.
2599 pub fn fill(&mut self, x: A)
2600 where
2601 S: DataMut,
2602 A: Clone,
2603 {
2604 self.map_inplace(move |elt| elt.clone_from(&x));
2605 }
2606
2607 pub(crate) fn zip_mut_with_same_shape<B, S2, E, F>(&mut self, rhs: &ArrayBase<S2, E>, mut f: F)
2608 where
2609 S: DataMut,
2610 S2: Data<Elem = B>,
2611 E: Dimension,
2612 F: FnMut(&mut A, &B),
2613 {
2614 debug_assert_eq!(self.shape(), rhs.shape());
2615
2616 if self.dim.strides_equivalent(&self.strides, &rhs.strides) {
2617 if let Some(self_s) = self.as_slice_memory_order_mut() {
2618 if let Some(rhs_s) = rhs.as_slice_memory_order() {
2619 for (s, r) in self_s.iter_mut().zip(rhs_s) {
2620 f(s, r);
2621 }
2622 return;
2623 }
2624 }
2625 }
2626
2627 // Otherwise, fall back to the outer iter
2628 self.zip_mut_with_by_rows(rhs, f);
2629 }
2630
2631 // zip two arrays where they have different layout or strides
2632 #[inline(always)]
2633 fn zip_mut_with_by_rows<B, S2, E, F>(&mut self, rhs: &ArrayBase<S2, E>, mut f: F)
2634 where
2635 S: DataMut,
2636 S2: Data<Elem = B>,
2637 E: Dimension,
2638 F: FnMut(&mut A, &B),
2639 {
2640 debug_assert_eq!(self.shape(), rhs.shape());
2641 debug_assert_ne!(self.ndim(), 0);
2642
2643 // break the arrays up into their inner rows
2644 let n = self.ndim();
2645 let dim = self.raw_dim();
2646 Zip::from(LanesMut::new(self.view_mut(), Axis(n - 1)))
2647 .and(Lanes::new(rhs.broadcast_assume(dim), Axis(n - 1)))
2648 .for_each(move |s_row, r_row| Zip::from(s_row).and(r_row).for_each(&mut f));
2649 }
2650
2651 fn zip_mut_with_elem<B, F>(&mut self, rhs_elem: &B, mut f: F)
2652 where
2653 S: DataMut,
2654 F: FnMut(&mut A, &B),
2655 {
2656 self.map_inplace(move |elt| f(elt, rhs_elem));
2657 }
2658
2659 /// Traverse two arrays in unspecified order, in lock step,
2660 /// calling the closure `f` on each element pair.
2661 ///
2662 /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
2663 ///
2664 /// **Panics** if broadcasting isn’t possible.
2665 #[track_caller]
2666 #[inline]
2667 pub fn zip_mut_with<B, S2, E, F>(&mut self, rhs: &ArrayBase<S2, E>, f: F)
2668 where
2669 S: DataMut,
2670 S2: Data<Elem = B>,
2671 E: Dimension,
2672 F: FnMut(&mut A, &B),
2673 {
2674 if rhs.dim.ndim() == 0 {
2675 // Skip broadcast from 0-dim array
2676 self.zip_mut_with_elem(rhs.get_0d(), f);
2677 } else if self.dim.ndim() == rhs.dim.ndim() && self.shape() == rhs.shape() {
2678 self.zip_mut_with_same_shape(rhs, f);
2679 } else {
2680 let rhs_broadcast = rhs.broadcast_unwrap(self.raw_dim());
2681 self.zip_mut_with_by_rows(&rhs_broadcast, f);
2682 }
2683 }
2684
2685 /// Traverse the array elements and apply a fold,
2686 /// returning the resulting value.
2687 ///
2688 /// Elements are visited in arbitrary order.
2689 pub fn fold<'a, F, B>(&'a self, init: B, f: F) -> B
2690 where
2691 F: FnMut(B, &'a A) -> B,
2692 A: 'a,
2693 S: Data,
2694 {
2695 if let Some(slc) = self.as_slice_memory_order() {
2696 slc.iter().fold(init, f)
2697 } else {
2698 let mut v = self.view();
2699 move_min_stride_axis_to_last(&mut v.dim, &mut v.strides);
2700 v.into_elements_base().fold(init, f)
2701 }
2702 }
2703
2704 /// Call `f` by reference on each element and create a new array
2705 /// with the new values.
2706 ///
2707 /// Elements are visited in arbitrary order.
2708 ///
2709 /// Return an array with the same shape as `self`.
2710 ///
2711 /// ```
2712 /// use kn0sys_ndarray::arr2;
2713 ///
2714 /// let a = arr2(&[[ 0., 1.],
2715 /// [-1., 2.]]);
2716 /// assert!(
2717 /// a.map(|x| *x >= 1.0)
2718 /// == arr2(&[[false, true],
2719 /// [false, true]])
2720 /// );
2721 /// ```
2722 pub fn map<'a, B, F>(&'a self, f: F) -> Array<B, D>
2723 where
2724 F: FnMut(&'a A) -> B,
2725 A: 'a,
2726 S: Data,
2727 {
2728 unsafe {
2729 if let Some(slc) = self.as_slice_memory_order() {
2730 ArrayBase::from_shape_trusted_iter_unchecked(
2731 self.dim.clone().strides(self.strides.clone()),
2732 slc.iter(),
2733 f,
2734 )
2735 } else {
2736 ArrayBase::from_shape_trusted_iter_unchecked(self.dim.clone(), self.iter(), f)
2737 }
2738 }
2739 }
2740
2741 /// Call `f` on a mutable reference of each element and create a new array
2742 /// with the new values.
2743 ///
2744 /// Elements are visited in arbitrary order.
2745 ///
2746 /// Return an array with the same shape as `self`.
2747 pub fn map_mut<'a, B, F>(&'a mut self, f: F) -> Array<B, D>
2748 where
2749 F: FnMut(&'a mut A) -> B,
2750 A: 'a,
2751 S: DataMut,
2752 {
2753 let dim = self.dim.clone();
2754 if self.is_contiguous() {
2755 let strides = self.strides.clone();
2756 let slc = self.as_slice_memory_order_mut().unwrap();
2757 unsafe { ArrayBase::from_shape_trusted_iter_unchecked(dim.strides(strides), slc.iter_mut(), f) }
2758 } else {
2759 unsafe { ArrayBase::from_shape_trusted_iter_unchecked(dim, self.iter_mut(), f) }
2760 }
2761 }
2762
2763 /// Call `f` by **v**alue on each element and create a new array
2764 /// with the new values.
2765 ///
2766 /// Elements are visited in arbitrary order.
2767 ///
2768 /// Return an array with the same shape as `self`.
2769 ///
2770 /// ```
2771 /// use kn0sys_ndarray::arr2;
2772 ///
2773 /// let a = arr2(&[[ 0., 1.],
2774 /// [-1., 2.]]);
2775 /// assert!(
2776 /// a.mapv(f32::abs) == arr2(&[[0., 1.],
2777 /// [1., 2.]])
2778 /// );
2779 /// ```
2780 pub fn mapv<B, F>(&self, mut f: F) -> Array<B, D>
2781 where
2782 F: FnMut(A) -> B,
2783 A: Clone,
2784 S: Data,
2785 {
2786 self.map(move |x| f(x.clone()))
2787 }
2788
2789 /// Call `f` by **v**alue on each element, update the array with the new values
2790 /// and return it.
2791 ///
2792 /// Elements are visited in arbitrary order.
2793 pub fn mapv_into<F>(mut self, f: F) -> Self
2794 where
2795 S: DataMut,
2796 F: FnMut(A) -> A,
2797 A: Clone,
2798 {
2799 self.mapv_inplace(f);
2800 self
2801 }
2802
2803 /// Consume the array, call `f` by **v**alue on each element, and return an
2804 /// owned array with the new values. Works for **any** `F: FnMut(A)->B`.
2805 ///
2806 /// If `A` and `B` are the same type then the map is performed by delegating
2807 /// to [`mapv_into`] and then converting into an owned array. This avoids
2808 /// unnecessary memory allocations in [`mapv`].
2809 ///
2810 /// If `A` and `B` are different types then a new array is allocated and the
2811 /// map is performed as in [`mapv`].
2812 ///
2813 /// Elements are visited in arbitrary order.
2814 ///
2815 /// [`mapv_into`]: ArrayBase::mapv_into
2816 /// [`mapv`]: ArrayBase::mapv
2817 pub fn mapv_into_any<B, F>(self, mut f: F) -> Array<B, D>
2818 where
2819 S: DataMut,
2820 F: FnMut(A) -> B,
2821 A: Clone + 'static,
2822 B: 'static,
2823 {
2824 if core::any::TypeId::of::<A>() == core::any::TypeId::of::<B>() {
2825 // A and B are the same type.
2826 // Wrap f in a closure of type FnMut(A) -> A .
2827 let f = |a| {
2828 let b = f(a);
2829 // Safe because A and B are the same type.
2830 unsafe { unlimited_transmute::<B, A>(b) }
2831 };
2832 // Delegate to mapv_into() using the wrapped closure.
2833 // Convert output to a uniquely owned array of type Array<A, D>.
2834 let output = self.mapv_into(f).into_owned();
2835 // Change the return type from Array<A, D> to Array<B, D>.
2836 // Again, safe because A and B are the same type.
2837 unsafe { unlimited_transmute::<Array<A, D>, Array<B, D>>(output) }
2838 } else {
2839 // A and B are not the same type.
2840 // Fallback to mapv().
2841 self.mapv(f)
2842 }
2843 }
2844
2845 /// Modify the array in place by calling `f` by mutable reference on each element.
2846 ///
2847 /// Elements are visited in arbitrary order.
2848 pub fn map_inplace<'a, F>(&'a mut self, f: F)
2849 where
2850 S: DataMut,
2851 A: 'a,
2852 F: FnMut(&'a mut A),
2853 {
2854 match self.try_as_slice_memory_order_mut() {
2855 Ok(slc) => slc.iter_mut().for_each(f),
2856 Err(arr) => {
2857 let mut v = arr.view_mut();
2858 move_min_stride_axis_to_last(&mut v.dim, &mut v.strides);
2859 v.into_elements_base().for_each(f);
2860 }
2861 }
2862 }
2863
2864 /// Modify the array in place by calling `f` by **v**alue on each element.
2865 /// The array is updated with the new values.
2866 ///
2867 /// Elements are visited in arbitrary order.
2868 ///
2869 /// ```
2870 /// # #[cfg(feature = "approx")] {
2871 /// use approx::assert_abs_diff_eq;
2872 /// use kn0sys_ndarray::arr2;
2873 ///
2874 /// let mut a = arr2(&[[ 0., 1.],
2875 /// [-1., 2.]]);
2876 /// a.mapv_inplace(f32::exp);
2877 /// assert_abs_diff_eq!(
2878 /// a,
2879 /// arr2(&[[1.00000, 2.71828],
2880 /// [0.36788, 7.38906]]),
2881 /// epsilon = 1e-5,
2882 /// );
2883 /// # }
2884 /// ```
2885 pub fn mapv_inplace<F>(&mut self, mut f: F)
2886 where
2887 S: DataMut,
2888 F: FnMut(A) -> A,
2889 A: Clone,
2890 {
2891 self.map_inplace(move |x| *x = f(x.clone()));
2892 }
2893
2894 /// Call `f` for each element in the array.
2895 ///
2896 /// Elements are visited in arbitrary order.
2897 pub fn for_each<'a, F>(&'a self, mut f: F)
2898 where
2899 F: FnMut(&'a A),
2900 A: 'a,
2901 S: Data,
2902 {
2903 self.fold((), move |(), elt| f(elt))
2904 }
2905
2906 /// Fold along an axis.
2907 ///
2908 /// Combine the elements of each subview with the previous using the `fold`
2909 /// function and initial value `init`.
2910 ///
2911 /// Return the result as an `Array`.
2912 ///
2913 /// **Panics** if `axis` is out of bounds.
2914 #[track_caller]
2915 pub fn fold_axis<B, F>(&self, axis: Axis, init: B, mut fold: F) -> Array<B, D::Smaller>
2916 where
2917 D: RemoveAxis,
2918 F: FnMut(&B, &A) -> B,
2919 B: Clone,
2920 S: Data,
2921 {
2922 let mut res = Array::from_elem(self.raw_dim().remove_axis(axis), init);
2923 for subview in self.axis_iter(axis) {
2924 res.zip_mut_with(&subview, |x, y| *x = fold(x, y));
2925 }
2926 res
2927 }
2928
2929 /// Reduce the values along an axis into just one value, producing a new
2930 /// array with one less dimension.
2931 ///
2932 /// Elements are visited in arbitrary order.
2933 ///
2934 /// Return the result as an `Array`.
2935 ///
2936 /// **Panics** if `axis` is out of bounds.
2937 #[track_caller]
2938 pub fn map_axis<'a, B, F>(&'a self, axis: Axis, mut mapping: F) -> Array<B, D::Smaller>
2939 where
2940 D: RemoveAxis,
2941 F: FnMut(ArrayView1<'a, A>) -> B,
2942 A: 'a,
2943 S: Data,
2944 {
2945 if self.len_of(axis) == 0 {
2946 let new_dim = self.dim.remove_axis(axis);
2947 Array::from_shape_simple_fn(new_dim, move || mapping(ArrayView::from(&[])))
2948 } else {
2949 Zip::from(self.lanes(axis)).map_collect(mapping)
2950 }
2951 }
2952
2953 /// Reduce the values along an axis into just one value, producing a new
2954 /// array with one less dimension.
2955 /// 1-dimensional lanes are passed as mutable references to the reducer,
2956 /// allowing for side-effects.
2957 ///
2958 /// Elements are visited in arbitrary order.
2959 ///
2960 /// Return the result as an `Array`.
2961 ///
2962 /// **Panics** if `axis` is out of bounds.
2963 #[track_caller]
2964 pub fn map_axis_mut<'a, B, F>(&'a mut self, axis: Axis, mut mapping: F) -> Array<B, D::Smaller>
2965 where
2966 D: RemoveAxis,
2967 F: FnMut(ArrayViewMut1<'a, A>) -> B,
2968 A: 'a,
2969 S: DataMut,
2970 {
2971 if self.len_of(axis) == 0 {
2972 let new_dim = self.dim.remove_axis(axis);
2973 Array::from_shape_simple_fn(new_dim, move || mapping(ArrayViewMut::from(&mut [])))
2974 } else {
2975 Zip::from(self.lanes_mut(axis)).map_collect(mapping)
2976 }
2977 }
2978
2979 /// Remove the `index`th elements along `axis` and shift down elements from higher indexes.
2980 ///
2981 /// Note that this "removes" the elements by swapping them around to the end of the axis and
2982 /// shortening the length of the axis; the elements are not deinitialized or dropped by this,
2983 /// just moved out of view (this only matters for elements with ownership semantics). It's
2984 /// similar to slicing an owned array in place.
2985 ///
2986 /// Decreases the length of `axis` by one.
2987 ///
2988 /// ***Panics*** if `axis` is out of bounds<br>
2989 /// ***Panics*** if not `index < self.len_of(axis)`.
2990 pub fn remove_index(&mut self, axis: Axis, index: usize)
2991 where S: DataOwned + DataMut
2992 {
2993 assert!(index < self.len_of(axis), "index {} must be less than length of Axis({})",
2994 index, axis.index());
2995 let (_, mut tail) = self.view_mut().split_at(axis, index);
2996 // shift elements to the front
2997 Zip::from(tail.lanes_mut(axis)).for_each(|mut lane| lane.rotate1_front());
2998 // then slice the axis in place to cut out the removed final element
2999 self.slice_axis_inplace(axis, Slice::new(0, Some(-1), 1));
3000 }
3001
3002 /// Iterates over pairs of consecutive elements along the axis.
3003 ///
3004 /// The first argument to the closure is an element, and the second
3005 /// argument is the next element along the axis. Iteration is guaranteed to
3006 /// proceed in order along the specified axis, but in all other respects
3007 /// the iteration order is unspecified.
3008 ///
3009 /// # Example
3010 ///
3011 /// For example, this can be used to compute the cumulative sum along an
3012 /// axis:
3013 ///
3014 /// ```
3015 /// use kn0sys_ndarray::{array, Axis};
3016 ///
3017 /// let mut arr = array![
3018 /// [[1, 2], [3, 4], [5, 6]],
3019 /// [[7, 8], [9, 10], [11, 12]],
3020 /// ];
3021 /// arr.accumulate_axis_inplace(Axis(1), |&prev, curr| *curr += prev);
3022 /// assert_eq!(
3023 /// arr,
3024 /// array![
3025 /// [[1, 2], [4, 6], [9, 12]],
3026 /// [[7, 8], [16, 18], [27, 30]],
3027 /// ],
3028 /// );
3029 /// ```
3030 pub fn accumulate_axis_inplace<F>(&mut self, axis: Axis, mut f: F)
3031 where
3032 F: FnMut(&A, &mut A),
3033 S: DataMut,
3034 {
3035 if self.len_of(axis) <= 1 {
3036 return;
3037 }
3038 let mut curr = self.raw_view_mut(); // mut borrow of the array here
3039 let mut prev = curr.raw_view(); // derive further raw views from the same borrow
3040 prev.slice_axis_inplace(axis, Slice::from(..-1));
3041 curr.slice_axis_inplace(axis, Slice::from(1..));
3042 // This implementation relies on `Zip` iterating along `axis` in order.
3043 Zip::from(prev).and(curr).for_each(|prev, curr| unsafe {
3044 // These pointer dereferences and borrows are safe because:
3045 //
3046 // 1. They're pointers to elements in the array.
3047 //
3048 // 2. `S: DataMut` guarantees that elements are safe to borrow
3049 // mutably and that they don't alias.
3050 //
3051 // 3. The lifetimes of the borrows last only for the duration
3052 // of the call to `f`, so aliasing across calls to `f`
3053 // cannot occur.
3054 f(&*prev, &mut *curr)
3055 });
3056 }
3057}
3058
3059/// Transmute from A to B.
3060///
3061/// Like transmute, but does not have the compile-time size check which blocks
3062/// using regular transmute in some cases.
3063///
3064/// **Panics** if the size of A and B are different.
3065#[track_caller]
3066#[inline]
3067unsafe fn unlimited_transmute<A, B>(data: A) -> B
3068{
3069 // safe when sizes are equal and caller guarantees that representations are equal
3070 assert_eq!(size_of::<A>(), size_of::<B>());
3071 let old_data = ManuallyDrop::new(data);
3072 (&*old_data as *const A as *const B).read()
3073}
3074
3075type DimMaxOf<A, B> = <A as DimMax<B>>::Output;
3076
3077#[cfg(test)]
3078mod tests
3079{
3080 use super::*;
3081 use crate::arr3;
3082 use defmac::defmac;
3083
3084 #[test]
3085 fn test_flatten()
3086 {
3087 let array = arr3(&[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
3088 let flattened = array.flatten();
3089 assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
3090 }
3091
3092 #[test]
3093 fn test_flatten_with_order()
3094 {
3095 let array = arr2(&[[1, 2], [3, 4], [5, 6], [7, 8]]);
3096 let flattened = array.flatten_with_order(Order::RowMajor);
3097 assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
3098 let flattened = array.flatten_with_order(Order::ColumnMajor);
3099 assert_eq!(flattened, arr1(&[1, 3, 5, 7, 2, 4, 6, 8]));
3100 }
3101
3102 #[test]
3103 fn test_into_flat()
3104 {
3105 let array = arr3(&[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
3106 let flattened = array.into_flat();
3107 assert_eq!(flattened, arr1(&[1, 2, 3, 4, 5, 6, 7, 8]));
3108 }
3109
3110 #[test]
3111 fn test_first_last()
3112 {
3113 let first = 2;
3114 let last = 3;
3115
3116 defmac!(assert_first mut array => {
3117 assert_eq!(array.first().copied(), Some(first));
3118 assert_eq!(array.first_mut().copied(), Some(first));
3119 });
3120 defmac!(assert_last mut array => {
3121 assert_eq!(array.last().copied(), Some(last));
3122 assert_eq!(array.last_mut().copied(), Some(last));
3123 });
3124
3125 let base = Array::from_vec(vec![first, last]);
3126 let a = base.clone();
3127 assert_first!(a);
3128
3129 let a = base.clone();
3130 assert_last!(a);
3131
3132 let a = CowArray::from(base.view());
3133 assert_first!(a);
3134 let a = CowArray::from(base.view());
3135 assert_last!(a);
3136
3137 let a = CowArray::from(base.clone());
3138 assert_first!(a);
3139 let a = CowArray::from(base.clone());
3140 assert_last!(a);
3141
3142 let a = ArcArray::from(base.clone());
3143 let _a2 = a.clone();
3144 assert_last!(a);
3145
3146 let a = ArcArray::from(base.clone());
3147 let _a2 = a.clone();
3148 assert_first!(a);
3149 }
3150}