Skip to content

The Array Abstraction

Mike Anderson edited this page Aug 13, 2015 · 4 revisions

Central to core.matrix design is the concept of the multi-dimensional array. This is an abstraction that describes values that have the following key properties:

  • dimensionality - every array has a fixed number of dimensions (zero or greater).
  • shape - for each dimension, the array has a integer size in terms of number of elements along each dimension. Collectively these sizes are the shape of the array.
  • elements - for every combination of valid positions along each dimension, there is an element that can be accessed (read) from the array

That is, in essence, all that is needed to qualify as an array! So any object that is able to satisfy these properties can potentially be considered or operate as a core.matrix array.

There are however some subtleties that need need some consideration. The rest of this page describes these concepts

Mutable arrays

Some arrays can be mutable, in the sense that aspects of the array can be changed (usually only elements can be changed, but in some cases the shape and dimensionality could also be modified).

Mutability is generally discouraged in Clojure, but in some cases it may be necessary to achieve maximum performance. Hence core.matrix allows implementations to provide mutable array instances.

An example of a mutable array supported by core.matrix is a Java array. These can be modified by core.matrix functions such as mset!. (As a convention, core.matrix functions that cause side effects such as array mutation end with a !).

(def a (object-array [1 2 3]))

(esum a)                 ;; sum of elements
;; => 6

(mset! a 0 10)           ;; set an element of a
a
;; => [10, 2, 3]         ;; note: first element has changed

(esum a) 
;; => 15                 ;; sum of elements

Scalar values vs. scalar arrays

In some senses, a single value (scalar) can be considered as a 0-dimensional array. It doesn't have any dimensions so the shape is [], however it does have a single element (accessible at the index []).

So is a scalar value an array or not?

core.matrix takes the following position:

  • Single scalar values are not normally counted as arrays. (array? 7.45) => false
  • Implementations may however provide 0-dimensional arrays if they choose. We call these scalar arrays

Some properties to observe:

(array? 1.5)
;; => false    ; a scalar value is not an array

(array? (scalar-array 1.5))
;; => true     ; a scalar array is an array

(shape 1.0)
;; => nil      ; scalars have no shape

(shape (scalar-array 1.0))
;; => []       ; scalar array have an empty shape vector

(ecount 1.0)   
;; => 1        ; scalars are just a single element  

(ecount (scalar-array 1.0))   
;; => 1        ; scalar arrays contain a single element  

Arrays with constrained element types

Many arrays can contain arbitrary element values (e.g. any java.lang.Object). However some arrays are constrained to specific element types. Some examples:

  • The :vectorz implementation constrains all elements to be double values.
  • You can use Java arrays as core.matrix arrays, in which case the element type is constrained to be the element type of the underlying Java array
  • Some implementations may constrain a subset of elements in order to implement a specific type of array, e.g. a diagonal matrix that may have any numerical value on the main diagonal but is constrained to be zero elsewhere.

There are two practical reasons why arrays with constrained elements exist:

  • For interop purposes, so that core.matrix can work with different data representations
  • For performance: constrained data representations may provide significantly better performance by using specialised code