# Concatenated ranges

**URL:** https://discourse.julialang.org/t/concatenated-ranges/126042
**Category:** General Usage
**Tags:** range, abstractrange
**Created:** [February 18, 2025, 6:58pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042 "2025-02-18T18:58:59Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [February 18, 2025, 6:58pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/1 "2025-02-18T18:58:59Z")

</div>

For some applications concatenated ranges would be nice. E.g. it would simplify working with rotated indices, obviating the need for `fftshift` for some calculations. E.g. if I want to construct a suitable Gaussian in Fourier-space without subsequently shifting it to the corner, The following line comes close to this:

```julia
f = Iterators.flatten((1:100000, -99999:0))

```

However, f is not an `AbstractRange`. Yet, this would be nice. It could support operations such as `size()`, `length()` and even `get_index`. Simple additions, subtractions, multiplications or divisions with scalars, could just modify the internally stored ranges without collecting. Ideally `CUDA` could even work with such ranges (e.g. by launching separate calculation kernels for each partial range, or letting the kernels figure out internally which sub-range a thread belongs to).  
Would it make sense to write such a `ConcatRange` support?  
Is there any overview of the Range and Iterator classes and how the Abstract class hierarchy is currently set up and which operations each such class needs to support?  
The `CatView` is also vaguely related to this, but it does not treat ranges either (even fails with a stack overflow if you try).

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [February 18, 2025, 7:09pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/2 "2025-02-18T19:09:36Z")

</div>

I think this can’t quite be an AbstractRange, at least if methods like this encode what linear range means:

```julia
maximum(r::AbstractRange) = isempty(r) ? throw(ArgumentError("range must be non-empty")) : max(first(r), last(r))

```

Some packages do define such things, but I don’t think they have much special support, from e.g. CUDA.jl:

```julia
julia> LazyArrays.Vcat(1:3, -2:0)
vcat(3-element UnitRange{Int64}, 3-element UnitRange{Int64}):
  1
  2
  3
 -2
 -1
  0

```

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [February 18, 2025, 7:40pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/3 "2025-02-18T19:40:35Z")

</div>

Interesting. I didn’t know that LazyArrays has support for this. As for your “maximum” example I guess one could specialize these functions for this type of range. Or is there something fundamentally wrong with this?  
I would interpret that implementation as a default which can be specialized (i.e. overwritten).

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [February 18, 2025, 8:48pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/4 "2025-02-18T20:48:05Z")

</div>

Maximum is just the canary in the coal mine here. There are myriads of such methods. All would be incorrect “by default.” Some would be obvious, others would result in silent data corruption or segfaults. One obvious such place is with indexing and views; they all have similar optimizations for ranges that would lead to OOB accesses — accesses in places authors may have (rightly!) marked as `@inbounds`.

You’re welcome to break the “rules” of a given supertype or interface, but you’re gonna be unleashing dragons. Maybe you can tame some, but they’re gonna be lurking everywhere.

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [February 19, 2025, 7:41am UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/5 "2025-02-19T07:41:29Z")

</div>

> [@mcabbott](#):
>
> `LazyArrays.Vcat`

I checked it, and indeed `LazyArrays.Vcat` does not support CUDA for ranges. Maybe it is worth writing an Adaptor for this at some point.

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [February 19, 2025, 7:45am UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/6 "2025-02-19T07:45:48Z")

</div>

Yes, I see. I did not quite realize what a rabbit hole this can be. The Vcat or ranges is not itself an `AbstractRange` range but it supports most of the operations `get_index(), size, length, end` in a sensible way. In fact is is an `AbstractArray` which is probably a more suitable type, and, hey, it can be also used for indexing, if you wish. So this maybe the right way to go ahead here.

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [February 19, 2025, 1:32pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/7 "2025-02-19T13:32:54Z")

</div>

Yes this is certainly an AbstractArray.

Note that instead of concatenation, you can think of what `fftshift` does as a lazy `circshift`. The package [ShiftedArrays.jl](https://github.com/JuliaArrays/ShiftedArrays.jl) has wrappers for this, and it appears there was some attempt to make it work with CUDA.jl, see e.g. [this thread](https://discourse.julialang.org/t/efficient-cuarray-shift-rotation/86845). Although earlier discussion is about shifting an arbitrary vector, and there may be shortcuts possible if you only handle ranges.

---

<div class="post-metadata">

### Author: ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)
#### Post date: [February 19, 2025, 4:51pm UTC](https://discourse.julialang.org/t/concatenated-ranges/126042/8 "2025-02-19T16:51:44Z")

</div>

Indeed `ShiftedArrays.jl` has great wrappers, but still needs the arrays to exist in memory. The CUDA support would be somewhat helpful but you would still need a `ShiftedArray(CuArray))` as a type, whereas a `LazyArray.Vcat` of ranges could potentially directly interface with a CuArray, even though the ranges are not converted to a CuArray themselves. This would be nice.  
Anyway, now that you mentioned `ShiftedArrays.jl`, I am unsure how to proceed there. I am having difficulty to reach @piever, as we need to decide to either go ahead with the pull request I made years ago (and updated the other day to new CUDA.jl versions:

> <https://github.com/JuliaArrays/ShiftedArrays.jl/pull/67>
>
> This second attempt, uses a very light-weight implementation to add \`CuArray\` su…pport to \`ShiftedArrays.jl\`.
> It is based on using an Extension Package, such that \`ShiftedArrays\` does not drag in any extra packages, but if \`CUDA.jl\` is present, the adaptation is used.
> Note that the \`show()\` function was specified by CuArrays preventing errors via the \`@allowscalar\` macro.
> The tests were extended to CuArray usage, but this has to be enabled manually in the \`runtests.jl\` file.

Or release a new package (`MutableShiftedArrays.jl`) based on `ShiftedArrays.jl`. The latter could be an option, since it would be great to also support a mutable version of `ShiftedArray` (`CircShiftedArray` is anyway mutable).  
Any ideas how to proceed? (I guess this should be in a different thread now)
