ndarray/dimension/
dimension_trait.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
9#[cfg(not(feature = "std"))]
10use alloc::vec::Vec;
11use std::fmt::Debug;
12use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
13use std::ops::{Index, IndexMut};
14
15use super::axes_of;
16use super::conversion::Convert;
17use super::ops::DimAdd;
18use super::{stride_offset, stride_offset_checked};
19use crate::itertools::{enumerate, zip};
20use crate::IntoDimension;
21use crate::RemoveAxis;
22use crate::{ArrayView1, ArrayViewMut1};
23use crate::{Axis, DimMax};
24use crate::{Dim, Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, IxDynImpl, Ixs};
25
26/// Array shape and index trait.
27///
28/// This trait defines a number of methods and operations that can be used on
29/// dimensions and indices.
30///
31/// **Note:** *This trait can not be implemented outside the crate*
32pub trait Dimension:
33    Clone
34    + Eq
35    + Debug
36    + Send
37    + Sync
38    + Default
39    + IndexMut<usize, Output = usize>
40    + Add<Self, Output = Self>
41    + AddAssign
42    + for<'x> AddAssign<&'x Self>
43    + Sub<Self, Output = Self>
44    + SubAssign
45    + for<'x> SubAssign<&'x Self>
46    + Mul<usize, Output = Self>
47    + Mul<Self, Output = Self>
48    + MulAssign
49    + for<'x> MulAssign<&'x Self>
50    + MulAssign<usize>
51    + DimMax<Ix0, Output = Self>
52    + DimMax<Self, Output = Self>
53    + DimMax<IxDyn, Output = IxDyn>
54    + DimMax<<Self as Dimension>::Smaller, Output = Self>
55    + DimMax<<Self as Dimension>::Larger, Output = <Self as Dimension>::Larger>
56    + DimAdd<Self>
57    + DimAdd<<Self as Dimension>::Smaller>
58    + DimAdd<<Self as Dimension>::Larger>
59    + DimAdd<Ix0, Output = Self>
60    + DimAdd<Ix1, Output = <Self as Dimension>::Larger>
61    + DimAdd<IxDyn, Output = IxDyn>
62{
63    /// For fixed-size dimension representations (e.g. `Ix2`), this should be
64    /// `Some(ndim)`, and for variable-size dimension representations (e.g.
65    /// `IxDyn`), this should be `None`.
66    const NDIM: Option<usize>;
67    /// Pattern matching friendly form of the dimension value.
68    ///
69    /// - For `Ix1`: `usize`,
70    /// - For `Ix2`: `(usize, usize)`
71    /// - and so on..
72    /// - For `IxDyn`: `IxDyn`
73    type Pattern: IntoDimension<Dim = Self> + Clone + Debug + PartialEq + Eq + Default;
74    /// Next smaller dimension (if applicable)
75    type Smaller: Dimension;
76    /// Next larger dimension
77    type Larger: Dimension + RemoveAxis;
78
79    /// Returns the number of dimensions (number of axes).
80    fn ndim(&self) -> usize;
81
82    /// Convert the dimension into a pattern matching friendly value.
83    fn into_pattern(self) -> Self::Pattern;
84
85    /// Compute the size of the dimension (number of elements)
86    fn size(&self) -> usize
87    {
88        self.slice().iter().product()
89    }
90
91    /// Compute the size while checking for overflow.
92    fn size_checked(&self) -> Option<usize>
93    {
94        self.slice()
95            .iter()
96            .try_fold(1_usize, |s, &a| s.checked_mul(a))
97    }
98
99    #[doc(hidden)]
100    fn slice(&self) -> &[Ix];
101
102    #[doc(hidden)]
103    fn slice_mut(&mut self) -> &mut [Ix];
104
105    /// Borrow as a read-only array view.
106    fn as_array_view(&self) -> ArrayView1<'_, Ix>
107    {
108        ArrayView1::from(self.slice())
109    }
110
111    /// Borrow as a read-write array view.
112    fn as_array_view_mut(&mut self) -> ArrayViewMut1<'_, Ix>
113    {
114        ArrayViewMut1::from(self.slice_mut())
115    }
116
117    #[doc(hidden)]
118    fn equal(&self, rhs: &Self) -> bool
119    {
120        self.slice() == rhs.slice()
121    }
122
123    /// Returns the strides for a standard layout array with the given shape.
124    ///
125    /// If the array is non-empty, the strides result in contiguous layout; if
126    /// the array is empty, the strides are all zeros.
127    #[doc(hidden)]
128    fn default_strides(&self) -> Self
129    {
130        // Compute default array strides
131        // Shape (a, b, c) => Give strides (b * c, c, 1)
132        let mut strides = Self::zeros(self.ndim());
133        // For empty arrays, use all zero strides.
134        if self.slice().iter().all(|&d| d != 0) {
135            let mut it = strides.slice_mut().iter_mut().rev();
136            // Set first element to 1
137            if let Some(rs) = it.next() {
138                *rs = 1;
139            }
140            let mut cum_prod = 1;
141            for (rs, dim) in it.zip(self.slice().iter().rev()) {
142                cum_prod *= *dim;
143                *rs = cum_prod;
144            }
145        }
146        strides
147    }
148
149    /// Returns the strides for a Fortran layout array with the given shape.
150    ///
151    /// If the array is non-empty, the strides result in contiguous layout; if
152    /// the array is empty, the strides are all zeros.
153    #[doc(hidden)]
154    fn fortran_strides(&self) -> Self
155    {
156        // Compute fortran array strides
157        // Shape (a, b, c) => Give strides (1, a, a * b)
158        let mut strides = Self::zeros(self.ndim());
159        // For empty arrays, use all zero strides.
160        if self.slice().iter().all(|&d| d != 0) {
161            let mut it = strides.slice_mut().iter_mut();
162            // Set first element to 1
163            if let Some(rs) = it.next() {
164                *rs = 1;
165            }
166            let mut cum_prod = 1;
167            for (rs, dim) in it.zip(self.slice()) {
168                cum_prod *= *dim;
169                *rs = cum_prod;
170            }
171        }
172        strides
173    }
174
175    /// Creates a dimension of all zeros with the specified ndim.
176    ///
177    /// This method is useful for generalizing over fixed-size and
178    /// variable-size dimension representations.
179    ///
180    /// **Panics** if `Self` has a fixed size that is not `ndim`.
181    fn zeros(ndim: usize) -> Self;
182
183    #[doc(hidden)]
184    #[inline]
185    fn first_index(&self) -> Option<Self>
186    {
187        for ax in self.slice().iter() {
188            if *ax == 0 {
189                return None;
190            }
191        }
192        Some(Self::zeros(self.ndim()))
193    }
194
195    #[doc(hidden)]
196    /// Iteration -- Use self as size, and return next index after `index`
197    /// or None if there are no more.
198    // FIXME: use &Self for index or even &mut?
199    #[inline]
200    fn next_for(&self, index: Self) -> Option<Self>
201    {
202        let mut index = index;
203        let mut done = false;
204        for (&dim, ix) in zip(self.slice(), index.slice_mut()).rev() {
205            *ix += 1;
206            if *ix == dim {
207                *ix = 0;
208            } else {
209                done = true;
210                break;
211            }
212        }
213        if done {
214            Some(index)
215        } else {
216            None
217        }
218    }
219
220    #[doc(hidden)]
221    /// Iteration -- Use self as size, and create the next index after `index`
222    /// Return false if iteration is done
223    ///
224    /// Next in f-order
225    #[inline]
226    fn next_for_f(&self, index: &mut Self) -> bool
227    {
228        let mut end_iteration = true;
229        for (&dim, ix) in zip(self.slice(), index.slice_mut()) {
230            *ix += 1;
231            if *ix == dim {
232                *ix = 0;
233            } else {
234                end_iteration = false;
235                break;
236            }
237        }
238        !end_iteration
239    }
240
241    /// Returns `true` iff `strides1` and `strides2` are equivalent for the
242    /// shape `self`.
243    ///
244    /// The strides are equivalent if, for each axis with length > 1, the
245    /// strides are equal.
246    ///
247    /// Note: Returns `false` if any of the ndims don't match.
248    #[doc(hidden)]
249    fn strides_equivalent<D>(&self, strides1: &Self, strides2: &D) -> bool
250    where D: Dimension
251    {
252        let shape_ndim = self.ndim();
253        shape_ndim == strides1.ndim()
254            && shape_ndim == strides2.ndim()
255            && izip!(self.slice(), strides1.slice(), strides2.slice())
256                .all(|(&d, &s1, &s2)| d <= 1 || s1 as isize == s2 as isize)
257    }
258
259    #[doc(hidden)]
260    /// Return stride offset for index.
261    fn stride_offset(index: &Self, strides: &Self) -> isize
262    {
263        let mut offset = 0;
264        for (&i, &s) in izip!(index.slice(), strides.slice()) {
265            offset += stride_offset(i, s);
266        }
267        offset
268    }
269
270    #[doc(hidden)]
271    /// Return stride offset for this dimension and index.
272    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize>
273    {
274        stride_offset_checked(self.slice(), strides.slice(), index.slice())
275    }
276
277    #[doc(hidden)]
278    fn last_elem(&self) -> usize
279    {
280        if self.ndim() == 0 {
281            0
282        } else {
283            self.slice()[self.ndim() - 1]
284        }
285    }
286
287    #[doc(hidden)]
288    fn set_last_elem(&mut self, i: usize)
289    {
290        let nd = self.ndim();
291        self.slice_mut()[nd - 1] = i;
292    }
293
294    #[doc(hidden)]
295    fn is_contiguous(dim: &Self, strides: &Self) -> bool
296    {
297        let defaults = dim.default_strides();
298        if strides.equal(&defaults) {
299            return true;
300        }
301        if dim.ndim() == 1 {
302            // fast case for ndim == 1:
303            // Either we have length <= 1, then stride is arbitrary,
304            // or we have stride == 1 or stride == -1, but +1 case is already handled above.
305            dim[0] <= 1 || strides[0] as isize == -1
306        } else {
307            let order = strides._fastest_varying_stride_order();
308            let strides = strides.slice();
309
310            let dim_slice = dim.slice();
311            let mut cstride = 1;
312            for &i in order.slice() {
313                // a dimension of length 1 can have unequal strides
314                if dim_slice[i] != 1 && (strides[i] as isize).unsigned_abs() != cstride {
315                    return false;
316                }
317                cstride *= dim_slice[i];
318            }
319            true
320        }
321    }
322
323    /// Return the axis ordering corresponding to the fastest variation
324    /// (in ascending order).
325    ///
326    /// Assumes that no stride value appears twice.
327    #[doc(hidden)]
328    fn _fastest_varying_stride_order(&self) -> Self
329    {
330        let mut indices = self.clone();
331        for (i, elt) in enumerate(indices.slice_mut()) {
332            *elt = i;
333        }
334        let strides = self.slice();
335        indices
336            .slice_mut()
337            .sort_by_key(|&i| (strides[i] as isize).abs());
338        indices
339    }
340
341    /// Compute the minimum stride axis (absolute value), under the constraint
342    /// that the length of the axis is > 1;
343    #[doc(hidden)]
344    fn min_stride_axis(&self, strides: &Self) -> Axis
345    {
346        let n = match self.ndim() {
347            0 => panic!("min_stride_axis: Array must have ndim > 0"),
348            1 => return Axis(0),
349            n => n,
350        };
351        axes_of(self, strides)
352            .rev()
353            .min_by_key(|ax| ax.stride.abs())
354            .map_or(Axis(n - 1), |ax| ax.axis)
355    }
356
357    /// Compute the maximum stride axis (absolute value), under the constraint
358    /// that the length of the axis is > 1;
359    #[doc(hidden)]
360    fn max_stride_axis(&self, strides: &Self) -> Axis
361    {
362        match self.ndim() {
363            0 => panic!("max_stride_axis: Array must have ndim > 0"),
364            1 => return Axis(0),
365            _ => {}
366        }
367        axes_of(self, strides)
368            .filter(|ax| ax.len > 1)
369            .max_by_key(|ax| ax.stride.abs())
370            .map_or(Axis(0), |ax| ax.axis)
371    }
372
373    /// Convert the dimensional into a dynamic dimensional (IxDyn).
374    fn into_dyn(self) -> IxDyn
375    {
376        IxDyn(self.slice())
377    }
378
379    #[doc(hidden)]
380    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self>
381    {
382        let mut s = Self::default();
383        if s.ndim() == d.ndim() {
384            for i in 0..d.ndim() {
385                s[i] = d[i];
386            }
387            Some(s)
388        } else {
389            None
390        }
391    }
392
393    #[doc(hidden)]
394    fn insert_axis(&self, axis: Axis) -> Self::Larger;
395
396    #[doc(hidden)]
397    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller;
398
399    private_decl! {}
400}
401
402// Dimension impls
403
404macro_rules! impl_insert_axis_array(
405    ($n:expr) => (
406        #[inline]
407        fn insert_axis(&self, axis: Axis) -> Self::Larger {
408            debug_assert!(axis.index() <= $n);
409            let mut out = [1; $n + 1];
410            out[0..axis.index()].copy_from_slice(&self.slice()[0..axis.index()]);
411            out[axis.index()+1..=$n].copy_from_slice(&self.slice()[axis.index()..$n]);
412            Dim(out)
413        }
414    );
415);
416
417impl Dimension for Dim<[Ix; 0]>
418{
419    const NDIM: Option<usize> = Some(0);
420    type Pattern = ();
421    type Smaller = Self;
422    type Larger = Ix1;
423    // empty product is 1 -> size is 1
424    #[inline]
425    fn ndim(&self) -> usize
426    {
427        0
428    }
429    #[inline]
430    fn slice(&self) -> &[Ix]
431    {
432        &[]
433    }
434    #[inline]
435    fn slice_mut(&mut self) -> &mut [Ix]
436    {
437        &mut []
438    }
439    #[inline]
440    fn _fastest_varying_stride_order(&self) -> Self
441    {
442        Ix0()
443    }
444    #[inline]
445    fn into_pattern(self) -> Self::Pattern {}
446    #[inline]
447    fn zeros(ndim: usize) -> Self
448    {
449        assert_eq!(ndim, 0);
450        Self::default()
451    }
452    #[inline]
453    fn next_for(&self, _index: Self) -> Option<Self>
454    {
455        None
456    }
457    impl_insert_axis_array!(0);
458    #[inline]
459    fn try_remove_axis(&self, _ignore: Axis) -> Self::Smaller
460    {
461        *self
462    }
463
464    private_impl! {}
465}
466
467impl Dimension for Dim<[Ix; 1]>
468{
469    const NDIM: Option<usize> = Some(1);
470    type Pattern = Ix;
471    type Smaller = Ix0;
472    type Larger = Ix2;
473    #[inline]
474    fn ndim(&self) -> usize
475    {
476        1
477    }
478    #[inline]
479    fn slice(&self) -> &[Ix]
480    {
481        self.ix()
482    }
483    #[inline]
484    fn slice_mut(&mut self) -> &mut [Ix]
485    {
486        self.ixm()
487    }
488    #[inline]
489    fn into_pattern(self) -> Self::Pattern
490    {
491        get!(&self, 0)
492    }
493    #[inline]
494    fn zeros(ndim: usize) -> Self
495    {
496        assert_eq!(ndim, 1);
497        Self::default()
498    }
499    #[inline]
500    fn next_for(&self, mut index: Self) -> Option<Self>
501    {
502        getm!(index, 0) += 1;
503        if get!(&index, 0) < get!(self, 0) {
504            Some(index)
505        } else {
506            None
507        }
508    }
509
510    #[inline]
511    fn equal(&self, rhs: &Self) -> bool
512    {
513        get!(self, 0) == get!(rhs, 0)
514    }
515
516    #[inline]
517    fn size(&self) -> usize
518    {
519        get!(self, 0)
520    }
521    #[inline]
522    fn size_checked(&self) -> Option<usize>
523    {
524        Some(get!(self, 0))
525    }
526
527    #[inline]
528    fn default_strides(&self) -> Self
529    {
530        if get!(self, 0) == 0 {
531            Ix1(0)
532        } else {
533            Ix1(1)
534        }
535    }
536
537    #[inline]
538    fn _fastest_varying_stride_order(&self) -> Self
539    {
540        Ix1(0)
541    }
542
543    #[inline(always)]
544    fn min_stride_axis(&self, _: &Self) -> Axis
545    {
546        Axis(0)
547    }
548
549    #[inline(always)]
550    fn max_stride_axis(&self, _: &Self) -> Axis
551    {
552        Axis(0)
553    }
554
555    #[inline]
556    fn first_index(&self) -> Option<Self>
557    {
558        if get!(self, 0) != 0 {
559            Some(Ix1(0))
560        } else {
561            None
562        }
563    }
564
565    /// Self is an index, return the stride offset
566    #[inline(always)]
567    fn stride_offset(index: &Self, stride: &Self) -> isize
568    {
569        stride_offset(get!(index, 0), get!(stride, 0))
570    }
571
572    /// Return stride offset for this dimension and index.
573    #[inline]
574    fn stride_offset_checked(&self, stride: &Self, index: &Self) -> Option<isize>
575    {
576        if get!(index, 0) < get!(self, 0) {
577            Some(stride_offset(get!(index, 0), get!(stride, 0)))
578        } else {
579            None
580        }
581    }
582    impl_insert_axis_array!(1);
583    #[inline]
584    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller
585    {
586        self.remove_axis(axis)
587    }
588
589    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self>
590    {
591        if 1 == d.ndim() {
592            Some(Ix1(d[0]))
593        } else {
594            None
595        }
596    }
597    private_impl! {}
598}
599
600impl Dimension for Dim<[Ix; 2]>
601{
602    const NDIM: Option<usize> = Some(2);
603    type Pattern = (Ix, Ix);
604    type Smaller = Ix1;
605    type Larger = Ix3;
606    #[inline]
607    fn ndim(&self) -> usize
608    {
609        2
610    }
611    #[inline]
612    fn into_pattern(self) -> Self::Pattern
613    {
614        self.ix().convert()
615    }
616    #[inline]
617    fn slice(&self) -> &[Ix]
618    {
619        self.ix()
620    }
621    #[inline]
622    fn slice_mut(&mut self) -> &mut [Ix]
623    {
624        self.ixm()
625    }
626    #[inline]
627    fn zeros(ndim: usize) -> Self
628    {
629        assert_eq!(ndim, 2);
630        Self::default()
631    }
632    #[inline]
633    fn next_for(&self, index: Self) -> Option<Self>
634    {
635        let mut i = get!(&index, 0);
636        let mut j = get!(&index, 1);
637        let imax = get!(self, 0);
638        let jmax = get!(self, 1);
639        j += 1;
640        if j >= jmax {
641            j = 0;
642            i += 1;
643            if i >= imax {
644                return None;
645            }
646        }
647        Some(Ix2(i, j))
648    }
649
650    #[inline]
651    fn equal(&self, rhs: &Self) -> bool
652    {
653        get!(self, 0) == get!(rhs, 0) && get!(self, 1) == get!(rhs, 1)
654    }
655
656    #[inline]
657    fn size(&self) -> usize
658    {
659        get!(self, 0) * get!(self, 1)
660    }
661
662    #[inline]
663    fn size_checked(&self) -> Option<usize>
664    {
665        let m = get!(self, 0);
666        let n = get!(self, 1);
667        m.checked_mul(n)
668    }
669
670    #[inline]
671    fn last_elem(&self) -> usize
672    {
673        get!(self, 1)
674    }
675
676    #[inline]
677    fn set_last_elem(&mut self, i: usize)
678    {
679        getm!(self, 1) = i;
680    }
681
682    #[inline]
683    fn default_strides(&self) -> Self
684    {
685        let m = get!(self, 0);
686        let n = get!(self, 1);
687        if m == 0 || n == 0 {
688            Ix2(0, 0)
689        } else {
690            Ix2(n, 1)
691        }
692    }
693    #[inline]
694    fn fortran_strides(&self) -> Self
695    {
696        let m = get!(self, 0);
697        let n = get!(self, 1);
698        if m == 0 || n == 0 {
699            Ix2(0, 0)
700        } else {
701            Ix2(1, m)
702        }
703    }
704
705    #[inline]
706    fn _fastest_varying_stride_order(&self) -> Self
707    {
708        if (get!(self, 0) as Ixs).abs() <= (get!(self, 1) as Ixs).abs() {
709            Ix2(0, 1)
710        } else {
711            Ix2(1, 0)
712        }
713    }
714
715    #[inline]
716    fn min_stride_axis(&self, strides: &Self) -> Axis
717    {
718        let s = get!(strides, 0) as Ixs;
719        let t = get!(strides, 1) as Ixs;
720        if s.abs() < t.abs() {
721            Axis(0)
722        } else {
723            Axis(1)
724        }
725    }
726
727    #[inline]
728    fn first_index(&self) -> Option<Self>
729    {
730        let m = get!(self, 0);
731        let n = get!(self, 1);
732        if m != 0 && n != 0 {
733            Some(Ix2(0, 0))
734        } else {
735            None
736        }
737    }
738
739    /// Self is an index, return the stride offset
740    #[inline(always)]
741    fn stride_offset(index: &Self, strides: &Self) -> isize
742    {
743        let i = get!(index, 0);
744        let j = get!(index, 1);
745        let s = get!(strides, 0);
746        let t = get!(strides, 1);
747        stride_offset(i, s) + stride_offset(j, t)
748    }
749
750    /// Return stride offset for this dimension and index.
751    #[inline]
752    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize>
753    {
754        let m = get!(self, 0);
755        let n = get!(self, 1);
756        let i = get!(index, 0);
757        let j = get!(index, 1);
758        let s = get!(strides, 0);
759        let t = get!(strides, 1);
760        if i < m && j < n {
761            Some(stride_offset(i, s) + stride_offset(j, t))
762        } else {
763            None
764        }
765    }
766    impl_insert_axis_array!(2);
767    #[inline]
768    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller
769    {
770        self.remove_axis(axis)
771    }
772    private_impl! {}
773}
774
775impl Dimension for Dim<[Ix; 3]>
776{
777    const NDIM: Option<usize> = Some(3);
778    type Pattern = (Ix, Ix, Ix);
779    type Smaller = Ix2;
780    type Larger = Ix4;
781    #[inline]
782    fn ndim(&self) -> usize
783    {
784        3
785    }
786    #[inline]
787    fn into_pattern(self) -> Self::Pattern
788    {
789        self.ix().convert()
790    }
791    #[inline]
792    fn slice(&self) -> &[Ix]
793    {
794        self.ix()
795    }
796    #[inline]
797    fn slice_mut(&mut self) -> &mut [Ix]
798    {
799        self.ixm()
800    }
801
802    #[inline]
803    fn size(&self) -> usize
804    {
805        let m = get!(self, 0);
806        let n = get!(self, 1);
807        let o = get!(self, 2);
808        m * n * o
809    }
810
811    #[inline]
812    fn zeros(ndim: usize) -> Self
813    {
814        assert_eq!(ndim, 3);
815        Self::default()
816    }
817
818    #[inline]
819    fn next_for(&self, index: Self) -> Option<Self>
820    {
821        let mut i = get!(&index, 0);
822        let mut j = get!(&index, 1);
823        let mut k = get!(&index, 2);
824        let imax = get!(self, 0);
825        let jmax = get!(self, 1);
826        let kmax = get!(self, 2);
827        k += 1;
828        if k == kmax {
829            k = 0;
830            j += 1;
831            if j == jmax {
832                j = 0;
833                i += 1;
834                if i == imax {
835                    return None;
836                }
837            }
838        }
839        Some(Ix3(i, j, k))
840    }
841
842    /// Self is an index, return the stride offset
843    #[inline]
844    fn stride_offset(index: &Self, strides: &Self) -> isize
845    {
846        let i = get!(index, 0);
847        let j = get!(index, 1);
848        let k = get!(index, 2);
849        let s = get!(strides, 0);
850        let t = get!(strides, 1);
851        let u = get!(strides, 2);
852        stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u)
853    }
854
855    /// Return stride offset for this dimension and index.
856    #[inline]
857    fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize>
858    {
859        let m = get!(self, 0);
860        let n = get!(self, 1);
861        let l = get!(self, 2);
862        let i = get!(index, 0);
863        let j = get!(index, 1);
864        let k = get!(index, 2);
865        let s = get!(strides, 0);
866        let t = get!(strides, 1);
867        let u = get!(strides, 2);
868        if i < m && j < n && k < l {
869            Some(stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u))
870        } else {
871            None
872        }
873    }
874
875    #[inline]
876    fn _fastest_varying_stride_order(&self) -> Self
877    {
878        let mut stride = *self;
879        let mut order = Ix3(0, 1, 2);
880        macro_rules! swap {
881            ($stride:expr, $order:expr, $x:expr, $y:expr) => {
882                if ($stride[$x] as isize).abs() > ($stride[$y] as isize).abs() {
883                    $stride.swap($x, $y);
884                    $order.ixm().swap($x, $y);
885                }
886            };
887        }
888        {
889            // stable sorting network for 3 elements
890            let strides = stride.slice_mut();
891            swap![strides, order, 1, 2];
892            swap![strides, order, 0, 1];
893            swap![strides, order, 1, 2];
894        }
895        order
896    }
897    impl_insert_axis_array!(3);
898    #[inline]
899    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller
900    {
901        self.remove_axis(axis)
902    }
903    private_impl! {}
904}
905
906macro_rules! large_dim {
907    ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => (
908        impl Dimension for Dim<[Ix; $n]> {
909            const NDIM: Option<usize> = Some($n);
910            type Pattern = $pattern;
911            type Smaller = Dim<[Ix; $n - 1]>;
912            type Larger = $larger;
913            #[inline]
914            fn ndim(&self) -> usize { $n }
915            #[inline]
916            fn into_pattern(self) -> Self::Pattern {
917                self.ix().convert()
918            }
919            #[inline]
920            fn slice(&self) -> &[Ix] { self.ix() }
921            #[inline]
922            fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
923            #[inline]
924            fn zeros(ndim: usize) -> Self {
925                assert_eq!(ndim, $n);
926                Self::default()
927            }
928            $($insert_axis)*
929            #[inline]
930            fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
931                self.remove_axis(axis)
932            }
933            private_impl!{}
934        }
935    );
936}
937
938large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, {
939    impl_insert_axis_array!(4);
940});
941large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, {
942    impl_insert_axis_array!(5);
943});
944large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, {
945    fn insert_axis(&self, axis: Axis) -> Self::Larger {
946        debug_assert!(axis.index() <= self.ndim());
947        let mut out = Vec::with_capacity(self.ndim() + 1);
948        out.extend_from_slice(&self.slice()[0..axis.index()]);
949        out.push(1);
950        out.extend_from_slice(&self.slice()[axis.index()..self.ndim()]);
951        Dim(out)
952    }
953});
954
955/// IxDyn is a "dynamic" index, pretty hard to use when indexing,
956/// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
957impl Dimension for IxDyn
958{
959    const NDIM: Option<usize> = None;
960    type Pattern = Self;
961    type Smaller = Self;
962    type Larger = Self;
963    #[inline]
964    fn ndim(&self) -> usize
965    {
966        self.ix().len()
967    }
968    #[inline]
969    fn slice(&self) -> &[Ix]
970    {
971        self.ix()
972    }
973    #[inline]
974    fn slice_mut(&mut self) -> &mut [Ix]
975    {
976        self.ixm()
977    }
978    #[inline]
979    fn into_pattern(self) -> Self::Pattern
980    {
981        self
982    }
983
984    #[inline]
985    fn zeros(ndim: usize) -> Self
986    {
987        IxDyn::zeros(ndim)
988    }
989
990    #[inline]
991    fn insert_axis(&self, axis: Axis) -> Self::Larger
992    {
993        debug_assert!(axis.index() <= self.ndim());
994        Dim::new(self.ix().insert(axis.index()))
995    }
996
997    #[inline]
998    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller
999    {
1000        if self.ndim() > 0 {
1001            self.remove_axis(axis)
1002        } else {
1003            self.clone()
1004        }
1005    }
1006
1007    fn from_dimension<D2: Dimension>(d: &D2) -> Option<Self>
1008    {
1009        Some(IxDyn(d.slice()))
1010    }
1011
1012    fn into_dyn(self) -> IxDyn
1013    {
1014        self
1015    }
1016
1017    private_impl! {}
1018}
1019
1020impl Index<usize> for Dim<IxDynImpl>
1021{
1022    type Output = <IxDynImpl as Index<usize>>::Output;
1023    fn index(&self, index: usize) -> &Self::Output
1024    {
1025        &self.ix()[index]
1026    }
1027}
1028
1029impl IndexMut<usize> for Dim<IxDynImpl>
1030{
1031    fn index_mut(&mut self, index: usize) -> &mut Self::Output
1032    {
1033        &mut self.ixm()[index]
1034    }
1035}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy