# Reshaped views might alias

**URL:** https://discourse.julialang.org/t/reshaped-views-might-alias/121495
**Category:** Performance
**Created:** [October 19, 2024, 10:30pm UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495 "2024-10-19T22:30:49Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![lxvm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lxvm/32/50010_2.png) [@lxvm](https://discourse.julialang.org/u/lxvm)
#### Post date: [October 19, 2024, 10:30pm UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/1 "2024-10-19T22:30:49Z")

</div>

Hi,  
I have implemented a linear operator as a method of `LinearAlgebra.mul!(x, A, b)` to use with IterativeSolvers.jl, but when profiling my code I noticed a huge performance difference due to unaliasing arrays when testing my operator on its own versus in a GMRES call. I realized that this is because my `mul!` method reshapes `x` and `b` and then does broadcasting with them, which matters because in GMRES `x` and `b` are views of columns of the same array whereas in my testing I had allocated `x` and `b` in different arrays. So my problem is that may reshaped views of non-overlapping memory may alias, shown here:

```jl
N=3
a = rand(N*N,2)
a1 = view(a,:,1)
a2 = view(a,:,2)
Base.mightalias(a1, a2) # false

aa1 = reshape(a1, N, N)
aa2 = reshape(a2, N, N)
Base.mightalias(aa1, aa2) # true

```

So I would like to ask if there is any way to tell the broadcasting machinery that these reshaped views wouldn’t alias.

Thanks,  
Lorenzo

P.S. Since I want the most performance possible for my linear operator, I will replace my problematic broadcast expressions with hand-written loops that improve memory locality, but I am still curious if there is a possibility of a more precise `Base.mightalias` method that can improve the performance of my naive broadcast expressions.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 19, 2024, 10:55pm UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/2 "2024-10-19T22:55:07Z")

</div>

I might be wrong, but my intuition is that `AbstractArray` wrappers of non-aliasing arrays wouldn’t alias either, and `mightalias` just doesn’t know how to check.

```julia
julia> @which Base.mightalias(a1, a2)
mightalias(A::SubArray, B::SubArray)
     @ Base multidimensional.jl:1049

julia> @which Base.mightalias(aa1, aa2)
mightalias(A::AbstractArray, B::AbstractArray)
     @ Base abstractarray.jl:1537

julia> methods(Base.mightalias)
# 3 methods for generic function "mightalias" from Base:
 [1] mightalias(A::SubArray, B::SubArray)
     @ multidimensional.jl:1049
 [2] mightalias(A::AbstractArray, B::AbstractArray)
     @ abstractarray.jl:1537
 [3] mightalias(x, y)
     @ abstractarray.jl:1538

```

These are the fallbacks:

```julia
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
mightalias(x, y) = false

```

The `::Any` fallback assumes no aliasing, but we can ignore that danger because we’re dealing with `AbstractArray`s. The `AbstractArray` fallback guesses no aliasing if:

- either array `isbits`, so they have no references to share data
- either array `isempty`, so they have no data to share at the moment. Odd to me because that can change real fast: `a = []; println(Base.mightalias(a, a)); push!(a, 1); println(Base.mightalias(a, a))`
- the arrays don’t reference the same memory regions, as reported by `Base.dataids`

It’s the last check that fails in this example:

```julia
julia> Base.dataids.([a1, a2, aa1, aa2])
4-element Vector{Tuple{UInt64}}:
 (0x000001bc38322b70,)
 (0x000001bc38322b70,)
 (0x000001bc38322b70,)
 (0x000001bc38322b70,)

```

---

<div class="post-metadata">

### Author: ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)
#### Post date: [October 19, 2024, 10:59pm UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/3 "2024-10-19T22:59:29Z")

</div>

One possible workaround is to replace broadcast expressions with `map!`, which doesn’t check for aliasing. Schematically, replace

```julia
y .= f.(x)

```

with

```julia
map!(f, y, x)

```

This is less flexible in that it doesn’t expand singleton dimensions like broadcasting does, but if it fits your use case it can help you save on the explicit loops.

---

<div class="post-metadata">

### Author: ![lxvm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lxvm/32/50010_2.png) [@lxvm](https://discourse.julialang.org/u/lxvm)
#### Post date: [October 23, 2024, 3:24am UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/4 "2024-10-23T03:24:59Z")

</div>

Thank you for the replies!

I agree that the logic in the generic `mightalias` method doesn’t know how to unwrap the `ReshapedArray` wrapper to apply the method for `SubArray`. Perhaps the logic can be improved like this?

```julia
mightalias(A::AbstractArray, B::AbstractArray) = (parent(A) === A || A isa SubArray) && (parent(B) === B || B isa SubArray) ? !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B)) : mightalias(A isa SubArray ? A : parent(A), B isa SubArray ? B : parent(B))

```

My only second thoughts about this are that it seems difficult to extend to other methods. I haven’t tried doing this with multiple dispatch.

I like the suggestion for `map!` since that gives the right semantics, so I’ve marked it as a solution. In my case I ended up just writing loops as it gave clearer code and since it was better for memory locality since I was originally breaking up many 2x2 matrix multiplications into a broadcast expression.

---

<div class="post-metadata">

### Author: ![jsjie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jsjie/32/22477_2.png) [@jsjie](https://discourse.julialang.org/u/jsjie)
#### Post date: [October 23, 2024, 7:53am UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/5 "2024-10-23T07:53:02Z")

</div>

I’ve met a similar problem [before](https://discourse.julialang.org/t/overhead-of-view-reshape-transpose-in-linear-algebra/110761/4), and Elrod suggests that [FastBroadcast.jl](https://github.com/YingboMa/FastBroadcast.jl) don’t have aliasing checks. I didn’t actually test it, though.

---

<div class="post-metadata">

### Author: ![lxvm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lxvm/32/50010_2.png) [@lxvm](https://discourse.julialang.org/u/lxvm)
#### Post date: [October 23, 2024, 12:54pm UTC](https://discourse.julialang.org/t/reshaped-views-might-alias/121495/6 "2024-10-23T12:54:41Z")

</div>

Actually this was already solved in [Forward aliasing check for `ReshapedArray`s to the parent by jishnub · Pull Request #54168 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/54168)
