Indexing
Indexing in ArrayFire is a powerful but easy to abuse feature. This feature allows you to reference or copy subsections of a larger array and perform operations on only a subset of elements.
This chapter is split into the following sections:
- Index an Array using Seq Objects
- Using Array and Seq combination
- Extract or Set rows/columns of an Array
- Negative Indices
Indexer structure is the key element used in Rust wrapper of ArrayFire for creating references
to existing Arrays. The above sections illustrate how it can be used in conjunction with Seq
and/or Array
. Apart from that, each section also showcases a macro based equivalent
code(if one exists) that is more terse in syntax but offers the same functionality.
Using Seq objects
Create a view of an existing Array
We will Sequences and the function index in this approach.
let dims = Dim4::new(&[5, 5, 1, 1]);
let a = randu::<f32>(dims);
//af_print!("a", a);
//a
//[5 5 1 1]
// 0.3990 0.5160 0.8831 0.9107 0.6688
// 0.6720 0.3932 0.0621 0.9159 0.8434
// 0.5339 0.2706 0.7089 0.0231 0.1328
// 0.1386 0.9455 0.9434 0.2330 0.2657
// 0.7353 0.1587 0.1227 0.2220 0.2299
// Index array using sequences
let seqs = &[Seq::new(1u32, 3, 1), Seq::default()];
let _sub = index(&a, seqs);
//af_print!("a(seq(1,3,1), span)", sub);
// [3 5 1 1]
// 0.6720 0.3932 0.0621 0.9159 0.8434
// 0.5339 0.2706 0.7089 0.0231 0.1328
// 0.1386 0.9455 0.9434 0.2330 0.2657
However, the same above code can be condensed into a much terse syntax with the help of view macro. Take a look at the following two approaches using view macro.
let dims = dim4!(5, 5, 1, 1);
let a = randu::<f32>(dims);
let first3 = seq!(1:3:1);
let allindim2 = seq!();
let _sub = view!(a[first3, allindim2]);
let a = randu::<f32>(dim4!(5, 5));
let _sub = view!(a[1:3:1, 1:1:0]); // 1:1:0 means all elements along axis
Modify a sub region of an existing Array
Let us take a look at an example where a portion of an existing Array will be set to with another Array. We will an constant value Array and the function assign_seq in the below example.
let mut a = constant(2.0 as f32, dim4!(5, 3));
//print(&a);
// 2.0 2.0 2.0
// 2.0 2.0 2.0
// 2.0 2.0 2.0
// 2.0 2.0 2.0
// 2.0 2.0 2.0
let b = constant(1.0 as f32, dim4!(3, 3));
let seqs = [seq!(1:3:1), seq!()];
assign_seq(&mut a, &seqs, &b);
//print(&a);
// 2.0 2.0 2.0
// 1.0 1.0 1.0
// 1.0 1.0 1.0
// 1.0 1.0 1.0
// 2.0 2.0 2.0
A much terser way of doing the same using macro is shown below
let mut a = randu::<f32>(dim4!(5, 5));
let b = randu::<f32>(dim4!(2, 2));
eval!(a[1:2:1, 1:2:1] = b);
NOTE Normally you want to avoid accessing individual elements of the array like this for performance reasons.
Using Array and Seq combination
Create a view of an existing Array
To use a combination of Array and Seq objects to index an existing Array, we will need a more generalized function index_gen.
let values: [f32; 3] = [1.0, 2.0, 3.0];
let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1]));
let seq4gen = Seq::new(0.0, 2.0, 1.0);
let a = randu::<f32>(Dim4::new(&[5, 3, 1, 1]));
// [5 3 1 1]
// 0.0000 0.2190 0.3835
// 0.1315 0.0470 0.5194
// 0.7556 0.6789 0.8310
// 0.4587 0.6793 0.0346
// 0.5328 0.9347 0.0535
let mut idxrs = Indexer::default();
idxrs.set_index(&indices, 0, None); // 2nd arg is indexing dimension
idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd arg indicates batch operation
let _sub2 = index_gen(&a, idxrs);
//println!("a(indices, seq(0, 2, 1))"); print(&sub2);
// [3 3 1 1]
// 0.1315 0.0470 0.5194
// 0.7556 0.6789 0.8310
// 0.4587 0.6793 0.0346
Similar to how view macro helped with abreviating the syntax when indexing with just sequences, it can also help when using a combination of Seq and Array.
let values: [f32; 3] = [1.0, 2.0, 3.0];
let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1]));
let seq4gen = seq!(0:2:1);
let a = randu::<f32>(Dim4::new(&[5, 3, 1, 1]));
let _sub2 = view!(a[indices, seq4gen]);
Modify a sub region of an existing Array
Set a portion of an existing Array with another Array using a combination of Seq
and Array
.
We will use assign_gen function to do it.
let values: [f32; 3] = [1.0, 2.0, 3.0];
let indices = Array::new(&values, dim4!(3, 1, 1, 1));
let seq4gen = seq!(0:2:1);
let mut a = randu::<f32>(dim4!(5, 3, 1, 1));
// [5 3 1 1]
// 0.0000 0.2190 0.3835
// 0.1315 0.0470 0.5194
// 0.7556 0.6789 0.8310
// 0.4587 0.6793 0.0346
// 0.5328 0.9347 0.0535
let b = constant(2.0 as f32, dim4!(3, 3, 1, 1));
let mut idxrs = Indexer::default();
idxrs.set_index(&indices, 0, None); // 2nd arg is indexing dimension
idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd arg indicates batch operation
let _sub2 = assign_gen(&mut a, &idxrs, &b);
//println!("a(indices, seq(0, 2, 1))"); print(&sub2);
// [5 3 1 1]
// 0.0000 0.2190 0.3835
// 2.0000 2.0000 2.0000
// 2.0000 2.0000 2.0000
// 2.0000 2.0000 2.0000
// 0.5328 0.9347 0.0535
let values: [f32; 3] = [1.0, 2.0, 3.0];
let indices = Array::new(&values, dim4!(3));
let seq4gen = seq!(0:2:1);
let mut a = randu::<f32>(dim4!(5, 3));
let b = constant(2.0 as f32, dim4!(3, 3));
eval!(a[indices, seq4gen] = b);
Extract or Set rows/columns of an Array
Extract a specific set of rows/coloumns from an existing Array.
let a = randu::<f32>(dim4!(5, 5, 1, 1));
//print(&a);
// [5 5 1 1]
// 0.6010 0.5497 0.1583 0.3636 0.6755
// 0.0278 0.2864 0.3712 0.4165 0.6105
// 0.9806 0.3410 0.3543 0.5814 0.5232
// 0.2126 0.7509 0.6450 0.8962 0.5567
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _r = row(&a, 4);
// [1 5 1 1]
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _c = col(&a, 4);
// [5 1 1 1]
// 0.6755
// 0.6105
// 0.5232
// 0.5567
// 0.7896
You can also use rows & cols to retrieve a subset of rows or coloumns respectively.
Similarly, set_row & set_rows can be used to change the values in a particular set of rows using another Array. set_col & set_cols has same functionality, except that it is for coloumns.
Negative Indices
Negative indices can also be used to refer elements from the end of a given axis. Negative value for a row/column/slice will fetch corresponding row/column/slice in reverse order. Given below are some examples that showcase getting row(s)/col(s) from an existing Array.
let a = randu::<f32>(dim4!(5, 5));
// [5 5 1 1]
// 0.6010 0.5497 0.1583 0.3636 0.6755
// 0.0278 0.2864 0.3712 0.4165 0.6105
// 0.9806 0.3410 0.3543 0.5814 0.5232
// 0.2126 0.7509 0.6450 0.8962 0.5567
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _r = row(&a, -1);
// [1 5 1 1]
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _c = col(&a, -1);
// [5 1 1 1]
// 0.6755
// 0.6105
// 0.5232
// 0.5567
// 0.7896
let a = randu::<f32>(dim4!(5, 5));
// [5 5 1 1]
// 0.6010 0.5497 0.1583 0.3636 0.6755
// 0.0278 0.2864 0.3712 0.4165 0.6105
// 0.9806 0.3410 0.3543 0.5814 0.5232
// 0.2126 0.7509 0.6450 0.8962 0.5567
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _r = rows(&a, -1, -2);
// [2 5 1 1]
// 0.2126 0.7509 0.6450 0.8962 0.5567
// 0.0655 0.4105 0.9675 0.3712 0.7896
let _c = cols(&a, -1, -3);
// [5 3 1 1]
// 0.1583 0.3636 0.6755
// 0.3712 0.4165 0.6105
// 0.3543 0.5814 0.5232
// 0.6450 0.8962 0.5567
// 0.9675 0.3712 0.7896