Skip to content

Commit

Permalink
DOC: Update README and version bump
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralph Urlus authored and RUrlus committed Jun 8, 2021
1 parent 0891801 commit 1637b61
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 106 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)

SET(CARMA_VERSION_INFO "1.0.0")
SET(CARMA_VERSION_INFO "0.4.0")

PROJECT(
carma
Expand Down
190 changes: 86 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,150 +4,132 @@

<br/>

<div align="center">
<!-- Build status -->
<a href="https://travis-ci.com/RUrlus/carma">
<img src="https://img.shields.io/travis/rurlus/carma/stable.svg?style=for-the-badge" alt="Build Status"/>
</a>
<!-- Coverage status -->
<a href="https://coveralls.io/github/RUrlus/carma?branch=stable">
<img src="https://img.shields.io/coveralls/github/RUrlus/carma?style=for-the-badge" alt="Coveralls github" >
</a>
<!-- Documentation status -->
<a href="https://carma.readthedocs.io/en/latest/?badge=latest">
<img src="https://readthedocs.org/projects/carma/badge/?version=latest&style=for-the-badge" alt="Documentation Status" />
</a>
<!-- Release version -->
<a href="https://github.com/RUrlus/carma/releases">
<img src="https://img.shields.io/github/v/release/RUrlus/carma.svg?style=for-the-badge" alt="Release Version" />
</a>
<!-- License -->
<a href="https://github.com/RUrlus/carma/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/RUrlus/carma.svg?style=for-the-badge" alt="license"/>
</a>
</div>

<br/>

CARMA is a header only library providing conversions between Numpy arrays and Armadillo matrices. Examples and reference documentation can be found at [carma.readthedocs.io](https://carma.readthedocs.io/).
<p align="center">
A C++ header only library providing conversions between Numpy arrays and Armadillo matrices.
</p>
<p align="center">
|
<a href="https://carma.readthedocs.io/en/latest/">Documentation</a>
|
</p>

[![Linux Build Status](https://github.com/RUrlus/carma/actions/workflows/linux.yml/badge.svg)](https://github.com/RUrlus/carma/actions/workflows/linux.yml)
[![MacOS Build Status](https://github.com/RUrlus/carma/actions/workflows/macos.yml/badge.svg)](https://github.com/RUrlus/carma/actions/workflows/macos.yml)
[![Windows Build Status](https://github.com/RUrlus/carma/actions/workflows/windows.yml/badge.svg)](https://github.com/RUrlus/carma/actions/workflows/windows.yml)
[![Coverage Status](https://coveralls.io/repos/github/RUrlus/carma/badge.svg?branch=master)](https://coveralls.io/github/RUrlus/carma?branch=master)
[![Documentation Status](https://readthedocs.org/projects/carma/badge/?version=latest)](https://carma.readthedocs.io/en/latest/?badge=latest)
[![License](https://img.shields.io/github/license/RUrlus/carma)](https://github.com/RUrlus/carma/blob/stable/LICENSE)
[![Release](https://img.shields.io/github/v/release/rurlus/carma)](https://github.com/RUrlus/carma/releases)

## Introduction

CARMA provides fast bidirectional conversions between [Numpy](https://numpy.org) arrays and [Armadillo](http://arma.sourceforge.net/docs.html) matrices, vectors and cubes, much like [RcppArmadillo](https://github.com/RcppCore/RcppArmadillo) does for R and Armadillo.

The library relies heavily on the impressive [pybind11](https://pybind11.readthedocs.io/en/stable/intro.html) library and is largely inspired by their Eigen conversion albeit with a less conservative approach to memory management.
For details on pybind11 and Armadillo refer to their respective documentation.
The library extends the impressive [pybind11](https://pybind11.readthedocs.io/en/stable/intro.html) library with support for Armadillo.
For details on Pybind11 and Armadillo refer to their respective documentation [1](https://pybind11.readthedocs.io/en/stable/intro.html), [2](http://arma.sourceforge.net/docs.html).

### Installation
## Installation
CARMA is a header only library that relies on two other header only libraries, Armadillo and Pybind11.

Carma is a header only library that relies on two other header only libraries, Armadillo and Pybind11.
Both libraries are linked as submodule in the `third_party` directory.
CARMA can be integrated in a CMake build using `ADD_SUBDIRECTORY(<path_to_carma>)` which provides an interface library target `carma`
that has been linked with Python, Numpy, Pybind11 and Armadillo.
**Note, at the time of writing CARMA requires a forked version of Armadillo that
uses Numpy's allocator and deallocator.** This fork is provided as an interface libary target
`carma_armadillo`.

### Considerations
To link with CARMA:
```cmake
ADD_SUBDIRECTORY(extern/carma)
TARGET_LINK_LIBRARIES(<your_target> PRIVATE carma)
```
CARMA and Armadillo can then be included using:
```C++
#include <carma>
#include <armadillo>
```

In order to achieve fast conversions the default behaviour is avoid copying both from and to Numpy whenever possible and reasonable.
This allows very low overhead conversions but it impacts memory safety and requires user vigilance.
CARMA provides a number of configurations that can be set in the `carma_config.cmake` file at the root of the directory or passed to CMake, see [Configuration](https://carma.readthedocs.io/en/stable/configuration.html) and [Build configuration](https://carma.readthedocs.io/en/stable/building.html) documentation sections for details.

A second consideration is memory layout. Armadillo is optimised for column-major (Fortran order) memory whereas Numpy defaults to row-major (C order).
The default behaviour is to automatically convert, read copy, C-order arrays to F-order arrays upon conversion to Armadillo. Users should note that the library will not convert back to C-order when returning, this has consequences for matrices and cubes.
## Requirements

For details see the documentation section Memory Management.
CARMA v0.5 requires a compiler with support for C++14 and supports:

### Examples
* Python 3.6 -- 3.9
* Numpy >= 1.14
* Pybind11 v2.6.0 -- v2.6.2
* Armadillo 10.4.x -- 10.5.x

On a high level Carma provides three ways to work Numpy arrays in Armadillo:
**Note, at the time of writing CARMA requires a forked version of Armadillo that
uses Numpy's allocator and deallocator.**
The forked version is shipped with the library and provided at build time.
For details see the [Build configuration](https://carma.readthedocs.io/en/stable/building.html).

#### Manual conversion
### Considerations

In order to achieve fast conversions the default behaviour is avoid copying both from and to Numpy whenever possible and reasonable.
This allows very low overhead conversions but it impacts memory safety and requires user vigilance.

The easiest way to use Carma is manual conversion, it gives you the most control over when to copy or not.
You pass a Numpy array as an argument and/or as the return type and call the respective conversion function.
If you intend to return the memory of the input array back as another array, you must make sure to either copy or steal the memory on the conversion in or copy the memory out.
If you don't the memory will be aliased by the two Numpy arrays and bad things will happen.

```cpp
#include <armadillo>
#include <carma/carma.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
A second consideration is memory layout. Armadillo is optimised for column-major (Fortran order) memory whereas Numpy defaults to row-major (C order).
The default behaviour is to automatically convert, read copy, C-order arrays to F-order arrays upon conversion to Armadillo. Users should note that the library will not convert back to C-order when returning.

py::array_t<double> manual_example(py::array_t<double> & arr) {
// convert to armadillo matrix without copying.
arma::Mat<double> mat = carma::arr_to_mat<double>(arr);
For details see the documentation section [Memory Management](https://carma.readthedocs.io/en/latest/memory_management.html).

// normally you do something useful here ...
arma::Mat<double> result = arma::Mat<double>(
arr.shape(0),
arr.shape(1),
arma::fill::randu
);
### Example

// convert to Numpy array and return
return carma::mat_to_arr(result);
}
```
On a high level CARMA provides two ways to work Numpy arrays in Armadillo:
Automatic conversion saves a bit on code but provides less flexibility with
regards to when to copy and when not.
Manual conversion should be used when you need fine grained control.

#### Update array
Combining the two; we use automatic conversion on the conversion in and manual when
creating the tuple for the way out.

```cpp

#include <carma>
#include <armadillo>
#include <carma/carma.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/pytypes.h>

void update_example(py::array_t<double> & arr) {
// convert to armadillo matrix without copying.
arma::Mat<double> mat = carma::arr_to_mat<double>(arr);
// normally you do something useful here with mat ...
mat += arma::Mat<double>(arr.shape(0), arr.shape(1), arma::fill::randu);
// update Numpy array buffer
carma::update_array(mat, arr);
}
```

#### Automatic conversion
py::tuple ols(arma::mat& X, arma::colvec& y) {
// We borrow the data underlying the numpy arrays
int n = X.n_rows, k = X.n_cols;

```cpp
#include <armadillo>
#include <carma/carma.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
arma::colvec coeffs = arma::solve(X, y);
arma::colvec resid = y - X * coeffs;

arma::Mat<double> automatic_example(arma::Mat<double> & mat) {
// normally you do something useful here with mat ...
arma::Mat<double> rand = arma::Mat<double>(mat.n_rows, mat.n_cols, arma::fill::randu);
double sig2 = arma::as_scalar(arma::trans(resid) * resid / (n-k));
arma::colvec std_errs = arma::sqrt(sig2 * arma::diagvec( arma::inv(arma::trans(X)*X)) );

arma::Mat<double> result = mat + rand;
// type caster will take care of casting `result` to a Numpy array.
return result;
// We take ownership of the memory from the armadillo objects and
// return to python as a tuple containing two Numpy arrays.
return py::make_tuple(
carma::col_to_arr(coeffs),
carma::col_to_arr(std_errs)
);
}
```
The repository contains tests, examples and CMake build instructions that can be used as an reference.
For manual compilation see the documentation section Usage.

### Compatibility
// adapted from https://gallery.rcpp.org/articles/fast-linear-model-with-armadillo/
```
`carma` has been tested with:
Which can be called using:
* armadillo-9.800.1
* pybind11-2.4.3
```python
y = np.linspace(1, 100, num=100) + np.random.normal(0, 0.5, 100)
X = np.hstack((np.ones(100)[:, None], np.arange(1, 101)[:, None]))
coeff, std_err = carma.ols(X, y)
```

The repository contains tests, examples and CMake build instructions that can be used as an reference.
For manual compilation see the documentation section Usage.
**Compiler requirements through pybind11**
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer)
2. GCC 4.8 or newer
3. Microsoft Visual Studio 2015 Update 3 or newer
4. Intel C++ compiler 17 or newer
5. Cygwin/GCC (tested on 2.5.1)

### About

This project was created by Ralph Urlus. Significant improvements to the project have been contributed by [Pascal H.](https://github.com/hpwxf)

### License

carma is provided under a Apache 2.0 license that can be found in the LICENSE file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license.
CARMA is provided under a Apache 2.0 license that can be found in the LICENSE file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'R. Urlus'

# The full version, including alpha/beta/rc tags
release = '0.5.0'
release = '0.4.0'


# -- General configuration ---------------------------------------------------
Expand Down

0 comments on commit 1637b61

Please sign in to comment.