-
Notifications
You must be signed in to change notification settings - Fork 114
Python like Range #2006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Python like Range #2006
Changes from 16 commits
4b5e5a3
124338d
801bd00
6dbb367
17b5e57
ce732f4
3d0195a
ddae21a
e243737
23a04d6
6a8995a
66be94f
0c4666e
d2886c0
ab3c185
ad5f132
1fc8ac3
c7589b4
744cbc5
c30299d
557dc27
b7b14db
2f9edca
0b1e0d2
03b4af1
5fd1ee6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,3 +94,68 @@ 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``, that strong type is preserved for the loop | ||
| variable when possible. | ||
| * Providing an explicit template argument, such as | ||
| ``RAJA::range<MyIndex>(end)``, overrides the deduced storage type. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should still be an error to, for example, explicitly ask for int but provide a strong index type as an argument, or explicitly ask for a strong index type and provide a different strong index type as an argument.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we can use c++20's require to test that these cases fail?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You definitely can, you could even make concepts to make it easier most likely. |
||
|
|
||
| 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>(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}, N, 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++ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | ||
| // 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. Mixed strong/numeric begin/end and strided ranges | ||
| */ | ||
|
|
||
| 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 mixed_end_values[N] = {}; | ||
| int mixed_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>(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; | ||
| }); | ||
|
|
||
| // Mixed numeric/strong range: preserves CellIndex for the loop index. | ||
| RAJA::forall<RAJA::seq_exec>(RAJA::range(1, CellIndex {6}), [&](CellIndex i) { | ||
| mixed_end_values[*i] = static_cast<int>(*i * 10); | ||
| }); | ||
|
|
||
| // Mixed strong begin with numeric end/stride for a strided range. | ||
| RAJA::forall<RAJA::seq_exec>(RAJA::range(CellIndex {1}, N, 2), | ||
| [&](CellIndex i) { | ||
| mixed_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>(N):"; | ||
| for (auto i : RAJA::range<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(1, CellIndex{6}):"; | ||
| for (auto i : RAJA::range(1, CellIndex {6})) { | ||
| std::cout << ' ' << mixed_end_values[*i]; | ||
| } | ||
| std::cout << '\n'; | ||
|
|
||
| std::cout << "range(CellIndex{1}, N, 2):"; | ||
| for (auto i : RAJA::range(CellIndex {1}, N, 2)) { | ||
| std::cout << ' ' << mixed_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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When possible? Doesn't it always use the strong type if one is provided?
The only case I'm worried about is something like a strong index type with underlying type int combined with a long choosing long instead of being an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is a good point, I think we should error if so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the code accordingly