Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

tdegeus/pyxtensor

Repository files navigation

Now fully covered in xtensor-python

pyxtensor

CI Travis Appveyor Conda Version

Disclaimer

This library is free to use under the MIT. Any additions are very much appreciated, in terms of suggested functionality, code, documentation, testimonials, word-of-mouth advertisement, etc. Bug reports or feature requests can be filed on GitHub. As always, the code comes with no guarantee. None of the developers can be held responsible for possible mistakes.

Download: .zip file | .tar.gz file.

(c - GPLv3) T.W.J. de Geus (Tom) | [email protected] | www.geus.me | github.com/tdegeus/pyxtensor

Contents

Introduction

This library provides details for pybind11 such that an interface to NumPy arrays is automatically provided when including a function that takes any of the xtensor classes as (return) argument(s).

The behaviour is distinctly different from xtensor-python. The latter 'maps' NumPy arrays to a so-called xt::pyarray giving direct memory access to it. In contrast, pyxtensor copies the NumPy object to a xt::xarray or xt::xtensor and vice versa. This results in a simpler usage in which a C++ library can be exposed without any wrapper functions, however, with the disadvantage of using copies (that cost time, and that disallow in-place modifications).

Getting pyxtensor

There are two ways of practically using pyxtensor. One way is to 'install' the C++ headers somewhere and use CMake or pkg-config to find the C++ headers. The other way is to 'install' the Python library that comes with pyxtensor and let it 'install' the C++ headers in the correct Python folder, and use Python to find the C++ headers.

Using conda

conda install -c conda-forge pyxtensor

Using pip (Python only)

pip install pyxtensor

From source

# Download pyxtensor
git checkout https://github.com/tdegeus/pyxtensor.git
cd pyxtensor

# For Python use
python setup.py install

# For CMake or pkg-config use
cmake .
make install

Usage

pybind11 module

Consider the following example:

#include <xtensor/xarray.hpp>
#include <pyxtensor/pyxtensor.hpp>

xt::xarray<double> timesTwo(const xt::xarray<double>& a)
{
    return 2. * a;
}

namespace py = pybind11;

PYBIND11_MODULE(example, m)
{
    m.def("timesTwo", &timesTwo);
}

download "example.cpp"

As observed the pybind11 wrapper immediately acts on the xtensor objects.

Compile project using Python

Using the pyxtensor Python module the setup.py can be as follows

from setuptools import setup, Extension

import pybind11
import pyxtensor

ext_modules = [
    Extension(
        'example',
        ['example.cpp'],
        include_dirs=[
            pyxtensor.find_pyxtensor(),
            pyxtensor.find_pybind11(),
            pyxtensor.find_xtensor()],
        language='c++'
    ),
]

setup(
    name='example',
    description='Short description',
    long_description='Long description',
    version='0.0.1',
    license='MIT',
    author='Tom de Geus',
    author_email='...',
    url='https://github.com/tdegeus/pyxtensor',
    ext_modules=ext_modules,
    setup_requires=['pybind11', 'pyxtensor'],
    cmdclass={'build_ext': pyxtensor.BuildExt},
    zip_safe=False,
)

download "setup.py"

Compilation can then proceed using

python setup.py build
python setup.py install

or

python -m pip install . -vvv

For certain xtensor-based codes xsimd is advisable. To enable one could do the following instead:

from setuptools import setup, Extension

import pybind11
import pyxtensor

include_dirs = [
    pyxtensor.find_pyxtensor(),
    pyxtensor.find_pybind11(),
    pyxtensor.find_xtensor(),
    pyxtensor.find_xtl()]

build = pyxtensor.BuildExt

xsimd = pyxtensor.find_xsimd()
if xsimd:
    if len(xsimd) > 0:
        include_dirs += [xsimd]
        build.c_opts['unix'] += ['-march=native', '-DXTENSOR_USE_XSIMD']
        build.c_opts['msvc'] += ['/DXTENSOR_USE_XSIMD']

ext_modules = [
    Extension(
        'example',
        ['example.cpp'],
        include_dirs = include_dirs,
        language = 'c++')
]

setup(
  name='example',
  description='Short description',
  long_description='Long description',
  version='0.0.1',
  license='MIT',
  author='Tom de Geus',
  author_email='...',
  url='https://github.com/...',
  ext_modules=ext_modules,
  setup_requires=['pybind11', 'pyxtensor'],
  cmdclass={'build_ext': build},
  zip_safe=False)

Compile project using CMake & Python

Using pyxtensor the CMakeLists.txt can be as follows

cmake_minimum_required(VERSION 3.4...3.18)
project(example)

find_package(pybind11 CONFIG REQUIRED)
find_package(pyxtensor REQUIRED)
find_package(xtensor REQUIRED)

pybind11_add_module(example example.cpp)

target_link_libraries(example PUBLIC
    pybind11::module
    pyxtensor
    xtensor::optimize)

# MYVERSION_INFO is defined by setup.py and passed into the C++ code as a define (VERSION_INFO) here
target_compile_definitions(example PRIVATE VERSION_INFO=${MYVERSION_INFO})

download "CMakeLists.txt"

with the corresponding setup.py:

import pyxtensor
from setuptools import setup, Extension

setup(
    name='example',
    description='Short description',
    long_description='Long description',
    version='0.0.1',
    license='MIT',
    author='Tom de Geus',
    author_email='...',
    url='https://github.com/tdegeus/pyxtensor',
    ext_modules=[pyxtensor.CMakeExtension("example")],
    cmdclass={"build_ext": pyxtensor.CMakeBuild},
    zip_safe=False,
)

download "setup.py"

Compilation can then proceed using

python setup.py build
python setup.py install

or

python -m pip install . -vvv