Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

xtensor-python

PyPI version Documentation License

Python bindings for the xtensor C++ multi-dimensional array library.

Overview

xtensor-python enables seamless interoperability between NumPy arrays and C++ through the xtensor library. It provides:

  • Zero-copy NumPy array integration with C++
  • Broadcasting and universal functions compatible with NumPy
  • STL-compliant APIs for familiar C++ development
  • Header-only library for easy integration
  • High performance through lazy evaluation and expression templates

Installation

From PyPI (Recommended)

pip install xtensor-python

From conda-forge

conda install -c conda-forge xtensor-python
# or
mamba install -c conda-forge xtensor-python

Development Installation

git clone https://github.com/xtensor-stack/xtensor-python.git
cd xtensor-python
pip install -e .

Quick Start

Python API

The Python package provides utilities for building C++ extensions:

import xtensor_python

# Get include directories for your C++ build
include_dirs = xtensor_python.get_include()
print(include_dirs)

# Use in your setup.py or pyproject.toml
from pybind11.setup_helpers import build_ext
from xtensor_python import get_cmake_dir

# CMake integration
cmake_dir = get_cmake_dir()

C++ Integration

Create a C++ extension using xtensor-python:

#include <pybind11/pybind11.h>
#include <xtensor/xmath.hpp>
#include <xtensor-python/pyarray.hpp>

// Enable numpy import
#define FORCE_IMPORT_ARRAY
#include <xtensor-python/pyarray.hpp>

double sum_of_sines(xt::pyarray<double>& arr) {
    auto sines = xt::sin(arr);  // Lazy evaluation
    return std::accumulate(sines.begin(), sines.end(), 0.0);
}

PYBIND11_MODULE(my_extension, m) {
    xt::import_numpy();
    m.def("sum_of_sines", sum_of_sines, "Sum the sines of array elements");
}

CMakeLists.txt Example

cmake_minimum_required(VERSION 3.15)
project(my_extension)

find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(pybind11 REQUIRED)
find_package(xtensor-python REQUIRED)

pybind11_add_module(my_extension src/main.cpp)
target_link_libraries(my_extension PRIVATE xtensor-python::xtensor-python)

Container Types

pyarray

Dynamic multi-dimensional arrays that can be reshaped:

#include <xtensor-python/pyarray.hpp>

void process_dynamic(xt::pyarray<double>& arr) {
    // Can reshape to different dimensions
    arr.reshape({10, 5});
    // Changes are reflected in Python
}

pytensor

Fixed-dimension arrays with compile-time optimization:

#include <xtensor-python/pytensor.hpp>

void process_2d(xt::pytensor<double, 2>& tensor) {
    // Fixed 2D tensor - faster than pyarray
    // Shape is stack-allocated
    auto result = xt::sum(tensor, {1});  // Sum along axis 1
}

Migration from CMake to pip

Before (CMake-based)

find_package(xtensor-python REQUIRED)
target_link_libraries(mylib xtensor-python)

After (pip-based)

  1. Install via pip:

    pip install xtensor-python
  2. Update CMakeLists.txt:

    find_package(Python COMPONENTS Interpreter Development REQUIRED)
    find_package(xtensor-python REQUIRED)
    target_link_libraries(mylib PRIVATE xtensor-python::xtensor-python)
  3. Or use in setup.py:

    from pybind11.setup_helpers import build_ext
    import xtensor_python
    
    ext_modules = [
        Pybind11Extension(
            "my_module",
            ["src/main.cpp"],
            include_dirs=[xtensor_python.get_include()],
        ),
    ]

Key Changes

  • Installation: Use pip install xtensor-python instead of conda/manual builds
  • CMake: The package now provides proper CMake config files
  • Headers: Automatically available through Python package
  • Dependencies: Managed through pip/pyproject.toml

Advanced Usage

Universal Functions

Create vectorized functions from scalar C++ functions:

#include <xtensor-python/pyvectorize.hpp>

double scalar_func(double x, double y) {
    return std::sin(x) - std::cos(y);
}

PYBIND11_MODULE(my_module, m) {
    xt::import_numpy();
    m.def("vectorized_func", xt::pyvectorize(scalar_func));
}

Custom Type Casting

#include <xtensor-python/pynative_casters.hpp>

// Automatic casting between NumPy and xtensor types
void process_array(const xt::xarray<double>& arr) {
    // Function automatically accepts NumPy arrays
}

Building Extensions

Using setuptools

# setup.py
from pybind11.setup_helpers import Pybind11Extension, build_ext
import xtensor_python

ext_modules = [
    Pybind11Extension(
        "my_extension",
        ["src/main.cpp"],
        include_dirs=[xtensor_python.get_include()],
        cxx_std=14,
    ),
]

setup(
    name="my_package",
    ext_modules=ext_modules,
    cmdclass={"build_ext": build_ext},
)

Using pyproject.toml

[build-system]
requires = ["setuptools", "pybind11", "xtensor-python"]

[tool.setuptools]
packages = ["my_package"]

[[tool.setuptools.ext-modules]]
name = "my_package._core"
sources = ["src/main.cpp"]

Dependencies

  • Python: ≥3.8
  • NumPy: ≥2.0
  • pybind11: ≥2.6.1,<4
  • xtensor: ≥0.26.0 (automatically resolved)

Performance Tips

  1. Use pytensor for fixed dimensions - faster than pyarray
  2. Leverage lazy evaluation - operations are computed only when needed
  3. Minimize copies - xtensor-python provides zero-copy views
  4. Use broadcasting - automatic shape alignment like NumPy

Examples

Complete examples are available in the documentation:

Documentation

Full documentation is available at: https://xtensor-python.readthedocs.io/

Contributing

Contributions are welcome! Please see our contributing guidelines.

License

This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.

Support