From c4ade2e9c7de909f74772289c9fb2442fdb12963 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Wed, 1 Jul 2026 16:53:43 +0200 Subject: [PATCH 1/7] Try running AMDGPU + MPSKit --- .buildkite/pipeline.yml | 28 ++++ test/Project.toml | 2 + test/gpu/amd/operators.jl | 269 ++++++++++++++++++++++++++++++++++++++ test/gpu/amd/roc_adapt.jl | 30 +++++ test/gpu/amd/states.jl | 92 +++++++++++++ test/gpu/cuda/states.jl | 3 +- test/runtests.jl | 7 + 7 files changed, 429 insertions(+), 2 deletions(-) create mode 100755 test/gpu/amd/operators.jl create mode 100755 test/gpu/amd/roc_adapt.jl create mode 100755 test/gpu/amd/states.jl diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 4424686e6..6c2dd8b81 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -29,3 +29,31 @@ steps: queue: "cuda" if: build.message !~ /\[skip tests\]/ timeout_in_minutes: 60 + + - label: "Julia v1 -- AMDGPU" + plugins: + - JuliaCI/julia#v1: + version: "1" + - JuliaCI/julia-test#v1: ~ + - JuliaCI/julia-coverage#v1: + dirs: + - src + - ext + agents: + queue: "rocm" + if: build.message !~ /\[skip tests\]/ + timeout_in_minutes: 60 + + - label: "Julia LTS -- AMDGPU" + plugins: + - JuliaCI/julia#v1: + version: "1.10" # "lts" isn't valid + - JuliaCI/julia-test#v1: ~ + - JuliaCI/julia-coverage#v1: + dirs: + - src + - ext + agents: + queue: "rocm" + if: build.message !~ /\[skip tests\]/ + timeout_in_minutes: 60 diff --git a/test/Project.toml b/test/Project.toml index b3c91b9ab..ea2afba0a 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -2,6 +2,7 @@ name = "MPSKitTests" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" @@ -24,6 +25,7 @@ cuTENSOR = "011b41b2-24ef-40a8-b3eb-fa098493e9e1" MPSKit = {path = ".."} [compat] +AMDGPU = "2" Aqua = "0.8.9" CUDA = "6" Combinatorics = "1" diff --git a/test/gpu/amd/operators.jl b/test/gpu/amd/operators.jl new file mode 100755 index 000000000..4e769c17a --- /dev/null +++ b/test/gpu/amd/operators.jl @@ -0,0 +1,269 @@ +using .TestSetup +using Test, TestExtras +using MPSKit +using MPSKit: GeometryStyle, FiniteChainStyle, InfiniteChainStyle, OperatorStyle, MPOStyle +using TensorKit +using MatrixAlgebraKit +using TensorKit: ℙ, tensormaptype, TensorMapWithStorage +using Adapt, AMDGPU + +@testset "CuFiniteMPO" for V in (ℂ^2, U1Space(0 => 1, 1 => 1)) + # start from random operators + L = 4 + T = ComplexF64 + + O₁ = rand(T, V^L, V^L) + O₂ = rand(T, space(O₁)) + O₃ = rand(real(T), space(O₁)) + + dO₁ = adapt(ROCArray, O₁) + dO₂ = adapt(ROCArray, O₂) + dO₃ = adapt(ROCArray, O₃) + + mpo₁ = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPO(O₁)) + mpo₂ = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPO(O₂)) + mpo₃ = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPO(O₃)) + + @test isfinite(mpo₁) + @test isfinite(typeof(mpo₁)) + @test GeometryStyle(typeof(mpo₁)) == FiniteChainStyle() + @test GeometryStyle(mpo₁) == FiniteChainStyle() + @test OperatorStyle(typeof(mpo₁)) == MPOStyle() + @test TensorKit.storagetype(mpo₁) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₂) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₃) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + + @test @constinferred physicalspace(mpo₁) == fill(V, L) + Vleft = @constinferred left_virtualspace(mpo₁) + Vright = @constinferred right_virtualspace(mpo₂) + for i in 1:L + @test Vleft[i] == left_virtualspace(mpo₁, i) + @test Vright[i] == right_virtualspace(mpo₁, i) + end + + TM = TensorMap + @test convert(TM, mpo₁) ≈ dO₁ + @test convert(TM, -mpo₂) ≈ -dO₂ + @test convert(TM, @constinferred complex(mpo₃)) ≈ complex(dO₃) + + # test scalar multiplication + α = rand(T) + @test convert(TM, α * mpo₁) ≈ α * dO₁ + @test convert(TM, mpo₁ * α) ≈ dO₁ * α + @test α * mpo₃ ≈ α * complex(mpo₃) atol = 1.0e-6 + + # test addition and multiplication + @test convert(TM, mpo₁ + mpo₂) ≈ dO₁ + dO₂ + @test convert(TM, mpo₁ + mpo₃) ≈ dO₁ + dO₃ + @test convert(TM, mpo₁ * mpo₂) ≈ dO₁ * dO₂ + @test convert(TM, mpo₁ * mpo₃) ≈ dO₁ * dO₃ + + # test application to a state + ψ₁ = adapt(ROCArray, rand(T, domain(O₁))) + ψ₂ = adapt(ROCArray, rand(real(T), domain(O₂))) + mps₁ = adapt(ROCArray, FiniteMPS(ψ₁)) + mps₂ = adapt(ROCArray, FiniteMPS(ψ₂)) + + @test @constinferred GeometryStyle(mps₁, mpo₁, mps₁) == GeometryStyle(mps₁) + + @test convert(TM, mpo₁ * mps₁) ≈ dO₁ * ψ₁ + @test mpo₁ * ψ₁ ≈ dO₁ * ψ₁ + @test convert(TM, mpo₃ * mps₁) ≈ dO₃ * ψ₁ + @test mpo₃ * ψ₁ ≈ dO₃ * ψ₁ + @test convert(TM, mpo₁ * mps₂) ≈ dO₁ * ψ₂ + @test mpo₁ * ψ₂ ≈ dO₁ * ψ₂ + + @test dot(mps₁, mpo₁, mps₁) ≈ dot(ψ₁, dO₁, ψ₁) + @test dot(mps₁, mpo₁, mps₁) ≈ dot(mps₁, mpo₁ * mps₁) + # test conversion to and from mps + mpomps₁ = convert(FiniteMPS, mpo₁) + mpompsmpo₁ = convert(FiniteMPO, mpomps₁) + + @test convert(FiniteMPO, mpomps₁) ≈ mpo₁ rtol = 1.0e-6 + + @test dot(mpomps₁, mpomps₁) ≈ dot(mpo₁, mpo₁) +end + +@testset "Finite CuMPOHamiltonian T ($T), V ($(spacetype(V)))" for T in (Float64, ComplexF64), V in (ℂ^2, U1Space(-1 => 1, 0 => 1, 1 => 1)) + L = 3 + lattice = fill(V, L) + O₁ = project_hermitian!(randn(T, V ← V)) + E = id(ROCVector{T, AMDGPU.Mem.HIPBuffer}, domain(O₁)) + O₂ = project_hermitian!(randn(T, V^2 ← V^2)) + + dO₁ = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, O₁) + dO₂ = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, O₂) + hH1 = FiniteMPOHamiltonian(lattice, i => O₁ for i in 1:L) + hH2 = FiniteMPOHamiltonian(lattice, (i, i + 1) => O₂ for i in 1:(L - 1)) + hH3 = FiniteMPOHamiltonian(lattice, 1 => O₁, (2, 3) => O₂, (1, 3) => O₂) + H1 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, hH1) + H2 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, hH2) + H3 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, hH3) + @test TensorKit.storagetype(H1) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(H2) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(H3) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + + @test scalartype(H1) == scalartype(H2) == scalartype(H3) == T + if !(T <: Complex) + for H in (H1, H2, H3) + Hc = @constinferred complex(H) + @test scalartype(Hc) == complex(T) + @test TensorKit.storagetype(Hc) == ROCVector{complex(T), AMDGPU.Mem.HIPBuffer} + end + end + + # check if constructor works by converting back to tensormap + hH1_tm = convert(TensorMap, hH1) + H1_tm = convert(TensorMap, H1) + @test TensorKit.storagetype(H1_tm) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + operators = vcat(fill(E, L - 1), dO₁) + @test H1_tm ≈ mapreduce(+, 1:L) do i + return reduce(⊗, circshift(operators, i)) + end + operators = vcat(fill(E, L - 2), dO₂) + @test convert(TensorMap, H2) ≈ mapreduce(+, 1:(L - 1)) do i + return reduce(⊗, circshift(operators, i)) + end + @test convert(TensorMap, H3) ≈ + dO₁ ⊗ E ⊗ E + E ⊗ dO₂ + permute(dO₂ ⊗ E, ((1, 3, 2), (4, 6, 5))) + + # check if adding terms on the same site works + single_terms = Iterators.flatten(Iterators.repeated((i => O₁ / 2 for i in 1:L), 2)) + H4 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(lattice, single_terms)) + @test TensorKit.storagetype(H4) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test H4 ≈ H1 atol = 1.0e-6 + double_terms = Iterators.flatten( + Iterators.repeated(((i, i + 1) => O₂ / 2 for i in 1:(L - 1)), 2) + ) + H5 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(lattice, double_terms)) + @test TensorKit.storagetype(H5) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test H5 ≈ H2 atol = 1.0e-6 + + # test linear algebra + @test H1 ≈ + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(lattice, 1 => O₁)) + + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(lattice, 2 => O₁)) + + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(lattice, 3 => O₁)) + @test TensorKit.storagetype(H1) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + + H1′a = 0.8 * H1 + @test TensorKit.storagetype(H1′a) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + H1′b = 0.2 * H1 + @test TensorKit.storagetype(H1′b) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + H1′ = H1′a + H1′b + @test TensorKit.storagetype(H1′) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test H1′ ≈ H1 atol = 1.0e-6 + @test convert(TensorMap, H1 + H2) ≈ convert(TensorMap, H1) + convert(TensorMap, H2) atol = 1.0e-6 + H1_trunc = changebonds(H1, SvdCut(; trscheme = truncrank(0))) + @test H1_trunc ≈ H1 + @test all(left_virtualspace(H1_trunc) .== left_virtualspace(H1)) + # test dot and application + hstate = rand(T, prod(lattice)) + state = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, hstate) + @test TensorKit.storagetype(state) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + hmps = FiniteMPS(hstate) + mps = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, hmps) + @test TensorKit.storagetype(mps) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test norm(mps) ≈ norm(state) + @test norm(H1) ≈ norm(H1_tm) + + @test TensorKit.storagetype(H1) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + hH1mps = hH1 * hmps + H1mps = H1 * mps + @test TensorKit.storagetype(H1mps) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + hH1tmstate = hH1_tm * hstate + H1tmstate = H1_tm * state + @test TensorKit.storagetype(H1tmstate) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test norm(H1mps) ≈ norm(H1tmstate) + + H1mpstm = convert(TensorMap, H1mps) + @test TensorKit.storagetype(H1mpstm) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test H1mpstm ≈ H1tmstate + @test H1 * state ≈ H1tmstate + + H2mps = H2 * mps + hH2mps = hH2 * hmps + @test TensorKit.storagetype(H2mps) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test dot(mps, H2, mps) ≈ dot(mps, H2mps) + @test dot(hmps, hH2mps) ≈ dot(mps, H2mps) + @test dot(mps, H2, mps) ≈ dot(hmps, hH2mps) + # test constructor from dictionary with mixed linear and Cartesian lattice indices as keys + grid = square = fill(V, 3, 3) + + local_operators = Dict((I,) => O₁ for I in eachindex(grid)) + I_vertical = CartesianIndex(1, 0) + vertical_operators = Dict( + (I, I + I_vertical) => O₂ for I in eachindex(IndexCartesian(), square) if I[1] < size(square, 1) + ) + I_horizontal = CartesianIndex(0, 1) + horizontal_operators = Dict( + (I, I + I_horizontal) => O₂ for I in eachindex(IndexCartesian(), square) if I[2] < size(square, 1) + ) + operators = merge(local_operators, vertical_operators, horizontal_operators) + H4 = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(grid, operators)) + @test TensorKit.storagetype(H4) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + + @test H4 ≈ + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(grid, local_operators)) + + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(grid, vertical_operators)) + + adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPOHamiltonian(grid, horizontal_operators)) atol = 1.0e-4 + @test TensorKit.storagetype(H4) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + + H4′ = H4 / 3 + 2H4 / 3 + @test TensorKit.storagetype(H4′) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + H5 = changebonds(H4′, SvdCut(; trscheme = trunctol(; atol = 1.0e-12))) + @test TensorKit.storagetype(H5) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + psi = adapt(ROCVector{real(T), AMDGPU.Mem.HIPBuffer}, FiniteMPS(real(T), physicalspace(H5), V ⊕ rightunitspace(V))) + @test expectation_value(psi, H4) ≈ expectation_value(psi, H5) +end + +pspaces = (ℙ^4, Rep[U₁](0 => 2), Rep[SU₂](1 => 1)) +vspaces = (ℙ^10, Rep[U₁]((0 => 20)), Rep[SU₂](1 // 2 => 10, 3 // 2 => 5, 5 // 2 => 1)) + +@testset "CuInfiniteMPOHamiltonian $(sectortype(pspace))" for (pspace, Dspace) in zip(pspaces, vspaces) + # generate a 1-2-3 body interaction + operators = ntuple(3) do i + O = rand(ComplexF64, pspace^i, pspace^i) + return O += O' + end + + H1 = adapt(ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer}, InfiniteMPOHamiltonian(operators[1])) + H2 = adapt(ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer}, InfiniteMPOHamiltonian(operators[2])) + H3 = adapt(ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer}, repeat(InfiniteMPOHamiltonian(operators[3]), 2)) + + @test TensorKit.storagetype(H1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(H2) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(H3) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + # make a teststate to measure expectation values for + ψ1 = adapt(ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer}, InfiniteMPS([pspace], [Dspace])) + ψ2 = adapt(ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer}, InfiniteMPS([pspace, pspace], [Dspace, Dspace])) + @test TensorKit.storagetype(ψ1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(ψ2) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + + e1 = expectation_value(ψ1, H1) + e2 = expectation_value(ψ1, H2) + + H1 = 2 * H1 + @test TensorKit.storagetype(H1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + H1 -= [1] + @test TensorKit.storagetype(H1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test e1 * 2 - 1 ≈ expectation_value(ψ1, H1) atol = 1.0e-10 + + H1 = H1 + H2 + @test TensorKit.storagetype(H1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test e1 * 2 + e2 - 1 ≈ expectation_value(ψ1, H1) atol = 1.0e-10 + + H1 = repeat(H1, 2) + @test TensorKit.storagetype(H1) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + + e1 = expectation_value(ψ2, H1) + e3 = expectation_value(ψ2, H3) + + @test e1 + e3 ≈ expectation_value(ψ2, H1 + H3) atol = 1.0e-10 + + H4 = H1 + H3 + @test TensorKit.storagetype(H4) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + h4 = H4 * H4 + @test TensorKit.storagetype(h4) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test real(expectation_value(ψ2, H4)) >= 0 +end diff --git a/test/gpu/amd/roc_adapt.jl b/test/gpu/amd/roc_adapt.jl new file mode 100755 index 000000000..774e1e4ab --- /dev/null +++ b/test/gpu/amd/roc_adapt.jl @@ -0,0 +1,30 @@ +using Test +using MPSKit +using TensorKit +using AMDGPU, Adapt + +@testset "Adapting to CuArray" begin + # start from random operators + L = 4 + T = ComplexF64 + + for V in (ℂ^2, U1Space(0 => 1, 1 => 1)) + O₁ = rand(T, V^L, V^L) + O₂ = rand(T, space(O₁)) + O₃ = rand(real(T), space(O₁)) + + # create MPO and convert it back to see if it is the same + mpo₁ = adapt(ROCArray, FiniteMPO(O₁)) + mpo₂ = adapt(ROCArray, FiniteMPO(O₂)) + mpo₃ = adapt(ROCArray, FiniteMPO(O₃)) + + @test isfinite(mpo₁) + @test isfinite(typeof(mpo₁)) + @test MPSKit.GeometryStyle(typeof(mpo₁)) == MPSKit.FiniteChainStyle() + @test MPSKit.GeometryStyle(mpo₁) == MPSKit.FiniteChainStyle() + @test MPSKit.OperatorStyle(typeof(mpo₁)) == MPSKit.MPOStyle() + @test TensorKit.storagetype(mpo₁) == ROCVector{T, AMD.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₂) == ROCVector{T, AMD.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₃) == ROCVector{real(T), AMD.Mem.HIPBuffer} + end +end diff --git a/test/gpu/amd/states.jl b/test/gpu/amd/states.jl new file mode 100755 index 000000000..c3112fefb --- /dev/null +++ b/test/gpu/amd/states.jl @@ -0,0 +1,92 @@ +using MPSKit +using MPSKit: _transpose_front, _transpose_tail +using MPSKit: GeometryStyle, InfiniteChainStyle, TransferMatrix +using TensorKit +using TensorKit: ℙ +using Adapt, AMDGPU + +@testset "CuMPS ($(sectortype(D)), $elt)" for (D, d, elt) in + [(ℙ^10, ℙ^2, ComplexF64), (Rep[U₁](1 => 3), Rep[U₁](0 => 1), ComplexF64)] + tol = Float64(eps(real(elt)) * 100) + + ψ = adapt(ROCArray, InfiniteMPS([rand(elt, D * d, D), rand(elt, D * d, D)]; tol)) + @test TensorKit.storagetype(ψ) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test eltype(ψ) == eltype(typeof(ψ)) + + for i in 1:length(ψ) + @plansor difference[-1 -2; -3] := ψ.AL[i][-1 -2; 1] * ψ.C[i][1; -3] - + ψ.C[i - 1][-1; 1] * ψ.AR[i][1 -2; -3] + @test norm(difference, Inf) < tol * 10 + + @test l_LL(ψ, i) * TransferMatrix(ψ.AL[i], ψ.AL[i]) ≈ l_LL(ψ, i + 1) + @test l_LR(ψ, i) * TransferMatrix(ψ.AL[i], ψ.AR[i]) ≈ l_LR(ψ, i + 1) + @test l_RL(ψ, i) * TransferMatrix(ψ.AR[i], ψ.AL[i]) ≈ l_RL(ψ, i + 1) + @test l_RR(ψ, i) * TransferMatrix(ψ.AR[i], ψ.AR[i]) ≈ l_RR(ψ, i + 1) + + @test TransferMatrix(ψ.AL[i], ψ.AL[i]) * r_LL(ψ, i) ≈ r_LL(ψ, i + 1) + @test TransferMatrix(ψ.AL[i], ψ.AR[i]) * r_LR(ψ, i) ≈ r_LR(ψ, i + 1) + @test TransferMatrix(ψ.AR[i], ψ.AL[i]) * r_RL(ψ, i) ≈ r_RL(ψ, i + 1) + @test TransferMatrix(ψ.AR[i], ψ.AR[i]) * r_RR(ψ, i) ≈ r_RR(ψ, i + 1) + end + + L = rand(3:20) + ψ = adapt(ROCArray, FiniteMPS(rand, elt, L, d, D)) + @test TensorKit.storagetype(ψ) == ROCVector{ComplexF64, AMDGPU.Mem.HIPBuffer} + @test eltype(ψ) == eltype(typeof(ψ)) + ovl = dot(ψ, ψ) + + @test ovl ≈ norm(ψ.AC[1])^2 + + for i in 1:length(ψ) + @test ψ.AC[i] ≈ ψ.AL[i] * ψ.C[i] + @test ψ.AC[i] ≈ _transpose_front(ψ.C[i - 1] * _transpose_tail(ψ.AR[i])) + end + + @test ComplexF64 == scalartype(ψ) + ψ = ψ * 3 + @test ovl * 9 ≈ norm(ψ)^2 + ψ = 3 * ψ + @test ovl * 9 * 9 ≈ norm(ψ)^2 + + @test norm(2 * ψ + ψ - 3 * ψ) ≈ 0.0 atol = sqrt(eps(real(ComplexF64))) +end + +@testset "CuMultilineMPS ($(sectortype(D)), $elt)" for (D, d, elt) in + [(ℙ^10, ℙ^2, ComplexF64), (Rep[U₁](1 => 3), Rep[U₁](0 => 1), ComplexF32)] + tol = Float64(eps(real(elt)) * 100) + ψ = adapt( + ROCVector{elt, AMDGPU.Mem.HIPBuffer}, MultilineMPS( + [ + rand(elt, D * d, D) rand(elt, D * d, D) + rand(elt, D * d, D) rand(elt, D * d, D) + ]; tol + ) + ) + + @test GeometryStyle(typeof(ψ)) == InfiniteChainStyle() + @test GeometryStyle(ψ) == InfiniteChainStyle() + @test TensorKit.storagetype(ψ) == ROCVector{elt, AMDGPU.Mem.HIPBuffer} + @test TensorKit.sectortype(ψ) == sectortype(D) + + @test !isfinite(typeof(ψ)) + + @test physicalspace(ψ) == fill(d, 2, 2) + @test all(x -> x ≾ D, left_virtualspace(ψ)) + @test all(x -> x ≾ D, right_virtualspace(ψ)) + + for i in 1:size(ψ, 1), j in 1:size(ψ, 2) + @plansor difference[-1 -2; -3] := ψ.AL[i, j][-1 -2; 1] * ψ.C[i, j][1; -3] - + ψ.C[i, j - 1][-1; 1] * ψ.AR[i, j][1 -2; -3] + @test norm(difference, Inf) < tol * 10 + + @test l_LL(ψ, i, j) * TransferMatrix(ψ.AL[i, j], ψ.AL[i, j]) ≈ l_LL(ψ, i, j + 1) + @test l_LR(ψ, i, j) * TransferMatrix(ψ.AL[i, j], ψ.AR[i, j]) ≈ l_LR(ψ, i, j + 1) + @test l_RL(ψ, i, j) * TransferMatrix(ψ.AR[i, j], ψ.AL[i, j]) ≈ l_RL(ψ, i, j + 1) + @test l_RR(ψ, i, j) * TransferMatrix(ψ.AR[i, j], ψ.AR[i, j]) ≈ l_RR(ψ, i, j + 1) + + @test TransferMatrix(ψ.AL[i, j], ψ.AL[i, j]) * r_LL(ψ, i, j) ≈ r_LL(ψ, i, j + 1) + @test TransferMatrix(ψ.AL[i, j], ψ.AR[i, j]) * r_LR(ψ, i, j) ≈ r_LR(ψ, i, j + 1) + @test TransferMatrix(ψ.AR[i, j], ψ.AL[i, j]) * r_RL(ψ, i, j) ≈ r_RL(ψ, i, j + 1) + @test TransferMatrix(ψ.AR[i, j], ψ.AR[i, j]) * r_RR(ψ, i, j) ≈ r_RR(ψ, i, j + 1) + end +end diff --git a/test/gpu/cuda/states.jl b/test/gpu/cuda/states.jl index a37712209..7c036ea09 100644 --- a/test/gpu/cuda/states.jl +++ b/test/gpu/cuda/states.jl @@ -4,7 +4,7 @@ using MPSKit: GeometryStyle, InfiniteChainStyle, TransferMatrix using TensorKit using TensorKit: ℙ using Adapt, CUDA, cuTENSOR -#= + @testset "CuMPS ($(sectortype(D)), $elt)" for (D, d, elt) in [(ℙ^10, ℙ^2, ComplexF64), (Rep[U₁](1 => 3), Rep[U₁](0 => 1), ComplexF64)] tol = Float64(eps(real(elt)) * 100) @@ -90,4 +90,3 @@ end @test TransferMatrix(ψ.AR[i, j], ψ.AR[i, j]) * r_RR(ψ, i, j) ≈ r_RR(ψ, i, j + 1) end end -=# diff --git a/test/runtests.jl b/test/runtests.jl index b2b237cb7..64e3e6509 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -19,6 +19,13 @@ using CUDA, cuTENSOR (CUDA.functional() && cuTENSOR.functional()) || filter!(!(startswith("gpu/cuda") ∘ first), testsuite) +# only run AMDGPU if available +using AMDGPU + +AMDGPU.functional() || + filter!(!(startswith("gpu/amd") ∘ first), testsuite) + + # parse arguments args = parse_args(ARGS; custom = ["fast"]) fast = !isnothing(args.custom["fast"]) From d8535b739ba02bd259a1e327f01026319e9c23e6 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Wed, 1 Jul 2026 20:02:09 +0200 Subject: [PATCH 2/7] Update test/gpu/amd/operators.jl Co-authored-by: Lukas Devos --- test/gpu/amd/operators.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gpu/amd/operators.jl b/test/gpu/amd/operators.jl index 4e769c17a..41147a091 100755 --- a/test/gpu/amd/operators.jl +++ b/test/gpu/amd/operators.jl @@ -7,7 +7,7 @@ using MatrixAlgebraKit using TensorKit: ℙ, tensormaptype, TensorMapWithStorage using Adapt, AMDGPU -@testset "CuFiniteMPO" for V in (ℂ^2, U1Space(0 => 1, 1 => 1)) +@testset "ROCFiniteMPO" for V in (ℂ^2, U1Space(0 => 1, 1 => 1)) # start from random operators L = 4 T = ComplexF64 From ca52ac381c4e4e67d92239f0a7ea2f08141f9b6c Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Thu, 2 Jul 2026 10:18:51 -0400 Subject: [PATCH 3/7] Fix memory type in ROC adapt tests --- test/gpu/amd/roc_adapt.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/gpu/amd/roc_adapt.jl b/test/gpu/amd/roc_adapt.jl index 774e1e4ab..ea7f0d21b 100755 --- a/test/gpu/amd/roc_adapt.jl +++ b/test/gpu/amd/roc_adapt.jl @@ -23,8 +23,8 @@ using AMDGPU, Adapt @test MPSKit.GeometryStyle(typeof(mpo₁)) == MPSKit.FiniteChainStyle() @test MPSKit.GeometryStyle(mpo₁) == MPSKit.FiniteChainStyle() @test MPSKit.OperatorStyle(typeof(mpo₁)) == MPSKit.MPOStyle() - @test TensorKit.storagetype(mpo₁) == ROCVector{T, AMD.Mem.HIPBuffer} - @test TensorKit.storagetype(mpo₂) == ROCVector{T, AMD.Mem.HIPBuffer} - @test TensorKit.storagetype(mpo₃) == ROCVector{real(T), AMD.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₁) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₂) == ROCVector{T, AMDGPU.Mem.HIPBuffer} + @test TensorKit.storagetype(mpo₃) == ROCVector{real(T), AMDGPU.Mem.HIPBuffer} end end From f2d154f9ac927dc036c6e58b3c4b03d05e921749 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Mon, 6 Jul 2026 09:20:54 -0400 Subject: [PATCH 4/7] Fix testset names --- test/gpu/amd/operators.jl | 4 ++-- test/gpu/amd/roc_adapt.jl | 2 +- test/gpu/amd/states.jl | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/gpu/amd/operators.jl b/test/gpu/amd/operators.jl index 41147a091..614e600ce 100755 --- a/test/gpu/amd/operators.jl +++ b/test/gpu/amd/operators.jl @@ -84,7 +84,7 @@ using Adapt, AMDGPU @test dot(mpomps₁, mpomps₁) ≈ dot(mpo₁, mpo₁) end -@testset "Finite CuMPOHamiltonian T ($T), V ($(spacetype(V)))" for T in (Float64, ComplexF64), V in (ℂ^2, U1Space(-1 => 1, 0 => 1, 1 => 1)) +@testset "Finite ROCMPOHamiltonian T ($T), V ($(spacetype(V)))" for T in (Float64, ComplexF64), V in (ℂ^2, U1Space(-1 => 1, 0 => 1, 1 => 1)) L = 3 lattice = fill(V, L) O₁ = project_hermitian!(randn(T, V ← V)) @@ -220,7 +220,7 @@ end pspaces = (ℙ^4, Rep[U₁](0 => 2), Rep[SU₂](1 => 1)) vspaces = (ℙ^10, Rep[U₁]((0 => 20)), Rep[SU₂](1 // 2 => 10, 3 // 2 => 5, 5 // 2 => 1)) -@testset "CuInfiniteMPOHamiltonian $(sectortype(pspace))" for (pspace, Dspace) in zip(pspaces, vspaces) +@testset "ROCInfiniteMPOHamiltonian $(sectortype(pspace))" for (pspace, Dspace) in zip(pspaces, vspaces) # generate a 1-2-3 body interaction operators = ntuple(3) do i O = rand(ComplexF64, pspace^i, pspace^i) diff --git a/test/gpu/amd/roc_adapt.jl b/test/gpu/amd/roc_adapt.jl index ea7f0d21b..e7fbc39ea 100755 --- a/test/gpu/amd/roc_adapt.jl +++ b/test/gpu/amd/roc_adapt.jl @@ -3,7 +3,7 @@ using MPSKit using TensorKit using AMDGPU, Adapt -@testset "Adapting to CuArray" begin +@testset "Adapting to ROCArray" begin # start from random operators L = 4 T = ComplexF64 diff --git a/test/gpu/amd/states.jl b/test/gpu/amd/states.jl index c3112fefb..bd422fbde 100755 --- a/test/gpu/amd/states.jl +++ b/test/gpu/amd/states.jl @@ -5,7 +5,7 @@ using TensorKit using TensorKit: ℙ using Adapt, AMDGPU -@testset "CuMPS ($(sectortype(D)), $elt)" for (D, d, elt) in +@testset "ROCMPS ($(sectortype(D)), $elt)" for (D, d, elt) in [(ℙ^10, ℙ^2, ComplexF64), (Rep[U₁](1 => 3), Rep[U₁](0 => 1), ComplexF64)] tol = Float64(eps(real(elt)) * 100) @@ -51,7 +51,7 @@ using Adapt, AMDGPU @test norm(2 * ψ + ψ - 3 * ψ) ≈ 0.0 atol = sqrt(eps(real(ComplexF64))) end -@testset "CuMultilineMPS ($(sectortype(D)), $elt)" for (D, d, elt) in +@testset "ROCMultilineMPS ($(sectortype(D)), $elt)" for (D, d, elt) in [(ℙ^10, ℙ^2, ComplexF64), (Rep[U₁](1 => 3), Rep[U₁](0 => 1), ComplexF32)] tol = Float64(eps(real(elt)) * 100) ψ = adapt( From 36bdad20100b847d8dcadc9cf5e6ecb344531131 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Mon, 6 Jul 2026 12:03:49 -0400 Subject: [PATCH 5/7] Try with sources for 1.12 --- Project.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Project.toml b/Project.toml index d985065a9..052ef1953 100644 --- a/Project.toml +++ b/Project.toml @@ -30,6 +30,9 @@ VectorInterface = "409d34a3-91d5-4945-b6ec-7529ddf182d8" [weakdeps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +[sources] +TensorKit = {url = "https://github.com/QuantumKitHub/TensorKit.jl", rev = "main"} + [extensions] MPSKitAdaptExt = "Adapt" From 9635d00df36bbb08265eedf9ab09055f57ea4399 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Thu, 9 Jul 2026 11:17:37 +0200 Subject: [PATCH 6/7] Increase AMD timeouts --- .buildkite/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 6c2dd8b81..ecabd3e0a 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -42,7 +42,7 @@ steps: agents: queue: "rocm" if: build.message !~ /\[skip tests\]/ - timeout_in_minutes: 60 + timeout_in_minutes: 90 - label: "Julia LTS -- AMDGPU" plugins: @@ -56,4 +56,4 @@ steps: agents: queue: "rocm" if: build.message !~ /\[skip tests\]/ - timeout_in_minutes: 60 + timeout_in_minutes: 90 From 3b6414f552bdd72c532c41b0e5241cd0798ebca3 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Thu, 9 Jul 2026 12:07:42 +0200 Subject: [PATCH 7/7] Don't force real --- test/gpu/amd/operators.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gpu/amd/operators.jl b/test/gpu/amd/operators.jl index 614e600ce..8a17f07b5 100755 --- a/test/gpu/amd/operators.jl +++ b/test/gpu/amd/operators.jl @@ -213,7 +213,7 @@ end @test TensorKit.storagetype(H4′) == ROCVector{T, AMDGPU.Mem.HIPBuffer} H5 = changebonds(H4′, SvdCut(; trscheme = trunctol(; atol = 1.0e-12))) @test TensorKit.storagetype(H5) == ROCVector{T, AMDGPU.Mem.HIPBuffer} - psi = adapt(ROCVector{real(T), AMDGPU.Mem.HIPBuffer}, FiniteMPS(real(T), physicalspace(H5), V ⊕ rightunitspace(V))) + psi = adapt(ROCVector{T, AMDGPU.Mem.HIPBuffer}, FiniteMPS(T, physicalspace(H5), V ⊕ rightunitspace(V))) @test expectation_value(psi, H4) ≈ expectation_value(psi, H5) end