Open Krastanov opened 5 months ago
@hongyehu , there are some failures related to the expectation value (the tests in test_nonclifford_quantumoptics.jl
). I will not have the time to investigate today, but it seems I have messed up a convention somewhere and we are getting expectation values that are occasionally imaginary. Hopefully I will get to it early next week, but let me know if you would like to discuss it together if you have time to investigate it.
@Krastanov Hi Stefan, I can take a look into the expect! function and see whether we missed anything!
here is a small reproducers:
using QuantumClifford
using QuantumOpticsBase # which provides Operator and Ket for conversion (kinda like qutip)
using LinearAlgebra
qo_basis = SpinBasis(1//2)
qo_tgate = sparse(identityoperator(qo_basis))
qo_tgate.data[2,2] = exp(im*pi/4)
for s in [S"X", S"Y", S"Z", S"-X", S"-Y", S"-Z"]
for p in [P"X", P"Y", P"Z", P"-X", P"-Y", P"-Z"]
gs = GeneralizedStabilizer(s)
apply!(gs, pcT)
ρ = dm(qo_tgate*Ket(s))
@test Operator(gs) ≈ ρ
if isapprox(expect(p, gs), expect(Operator(p),ρ); atol=1e-5)
else
println("failure of expectation calculation for state = T*(", s, ") and observable = ", p)
end
end
end
It prints the following failing cases:
failure of expect for state = T*(+ X) and observable = + Y
failure of expect for state = T*(+ X) and observable = - Y
failure of expect for state = T*(+ Y) and observable = + X
failure of expect for state = T*(+ Y) and observable = - X
failure of expect for state = T*(- X) and observable = + Y
failure of expect for state = T*(- X) and observable = - Y
failure of expect for state = T*(- Y) and observable = + X
failure of expect for state = T*(- Y) and observable = - X
Hello, @Krastanov, I adressed some of the TODOs. Please do let me know do these #TODO improvements look plausible.
#After TODO 1: consider using bitpacking and SIMD xor with less eager shortcircuiting -- probably would be much faster
"""Same as `all(==(0), (a.+b.+c) .% 2)`"""
function _allthreesumtozero(a, b, c)
packed_sum = a .+ b .+ c
all_even = all(@. iseven(packed_sum))
return all_even
end
After TODO 2: there must be a cleaner way to do this
function _dictvaltype(dict)
return Base.getindex(eltype(dict).parameters, 2)
end
----------------
example: suppose genstab
julia> e = zero(_dictvaltype(genstab.destabweights))
0.0 + 0.0im
-----------------
After TODO 3: newdict = typeof(dict)(tzero) # TODO jeez, this is ugly
function apply!(state::GeneralizedStabilizer, gate::PauliChannel)
dict = state.destabweights
stab = state.stab
dtype = _dictvaltype(dict)
tzero = zero(dtype)
tone = one(dtype)
newdict = DefaultDict{Tuple{BitVector, BitVector}, Complex{Float64}}(Complex{Float64}(0, 0))
for ((dᵢ,dⱼ), χ) in dict
for ((Pₗ,Pᵣ), w) in zip(gate.paulis, gate.weights)
phaseₗ, dₗ, dₗˢᵗᵃᵇ = rowdecompose(Pₗ, stab)
phaseᵣ, dᵣ, dᵣˢᵗᵃᵇ = rowdecompose(Pᵣ, stab)
c = (dot(dₗˢᵗᵃᵇ, dᵢ) + dot(dᵣˢᵗᵃᵇ, dⱼ)) * 2
dᵢ′ = dₗ .⊻ dᵢ
dⱼ′ = dᵣ .⊻ dⱼ
χ′ = χ * w * (-tone)^c * (im)^(-phaseₗ + phaseᵣ + 4)
newdict[(dᵢ′, dⱼ′)] += χ′
end
end
keys_to_delete = Tuple[]
for (k, v) in newdict
if abs(v) < 1e-14
push!(keys_to_delete, k)
end
end
for k in keys_to_delete
delete!(newdict, k)
end
state.destabweights = newdict
return state
end
I reran the this test to confirm that there was no error:
julia> for n in 1:5
i = rand(1:n)
stab = random_stabilizer(n)
genstab = GeneralizedStabilizer(stab)
ket = Ket(stab)
@test dm(ket) ≈ Operator(stab)
@test dm(ket) ≈ Operator(genstab)
pauli = random_pauli(n; nophase=false, realphase=true)
qo_pauli = Operator(pauli)
qo_bigtgate = n==1 ? qo_tgate : embed(qo_basis^n, i, qo_tgate)
bigtgate = embed(n,i, pcT)
@test qo_bigtgate ≈ Operator(bigtgate)
for step in 1:10
# apply!(ket, qo_bigtgate) TODO implement this API
ket = qo_bigtgate*ket
apply!(genstab, bigtgate)
@test dm(ket) ≈ Operator(genstab)
@test isapprox(expect(qo_pauli, ket), expect(pauli, genstab); atol=1e-10)
end
end
Hi, Feroz. I am not following what you mean with your last comment. If you want to discus some changes to the code, I would suggest making a new branch or even a pull request on which we can talk. Very importantly, though, if you want to discuss specific changes, make sure you have clear separation of a single semantic change per commit. You will need to learn how to use an interactive rebase and potentially do force pushes, to keep the history of your changes easy to work with.
@hongyehu , this is what be built yesterday during the meeting, with a bit of polish. I tried to make the commits well separated and easy to read one by one. Hopefully this will make it easier to follow as you do not need to read the entire diff.
I will wait for tests to pass and then merge. I will add a long list of issues to track necessary enhancements.