|
1 | | -# Requirement |
| 1 | +# xtensor-python |
2 | 2 |
|
3 | | - - pybind11 master (not 1.8.1) |
4 | | - - xtensor 0.1.0 |
| 3 | +Python bindings for the [xtensor](https://github.com/QuantStack/xtensor) C++ multi-dimensional array library. |
5 | 4 |
|
6 | | -# Installation |
| 5 | + - `xtensor` is a C++ library for multi-dimensional arrays enabling numpy-style broadcasting and lazy computing. |
| 6 | + - `xtensor-python` enables inplace use of numpy arrays with all the benefits from `xtensor` |
7 | 7 |
|
8 | | - - build and install conda recipe |
| 8 | + - C++ universal function and broadcasting |
| 9 | + - STL - compliant APIs. |
9 | 10 |
|
10 | | -# Dev installation |
| 11 | +The Python bindings for `xtensor` are based on the [pybind11](https://github.com/pybind/pybind11/) C++ library, which enables seemless interoperability between C++ and Python. |
11 | 12 |
|
12 | | - - symlink `include\xtensor-python` to `$SYS_PREFIX\include\xtensor-python` |
| 13 | +## Usage |
13 | 14 |
|
14 | | -# Testing |
| 15 | +### Example 1: Use an algorithm of the C++ library on a numpy array inplace. |
15 | 16 |
|
16 | | - Testing `xtensor-python` requires `nosetests` |
| 17 | +**C++ code** |
| 18 | + |
| 19 | +```cpp |
| 20 | +#include <numeric> // Standard library import for std::accumulate |
| 21 | +#include "pybind11/pybind11.h" // Pybind11 import to define Python bindings |
| 22 | +#include "xtensor/xmath.hpp" // xtensor import for the C++ universal functions |
| 23 | +#include "xtensor-python/pyarray.hpp" // Numpy bindings |
| 24 | + |
| 25 | +double sum_of_sines(xt::pyarray<double> &m) |
| 26 | +{ |
| 27 | + auto sines = xt::sin(m); // sines does not actually hold any value, which are only computed upon access |
| 28 | + return std::accumulate(sines.begin(), sines.end(), 0.0); |
| 29 | +} |
| 30 | + |
| 31 | +PYBIND11_PLUGIN(xtensor_python_test) |
| 32 | +{ |
| 33 | + pybind11::module m("xtensor_python_test", "Test module for xtensor python bindings"); |
| 34 | + |
| 35 | + m.def("sum_of_sines", sum_of_sines, "Computes the sum of the sines of the values of the input array"); |
| 36 | + |
| 37 | + return m.ptr(); |
| 38 | +} |
| 39 | +``` |
| 40 | +
|
| 41 | +**Python Code** |
| 42 | +
|
| 43 | +```python |
| 44 | +import numpy as np |
| 45 | +import xtensor_python_test as xt |
| 46 | +
|
| 47 | +a = np.arange(15).reshape(3, 5) |
| 48 | +s = xt.sum_of_sines(v) |
| 49 | +s |
| 50 | +``` |
| 51 | + |
| 52 | +**Outputs** |
| 53 | + |
| 54 | +``` |
| 55 | +1.2853996391883833 |
| 56 | +``` |
| 57 | + |
| 58 | +### Example 2: Create a universal function from a C++ scalar function |
| 59 | + |
| 60 | +**C++ code** |
| 61 | + |
| 62 | +```cpp |
| 63 | +#include "pybind11/pybind11.h" |
| 64 | +#include "xtensor-python/pyvectorize.hpp" |
| 65 | +#include <numeric> |
| 66 | +#include <cmath> |
| 67 | + |
| 68 | +namespace py = pybind11; |
| 69 | + |
| 70 | +double scalar_func(double i, double j) |
| 71 | +{ |
| 72 | + return std::sin(i) - std::cos(j); |
| 73 | +} |
| 74 | + |
| 75 | +PYBIND11_PLUGIN(xtensor_python_test) |
| 76 | +{ |
| 77 | + py::module m("xtensor_python_test", "Test module for xtensor python bindings"); |
| 78 | + |
| 79 | + m.def("vectorized_func", xt::pyvectorize(scalar_func), ""); |
| 80 | + |
| 81 | + return m.ptr(); |
| 82 | +} |
| 83 | +``` |
| 84 | +
|
| 85 | +**Python Code** |
| 86 | +
|
| 87 | +```python |
| 88 | +import numpy as np |
| 89 | +import xtensor_python_test as xt |
| 90 | +
|
| 91 | +x = np.arange(15).reshape(3, 5) |
| 92 | +y = [1, 2, 3] |
| 93 | +z = xt.vectorized_func(x, y) |
| 94 | +z |
| 95 | +``` |
| 96 | + |
| 97 | +**Outputs** |
| 98 | + |
| 99 | +``` |
| 100 | +[[-1. , 0.301169, 1.325444, 1.131113, -0.103159], |
| 101 | + [-1.958924, -0.819718, 1.073133, 1.979351, 1.065762], |
| 102 | + [-1.544021, -1.540293, -0.120426, 1.41016 , 1.644251]] |
| 103 | +``` |
| 104 | + |
| 105 | +## Installation |
| 106 | + |
| 107 | +We provide a package for the conda package manager. |
| 108 | + |
| 109 | +```bash |
| 110 | +conda install -c conda-forge xtensor-python |
| 111 | +``` |
| 112 | + |
| 113 | +This will pull the dependencies to xtensor-python, that is `pybind11` and `xtensor`. |
| 114 | + |
| 115 | +## Project cookiecutter |
| 116 | + |
| 117 | +A template for a project making use of `xtensor-python` is available in the form of a cookie cutter [here](https://github.com/QuantStack/xtensor-cookiecutter). |
| 118 | + |
| 119 | +This project is meant to help library authors get started with the xtensor python bindings. |
| 120 | + |
| 121 | +It produces a project following the best practices for the packaging and distribution of Python extensions based on `xtensor-python`, including a `setup.py` file and a conda recipe. |
| 122 | + |
| 123 | +## Building and Running the Tests |
| 124 | + |
| 125 | +Testing `xtensor-python` requires `nosetests` |
17 | 126 |
|
18 | 127 | ``` bash |
19 | 128 | nosetests . |
20 | 129 | ``` |
21 | 130 |
|
22 | | - To pick up changes in `xtensor-python` while rebuilding, delete the `build/` directory. |
| 131 | +To pick up changes in `xtensor-python` while rebuilding, delete the `build/` directory. |
| 132 | + |
| 133 | +## License |
| 134 | + |
| 135 | +We use a shared copyright model that enables all contributors to maintain the |
| 136 | +copyright on their contributions. |
| 137 | + |
| 138 | +This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. |
0 commit comments