ndarray/layout/
mod.rs

1mod layoutfmt;
2
3// Layout it a bitset used for internal layout description of
4// arrays, producers and sets of producers.
5// The type is public but users don't interact with it.
6#[doc(hidden)]
7/// Memory layout description
8#[derive(Copy, Clone)]
9pub struct Layout(u32);
10
11impl Layout {
12    pub(crate) const CORDER: u32 = 0b01;
13    pub(crate) const FORDER: u32 = 0b10;
14    pub(crate) const CPREFER: u32 = 0b0100;
15    pub(crate) const FPREFER: u32 = 0b1000;
16
17    #[inline(always)]
18    pub(crate) fn is(self, flag: u32) -> bool {
19        self.0 & flag != 0
20    }
21
22    /// Return layout common to both inputs
23    #[inline(always)]
24    pub(crate) fn intersect(self, other: Layout) -> Layout {
25        Layout(self.0 & other.0)
26    }
27
28    /// Return a layout that simultaneously "is" what both of the inputs are
29    #[inline(always)]
30    pub(crate) fn also(self, other: Layout) -> Layout {
31        Layout(self.0 | other.0)
32    }
33
34    #[inline(always)]
35    pub(crate) fn one_dimensional() -> Layout {
36        Layout::c().also(Layout::f())
37    }
38
39    #[inline(always)]
40    pub(crate) fn c() -> Layout {
41        Layout(Layout::CORDER | Layout::CPREFER)
42    }
43
44    #[inline(always)]
45    pub(crate) fn f() -> Layout {
46        Layout(Layout::FORDER | Layout::FPREFER)
47    }
48
49    #[inline(always)]
50    pub(crate) fn cpref() -> Layout {
51        Layout(Layout::CPREFER)
52    }
53
54    #[inline(always)]
55    pub(crate) fn fpref() -> Layout {
56        Layout(Layout::FPREFER)
57    }
58
59    #[inline(always)]
60    pub(crate) fn none() -> Layout {
61        Layout(0)
62    }
63
64    /// A simple "score" method which scores positive for preferring C-order, negative for F-order
65    /// Subject to change when we can describe other layouts
66    #[inline]
67    pub(crate) fn tendency(self) -> i32 {
68        (self.is(Layout::CORDER) as i32 - self.is(Layout::FORDER) as i32) +
69        (self.is(Layout::CPREFER) as i32 - self.is(Layout::FPREFER) as i32)
70
71    }
72}
73
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::imp_prelude::*;
79    use crate::NdProducer;
80
81    type M = Array2<f32>;
82    type M1 = Array1<f32>;
83    type M0 = Array0<f32>;
84
85    macro_rules! assert_layouts {
86        ($mat:expr, $($layout:ident),*) => {{
87            let layout = $mat.view().layout();
88            $(
89            assert!(layout.is(Layout::$layout),
90                "Assertion failed: array {:?} is not layout {}",
91                $mat,
92                stringify!($layout));
93            )*
94        }}
95    }
96
97    macro_rules! assert_not_layouts {
98        ($mat:expr, $($layout:ident),*) => {{
99            let layout = $mat.view().layout();
100            $(
101            assert!(!layout.is(Layout::$layout),
102                "Assertion failed: array {:?} show not have layout {}",
103                $mat,
104                stringify!($layout));
105            )*
106        }}
107    }
108
109    #[test]
110    fn contig_layouts() {
111        let a = M::zeros((5, 5));
112        let b = M::zeros((5, 5).f());
113        let ac = a.view().layout();
114        let af = b.view().layout();
115        assert!(ac.is(Layout::CORDER) && ac.is(Layout::CPREFER));
116        assert!(!ac.is(Layout::FORDER) && !ac.is(Layout::FPREFER));
117        assert!(!af.is(Layout::CORDER) && !af.is(Layout::CPREFER));
118        assert!(af.is(Layout::FORDER) && af.is(Layout::FPREFER));
119    }
120
121    #[test]
122    fn contig_cf_layouts() {
123        let a = M::zeros((5, 1));
124        let b = M::zeros((1, 5).f());
125        assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
126        assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
127
128        let a = M1::zeros(5);
129        let b = M1::zeros(5.f());
130        assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
131        assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
132
133        let a = M0::zeros(());
134        assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
135
136        let a = M::zeros((5, 5));
137        let b = M::zeros((5, 5).f());
138        let arow = a.slice(s![..1, ..]);
139        let bcol = b.slice(s![.., ..1]);
140        assert_layouts!(arow, CORDER, CPREFER, FORDER, FPREFER);
141        assert_layouts!(bcol, CORDER, CPREFER, FORDER, FPREFER);
142
143        let acol = a.slice(s![.., ..1]);
144        let brow = b.slice(s![..1, ..]);
145        assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
146        assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
147    }
148
149    #[test]
150    fn stride_layouts() {
151        let a = M::zeros((5, 5));
152
153        {
154            let v1 = a.slice(s![1.., ..]).layout();
155            let v2 = a.slice(s![.., 1..]).layout();
156
157            assert!(v1.is(Layout::CORDER) && v1.is(Layout::CPREFER));
158            assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
159            assert!(!v2.is(Layout::CORDER) && v2.is(Layout::CPREFER));
160            assert!(!v2.is(Layout::FORDER) && !v2.is(Layout::FPREFER));
161        }
162
163        let b = M::zeros((5, 5).f());
164
165        {
166            let v1 = b.slice(s![1.., ..]).layout();
167            let v2 = b.slice(s![.., 1..]).layout();
168
169            assert!(!v1.is(Layout::CORDER) && !v1.is(Layout::CPREFER));
170            assert!(!v1.is(Layout::FORDER) && v1.is(Layout::FPREFER));
171            assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
172            assert!(v2.is(Layout::FORDER) && v2.is(Layout::FPREFER));
173        }
174    }
175
176    #[test]
177    fn no_layouts() {
178        let a = M::zeros((5, 5));
179        let b = M::zeros((5, 5).f());
180
181        // 2D row/column matrixes
182        let arow = a.slice(s![0..1, ..]);
183        let acol = a.slice(s![.., 0..1]);
184        let brow = b.slice(s![0..1, ..]);
185        let bcol = b.slice(s![.., 0..1]);
186        assert_layouts!(arow, CORDER, FORDER);
187        assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
188        assert_layouts!(bcol, CORDER, FORDER);
189        assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
190
191        // 2D row/column matrixes - now made with insert axis
192        for &axis in &[Axis(0), Axis(1)] {
193            let arow = a.slice(s![0, ..]).insert_axis(axis);
194            let acol = a.slice(s![.., 0]).insert_axis(axis);
195            let brow = b.slice(s![0, ..]).insert_axis(axis);
196            let bcol = b.slice(s![.., 0]).insert_axis(axis);
197            assert_layouts!(arow, CORDER, FORDER);
198            assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
199            assert_layouts!(bcol, CORDER, FORDER);
200            assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
201        }
202    }
203
204    #[test]
205    fn skip_layouts() {
206        let a = M::zeros((5, 5));
207        {
208            let v1 = a.slice(s![..;2, ..]).layout();
209            let v2 = a.slice(s![.., ..;2]).layout();
210
211            assert!(!v1.is(Layout::CORDER) && v1.is(Layout::CPREFER));
212            assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
213            assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
214            assert!(!v2.is(Layout::FORDER) && !v2.is(Layout::FPREFER));
215        }
216
217        let b = M::zeros((5, 5).f());
218        {
219            let v1 = b.slice(s![..;2, ..]).layout();
220            let v2 = b.slice(s![.., ..;2]).layout();
221
222            assert!(!v1.is(Layout::CORDER) && !v1.is(Layout::CPREFER));
223            assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
224            assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
225            assert!(!v2.is(Layout::FORDER) && v2.is(Layout::FPREFER));
226        }
227    }
228}