Skip to content

Add start/stop keywords to reverse and reverse! - #119

Closed
shreyas-omkar wants to merge 1 commit into
JuliaGPU:mainfrom
shreyas-omkar:sh/reverse-subrange
Closed

Add start/stop keywords to reverse and reverse!#119
shreyas-omkar wants to merge 1 commit into
JuliaGPU:mainfrom
shreyas-omkar:sh/reverse-subrange

Conversation

@shreyas-omkar

@shreyas-omkar shreyas-omkar commented Sep 1, 2026

Copy link
Copy Markdown
Member

Reverse part of a vector without changing the elements outside it. This extends the
whole-array and dims forms from #114 to support the subranges accepted by
Base.reverse!(v, start, stop). Bounds are keywords because AK uses positional
arguments for the backend.

import AcceleratedKernels as AK

v = [1, 2, 3, 4, 5]                  # GPU vectors work the same way
AK.reverse!(v; start=2, stop=4)       # v == [1, 4, 3, 2, 5]
w = AK.reverse(v; start=3)           # w == [1, 4, 5, 2, 3]; v is unchanged

dst = similar(v)
AK.reverse!(dst, v; start=2, stop=4)  # write into a preallocated destination

Either integer bound may be omitted, defaulting to that end of the vector. Bounds
are supported only for vectors and cannot be combined with dims other than :.
For start < stop, both bounds must be in bounds. For start >= stop, the in-place
form does nothing and the out-of-place forms copy the source, without checking
bounds. This follows Base's in-place behavior; Base's allocating reverse can
throw for out-of-bounds empty or singleton ranges. A destination must have the same
length as the source and must not alias it.

In place, the implementation reverses a view using the existing loop. Out of place,
one pass copies elements outside the range and reverses those inside it. This avoids
processing the reversed range twice and avoids separate device copies that can
synchronize on Metal.

For context, these earlier review measurements use Float32 vectors of length
2^26, Julia 1.12.7, and synchronized medians of 30 samples (milliseconds):

Device In place: whole vector In place: middle half Out of place: middle half
NVIDIA RTX 5080 0.662 0.332 0.663
Apple M1 9.52 4.77 9.20
Intel Iris Xe 28.6 14.1 33.0

The in-place keyword form measured similarly to reversing a view. Its work scales
with the range length; out of place, the whole vector still needs copying. CUDA.jl
measured 0.363 ms in place and 0.660 ms allocating for the middle half on the RTX
5080; AK's out-of-place measurement uses a preallocated destination. The Intel
middle-half copy/reversal was about 15% slower than its whole-vector reversal.

@christiangnrd

Copy link
Copy Markdown
Member

How does this behave when incompatible args are used together? In base, start and stop are only defined for AbstractVector, and dims isn't an option with start and stop

@shreyas-omkar

Copy link
Copy Markdown
Member Author

start/stop + dims already threw ArgumentError (mutually exclusive).
But start/stop were being accepted on N-D arrays too which Base doesn't allow. they're now restricted to vectors with an ArgumentError, matching Base.reverse, while the whole-array default range still works on any array.

@shreyas-omkar
shreyas-omkar force-pushed the sh/reverse-subrange branch 2 times, most recently from d4f280b to 9fcc67e Compare September 9, 2026 05:04
@shreyas-omkar

Copy link
Copy Markdown
Member Author

@christiangnrd and @maleadt Can we get a review? This should land right after #114 and #118

@shreyas-omkar

Copy link
Copy Markdown
Member Author

Resolved conflicts.

@maleadt

maleadt commented Sep 9, 2026

Copy link
Copy Markdown
Member

Taking a look.

Reverse a vector subrange in place or into a separate destination, with omitted bounds defaulting to the ends. Keep bounds exclusive with dimension selection and use Base.reverse! semantics for trivial ranges.

Reuse the in-place loop through a view and fuse out-of-place copying with reversal, avoiding extra passes and synchronous device copies.
@maleadt
maleadt force-pushed the sh/reverse-subrange branch from e499dc8 to c6e14bc Compare September 9, 2026 10:07
@maleadt maleadt changed the title feat(reverse): reverse a linear sub-range via start/stop Add start/stop keywords to reverse and reverse! Sep 9, 2026
@maleadt

maleadt commented Sep 9, 2026

Copy link
Copy Markdown
Member

Rebased and cleaned up. I'm not sure this has much value though; what does it add over reverse with a view? I guess one think is the out-of-place reversal of a view not needing a separate copy first because it keeps the elements outside of start:stop intact, but that's pretty niche.

@shreyas-omkar

Copy link
Copy Markdown
Member Author

The only real thing it adds over a view is the out-of-place case: reverse(v; start, stop) gives you a full array with the middle reversed and the ends copied in one pass. I'm fine either way if it's not worth the extra API I can close it. So its what do you think, would be better in this case?

@shreyas-omkar

Copy link
Copy Markdown
Member Author

Closed as per discussed

@maleadt

maleadt commented Sep 9, 2026

Copy link
Copy Markdown
Member

Yeah, we can always revisit this when people request it, or when it turns out necessary for a Base API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants