The original implementation in #1823 only supported single-axis roll operations. According to NumPy's roll signature, both shift and axis parameters can be tuples of ints:
numpy.roll(a, shift, axis=None)
# shift : int or tuple of ints# axis : int or tuple of ints, optional
This PR adds the missing multi-axis support:
xt::xarray<int> a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
auto result = xt::roll(a, {1, 2}, {0, 1}); // roll 1 on axis 0, roll 2 on axis 1
Commits
1. feat: add multi-axis support for xt::roll with optimized pointer arithmetic
Implemented detail::roll_multi() using recursive pointer arithmetic algorithm extended from the existing single-axis implementation
Added two new xt::roll() overloads: one for containers (std::vector, std::array) and one for C-style arrays
Supports accumulated shifts when the same axis appears multiple times (NumPy-compatible behavior)
Supports negative axis indices
Added comprehensive unit tests covering various scenarios (2D/3D, negative shifts, different container types, column-major layout, etc.)
2. docs: add multi-axis roll examples to documentation
Updated docs/source/numpy.rst with NumPy-to-xtensor comparison for multi-axis roll
Updated docs/source/quickref/manipulation.rst with usage examples
3. bench: add benchmark for multi-axis roll
Added benchmark/benchmark_roll.cpp with comprehensive benchmarks comparing sequential single-axis rolls vs. the new multi-axis implementation
Benchmarks cover 2D to 5D tensors, various sizes, and realistic image processing scenarios (RGB 1080p to 8K)
Build & Test
# Run unit tests
mkdir build &&cd build
cmake .. -DBUILD_TESTS=ON -DDOWNLOAD_GTEST=ON
make -j8 test_xmanipulation
./test/test_xmanipulation --test-case="*roll*" -s
# Run benchmarkscd benchmark
mkdir build &&cd build
cmake .. -DDOWNLOAD_GBENCHMARK=ON -Dxtensor_DIR=$(realpath ../../build)
make -j8 benchmark_xtensor
./benchmark_xtensor --benchmark_filter=roll
📊 Benchmark Results (click to expand)
Test Environment: Intel Core i7-12700H, 16GB RAM, Ubuntu 24.04.3 LTS
The multi-axis implementation achieves significant speedups over sequential single-axis roll calls:
Scenario
Speedup
2D tensors
~2-3x
3D tensors (2-3 axes)
~2-10x
4D tensors (4 axes)
~4-25x
5D tensors (5 axes)
~5-20x
RGB images (1080p-8K)
~2x
The performance gain increases with the number of axes being rolled, as the multi-axis version avoids creating intermediate temporary arrays and performs the roll operation in a single pass through the data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist
Description
This PR extends the xt::roll function to support multiple axes simultaneously, completing the NumPy-compatible API as originally requested.
Related: #1766, #1823
The original implementation in #1823 only supported single-axis roll operations. According to NumPy's roll signature, both shift and axis parameters can be tuples of ints:
This PR adds the missing multi-axis support:
Commits
1. feat: add multi-axis support for xt::roll with optimized pointer arithmetic
2. docs: add multi-axis roll examples to documentation
3. bench: add benchmark for multi-axis roll
Build & Test
Test Environment: Intel Core i7-12700H, 16GB RAM, Ubuntu 24.04.3 LTS
Performance Summary
The multi-axis implementation achieves significant speedups over sequential single-axis roll calls:
The performance gain increases with the number of axes being rolled, as the multi-axis version avoids creating intermediate temporary arrays and performs the roll operation in a single pass through the data.