-
Notifications
You must be signed in to change notification settings - Fork 128
Tutorial: Indexing and Slicing
Indexing and slicing is arguably one of the most important functions in any numerical library. The flexible design can significantly reduce the code and enable us to write concise algorithms. In this tutorial, I will present how to use slice function in Owl.
Before we start, let's clarify some things.
-
Slicing refers to the operation that takes part of the data (e.g., ndarrays or matrices) according to the well-defined slice definition.
-
Slice definition is a
int list listwhich clarifies what indices will be accessed and in what order for each dimension of the passed in variable. -
Slice can be applied to all the dense data structures such as Ndarray, Matrix, and Vector. In this tutorial, I will only use Matrix to present examples.
The core slicing operation is slice which you can find in all Dense modules. Essentially, Owl offers a slicing function very similar to that in Numpy. So if you already know how to slice n-dimensional arrays in Numpy, you should find this tutorial very easy.
The basic grammar is Mat.slice s x where x is the data (a matrix in this case) to be sliced, and s is the slice definition. The returned result is part of x of the same dimensionality. Briefly, the slice function follows the conventions below.
-
Slice definition is a
int list list. Eachint listwithin theint list listcorresponds one dimension in the passed in data, and it defines how the indices along this dimension should be accessed. -
The format of the aforementioned
int listdefinition follows[ start; stop; step ]. Obviously,startspecifies the starting index;stopspecifies the stopping index; andstepspecifies the step size. You do not have to specifies all three variables in the definition, please see the following rules. -
All three variable
start,stop, andstepcan take both positive and negative values, butstepis not allowed to take0value. Positive step indicates that indices will be visited in increasing order fromstarttostop; and vice versa. -
For
startandstopvariables, positive value refers to a specific index; whereas negative valueawill be translated inton + awherenis the total number of indices. E.g.,[ -1; 0 ]means from the last index to the first one. -
If you pass in an empty list
[], this will be expanded into[ 0; n - 1; 1 ]which means all the indices will be visited in increasing order with step size1. -
If you only specify one variable such as
[ start ], thenslicefunction assumes that you will take one specific index by automatically extending it into[ start; start; 1 ]. As we can see,startandstopare the same, with step size 1. -
If you only specify two variables then
slicefunction assumes they are[ start; stop ]which defines the range of indices. However, howslicewill expand this depends:- if
start <= stop, then it will be expanded to[ start; stop; 1 ]; - if
start > stop, then it will be expanded to[ start; stop; -1 ]; as we can see,slicewill visit the indices in different orders.
- if
-
It is not necessary to specify all the definitions for all the dimensions,
slicefunction will also expand it by assuming you will take all the data in higher dimensions. E.g.,xhas the shape[ 2; 3; 4 ], if we define the slice as[ [0] ]thenslicewill expand the definition into[ [0]; []; [] ]
OK, that's all. Please make sure you understand it well before you start, but it is also fine you just learn by doing.
I always believe that nothing is better than concrete example while learning. Note that all the following example can be equally applied to ndarray. OK, here they are.
Let's first define a sequential matrix as the input data for the following examples.
let x = Mat.sequential 5 7;;You should be able to see the following output in utop.
C0 C1 C2 C3 C4 C5 C6
R0 0 1 2 3 4 5 6
R1 7 8 9 10 11 12 13
R2 14 15 16 17 18 19 20
R3 21 22 23 24 25 26 27
R4 28 29 30 31 32 33 34
val x : Mat.mat =Now, we can finally start our experiment. It is better you play around with these code in utop so that you can observe the output to help you understand how slice function works.
(* simply take all the elements *)
let s = [ ] in
Mat.slice s x;;
(* take row 2 *)
let s = [ [2]; [] ] in
Mat.slice s x;;
(* same as above, take row 2, but only specify low dimension slice definition *)
let s = [ [2] ] in
Mat.slice s x;;
(* take form row 1 to 3 *)
let s = [ [1;3] ] in
Mat.slice s x;;