Array#
Introduction#
Loupe’s core object is the array. It is a multi-dimensional collection of
elements of a single data type that are accessible using Python’s standard
indexing notation. Loupe’s array interface is designed to be similar to
Numpy’s ndarray with additional features for tracking array operations on
a computational graph. Like in Numpy, Loupe’s array
dimensions are called axes. The most commonly used array attributes are:
- array.shape
 The dimensions of the array. This is a tuple of integers indicating the size of the array in each dimension.
- array.ndim
 The number of axes (dimensions) of the array
- array.size
 The total number of elements of the array.
- array.dtype
 An object describing the type of the elements in the array.
- array.data
 The actual array data, stored as a Numpy array. Normally, we won’t need to use this attribute because we will access the elements in an array using indexing facilities.
- array.requires_grad
 A boolean indicating whether the gradient should be computed for the array.
- array.grad
 The gradient of the array, stored as a Numpy array.
Array creation#
There are several ways to create arrays. The simplest way is to pass a
Python list or tuple to the array function:
>>> import loupe
>>> a = loupe.array([1,2,3])
>>> a
array([1., 2., 3.])
array transforms sequences of sequences into two-dimensional arrays,
sequences of sequences of sequences into three-dimensional arrays, and so on:
>>> b = loupe.array([[1,2], [3,4]])
>>> b
array([[1., 2.],
       [3., 4.]])
>>> b.ndim
2
Loupe also provides several functions to create arrays with placeholder
content. The function zeros creates an array full of zeros and the
function ones creates an array full of ones:
>>> loupe.zeros((2,3))
array([[0., 0., 0.],
       [0., 0., 0.]])
>>> loupe.ones(5)
array([1., 1., 1., 1., 1.])
See also
array(), zeros(), zeros_like(),
ones(), ones_like(), asarray(),
rand(), randn()
Indexing#
Array indexing refers to any use of the square brackets ([]) to index array values.
Note
Most of the following examples show the use of indexing when referencing data in an array. The examples work just as well when assigning to an array.
Indexing one-dimensional arrays#
Indexing for a 1-D array is what one expects. It work exactly like that for other standard Python sequences. Indexing is 0-based, and accepts negative indices for indexing from the end of the array:
>>> a = loupe.array([1,2,3,4,5])
>>> a[2]
3
>>> a[-2]
4
Indexing multi-dimensional arrays#
Unlike lists and tuples, arrays support multidimensional indexing for multidimensional arrays. It is not necessary to separate each dimension’s index into its own set of square brackets:
>>> b = loupe.array([[1,2,3], [4,5,6]])
>>> b[1,2]
6
Note that if one indexes a multidimensional array with fewer indices than dimensions, one gets a subdimensional array. For example:
>>> b[1]
array([4., 5., 6.])
Slices#
Arrays can be sliced using Python’s slice notation. Note that in order to
preserve algorithmic differentation capibility, slices are returned as new
slice objects rather than views of the underlying data.
For a one-dimensional array:
>>> c = loupe.array([5,6,7,8,9])
>>> c[2:]
array([7., 8., 9.])
and for multi-dimensional arrays:
>>> d = loupe.array([[2,4,6], [8,10,12], [14,16,18]])
>>> d[:,1:]
array([[  4.,  6.],
       [ 10., 12.],
       [ 16., 18.]])
Data types#
Numpy interoperability#
Loupe’s array implements Numpy’s dispatch mechanism, meaning Loupe arrays
can be used anywhere Numpy arrays can be used:
>>> import numpy as np
>>> e = loupe.array([1,2,3])
>>> np.std(e)
5.163977794943222
>>> import matplotlib.pyplot as plt
>>> f = loupe.rand(size=(10,10))
>>> plt.imshow(f)
This can be very useful for general analysis and plotting, but be aware that you will be leaving the Loupe ecosystem and dispatched operations are not tracked on Loupe’s computational graph.