Skip to content

Commit 2b97ab2

Browse files
kshyattmaleadt
andauthored
Update to cuQuantum 23.10 (#2210)
Co-authored-by: Tim Besard <tim.besard@gmail.com>
1 parent 7d74f90 commit 2b97ab2

File tree

12 files changed

+1115
-48
lines changed

12 files changed

+1115
-48
lines changed

.buildkite/pipeline.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,12 @@ steps:
106106
setup:
107107
cuda:
108108
- "11.4"
109+
- "12.0"
109110
package:
110111
- "cuDNN"
111112
- "cuTENSOR"
112113
- "cuStateVec"
113114
- "cuTensorNet"
114-
adjustments:
115-
- with:
116-
cuda: "12.0"
117-
package: "cuDNN"
118-
- with:
119-
cuda: "12.0"
120-
package: "cuTENSOR"
121115
plugins:
122116
- JuliaCI/julia#v1:
123117
version: "1.9"

lib/custatevec/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ cuQuantum_jll = "b75408ef-6fdf-5d74-b65a-7df000ad18e6"
1313
CEnum = "0.2, 0.3, 0.4"
1414
CUDA = "~5.1"
1515
CUDA_Runtime_Discovery = "0.2"
16-
cuQuantum_jll = "~23.6"
16+
cuQuantum_jll = "~23.10"
1717
julia = "1.6"

lib/custatevec/src/cuStateVec.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module cuStateVec
22

33
using CUDA
4-
using CUDA: CUstream, cudaDataType, @checked, HandleCache, with_workspace, libraryPropertyType
4+
using CUDA: CUstream, cudaDataType, cudaEvent_t, @checked, HandleCache, with_workspace, libraryPropertyType
55
using CUDA: unsafe_free!, retry_reclaim, initialize_context, isdebug
66

77
using CEnum: @cenum

lib/custatevec/src/libcustatevec.jl

Lines changed: 364 additions & 11 deletions
Large diffs are not rendered by default.

lib/custatevec/src/statevec.jl

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ function applyMatrix!(sv::CuStateVec, matrix::Union{Matrix, CuMatrix}, adjoint::
1616
sv
1717
end
1818

19+
function applyMatrixBatched!(sv::CuStateVec, n_svs::Int, map_type::custatevecMatrixMapType_t, matrix_inds::Vector{Int}, matrix::Union{Vector, CuVector}, n_matrices::Int, adjoint::Bool, targets::Vector{<:Integer}, controls::Vector{<:Integer}, controlValues::Vector{<:Integer}=fill(one(Int32), length(controls)))
20+
sv_stride = div(length(sv.data), n_svs)
21+
n_index_bits = Int(log2(div(length(sv.data), n_svs)))
22+
function bufferSize()
23+
out = Ref{Csize_t}()
24+
custatevecApplyMatrixBatchedGetWorkspaceSize(handle(), eltype(sv), n_index_bits, n_svs, sv_stride, map_type, matrix_inds, matrix, eltype(matrix), CUSTATEVEC_MATRIX_LAYOUT_COL, Int32(adjoint), n_matrices, length(targets), length(controls), compute_type(eltype(sv), eltype(matrix)), out)
25+
out[]
26+
end
27+
with_workspace(bufferSize) do buffer
28+
custatevecApplyMatrixBatched(handle(), sv.data, eltype(sv), n_index_bits, n_svs, sv_stride, map_type, matrix_inds, matrix, eltype(matrix), CUSTATEVEC_MATRIX_LAYOUT_COL, Int32(adjoint), n_matrices, convert(Vector{Int32}, targets), length(targets), convert(Vector{Int32}, controls), convert(Vector{Int32}, controlValues), length(controls), compute_type(eltype(sv), eltype(matrix)), buffer, length(buffer))
29+
end
30+
sv
31+
end
32+
1933
function applyGeneralizedPermutationMatrix!(sv::CuStateVec, permutation::Union{Vector{<:Integer}, CuVector{<:Integer}}, diagonals::Union{Vector, CuVector}, adjoint::Bool, targets::Vector{<:Integer}, controls::Vector{<:Integer}, controlValues::Vector{<:Integer}=fill(one(Int32), length(controls)))
2034
function bufferSize()
2135
out = Ref{Csize_t}()
@@ -29,8 +43,8 @@ function applyGeneralizedPermutationMatrix!(sv::CuStateVec, permutation::Union{V
2943
end
3044

3145
function abs2SumOnZBasis(sv::CuStateVec, basisInds::Vector{<:Integer})
32-
abs2sum0 = Ref{Float64}[]
33-
abs2sum1 = Ref{Float64}[]
46+
abs2sum0 = Ref{Float64}(0.0)
47+
abs2sum1 = Ref{Float64}(0.0)
3448
custatevecAbs2SumOnZBasis(handle(), sv.data, eltype(sv), sv.nbits, abs2sum0, abs2sum1, basisInds, length(basisInds))
3549
return abs2sum0[], abs2sum1[]
3650
end
@@ -52,12 +66,35 @@ function collapseByBitString!(sv::CuStateVec, bitstring::Union{Vector{<:Integer}
5266
sv
5367
end
5468

69+
function collapseByBitStringBatched!(sv::CuStateVec, n_svs::Int, bitstrings::Vector{<:Integer}, bitordering::Vector{<:Integer}, norms::Vector{Float64})
70+
function bufferSize()
71+
out = Ref{Csize_t}()
72+
custatevecCollapseByBitStringBatchedGetWorkspaceSize(handle(), n_svs, convert(Vector{custatevecIndex_t}, bitstrings), norms, out)
73+
out[]
74+
end
75+
sv_stride = div(length(sv.data), n_svs)
76+
n_index_bits = Int(log2(div(length(sv.data), n_svs)))
77+
with_workspace(bufferSize) do buffer
78+
custatevecCollapseByBitStringBatched(handle(), sv.data, eltype(sv), n_index_bits, n_svs, sv_stride, convert(Vector{custatevecIndex_t}, bitstrings), convert(Vector{Int32}, bitordering), n_index_bits, norms, buffer, length(buffer))
79+
end
80+
sv
81+
end
82+
5583
function abs2SumArray(sv::CuStateVec, bitordering::Vector{<:Integer}, maskBitString::Vector{<:Integer}, maskOrdering::Vector{<:Integer})
5684
abs2sum = Vector{Float64}(undef, 2^length(bitordering))
5785
custatevecAbs2SumArray(handle(), sv.data, eltype(sv), sv.nbits, abs2sum, convert(Vector{Int32}, bitordering), length(bitordering), convert(Vector{Int32}, maskBitString), convert(Vector{Int32}, maskOrdering), length(maskOrdering))
5886
return abs2sum
5987
end
6088

89+
function abs2SumArrayBatched(sv::CuStateVec, n_svs::Int, bitordering::Vector{<:Integer}, maskBitStrings::Vector{<:Integer}, maskOrdering::Vector{<:Integer})
90+
abs2sum = zeros(Float64, n_svs * 2^length(bitordering))
91+
sv_stride = div(length(sv.data), n_svs)
92+
n_index_bits = Int(log2(div(length(sv.data), n_svs)))
93+
sum_stride = 2^length(bitordering)
94+
custatevecAbs2SumArrayBatched(handle(), sv.data, eltype(sv), n_index_bits, n_svs, sv_stride, abs2sum, sum_stride, convert(Vector{Int32}, bitordering), length(bitordering), convert(Vector{Int32}, maskBitStrings), convert(Vector{Int32}, maskOrdering), length(maskOrdering))
95+
return abs2sum
96+
end
97+
6198
function batchMeasure!(sv::CuStateVec, bitordering::Vector{<:Integer}, randnum::Float64, collapse::custatevecCollapseOp_t=CUSTATEVEC_COLLAPSE_NONE)
6299
0.0 <= randnum < 1.0 || throw(ArgumentError("randnum $randnum must be in the interval [0, 1)."))
63100
bitstring = zeros(Int32, length(bitordering))
@@ -86,9 +123,9 @@ function expectation(sv::CuStateVec, matrix::Union{Matrix, CuMatrix}, basis_bits
86123
return expVal[], residualNorm[]
87124
end
88125

89-
function expectationsOnPauliBasis(sv::CuStateVec, pauliOps::Vector{Pauli}, basisInds::Vector{Vector{<:Integer}})
90-
exp_vals = Vector{Float64}(undef, length(pauliOps))
91-
cupaulis = CuStateVecPauli.(pauliOps)
126+
function expectationsOnPauliBasis(sv::CuStateVec, pauliOps::Vector{Vector{Pauli}}, basisInds::Vector{Vector{Int}})
127+
exp_vals = zeros(Float64, length(pauliOps))
128+
cupaulis = [[CuStateVecPauli(O) for O in op] for op in pauliOps]
92129
custatevecComputeExpectationsOnPauliBasis(handle(), sv.data, eltype(sv), sv.nbits, exp_vals, cupaulis, length(pauliOps), convert(Vector{Vector{Int32}}, basisInds), length.(basisInds))
93130
return exp_vals
94131
end
@@ -141,3 +178,11 @@ function testMatrixType(matrix::Union{Matrix, CuMatrix}, adjoint::Bool, matrix_t
141178
end
142179
return residualNorm[]
143180
end
181+
182+
function accessorSet(a::CuStateVecAccessor, external_buf::Union{Vector, CuVector}, i_begin::Int, i_end::Int)
183+
custatevecAccessorSet(handle(), a, external_buf, i_begin, i_end)
184+
end
185+
186+
function accessorGet(a::CuStateVecAccessor, external_buf::Union{Vector, CuVector}, i_begin::Int, i_end::Int)
187+
custatevecAccessorGet(handle(), a, external_buf, i_begin, i_end)
188+
end

lib/custatevec/src/types.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ CuStateVec(v::CuVector{T}) where {T} = CuStateVec{T}(v, UInt32(log2(length(v))))
7979
CuStateVec(v::Vector{T}) where {T} = CuStateVec(CuVector{T}(v))
8080

8181
Base.eltype(sv::CuStateVec{T}) where T = T
82+
Base.copy(sv::CuStateVec{T}) where {T} = CuStateVec(copy(sv.data))
8283

8384
mutable struct CuStateVecSampler
8485
handle::custatevecSamplerDescriptor_t
@@ -94,3 +95,16 @@ mutable struct CuStateVecSampler
9495
end
9596

9697
Base.unsafe_convert(::Type{custatevecSamplerDescriptor_t}, desc::CuStateVecSampler) = desc.handle
98+
99+
mutable struct CuStateVecAccessor
100+
handle::custatevecAccessorDescriptor_t
101+
ws_size::Csize_t
102+
function CuStateVecAccessor(sv::CuStateVec, bit_ordering::Vector{Int}, mask_bit_string::Vector{Int}, mask_ordering::Vector{Int})
103+
desc_ref = Ref{custatevecAccessorDescriptor_t}()
104+
extra_size = Ref{Csize_t}(0)
105+
custatevecAccessorCreate(handle(), pointer(sv.data), eltype(sv), sv.nbits, desc_ref, bit_ordering, length(bit_ordering), mask_bit_string, mark_ordering, length(mask_bit_string), extra_size)
106+
obj = new(desc_ref[], extra_size[])
107+
finalizer(custatevecAccessorDestroy, obj)
108+
obj
109+
end
110+
end

lib/custatevec/test/runtests.jl

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ using cuStateVec
88
@info "cuStateVec version: $(cuStateVec.version())"
99

1010
@testset "cuStateVec" begin
11-
import cuStateVec: CuStateVec, applyMatrix!, applyPauliExp!, applyGeneralizedPermutationMatrix!, expectation, expectationsOnPauliBasis, sample, testMatrixType, Pauli, PauliX, PauliY, PauliZ, PauliI, measureOnZBasis!, swapIndexBits!
11+
import cuStateVec: CuStateVec, applyMatrix!, applyMatrixBatched!, applyPauliExp!, applyGeneralizedPermutationMatrix!, expectation, expectationsOnPauliBasis, sample, testMatrixType, Pauli, PauliX, PauliY, PauliZ, PauliI, measureOnZBasis!, swapIndexBits!, abs2SumOnZBasis, collapseOnZBasis!, batchMeasure!, abs2SumArray, collapseByBitString!, abs2SumArrayBatched, collapseByBitStringBatched!
1212

1313
@testset "applyMatrix! and expectation" begin
1414
# build a simple state and compute expectations
@@ -19,7 +19,8 @@ using cuStateVec
1919
Z = convert(Matrix{elty}, [1 0; 0 -1])
2020
sv = CuStateVec(elty, n_q)
2121
sv = applyMatrix!(sv, H, false, Int32[0], Int32[])
22-
exp, res = expectation(sv, Z, Int32[0])
22+
sv = applyMatrix!(sv, H, false, Int32[1], Int32[])
23+
exp, res = expectation(sv, Z, Int32[1])
2324
@test exp 0.0 atol=1e-6
2425
exp, res = expectation(sv, X, Int32[0])
2526
@test exp 1.0 atol=1e-6
@@ -38,6 +39,69 @@ using cuStateVec
3839
exp, res = expectation(sv, X, Int32[0])
3940
@test exp 0.0 atol=1e-6
4041
end
42+
# with expectationsOnPauliBasis
43+
n_q = 2
44+
@testset for elty in [ComplexF32, ComplexF64]
45+
H = convert(Matrix{elty}, (1/√2).*[1 1; 1 -1])
46+
X = convert(Matrix{elty}, [0 1; 1 0])
47+
Z = convert(Matrix{elty}, [1 0; 0 -1])
48+
sv = CuStateVec(elty, n_q)
49+
sv = applyMatrix!(sv, H, false, Int32[0], Int32[])
50+
sv = applyMatrix!(sv, H, false, Int32[1], Int32[])
51+
pauli_ops = [cuStateVec.Pauli[cuStateVec.PauliX()], cuStateVec.Pauli[cuStateVec.PauliX()]]
52+
exp_vals = expectationsOnPauliBasis(sv, pauli_ops, [[0], [1]])
53+
@test exp_vals[1] 1.0 atol=1e-6
54+
@test exp_vals[2] 1.0 atol=1e-6
55+
end
56+
end
57+
@testset "applyMatrixBatched! and expectation" begin
58+
# build a simple state and compute expectations
59+
n_q = 2
60+
@testset for elty in [ComplexF32, ComplexF64]
61+
H = convert(Matrix{elty}, (1/√2).*[1 1; 1 -1])
62+
X = convert(Matrix{elty}, [0 1; 1 0])
63+
Z = convert(Matrix{elty}, [1 0; 0 -1])
64+
@testset for n_svs in (1, 2)
65+
@testset for (mapping, mat_inds, n_mats) in (
66+
(cuStateVec.CUSTATEVEC_MATRIX_MAP_TYPE_MATRIX_INDEXED, collect(0:n_svs-1), n_svs),
67+
(cuStateVec.CUSTATEVEC_MATRIX_MAP_TYPE_MATRIX_INDEXED, fill(0, n_svs), 1),
68+
(cuStateVec.CUSTATEVEC_MATRIX_MAP_TYPE_BROADCAST, fill(0, n_svs), 1),
69+
)
70+
batched_vec = CUDA.zeros(elty, n_svs*2^(n_q))
71+
for sv_ix in 0:n_svs-1
72+
CUDA.@allowscalar batched_vec[sv_ix*(2^n_q) + 1] = one(elty)
73+
end
74+
sv = CuStateVec(batched_vec) # padded state vector
75+
H_batch = CuVector{elty}(repeat(vec(H), n_mats))
76+
sv = applyMatrixBatched!(sv, n_svs, mapping, mat_inds, H_batch, n_mats, false, Int32[0], Int32[])
77+
CUDA.@allowscalar begin
78+
for sv_ix in 0:n_svs-1
79+
ix_begin = sv_ix*2^n_q + 1
80+
ix_end = (sv_ix+1)*2^n_q
81+
sv_ = CuStateVec(sv.data[ix_begin:ix_end])
82+
exp, res = expectation(sv_, Z, Int32[0])
83+
@test exp 0.0 atol=1e-6
84+
exp, res = expectation(sv_, X, Int32[0])
85+
@test exp 1.0 atol=1e-6
86+
end
87+
end
88+
end
89+
end
90+
end
91+
# build a simple state with controls and compute expectations
92+
n_q = 2
93+
@testset for elty in [ComplexF32, ComplexF64]
94+
H = convert(Matrix{elty}, (1/√2).*[1 1; 1 -1])
95+
X = convert(Matrix{elty}, [0 1; 1 0])
96+
Z = convert(Matrix{elty}, [1 0; 0 -1])
97+
sv = CuStateVec(elty, n_q)
98+
sv = applyMatrix!(sv, H, false, Int32[0], Int32[])
99+
sv = applyMatrix!(sv, X, false, Int32[1], Int32[0]) # CNOT
100+
exp, res = expectation(sv, Z, Int32[0])
101+
@test exp 0.0 atol=1e-6
102+
exp, res = expectation(sv, X, Int32[0])
103+
@test exp 0.0 atol=1e-6
104+
end
41105
end
42106
@testset "applyMatrix! and sample" begin
43107
# build a simple state and compute samples
@@ -74,6 +138,22 @@ using cuStateVec
74138
@test collect(sv_result.data) h_sv_result
75139
end
76140
end
141+
@testset "abs2sumOnZBasis and collapseOnZBasis!" begin
142+
@testset for elty in [ComplexF32, ComplexF64]
143+
h_sv = 1.0/√8 .* elty[0.0, im, 0.0, im, 0.0, im, 0.0, im]
144+
h_sv_result_0 = 1.0/√2 * elty[0.0, 0.0, 0.0, im, 0.0, im, 0.0, 0.0]
145+
h_sv_result_1 = 1.0/√2 * elty[0.0, im, 0.0, 0.0, 0.0, 0.0, 0.0, im]
146+
sv = CuStateVec(h_sv)
147+
abs2sum0, abs2sum1 = abs2SumOnZBasis(sv, [0, 1, 2])
148+
abs2sum = abs2sum0 + abs2sum1
149+
for (parity, norm, h_sv_result) in ((0, abs2sum0, h_sv_result_0), (1, abs2sum1, h_sv_result_1))
150+
d_sv = copy(sv)
151+
d_sv = collapseOnZBasis!(d_sv, parity, [0, 1, 2], norm)
152+
sv_result = collect(d_sv.data)
153+
@test sv_result h_sv_result
154+
end
155+
end
156+
end
77157
@testset "measureOnZBasis" begin
78158
@testset for elty in [ComplexF32, ComplexF64]
79159
h_sv = 1.0/√8 .* elty[0.0, im, 0.0, im, 0.0, im, 0.0, im]
@@ -84,6 +164,61 @@ using cuStateVec
84164
@test sv_result h_sv_result
85165
end
86166
end
167+
@testset "abs2SumArray and collapseByBitString!" begin
168+
nq = 3
169+
bit_ordering = [2, 1, 0]
170+
@testset for elty in [ComplexF32, ComplexF64]
171+
h_sv = elty[0.0, 0.1*im, 0.1+0.1*im, 0.1+0.2*im, 0.2+0.2*im, 0.3+0.3im, 0.3+0.4*im, 0.4+0.5*im]
172+
h_sv_result = elty[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3+0.4*im, 0.0]
173+
sv = CuStateVec(h_sv)
174+
abs2sum = abs2SumArray(sv, bit_ordering, Int[], Int[])
175+
bitstr = [1, 1, 0]
176+
d_sv = copy(sv)
177+
d_sv = collapseByBitString!(d_sv, bitstr, bit_ordering, 1.)
178+
sv_result = collect(d_sv.data)
179+
@test sv_result h_sv_result
180+
end
181+
end
182+
@testset "abs2SumArrayBatched" begin
183+
bit_ordering = [1]
184+
@testset for elty in [ComplexF32, ComplexF64]
185+
@testset for n_svs in (2,)
186+
h_sv = elty[0.0, 0.1*im, 0.1 + 0.1*im, 0.1 + 0.2*im, 0.2+0.2*im, 0.3+0.3*im, 0.3+0.4*im, 0.4+0.5*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im, 0.25+0.25*im]
187+
a2s_result = real(elty)[0.27, 0.73, 0.5, 0.5]
188+
sv = CuStateVec(h_sv)
189+
abs2sum = abs2SumArrayBatched(sv, n_svs, bit_ordering, Int[], Int[])
190+
@test abs2sum a2s_result
191+
end
192+
end
193+
end
194+
@testset "collapseByBitStringBatched!" begin
195+
bit_ordering = [0, 1, 2]
196+
@testset for elty in [ComplexF32, ComplexF64]
197+
@testset for n_svs in (2,)
198+
h_sv = elty[0.0, 0.1*im, 0.1 + 0.1*im, 0.1 + 0.2*im, 0.2+0.2*im, 0.3+0.3*im, 0.3+0.4*im, 0.4+0.5*im, 0.0, 0.1*im, 0.1+0.1*im, 0.1+0.2*im, 0.2+0.2*im, 0.3+0.3*im, 0.3+0.4*im, 0.4*0.5*im]
199+
h_sv_result = elty[0.0, im, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6+0.8*im, 0.0]
200+
sv = CuStateVec(h_sv)
201+
bitstr = [0b001, 0b110]
202+
d_sv = copy(sv)
203+
d_sv = collapseByBitStringBatched!(d_sv, n_svs, bitstr, bit_ordering, [0.01, 0.25])
204+
sv_result = collect(d_sv.data)
205+
@test sv_result h_sv_result
206+
end
207+
end
208+
end
209+
@testset "batchMeasure!" begin
210+
nq = 3
211+
bit_ordering = [2, 1, 0]
212+
@testset for elty in [ComplexF32, ComplexF64]
213+
h_sv = elty[0.0, 0.1*im, 0.1+0.1*im, 0.1+0.2*im, 0.2+0.2*im, 0.3+0.3im, 0.3+0.4*im, 0.4+0.5*im]
214+
h_sv_result = elty[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6+0.8*im, 0.0]
215+
sv = CuStateVec(h_sv)
216+
sv, bitstr = batchMeasure!(sv, bit_ordering, 0.5, cuStateVec.CUSTATEVEC_COLLAPSE_NORMALIZE_AND_ZERO)
217+
sv_result = collect(sv.data)
218+
@test sv_result h_sv_result
219+
@test bitstr == [1, 1, 0]
220+
end
221+
end
87222
@testset "swapIndexBits" begin
88223
@testset for elty in [ComplexF32, ComplexF64]
89224
# 0.1|000> + 0.4|011> - 0.4|101> - 0.3im|111>

lib/cutensornet/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ cuTENSOR = "011b41b2-24ef-40a8-b3eb-fa098493e9e1"
1515
CEnum = "0.2, 0.3, 0.4"
1616
CUDA = "~5.1"
1717
CUDA_Runtime_Discovery = "0.2"
18-
cuQuantum_jll = "~22.11"
18+
cuQuantum_jll = "~23.10"
1919
cuTENSOR = "~1.0, ~1.1, ~1.2"
2020
julia = "1.6"
2121
LinearAlgebra = "1"

lib/cutensornet/src/cuTensorNet.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module cuTensorNet
33
using LinearAlgebra
44
using CUDA
55
using CUDA: CUstream, cudaDataType, @checked, HandleCache, with_workspace
6-
using CUDA: retry_reclaim, initialize_context, isdebug
6+
using CUDA: retry_reclaim, initialize_context, isdebug, cuDoubleComplex
77

88
using cuTENSOR
99
using cuTENSOR: CuTensor

0 commit comments

Comments
 (0)