@@ -3,115 +3,118 @@ Anatomy of an array
3
3
4
4
.. contents :: **Contents**
5
5
:local:
6
+
7
+ |WIP |
6
8
7
- Data type
8
- ---------
9
+ ..
10
+ Data type
11
+ ---------
12
+
13
+ Memory layout
14
+ -------------
15
+
16
+ View and copy
17
+ -------------
18
+
19
+ Let's consider two vectors `Z1 ` and `Z2 `. We would like to know if `Z2 ` is a
20
+ view of `Z1 ` and if yes, what is this view ? Let's consider a simple example:
21
+
22
+ .. code-block ::
9
23
10
- Memory layout
11
- -------------
24
+ >>> Z1 = np.arange(10)
25
+ >>> Z2 = Z1[1:-1:2]
12
26
13
- View and copy
14
- -------------
27
+ .. code-block ::
28
+ :class: output
15
29
16
- Let's consider two vectors `Z1 ` and `Z2 `. We would like to know if `Z2 ` is a
17
- view of `Z1 ` and if yes, what is this view ? Let's consider a simple example:
30
+ ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
31
+ Z1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
32
+ ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌
33
+ ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
34
+ Z2 │ 1 │ │ 3 │ │ 5 │ │ 7 │
35
+ ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌
18
36
19
- .. code-block ::
37
+ First test is to check whether ` Z1 ` is the base of ` Z2 `
20
38
21
- >>> Z1 = np.arange(10)
22
- >>> Z2 = Z1[1:-1:2]
39
+ .. code-block ::
23
40
24
- .. code-block ::
25
- :class: output
41
+ >>> print(Z2.base is Z1)
42
+ True
26
43
27
- ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
28
- Z1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
29
- ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌
30
- ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
31
- Z2 │ 1 │ │ 3 │ │ 5 │ │ 7 │
32
- ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌
44
+ At this point, we know ` Z2 ` is a view of ` Z1 `, meaning ` Z2 ` can be expressed as
45
+ ` Z1[start:stop:step] `. The difficulty now is to find ` start `, ` stop ` and
46
+ ` step `. For the ` step `, we can use the ` strides ` property of any array that
47
+ gives the number of bytes to go from one element to the other in each
48
+ dimension. In our case, and because both arrays are one-dimensional, we can
49
+ directly compare the first stride only:
33
50
34
- First test is to check whether ` Z1 ` is the base of ` Z2 `
51
+ .. code-block ::
35
52
36
- .. code-block ::
53
+ >>> step = Z2.strides[0] // Z1.strides[0]
54
+ >>> print(step)
55
+ 2
37
56
38
- >>> print(Z2.base is Z1)
39
- True
57
+ Next difficulty is to find the `start ` and the `stop ` indices. To do this, we
58
+ can take advantage of the `byte_bounds ` method that returns a pointer to the
59
+ end-points of an array.
40
60
41
- At this point, we know `Z2 ` is a view of `Z1 `, meaning `Z2 ` can be expressed as
42
- `Z1[start:stop:step] `. The difficulty now is to find `start `, `stop ` and
43
- `step `. For the `step `, we can use the `strides ` property of any array that
44
- gives the number of bytes to go from one element to the other in each
45
- dimension. In our case, and because both arrays are one-dimensional, we can
46
- directly compare the first stride only:
61
+ .. code-block ::
62
+ :class: output
47
63
48
- .. code-block ::
64
+ byte_bounds(Z1)[0] byte_bounds(Z1)[-1]
65
+ ↓ ↓
66
+ ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
67
+ Z1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
68
+ ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌
49
69
50
- >>> step = Z2.strides[0] // Z1.strides[0]
51
- >>> print(step)
52
- 2
70
+ byte_bounds(Z2)[0] byte_bounds(Z2)[-1]
71
+ ↓ ↓
72
+ ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
73
+ Z2 │ 1 │ │ 3 │ │ 5 │ │ 7 │
74
+ ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌
53
75
54
- Next difficulty is to find the `start ` and the `stop ` indices. To do this, we
55
- can take advantage of the `byte_bounds ` method that returns a pointer to the
56
- end-points of an array.
57
76
58
- .. code-block ::
59
- :class: output
77
+ .. code-block ::
60
78
61
- byte_bounds(Z1)[0] byte_bounds(Z1)[-1]
62
- ↓ ↓
63
- ╌╌╌┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬╌╌
64
- Z1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
65
- ╌╌╌┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴╌╌
79
+ >>> offset_start = np.byte_bounds(Z2)[0] - np.byte_bounds(Z1)[0]
80
+ >>> print(offset_start) # bytes
81
+ 8
66
82
67
- byte_bounds(Z2)[0] byte_bounds(Z2)[-1]
68
- ↓ ↓
69
- ╌╌╌╌╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌┬───┬╌╌╌╌╌╌╌╌╌╌
70
- Z2 │ 1 │ │ 3 │ │ 5 │ │ 7 │
71
- ╌╌╌╌╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌┴───┴╌╌╌╌╌╌╌╌╌╌
83
+ >>> offset_stop = np.byte_bounds(Z2)[-1] - np.byte_bounds(Z1)[-1]
84
+ >>> print(offset_stop) # bytes
85
+ -16
72
86
87
+ Converting these offsets into indices is straightforward using the `itemsize `
88
+ and taking into account that the `offset_stop ` is negative (end-bound of `Z2 `
89
+ is logically smaller than end-bound of `Z1 ` array). We thus need to add the
90
+ items size of Z1 to get the right end index.
73
91
74
- .. code-block ::
92
+ .. code-block ::
75
93
76
- >>> offset_start = np.byte_bounds(Z2)[0] - np.byte_bounds(Z1)[0]
77
- >>> print(offset_start) # bytes
78
- 8
79
-
80
- >>> offset_stop = np.byte_bounds(Z2)[-1] - np.byte_bounds(Z1)[-1]
81
- >>> print(offset_stop) # bytes
82
- -16
94
+ >>> start = offset_start // Z1.itemsize
95
+ >>> stop = Z1.size + offset_stop // Z1.itemsize
96
+ >>> print(start, stop, step)
97
+ 1, 8, 2
83
98
84
- Converting these offsets into indices is straightforward using the `itemsize `
85
- and taking into account that the `offset_stop ` is negative (end-bound of `Z2 `
86
- is logically smaller than end-bound of `Z1 ` array). We thus need to add the
87
- items size of Z1 to get the right end index.
88
-
89
- .. code-block ::
99
+ Last we test our results:
90
100
91
- >>> start = offset_start // Z1.itemsize
92
- >>> stop = Z1.size + offset_stop // Z1.itemsize
93
- >>> print(start, stop, step)
94
- 1, 8, 2
101
+ .. code-block ::
95
102
96
- Last we test our results:
103
+ >>> print(np.allclose(Z1[start,stop,step], Z2))
104
+ True
97
105
98
- .. code-block ::
99
106
100
- >>> print(np.allclose(Z1[start,stop,step], Z2))
101
- True
102
-
107
+ Exercice
108
+ ++++++++
103
109
104
- Exercice
105
- ++++++++
110
+ As an exercise, you can improve this first and very simple implementation by
111
+ taking into account:
106
112
107
- As an exercise, you can improve this first and very simple implementation by
108
- taking into account:
113
+ * Negative steps
114
+ * Multi-dimensional arrays
109
115
110
- * Negative steps
111
- * Multi-dimensional arrays
112
116
113
-
114
- Sources
115
- +++++++
117
+ Sources
118
+ +++++++
116
119
117
- * `find_index < ../ code/find_index.py >`_ (solution to the exercise)
120
+ * `find_index.py < code/find_index.py >`_ (solution to the exercise)
0 commit comments