QuantumBFS / Yao.jl

Extensible, Efficient Quantum Algorithm Design for Humans.

Home Page:https://yaoquantum.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can't calculate `von_neumann_entropy()` in gpu

zipeilee opened this issue · comments

When calculating the von_neumann_entropy() of a certain quantum state on the GPU, I often receive CUDA errors like

ERROR: ArgumentError: cannot take the CPU address of a CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}
Stacktrace:
 [1] unsafe_convert(#unused#::Type{Ptr{Float32}}, x::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
   @ CUDA ~/.julia/packages/CUDA/pCcGc/src/array.jl:370
 [2] geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
   @ LinearAlgebra.LAPACK ~/packages/julias/julia-1.9/share/julia/stdlib/v1.9/LinearAlgebra/src/lapack.jl:2093
 [3] eigvals!(A::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}; permute::Bool, scale::Bool, sortby::typeof(LinearAlgebra.eigsortby))
   @ LinearAlgebra ~/packages/julias/julia-1.9/share/julia/stdlib/v1.9/LinearAlgebra/src/eigen.jl:306
 [4] eigvals!(A::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
   @ LinearAlgebra ~/packages/julias/julia-1.9/share/julia/stdlib/v1.9/LinearAlgebra/src/eigen.jl:304
 [5] eigvals(A::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}; kws::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ LinearAlgebra ~/packages/julias/julia-1.9/share/julia/stdlib/v1.9/LinearAlgebra/src/eigen.jl:339
 [6] eigvals(A::CuArray{Float32, 2, CUDA.Mem.DeviceBuffer})
   @ LinearAlgebra ~/packages/julias/julia-1.9/share/julia/stdlib/v1.9/LinearAlgebra/src/eigen.jl:339

Then I remind that function von_neumann_entropy() have a operattion p = max.(eigvals(dm), eps(real(eltype(dm)))) but it seems eigvals() operation have not been implemented in CUDA.jl.

I wander if there is any way to improve this operation in Yao.jl so that it can run successfully on the GPU, or alternatively, to only load the quantum state onto the CPU when calculating the entropy?

I have tried change the
p = max.(eigvals(dm), eps(real(eltype(dm))))
to

 _, l = eigen(dm)
p = max.(l, eps(real(eltype(dm))))

but due to computational precision, the density matrix is not a Hermitian matrix and LinearAlgebra.eigen() only seems to work for symmetric/hermitian inputs.