Memory Order

A significant difference between Numpy arrays and Armadillo matrices is the memory order. Armadillo is optimised for column-major (Fortran order) memory whereas Numpy defaults to row-major (C order).

The default behaviour is to automatically convert matrices and cubes, read copy, C-order arrays to F-order arrays upon conversion to Armadillo. This behaviour can be disabled at compile time, see Configuration.

This conversion can be avoided by ensuring all data generated by Numpy is done with order=’F’ or converted using:

np.asarray(cdata, type=np.float64, order='F')

Note

Carma will not convert F-order memory back to C-order when returning, this has consequences for matrices and cubes.

Memory (de)allocator

Armadillo will not always hold the same memory for the entirety of a object’s lifetime, e.g. you add columns to a matrix. To be able to transfer ownership we have to be sure that the memory will be deallocated by the function matching the allocator. In the case of CARMA this means Armadillo must use the Numpy allocator (PyDataMem_NEW) and deallocator (PyDataMem_FREE). Numpy’s allocator is compatible with Armadillo as both call/wrap malloc/calloc.

Memory Safety

In order to provide fast conversions the default behaviour of CARMA is to avoid copying where possible. However, this requires users to be vigilant to avoid aliasing of memory. This section describes when copies are made by default.

Note when borrowing the memory of an array the Armadillo object cannot be changed in size, this will trigger an exception. If the Armadillo object will change in size you should use a copy or steal.

Warning

Armadillo objects are not copied out by default. You should not return a object without copying when the Armadillo object points to borrowed memory as this will cause double frees and segfaults.

Well behaved

Armadillo expects the memory to be aligned and Fortran order (column contiguous). To ensure this we check if the array is well-behaved which is not true when one of the following is true:

  1. memory is not aligned

  2. memory is not writable

  3. array does not own the memory (OWNDATA=false)

  4. array has ndim >= 2 and memory is not F-contiguous

Note

Conditions 3 and 4 can be disabled, independently, with compile time definitions, see the section Configuration.

Based on the type of conversion, steal, borrow or view, the effect on the input array differs.

Borrow

The memory of the array is copied to well-behaved memory and swapped in the place of the original memory. This is done to ensure the design that pattern that borrowed arrays don’t require a return to reflect the changes.

Stealing

If an array will be stolen but it’s not well-behaved the memory is copied to well-behaved memory and ownership of the new memory is transferred to Armadillo. Note this steals a reference to the input array, which will be destructed by Numpy/Python.

Copy

If an array will be copied it is automatically copied to well-behaved memory and ownership of the new memory is transferred to Armadillo. This has no effect on the input array.

View

For view’s the definition of well-behaved ignores the writeable flag as the Armadillo object will be read-only.