.. _memorder:

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 :ref:`Configuration`.

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

.. code-block:: python
    
   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.

.. _memsafe:

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:

#. memory is not aligned
#. memory is not writable
#. array does not own the memory (OWNDATA=false)
#. 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 :ref:`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.
