|
| 1 | +function get_matrix(::Type{Tv}, op::AbstractBlock, ::FullSpace) where Tv |
| 2 | + return mat(Tv, op) |
| 3 | +end |
| 4 | + |
| 5 | +function get_matrix(::Type{Tv}, op::AbstractBlock, space::Subspace) where Tv |
| 6 | + return mat(Tv, op, space) |
| 7 | +end |
| 8 | + |
| 9 | +function get_matrix(::Type{Tv}, op::AbstractTerm, space::AbstractSpace) where Tv |
| 10 | + return SparseMatrixCSC{Tv}(op, space) |
| 11 | +end |
| 12 | + |
| 13 | +struct ConstTermCache{FS <: Tuple, HS <: Tuple} |
| 14 | + fs::FS # time-dependent factors |
| 15 | + hs::HS # const terms |
| 16 | +end |
| 17 | + |
| 18 | +function storage_size(h::ConstTermCache) |
| 19 | + return sum(storage_size, h.hs) |
| 20 | +end |
| 21 | + |
| 22 | +# split const term and its dynamic prefactors from hamiltonian expr |
| 23 | +function split_const_term(::Type{Tv}, h::Hamiltonian, space::AbstractSpace) where {Tv} |
| 24 | + fs, hs = [], [] |
| 25 | + for t in h.terms, (f, h) in _split_term(Tv, t, space) |
| 26 | + push!(fs, f) |
| 27 | + # NOTE: we force converting blocks to a matrix as a workaround |
| 28 | + # of https://github.com/QuantumBFS/BQCESubroutine.jl/issues/37 |
| 29 | + # so that we don't need to special case blocks to preallocate |
| 30 | + # the intermediate state for dstate. |
| 31 | + if h isa AbstractBlock |
| 32 | + push!(hs, get_matrix(Tv, h, space)) |
| 33 | + elseif h isa SparseMatrixCSC |
| 34 | + # always use CSR since it's faster in gemv |
| 35 | + push!(hs, transpose(h)) |
| 36 | + else |
| 37 | + push!(hs, h) |
| 38 | + end |
| 39 | + end |
| 40 | + return ConstTermCache((fs...,), (hs...,)) |
| 41 | +end |
| 42 | + |
| 43 | +function _split_term(::Type{Tv}, h::RydInteract, space::AbstractSpace) where {Tv} |
| 44 | + # TODO: actually implement it as Diagonal |
| 45 | + ((_const_param_, Diagonal(Vector(diag(SparseMatrixCSC{Tv}(h, space))))), ) |
| 46 | +end |
| 47 | + |
| 48 | +function _split_term(::Type{Tv}, h::Negative, space::AbstractSpace) where {Tv} |
| 49 | + return map(_split_term(Tv, h.term, space)) do (f, h) |
| 50 | + f, -h |
| 51 | + end |
| 52 | +end |
| 53 | + |
| 54 | +_const_param_(t) = one(t) |
| 55 | + |
| 56 | +function _split_term(::Type{Tv}, h::XTerm, space::AbstractSpace) where {Tv} |
| 57 | + n = nsites(h) |
| 58 | + @switch (h.Ωs, h.ϕs) begin |
| 59 | + @case (Ωs::ConstParamListType, ϕ::Number) || (Ωs::ConstParamListType, ::Nothing) || (Ω::Number, ϕ::Number) || |
| 60 | + (Ω::Number, ::ConstParamListType) || (Ω::Number, ::Nothing) |
| 61 | + ((_const_param_, SparseMatrixCSC{Tv, Cint}(h, space)), ) |
| 62 | + @case (Ωs::AbstractVector, ϕs::ConstParamListType) # directly apply is faster |
| 63 | + map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 64 | + x_phase = PermMatrix([2, 1], Tv[exp(ϕ * im), exp(-ϕ * im)]) |
| 65 | + t->Ω(t)/2, put(n, i => matblock(x_phase)) |
| 66 | + end |
| 67 | + @case (Ωs::ConstParamListType, ϕs::ParamsList) # directly apply is faster |
| 68 | + op1 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 69 | + t->(Ω/2 * exp(ϕ(t) * im)), put(n, i => matblock(Tv[0 1;0 0])) |
| 70 | + end |
| 71 | + |
| 72 | + op2 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 73 | + t->(Ω/2 * exp(-ϕ(t) * im)), put(n, i => matblock(Tv[0 0;1 0])) |
| 74 | + end |
| 75 | + return (op1..., op2...) |
| 76 | + @case (Ωs::ParamsList, ϕs::ParamsList) |
| 77 | + op1 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 78 | + t->(Ω(t)/2 * exp(ϕ(t) * im)), put(n, i => matblock(Tv[0 1;0 0])) |
| 79 | + end |
| 80 | + |
| 81 | + op2 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 82 | + t->(Ω(t)/2 * exp(-ϕ(t) * im)), put(n, i => matblock(Tv[0 0;1 0])) |
| 83 | + end |
| 84 | + return (op1..., op2...) |
| 85 | + @case (Ωs::ConstParamListType, ϕ) |
| 86 | + op1 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 87 | + t->(Ω/2 * exp(ϕ(t) * im)), put(n, i => matblock(Tv[0 1;0 0])) |
| 88 | + end |
| 89 | + |
| 90 | + op2 = map(enumerate(zip(Ωs, ϕs))) do (i, (Ω, ϕ)) |
| 91 | + t->(Ω/2 * exp(-ϕ(t) * im)), put(n, i => matblock(Tv[0 0;1 0])) |
| 92 | + end |
| 93 | + return (op1..., op2...) |
| 94 | + @case (Ωs::ParamsList, ::Nothing) |
| 95 | + map(enumerate(Ωs)) do (i, Ω) |
| 96 | + t->Ω(t)/2, put(n, i=>X) |
| 97 | + end |
| 98 | + @case (Ω::Number, ::ParamsList) |
| 99 | + op1 = map(enumerate(ϕs)) do (i, ϕ) |
| 100 | + t->(Ω/2 * exp(ϕ(t) * im)), put(n, i => matblock(Tv[0 1;0 0])) |
| 101 | + end |
| 102 | + |
| 103 | + op2 = map(enumerate(ϕs)) do (i, ϕ) |
| 104 | + t->(Ω/2 * exp(-ϕ(t) * im)), put(n, i => matblock(Tv[0 0;1 0])) |
| 105 | + end |
| 106 | + return (op1..., op2...) |
| 107 | + @case (Ω, ϕ::Number) |
| 108 | + A = get_matrix(Tv, sum(put(n, i=>matblock(Tv[0 1;0 0]))), space) |
| 109 | + B = get_matrix(Tv, sum(put(n, i=>matblock(Tv[0 0;1 0]))), space) |
| 110 | + return (t->Ω(t)/2 * exp(ϕ * im), A), (t->Ω(t)/2 * exp(-ϕ * im), B) |
| 111 | + @case (Ω, ::Nothing) # no 1/2 in prefactor, it's in the matrix already |
| 112 | + return ((t->Ω(t), SparseMatrixCSC{Tv, Cint}(XTerm(n, 1.0), space)), ) |
| 113 | + @case (Ω, ϕ) |
| 114 | + A = get_matrix(Tv, sum(put(n, i=>matblock(Tv[0 1;0 0]))), space) |
| 115 | + B = get_matrix(Tv, sum(put(n, i=>matblock(Tv[0 0;1 0]))), space) |
| 116 | + return (t->Ω(t)/2 * exp(ϕ(t) * im), A), (t->Ω(t)/2 * exp(-ϕ(t) * im), B) |
| 117 | + end |
| 118 | +end |
| 119 | + |
| 120 | +function _split_term(::Type{Tv}, h::NTerm, space::AbstractSpace) where {Tv} |
| 121 | + n = nsites(h) |
| 122 | + return if h.Δs isa ConstParamType |
| 123 | + M = Diagonal(Vector(diag(SparseMatrixCSC{Tv}(h, space)))) |
| 124 | + ((_const_param_, M), ) |
| 125 | + elseif h.Δs isa ParamsList |
| 126 | + return map(enumerate(h.Δs)) do (i, Δ) |
| 127 | + Δ, put(n, i=>Yao.ConstGate.P1) |
| 128 | + end |
| 129 | + else |
| 130 | + M = Diagonal(Vector(diag(SparseMatrixCSC{Tv}(NTerm(n, one(Tv)), space)))) |
| 131 | + return ((h.Δs, M), ) |
| 132 | + end |
| 133 | +end |
0 commit comments