From 0281e474217b788fa03414059f33f516efccb4b4 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Tue, 28 Jan 2025 11:42:36 -0500 Subject: [PATCH 1/2] Fix some aliasing issues --- src/op.jl | 11 ++++ src/sitetypes/qubit.jl | 129 +++++++++++++++++++++------------------ src/sitetypes/spinone.jl | 10 +-- src/state.jl | 13 ++-- test/test_basics.jl | 28 ++++++++- 5 files changed, 118 insertions(+), 73 deletions(-) diff --git a/src/op.jl b/src/op.jl index 13b23b7..c7fbf43 100644 --- a/src/op.jl +++ b/src/op.jl @@ -516,6 +516,17 @@ end @op_alias "CCCNOT" "Controlled" ncontrol = 3 op = OpName"X"() +## # 1-qudit rotation around generic axis n̂. +## # exp(-im * α / 2 * n̂ ⋅ σ⃗) +## function (n::OpName"Rn")(domain) +## # TODO: Is this a good parametrization? +## n̂ = (sin(n.θ/2) * cos(n.ϕ), sin(n.θ/2) * sin(n.ϕ/2), cos(n.θ/2)) +## σ⃗ = (OpName"X"(domain), OpName"Y"(domain), OpName"Z"(domain)) +## n̂σ⃗ = mapreduce(*, +, n̂, σ⃗) +## return cis(-(n.λ/2) * n̂σ⃗) +## end +## @op_alias "Rn̂" "Rn" + # Version of `sign` that returns one # if `x == 0`. function nonzero_sign(x) diff --git a/src/sitetypes/qubit.jl b/src/sitetypes/qubit.jl index ceccae4..a322671 100644 --- a/src/sitetypes/qubit.jl +++ b/src/sitetypes/qubit.jl @@ -6,35 +6,39 @@ alias(::SiteType"SpinHalf=1/2") = SiteType"Qubit"() Base.length(::SiteType"Qubit") = 2 -(::StateName"↑")(::SiteType"Qubit") = StateName"0"()(2) -(::StateName"Up")(::SiteType"Qubit") = StateName"0"()(2) +# Avoid aliases since these aren't generic +# to Qudits/higher spin. (::StateName"Z+")(::SiteType"Qubit") = StateName"0"()(2) -(::StateName"Zp")(::SiteType"Qubit") = StateName"0"()(2) -(::StateName"Emp")(::SiteType"Qubit") = StateName"0"()(2) +(::StateName"Zp")(domain::SiteType"Qubit") = StateName"Z+"()(domain) +(::StateName"↑")(domain::SiteType"Qubit") = StateName"Z+"()(domain) +(::StateName"Up")(domain::SiteType"Qubit") = StateName"Z+"()(domain) +(::StateName"Emp")(domain::SiteType"Qubit") = StateName"Z+"()(domain) -(::StateName"↓")(::SiteType"Qubit") = StateName"1"()(2) -(::StateName"Dn")(::SiteType"Qubit") = StateName"1"()(2) +# Avoid aliases since these aren't generic +# to Qudits/higher spin. (::StateName"Z-")(::SiteType"Qubit") = StateName"1"()(2) -(::StateName"Zm")(::SiteType"Qubit") = StateName"1"()(2) -(::StateName"Occ")(::SiteType"Qubit") = StateName"1"()(2) +(::StateName"Zm")(domain::SiteType"Qubit") = StateName"Z-"()(domain) +(::StateName"↓")(domain::SiteType"Qubit") = StateName"Z-"()(domain) +(::StateName"Dn")(domain::SiteType"Qubit") = StateName"Z-"()(domain) +(::StateName"Occ")(domain::SiteType"Qubit") = StateName"Z-"()(domain) # `eigvecs(X)` -alias(::StateName"+") = (StateName"0"() + StateName"1"()) / √2 -@state_alias "X+" "+" -@state_alias "Xp" "+" +(::StateName"X+")(::SiteType"Qubit") = ((StateName"0"() + StateName"1"()) / √2)(2) +(::StateName"Xp")(domain::SiteType"Qubit") = StateName"X+"()(domain) +(::StateName"+")(domain::SiteType"Qubit") = StateName"X+"()(domain) -alias(::StateName"-") = (StateName"0"() - StateName"1"()) / √2 -@state_alias "X-" "-" -@state_alias "Xm" "-" +(::StateName"X-")(::SiteType"Qubit") = ((StateName"0"() - StateName"1"()) / √2)(2) +(::StateName"Xm")(domain::SiteType"Qubit") = StateName"X-"()(domain) +(::StateName"-")(domain::SiteType"Qubit") = StateName"X-"()(domain) # `eigvecs(Y)` -alias(::StateName"i") = (StateName"0"() + im * StateName"1"()) / √2 -@state_alias "Y+" "i" -@state_alias "Yp" "i" +(::StateName"Y+")(::SiteType"Qubit") = ((StateName"0"() + im * StateName"1"()) / √2)(2) +(::StateName"Yp")(domain::SiteType"Qubit") = StateName"Y+"()(domain) +(::StateName"i")(domain::SiteType"Qubit") = StateName"Y+"()(domain) -alias(::StateName"-i") = (StateName"0"() - im * StateName"1"()) / √2 -@state_alias "Y-" "-i" -@state_alias "Ym" "-i" +(::StateName"Y-")(::SiteType"Qubit") = ((StateName"0"() - im * StateName"1"()) / √2)(2) +(::StateName"Ym")(domain::SiteType"Qubit") = StateName"Y-"()(domain) +(::StateName"-i")(domain::SiteType"Qubit") = StateName"Y-"()(domain) # SIC-POVMs (::StateName"Tetra0")(::SiteType"Qubit") = [ @@ -55,48 +59,51 @@ alias(::StateName"-i") = (StateName"0"() - im * StateName"1"()) / √2 ] # TODO: Define as `(I + σᶻ) / 2`? -alias(::OpName"ProjUp") = OpName"Proj"(; index=1) -@op_alias "projUp" "ProjUp" -@op_alias "Proj↑" "ProjUp" -@op_alias "proj↑" "ProjUp" -@op_alias "Proj0" "ProjUp" -@op_alias "proj0" "ProjUp" +(::OpName"ProjUp")(::SiteType"Qubit") = OpName"Proj"(; index=1)(2) +(::OpName"projUp")(domain::SiteType"Qubit") = OpName"ProjUp"()(domain) +(::OpName"Proj↑")(domain::SiteType"Qubit") = OpName"ProjUp"()(domain) +(::OpName"proj↑")(domain::SiteType"Qubit") = OpName"ProjUp"()(domain) +(::OpName"Proj0")(domain::SiteType"Qubit") = OpName"ProjUp"()(domain) +(::OpName"proj0")(domain::SiteType"Qubit") = OpName"ProjUp"()(domain) # TODO: Define as `σ⁺ * σ⁻`? # TODO: Define as `(I - σᶻ) / 2`? -alias(::OpName"ProjDn") = OpName"Proj"(; index=2) -@op_alias "projDn" "ProjDn" -@op_alias "Proj↓" "ProjDn" -@op_alias "proj↓" "ProjDn" -@op_alias "Proj1" "ProjDn" -@op_alias "proj1" "ProjDn" +(::OpName"ProjDn")(::SiteType"Qubit") = OpName"Proj"(; index=2)(2) +(::OpName"projDn")(domain::SiteType"Qubit") = OpName"ProjDn"()(domain) +(::OpName"Proj↓")(domain::SiteType"Qubit") = OpName"ProjDn"()(domain) +(::OpName"proj↓")(domain::SiteType"Qubit") = OpName"ProjDn"()(domain) +(::OpName"Proj1")(domain::SiteType"Qubit") = OpName"ProjDn"()(domain) +(::OpName"proj1")(domain::SiteType"Qubit") = OpName"ProjDn"()(domain) -# Rotation around generic axis n̂ -# exp(-im * n.θ / 2 * n̂ ⋅ σ⃗) -#= -TODO: Define R-gate when `λ == -ϕ`, i.e.: -```julia -function Base.AbstractArray(n::OpName"R", ::Tuple{SiteType"Qubit"}) - return [ - cos(n.θ / 2) -exp(-im * n.ϕ)*sin(n.θ / 2) - exp(im * n.ϕ)*sin(n.θ / 2) cos(n.θ / 2) - ] -end -``` -or: -```julia -alias(n::OpName"R") = OpName"Rn"(; θ=n.θ, ϕ=n.ϕ, λ=-n.ϕ) -=# -# https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.UGate -# TODO: Generalize to `"Qudit"`, see: -# https://quantumcomputing.stackexchange.com/questions/16251/how-does-a-general-rotation-r-hatn-theta-related-to-u-3-gate -# https://quantumcomputing.stackexchange.com/questions/4249/decomposition-of-an-arbitrary-1-qubit-gate-into-a-specific-gateset -# https://en.wikipedia.org/wiki/List_of_quantum_logic_gates#Other_named_gates -# https://en.wikipedia.org/wiki/Spin_(physics)#Higher_spins -function (n::OpName"Rn")(::SiteType"Qubit") - return [ - cos(n.θ / 2) -exp(im * n.λ)*sin(n.θ / 2) - exp(im * n.ϕ)*sin(n.θ / 2) exp(im * (n.ϕ + n.λ))*cos(n.θ / 2) - ] -end -@op_alias "Rn̂" "Rn" +## TODO: Bring this back, decide on names and angle conventions. +## # Related to rotation `"Rn"` around generic axis n̂: +## # exp(-im * n.θ / 2 * n̂ ⋅ σ⃗) +## #= +## TODO: Define R-gate when `λ == -ϕ`, i.e.: +## ```julia +## function Base.AbstractArray(n::OpName"R", ::Tuple{SiteType"Qubit"}) +## return [ +## cos(n.θ / 2) -exp(-im * n.ϕ)*sin(n.θ / 2) +## exp(im * n.ϕ)*sin(n.θ / 2) cos(n.θ / 2) +## ] +## end +## ``` +## or: +## ```julia +## alias(n::OpName"R") = OpName"Rn"(; θ=n.θ, ϕ=n.ϕ, λ=-n.ϕ) +## =# +## # https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.UGate +## # TODO: Generalize to `"Qudit"`, see: +## # https://quantumcomputing.stackexchange.com/questions/16251/how-does-a-general-rotation-r-hatn-theta-related-to-u-3-gate +## # https://quantumcomputing.stackexchange.com/questions/4249/decomposition-of-an-arbitrary-1-qubit-gate-into-a-specific-gateset +## # https://en.wikipedia.org/wiki/List_of_quantum_logic_gates#Other_named_gates +## # https://en.wikipedia.org/wiki/Spin_(physics)#Higher_spins +## # https://qudev.phys.ethz.ch/static/content/courses/QSIT07/presentations/Schmassmann.pdf +## # http://theory.caltech.edu/~preskill/ph219/chap5_15.pdf +## # https://almuhammadi.com/sultan/books_2020/Nielsen_Chuang.pdf (Chapter 4) +## function (n::OpName"GeneralRotation")(::SiteType"Qubit") +## return [ +## cos(n.θ / 2) -exp(im * n.λ)*sin(n.θ / 2) +## exp(im * n.ϕ)*sin(n.θ / 2) exp(im * (n.ϕ + n.λ))*cos(n.θ / 2) +## ] +## end diff --git a/src/sitetypes/spinone.jl b/src/sitetypes/spinone.jl index 84f12e8..82f7e7d 100644 --- a/src/sitetypes/spinone.jl +++ b/src/sitetypes/spinone.jl @@ -9,11 +9,11 @@ alias(::SiteType"SpinOne") = SiteType"S=1"() (::StateName"Z-")(::SiteType"S=1") = [0, 0, 1] ## TODO: Decide on these aliases. -(::StateName"↑")(::SiteType"S=1") = StateName"Z+"()(domain) -(::StateName"Up")(::SiteType"S=1") = StateName"Z+"()(domain) -(::StateName"0")(::SiteType"S=1") = StateName"Z0"()(domain) -(::StateName"↓")(::SiteType"S=1") = StateName"Z-"()(domain) -(::StateName"Dn")(::SiteType"S=1") = StateName"Z-"()(domain) +(::StateName"↑")(domain::SiteType"S=1") = StateName"Z+"()(domain) +(::StateName"Up")(domain::SiteType"S=1") = StateName"Z+"()(domain) +(::StateName"0")(domain::SiteType"S=1") = StateName"Z0"()(domain) +(::StateName"↓")(domain::SiteType"S=1") = StateName"Z-"()(domain) +(::StateName"Dn")(domain::SiteType"S=1") = StateName"Z-"()(domain) # TODO: Make these more general, define as something like: # `(n::StateName"X")(::SiteType"S=1") = eigvecs(OpName"X"())[n.eigval]` diff --git a/src/state.jl b/src/state.jl index 969ead4..d9904a5 100644 --- a/src/state.jl +++ b/src/state.jl @@ -141,11 +141,16 @@ function (n::StateName"StandardBasis")(domain) a[n.index] = one(Bool) return a end -function (n::StateName{N})(domain) where {N} +function (n::StateName{N})(domain...) where {N} + # TODO: Try one alias at a time? + # TODO: First call `alias(n, domain...)` + # to allow for aliases specific to certain + # SiteTypes? n′ = alias(n) - if n == n′ + domain′ = alias.(domain) + if n == n′ && domain′ == domain index = parse(Int, String(N)) + 1 - return StateName"StandardBasis"(; index)(domain) + return StateName"StandardBasis"(; index)(domain...) end - return n′(domain) + return n′(domain′...) end diff --git a/test/test_basics.jl b/test/test_basics.jl index b1d5eeb..53f2595 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -223,9 +223,31 @@ const elts = (real_elts..., complex_elts...) end for t in (SiteType("S=1"), SiteType("SpinOne")) - @test state("Z+", SiteType("S=1")) == [1, 0, 0] - @test state("Z0", SiteType("S=1")) == [0, 1, 0] - @test state("Z-", SiteType("S=1")) == [0, 0, 1] + for (ns, x) in ( + (("Z+", "↑", "Up"), [1, 0, 0]), + (("Z0", "0"), [0, 1, 0]), + (("Z-", "↓", "Dn"), [0, 0, 1]), + (("X+",), [1 / 2, 1 / sqrt(2), 1 / 2]), + (("X0",), [-1 / sqrt(2), 0, 1 / sqrt(2)]), + (("X-",), [1 / 2, -1 / sqrt(2), 1 / 2]), + (("Y+",), [-1 / 2, -im / sqrt(2), 1 / 2]), + (("Y0",), [1 / sqrt(2), 0, 1 / sqrt(2)]), + (("Y-",), [-1 / 2, im / sqrt(2), 1 / 2]), + ) + for n in ns + @test state(n, t) ≈ x + end + end + end + + # Check they are eigenvalues + (λ⁺, λ⁰, λ⁻) = (2, 0, -2) + for t in (SiteType("S=1"), SiteType("SpinOne")) + for n in ("X", "Y", "Z") + @test op(n, t) * state("$(n)+", t) ≈ λ⁺ * state("$(n)+", t) atol = eps() + @test op(n, t) * state("$(n)0", t) ≈ λ⁰ * state("$(n)0", t) atol = eps() + @test op(n, t) * state("$(n)-", t) ≈ λ⁻ * state("$(n)-", t) atol = eps() + end end end end From 7376b1d75bf81704bc2f56e5ad7ef3826e380a90 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Tue, 28 Jan 2025 11:43:13 -0500 Subject: [PATCH 2/2] Bump versions --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c882343..85d6394 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "QuantumOperatorDefinitions" uuid = "826dd319-6fd5-459a-a990-3a4f214664bf" authors = ["ITensor developers and contributors"] -version = "0.1.3" +version = "0.1.4" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"