$darkmode
A high-performance general-purpose compute library
/home/abuild/rpmbuild/BUILD/arrayfire-full-v3.9.0/docs/pages/indexing.md
Go to the documentation of this file.
1 Indexing {#indexing}
2 ========
3 
4 Indexing in ArrayFire is a powerful but easy to abuse feature of the af::array
5 class. This feature allows you to reference or copy subsections of a larger array
6 and perform operations on only a subset of elements.
7 
8 Indexing in ArrayFire can be performed using the parenthesis operator or one of
9 the member functions of the af::array class. These functions allow you to
10 reference one or a range of elements from the original array.
11 
12 Here we will demonstrate some of the ways you can use indexing in ArrayFire and
13 discuss ways to minimize the memory and performance impact of these operations.
14 
15 Lets start by creating a new 4x4 matrix of floating point numbers:
16 
17 \snippet test/index.cpp index_tutorial_1
18 
19 ArrayFire is column-major so the resulting A array will look like this:
20 
21 \f[
22 \begin{bmatrix}
23  0 & 4 & 8 & 12 \\
24  1 & 5 & 9 & 13 \\
25  2 & 6 & 10 & 14 \\
26  3 & 7 & 11 & 15
27 \end{bmatrix}
28 \f]
29 
30 This is a two dimensional array so we can access the first element of this
31 matrix by passing `0,0` into the parenthesis operator of the af::array.
32 
33 \snippet test/index.cpp index_tutorial_first_element
34 
35 \f[ A(2, 3) = [ 14 ] \f]
36 
37 We can also access the array using linear indexing by passing in one value. Here
38 we are accessing the fifth element of the array.
39 
40 \snippet test/index.cpp index_tutorial_fifth_element
41 
42 \f[ A(5) = [ 5 ] \f]
43 
44 \note Normally you want to avoid accessing individual elements of the array like this
45 for performance reasons.
46 
47 Indexing with negative values will access from the end of the array. For example,
48 the value negative one and negative two(-2) will return the last and second to
49 last element of the array, respectively. ArrayFire provides the `end` alias for
50 this which also allows you to index the last element of the array.
51 
52 \snippet test/index.cpp index_tutorial_negative_indexing
53 
54 ## Indexing slices and subarrays
55 
56 You can access regions of the array via the af::seq and af::span objects. The
57 span objects allows you to select the entire set of elements across a particular
58 dimension/axis of an array. For example, we can select the third column of the
59 array by passing span as the first argument and 2 as the second argument to the
60 parenthesis operator.
61 
62 \snippet test/index.cpp index_tutorial_third_column
63 
64 \f[
65 A(span, 2) =
66 \begin{bmatrix}
67  8 \\
68  9 \\
69  10 \\
70  11
71 \end{bmatrix}
72 \f]
73 
74 You can read that as saying that you want all values across the first dimension,
75 but only from index 2 of the second dimension.
76 
77 You can access the second row by passing (1, span) to the array
78 
79 \snippet test/index.cpp index_tutorial_second_row
80 
81 \f[ A(1, span) = [ 1, 5, 9, 13 ] \f]
82 
83 You can use the af::seq (short for sequence) object to define a range when
84 indexing. For example, if you want to get the first two columns, you can access
85 the array by passing af::span for the first argument and af::seq(2) as the
86 second argument.
87 
88 \snippet test/index.cpp index_tutorial_first_two_columns
89 
90 \f[
91 A(span, seq(2)) =
92 \begin{bmatrix}
93  0 & 4 \\
94  1 & 5 \\
95  2 & 6 \\
96  3 & 7
97 \end{bmatrix}
98 \f]
99 
100 There are three constructors for af::seq.
101 
102 * af::seq(N): Defines a range between 0 and N-1
103 * af::seq(begin, end) Defines a range between begin and end inclusive
104 * af::seq(begin, end, step) defines a range between begin and end striding by step values
105 
106 The last constructor that can help create non-continuous ranges. For example,
107 you can select the second and forth(last) rows by passing (seq(1, end, 2), span)
108 to the indexing operator.
109 
110 \snippet test/index.cpp index_tutorial_second_and_fourth_rows
111 
112 \f[
113 A(seq(1, end, 2), span) =
114 \begin{bmatrix}
115  1 & 5 & 9 & 13 \\
116  3 & 7 & 11 & 15
117 \end{bmatrix}
118 \f]
119 
120 ## Indexing using af::array
121 
122 You can also index using other af::array objects. ArrayFire performs a Cartesian
123 product of the input arrays.
124 
125 \snippet test/index.cpp index_tutorial_array_indexing
126 
127 \f[
128 A =
129 \begin{bmatrix}
130  0 & 4 & 8 & 12 \\
131  1 & 5 & 9 & 13 \\
132  2 & 6 & 10 & 14 \\
133  3 & 7 & 11 & 15
134 \end{bmatrix}
135 \\
136 A(
137 \begin{bmatrix}
138 2 \\ 1 \\ 3
139 \end{bmatrix}
140 ,
141 \begin{bmatrix}
142 3 \\ 1 \\ 2
143 \end{bmatrix}
144 ) =
145 
146 \begin{bmatrix}
147 (2,3) & (2,1) & (2,2) \\
148 (1,3) & (1,1) & (1,2) \\
149 (3,3) & (3,1) & (3,2)
150 \end{bmatrix}
151 =
152 \begin{bmatrix}
153 14 & 6 & 10 \\
154 13 & 5 & 9 \\
155 15 & 7 & 11
156 \end{bmatrix}
157 \f]
158 
159 
160 If you want to index an af::array using coordinate arrays, you can do that using the
161 af::approx1 and af::approx2 functions.
162 
163 \snippet test/index.cpp index_tutorial_approx
164 
165 \f[
166 approx2(A,
167 \begin{bmatrix}
168 2 \\ 1 \\ 3
169 \end{bmatrix}
170 ,
171 \begin{bmatrix}
172 3 \\ 1 \\ 2
173 \end{bmatrix}
174 ) =
175 \begin{bmatrix}
176 (2,3) \\
177 (1,1) \\
178 (3,2)
179 \end{bmatrix}
180 =
181 \begin{bmatrix}
182 14 \\
183  5 \\
184 11
185 \end{bmatrix}
186 \f]
187 
188 Boolean(b8) arrays can be used to index into another array. In this type of
189 indexing the non-zero values will be selected by the boolean operation. If we
190 want to select all values less than 5, we can pass a boolean expression into
191 the parenthesis operator.
192 
193 \snippet test/index.cpp index_tutorial_boolean
194 
195 \f[
196 out =
197 \begin{bmatrix}
198 0 \\ 1 \\ 2 \\ 3 \\ 4
199 \end{bmatrix}
200 \f]
201 
202 ## References and copies
203 
204 All ArrayFire indexing functions return af::array(technically its an array_proxy
205 class) objects. These objects may be new arrays or they may reference the
206 original array depending on the type of indexing that was performed on them.
207 
208 - If an array was indexed using another af::array or it was indexed using the
209 af::approx functions, then a new array is created. It does not reference the
210 original data.
211 - If an array was indexed using a scalar, af::seq or af::span, then
212 the resulting array will reference the original data IF the first dimension is
213 continuous. The following lines will not allocate additional memory.
214 
215 \note The new arrays wither references or newly allocated arrays, are
216 independent of the original data. Meaning that any changes to the original array
217 will not propagate to the references. Likewise, any changes to the reference
218 arrays will not modify the original data.
219 
220 \snippet test/index.cpp index_tutorial_references
221 
222 The following code snippet shows some examples of indexing that will allocate
223 new memory.
224 
225 \snippet test/index.cpp index_tutorial_copies
226 
227 Notice that even though the copy3 array is referencing continuous memory in the
228 original array, a new array is created because we used an array to index into
229 the af::array.
230 
231 ## Assignment
232 
233 An assignment on an af::array will replace the array with the result of the
234 expression on the right hand side of the equal(=) operator. This means that the
235 type and shape of the result can be different from the array on the left had
236 side of the equal operator. Assignments will not update the array that was
237 previously referenced through an indexing operation. Here is an example:
238 
239 \snippet test/index.cpp index_tutorial_assignment
240 
241 The `ref` array is created by indexing into the data array. The initialized
242 `ref` array points to the data array and does not allocate memory when it is
243 created. After the matmul call, the `ref` array will not be pointing to the data
244 array. The matmul call will not update the values of the data array.
245 
246 You can update the contents of an af::array by assigning with the operator
247 parenthesis. For example, if you wanted to change the third column of the
248 `A` array you can do that by assigning to `A(span, 2)`.
249 
250 \snippet test/index.cpp index_tutorial_assignment_third_column
251 
252 \f[
253 ref =
254 \begin{bmatrix}
255  8 \\
256  9 \\
257  10 \\
258  11
259 \end{bmatrix}
260 A =
261 \begin{bmatrix}
262  0 & 4 & 3.14 & 12 \\
263  1 & 5 & 3.14 & 13 \\
264  2 & 6 & 3.14 & 14 \\
265  3 & 7 & 3.14 & 15
266 \end{bmatrix}
267 \f]
268 
269 This will update only the array being modified. If there are arrays that
270 are referring to this array because of an indexing operation, those values
271 will remain unchanged.
272 
273 Allocation will only be performed if there are other arrays referencing the data
274 at the point of assignment. In the previous example, an allocation will be
275 performed when assigning to the `A` array because the `ref` array is pointing
276 to the original data. Here is another example demonstrating when an allocation
277 will occur:
278 
279 \snippet test/index.cpp index_tutorial_assignment_alloc
280 
281 In this example, no allocation will take place because when the `ref` object
282 is created, it is pointing to `A`'s data. Once it goes out of scope, no data
283 points to `A`, therefore when the assignment takes place, the data is modified in
284 place instead of being copied to a new address.
285 
286 You can also assign to arrays using another af::arrays as an indexing array.
287 This works in a similar way to the other types of assignment but care must be
288 taken to assure that the indexes are unique. Non-unique indexes will result in a
289 race condition which will cause non-deterministic values.
290 
291 \snippet test/index.cpp index_tutorial_assignment_race_condition
292 
293 \f[
294 idx =
295 \begin{bmatrix}
296  4 \\
297  3 \\
298  4 \\
299  0
300 \end{bmatrix}
301 vals =
302 \begin{bmatrix}
303  9 \\
304  8 \\
305  7 \\
306  6
307 \end{bmatrix}
308 \\
309 A =
310 \begin{bmatrix}
311  6 & 9\ or\ 7 & 8 & 12 \\
312  1 & 5 & 9 & 13 \\
313  2 & 6 & 10 & 14 \\
314  8 & 7 & 11 & 15
315 \end{bmatrix}
316 \f]
317 
318 ## Member functions
319 
320 There are several member functions which allow you to index into an af::array. These
321 functions have similar functionality but may be easier to parse for some.
322 
323 * [row(i)](\ref af::array::row) or [col(i)](\ref af::array::col) specifying a single row/column
324 * [rows(first,last)](\ref af::array::rows) or [cols(first,last)](\ref af::array::cols)
325  specifying multiple rows or columns
326 * [slice(i)](\ref af::array::slice) or [slices(first, last)](\ref af::array::slices) to
327  select one or a range of slices
328 
329 # Additional examples
330 
331 See \ref index_mat for the full listing.
332 
333 \snippet test/index.cpp ex_indexing_first
334 
335 You can set values in an array:
336 
337 \snippet test/index.cpp ex_indexing_set
338 
339 Use one array to reference into another.
340 
341 \snippet test/index.cpp ex_indexing_ref