# CUDA atomics on complex-valued arrays

**URL:** <https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054>\
**Category:** GPU\
**Tags:** cuda\
**Created:** [April 11, 2021, 7:42pm UTC](https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054 "2021-04-11T19:42:45Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![weylspinor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weylspinor/32/23897_2.png) [@weylspinor](https://discourse.julialang.org/u/weylspinor)\
**Post date:** [April 11, 2021, 7:42pm UTC](https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054/1 "2021-04-11T19:42:45Z")

</div>

Hi,

I am curious if there is an way to do atomic operations on complex-valued arrays in `CUDA` kernel, e.g.

```julia
using CUDA

function kernel!(x::CuDeviceArray{T}, y::CuDeviceArray{T}) where T
    i = (blockIdx().x-1)*blockDim().x + threadIdx().x
    if i <= length(x)
        CUDA.atomic_add!(pointer(x, i), y[i])
    end
    return nothing
end

function test(T)
    x = CuArray(rand(T, 2, 2))
    y = CuArray(rand(T, 2, 2))

    threads = 100
    blocks = cld(length(x), threads)
    @cuda threads=threads blocks=blocks kernel!(x,y)
end

```

will work if I run `test(Float32)` but not if `test(ComplexF32)`. I know this is because the atomics do not support the complex numbers. I can certainly divide a complex atomic operation with two atomics (one on real part and the other on imaginary part). But then, for example, I do not know how to pass the pointer to the real part of the i-th element of `x`: `x[i].re`.

In C++, I am able to do this by simply using `atomicAdd(&x[i].x, y[i].x)`. However, I found that in Julia `CUDA`, both the assignment to `x[i].re` and taking pointer of it is troublesome (I met errors regarding `setindex!`).

One may suggest using a shared memory to accumulate the summation first, but in my real code, the order of access to `y` is not simple, so the use of shared memory is not straightforward.

I would like to ask if what I want to do is actually impossible, or there is a method to tackle this.  
Thanks.

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [April 12, 2021, 11:52am UTC](https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054/2 "2021-04-12T11:52:04Z")

</div>

You could try `reinterpret` to create a real array from the complex one and index the real and imaginary part directly? Also, you can use `@atomic x[i] += y[i]` instead of the manual calls to `atomic_add!` to get rid of the call to `pointer`.

---

<div class="post-metadata">

**Author:** ![weylspinor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weylspinor/32/23897_2.png) [@weylspinor](https://discourse.julialang.org/u/weylspinor)\
**Post date:** [April 12, 2021, 2:47pm UTC](https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054/3 "2021-04-12T14:47:27Z")

</div>

Thank you! One last question: does `@atomic` have any actual performance advantage over `atomic_op(pointer(...))`?

For those who want to use `reinterpret`, I write an example code here:

```julia
using CUDA

function kernel!(x, y)
    i = (blockIdx().x-1)*blockDim().x + threadIdx().x
    if i <= length(x) && i % 2 == 1
        for j = 1:2:i
            CUDA.atomic_add!(pointer(y,i), x[j])
        end
    end
    return nothing
end

function test()
    x = CuArray(ones(ComplexF32, 10))
    y = CuArray(zeros(ComplexF32, 10))

    x_ = reinterpret(Float32, x)
    y_ = reinterpret(Float32, y)
    threads = 100
    blocks = cld(length(x), threads)
    @cuda threads=threads blocks=blocks kernel!(x_, y_)
    
    println(y) # will print [1.0+0.0im, 2.0+0.0im, ..., 10.0+0.0im]
end

```

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [April 12, 2021, 2:52pm UTC](https://discourse.julialang.org/t/cuda-atomics-on-complex-valued-arrays/59054/4 "2021-04-12T14:52:57Z")

</div>

`CUDA.@atomic` just lowers down to `atomic_xxx!`, but does the array referencing for you.
