Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions docs/sphinx/user_guide/feature/iteration_spaces.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,75 @@ and two types:

Thus, any iterable type that defines these methods and types appropriately
can be used as a segment with RAJA kernel execution templates.

Python-like Range Helpers
^^^^^^^^^^^^^^^^^^^^^^^^^

RAJA also provides ``RAJA::range(...)`` helpers that construct the segment
type for common half-open iteration patterns. These helpers are intended to
mirror the shape of Python's ``range`` while returning RAJA segment objects
that can be passed directly to ``RAJA::forall`` and other execution
interfaces.

The supported forms are::

RAJA::range(end) // [0, end)
RAJA::range<IndexT>(end) // [0, end) with explicit storage type
RAJA::range(begin, end) // [begin, end)
RAJA::range(begin, end, stride) // [begin, end) with stride

The return type depends on the arguments:

* ``RAJA::range(end)`` and ``RAJA::range(begin, end)`` return a
``RAJA::TypedRangeSegment``.
* ``RAJA::range(begin, end, stride)`` returns a
``RAJA::TypedRangeStrideSegment``.
* When one of the bounds is a RAJA strong index type, such as a type created
with ``RAJA_INDEX_VALUE``, all bounds must use that same strong type. Mixed
strong and plain integral bounds are rejected rather than narrowed.
* Providing an explicit template argument, such as
``RAJA::range<MyIndex>(end)``, overrides the deduced storage type, but
explicit storage must still match the argument types. For example,
``RAJA::range<int>(RangeStrongIndex(3), 17)`` and
``RAJA::range<RangeStrongIndex>(AnotherRangeStrongIndex(3), 17)`` are
rejected, while ``RAJA::range<RangeStrongIndex>(RangeStrongIndex(3),
RangeStrongIndex(17))`` is valid.

For example::

RAJA_INDEX_VALUE(CellIndex, "CellIndex");

RAJA::forall<RAJA::seq_exec>(RAJA::range(N), [=](RAJA::Index_type i) {
values[i] = i * i;
});

RAJA::forall<RAJA::seq_exec>(RAJA::range<CellIndex>(CellIndex {N}),
[=](CellIndex i) {
typed_values[*i] = *i + 10;
});

RAJA::forall<RAJA::seq_exec>(RAJA::range(2, 6), [=](int i) {
subrange_values[i] = i;
});

RAJA::forall<RAJA::seq_exec>(RAJA::range(CellIndex {1}, CellIndex {N},
CellIndex {2}),
[=](CellIndex i) {
strided_values[*i] = *i;
});

Strided ranges follow the same half-open interval convention as
``RAJA::TypedRangeStrideSegment``. Positive strides move forward, and negative
strides move backward. For example, ``RAJA::range(N - 1, -1, -2)`` visits
``N - 1, N - 3, ...`` down to the first value that remains greater than
``-1``. A zero stride is invalid and causes RAJA to abort or throw, depending
on the build configuration.

The older ``RAJA::make_range`` and ``RAJA::make_strided_range`` helpers remain
available. Use ``RAJA::range(...)`` when the Python-like spelling improves
readability or when you want the one-argument ``[0, end)`` shorthand.

The complete example added in this branch is shown below:

.. literalinclude:: ../../../../examples/raja-ranges.cpp
:language: c++
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ raja_add_executable(
NAME resource-forall
SOURCES resource-forall.cpp)

raja_add_executable(
NAME raja-ranges
SOURCES raja-ranges.cpp)

raja_add_executable(
NAME dynamic-forall
SOURCES dynamic-forall.cpp)
Expand Down
114 changes: 114 additions & 0 deletions examples/raja-ranges.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Copyright (c) Lawrence Livermore National Security, LLC and other
// RAJA Project Developers. See top-level LICENSE and COPYRIGHT
// files for dates and other details. No copyright assignment is required
// to contribute to RAJA.
//
// SPDX-License-Identifier: (BSD-3-Clause)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

#include <iostream>

#include "RAJA/RAJA.hpp"

/*
* RAJA ranges example
*
* Demonstrates Python-like range helpers backed by RAJA segments:
* 1. RAJA::range(N) for [0, N)
* 2. RAJA::range<T>(N) for a TypedRangeSegment<T> over [0, N)
* 3. RAJA::range(begin, end) for [begin, end)
* 4. RAJA::range(begin, end, step) for a strided half-open interval
* 5. Strong-index ranges using consistent strong types
*/

RAJA_INDEX_VALUE(CellIndex, "CellIndex");

int main(int RAJA_UNUSED_ARG(argc), char** RAJA_UNUSED_ARG(argv))
{
constexpr RAJA::Index_type N = 8;

int values[N] = {};
int typed_values[N] = {};
int subrange_values[N] = {};
int odd_values[N] = {};
int strong_end_values[N] = {};
int strong_stride_values[N] = {};

// Equivalent to Python range(N): [0, N)
RAJA::forall<RAJA::seq_exec>(RAJA::range(N), [&](RAJA::Index_type i) {
values[i] = static_cast<int>(i * i);
});

// Equivalent to Python range(N), but preserving a strong index type.
RAJA::forall<RAJA::seq_exec>(
RAJA::range<CellIndex>(CellIndex {N}), [&](CellIndex i) {
typed_values[*i] = static_cast<int>(*i + 10);
});

// Equivalent to Python range(2, 6): [2, 6)
RAJA::forall<RAJA::seq_exec>(RAJA::range(2, 6), [&](int i) {
subrange_values[i] = i;
});

// Equivalent to Python range(1, N, 2): odd indices in [1, N)
RAJA::forall<RAJA::seq_exec>(RAJA::range(1, N, 2), [&](int i) {
odd_values[i] = i;
});

// Strong-index range with consistent strong bounds.
RAJA::forall<RAJA::seq_exec>(
RAJA::range(CellIndex {1}, CellIndex {6}),
[&](CellIndex i) { strong_end_values[*i] = static_cast<int>(*i * 10); });

// Strong-index strided range with consistent strong bounds.
RAJA::forall<RAJA::seq_exec>(
RAJA::range(CellIndex {1}, CellIndex {N}, CellIndex {2}),
[&](CellIndex i) {
strong_stride_values[*i] = static_cast<int>(*i * 100);
});

std::cout << "range(N):";
for (auto i : RAJA::range(N)) {
std::cout << ' ' << values[i];
}
std::cout << '\n';

std::cout << "range<CellIndex>(CellIndex{N}):";
for (auto i : RAJA::range<CellIndex>(CellIndex {N})) {
std::cout << ' ' << typed_values[*i];
}
std::cout << '\n';

std::cout << "range(2, 6):";
for (auto i : RAJA::range(2, 6)) {
std::cout << ' ' << subrange_values[i];
}
std::cout << '\n';

std::cout << "range(1, N, 2):";
for (auto i : RAJA::range(1, N, 2)) {
std::cout << ' ' << odd_values[i];
}
std::cout << '\n';

std::cout << "range(CellIndex{1}, CellIndex{6}):";
for (auto i : RAJA::range(CellIndex {1}, CellIndex {6})) {
std::cout << ' ' << strong_end_values[*i];
}
std::cout << '\n';

std::cout << "range(CellIndex{1}, CellIndex{N}, CellIndex{2}):";
for (auto i : RAJA::range(CellIndex {1}, CellIndex {N}, CellIndex {2})) {
std::cout << ' ' << strong_stride_values[*i];
}
std::cout << '\n';

std::cout << "range(N - 1, -1, -2):";
for (auto i : RAJA::range(N - 1, -1, -2)) {
std::cout << ' ' << i;
}
std::cout << '\n';

return 0;
}
Loading
Loading