From 7422cb39ba9f5de46c6c793c803cb86cf997830d Mon Sep 17 00:00:00 2001 From: Katharine Hyatt <67932820+kshyatt-aws@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:47:54 -0400 Subject: [PATCH] change: Allow any real number for gate angles (#97) --- .github/workflows/CI.yml | 3 +- Project.toml | 6 +- PyBraket/Project.toml | 6 +- src/gate_applicators.jl | 42 ++++---- src/gates.jl | 151 ++++++++++++++++---------- src/local_simulator.jl | 5 +- src/noise_applicators.jl | 32 +++--- src/noises.jl | 101 ++++++++++------- src/raw_schema.jl | 142 ++---------------------- src/schemas.jl | 8 +- test/gates.jl | 227 +++++++++++++++++++++++---------------- test/runtests.jl | 2 +- test/schemas_misc.jl | 2 - 13 files changed, 349 insertions(+), 378 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8b9b8855..8611805a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -152,12 +152,13 @@ jobs: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: - version: '1' + version: '1.10' - uses: julia-actions/cache@v1 - name: Configure doc environment shell: julia --project=docs --color=yes {0} run: | using Pkg + Pkg.Registry.update() Pkg.develop(PackageSpec(path=pwd())) Pkg.instantiate() - uses: julia-actions/julia-buildpkg@v1 diff --git a/Project.toml b/Project.toml index 64a30917..f95d974d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Braket" uuid = "19504a0f-b47d-4348-9127-acc6cc69ef67" authors = ["Katharine Hyatt "] -version = "0.9.3" +version = "0.9.4" [deps] AWS = "fbe9abb3-538b-5e4e-ba9e-bc94f4f92ebc" @@ -39,8 +39,8 @@ Aqua = "=0.8" AxisArrays = "=0.4.7" Base64 = "1.6" CSV = "=0.10.14" -CodeTracking = "=1.3.5" -Compat = "=4.15.0" +CodeTracking = "=1.3.6" +Compat = "=4.16.0" DataStructures = "=0.18.20" Dates = "1.6" DecFP = "=1.3.2" diff --git a/PyBraket/Project.toml b/PyBraket/Project.toml index ea413382..df115738 100644 --- a/PyBraket/Project.toml +++ b/PyBraket/Project.toml @@ -1,7 +1,7 @@ name = "PyBraket" uuid = "e85266a6-1825-490b-a80e-9b9469c53660" authors = ["Katharine Hyatt "] -version = "0.9.3" +version = "0.9.4" [deps] Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" @@ -14,11 +14,11 @@ StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" [compat] Aqua = "=0.8" -Braket = "=0.9.3" +Braket = "=0.9.4" CondaPkg = "=0.2.23" DataStructures = "=0.18.20" LinearAlgebra = "1.6" -PythonCall = "=0.9.21" +PythonCall = "=0.9.22" Statistics = "1" StructTypes = "=1.10.0" Test = "1.6" diff --git a/src/gate_applicators.jl b/src/gate_applicators.jl index 428a98d0..8a22fae0 100644 --- a/src/gate_applicators.jl +++ b/src/gate_applicators.jl @@ -1,28 +1,28 @@ (::Type{G})(c::Circuit) where {G<:Gate} = throw(ArgumentError("gate applied to a circuit must have targets.")) -(::Type{G})(c::Circuit, args...) where {G<:Gate} = apply_gate!(Val(n_angles(G)), IR.Control(ir_typ(G)), IR.Target(ir_typ(G)), G, c, args...) -apply_gate!(::Type{G}, c::Circuit, args...) where {G<:Gate} = apply_gate!(Val(n_angles(G)), IR.Control(ir_typ(G)), IR.Target(ir_typ(G)), G, c, args...) +(::Type{G})(c::Circuit, args...) where {G<:Gate} = apply_gate!(Val(n_angles(G)), n_controls(G), n_targets(G), G, c, args...) +(::Type{Unitary})(c::Circuit, args...) = apply_gate!(Unitary, c, args...) +apply_gate!(::Type{G}, c::Circuit, args...) where {G<:Gate} = apply_gate!(Val(n_angles(G)), n_controls(G), n_targets(G), G, c, args...) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, arg::IntOrQubit, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), arg)) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, v::VecOrQubitSet, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = (foreach(i->add_instruction!(c, Instruction{G}(G(angle), i)), v); return c) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, v::NTuple{Nq, Ti}, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N, Nq, Ti} = (foreach(i->add_instruction!(c, Instruction{G}(G(angle), i)), v); return c) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, args...) where {G<:Gate, N} = (foreach(i->add_instruction!(c, Instruction{G}(G(args[end-(N-1):end]), i)), args[1:end-N]); return c) -apply_gate!(::Val{0}, ::IR.NoControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, qs::IntOrQubit...) where {G<:Gate} = (foreach(i->add_instruction!(c, Instruction{G}(G(), i)), qs); return c) +apply_gate!(::Val{N}, ::Val{0}, ::Val{1}, ::Type{G}, c::Circuit, args...) where {G<:Gate, N} = (foreach(i->add_instruction!(c, Instruction{G}(G(args[end-(N-1):end]), i)), args[1:end-N]); return c) +apply_gate!(::Val{0}, ::Val{0}, ::Val{1}, ::Type{G}, c::Circuit, args::IntOrQubit...) where {G<:Gate} = (foreach(i->add_instruction!(c, Instruction{G}(G(), i)), args); return c) +apply_gate!(::Val{0}, ::Val{0}, ::Val{1}, ::Type{G}, c::Circuit, args::VecOrQubitSet) where {G<:Gate} = (foreach(i->add_instruction!(c, Instruction{G}(G(), i)), args); return c) +apply_gate!(::Val{N}, ::Val{0}, ::Val{1}, ::Type{G}, c::Circuit, args::VecOrQubitSet, angles::Union{Real, FreeParameter}...) where {N, G<:Gate} = (foreach(i->add_instruction!(c, Instruction{G}(G(tuple(angles[1:N]...)), i)), args); return c) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, t1::IntOrQubit, t2::IntOrQubit, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [t1, t2])) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:2])) -apply_gate!(::Val{N}, ::IR.NoControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, args::NTuple{2, Ti}, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), args[1:2])) +apply_gate!(::Val{N}, ::Val{0}, ::Val{2}, ::Type{G}, c::Circuit, t1::IntOrQubit, t2::IntOrQubit, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [t1, t2])) +apply_gate!(::Val{N}, ::Val{0}, ::Val{2}, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:2])) +apply_gate!(::Val{N}, ::Val{0}, ::Val{2}, ::Type{G}, c::Circuit, args::NTuple{2, Ti}, angle::Union{Real, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), args[1:2])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, ci::IntOrQubit, ti::IntOrQubit, angles::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angles), [ci, ti])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, args::VecOrQubitSet, angles::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angles), args[1:2])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, args::NTuple{2, Ti}, angles::Union{Float64, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angles), [args...])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{1}, ::Type{G}, c::Circuit, ci::IntOrQubit, ti::IntOrQubit, angles::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angles), [ci, ti])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{1}, ::Type{G}, c::Circuit, args::VecOrQubitSet, angles::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angles), args[1:2])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{1}, ::Type{G}, c::Circuit, args::NTuple{2, Ti}, angles::Union{Real, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angles), [args...])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, ci::IntOrQubit, t1::IntOrQubit, t2::IntOrQubit, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [ci, t1, t2])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:3])) -apply_gate!(::Val{N}, ::IR.SingleControl, ::IR.DoubleTarget, ::Type{G}, c::Circuit, args::NTuple{3, Ti}, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), [args...])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{2}, ::Type{G}, c::Circuit, ci::IntOrQubit, t1::IntOrQubit, t2::IntOrQubit, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [ci, t1, t2])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{2}, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:3])) +apply_gate!(::Val{N}, ::Val{1}, ::Val{2}, ::Type{G}, c::Circuit, args::NTuple{3, Ti}, angle::Union{Real, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), [args...])) -apply_gate!(::Val{N}, ::IR.DoubleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, c1::IntOrQubit, c2::IntOrQubit, ti::IntOrQubit, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [c1, c2, ti])) -apply_gate!(::Val{N}, ::IR.DoubleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:3])) -apply_gate!(::Val{N}, ::IR.DoubleControl, ::IR.SingleTarget, ::Type{G}, c::Circuit, args::NTuple{3, Ti}, angle::Union{Float64, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), [args...])) +apply_gate!(::Val{N}, ::Val{2}, ::Val{1}, ::Type{G}, c::Circuit, c1::IntOrQubit, c2::IntOrQubit, ti::IntOrQubit, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), [c1, c2, ti])) +apply_gate!(::Val{N}, ::Val{2}, ::Val{1}, ::Type{G}, c::Circuit, args::VecOrQubitSet, angle::Union{Real, FreeParameter}...) where {G<:Gate, N} = add_instruction!(c, Instruction{G}(G(angle), args[1:3])) +apply_gate!(::Val{N}, ::Val{2}, ::Val{1}, ::Type{G}, c::Circuit, args::NTuple{3, Ti}, angle::Union{Real, FreeParameter}...) where {G<:Gate, N, Ti} = add_instruction!(c, Instruction{G}(G(angle), [args...])) -apply_gate!(::Val{0}, ::IR.NoControl, ::IR.MultiTarget, ::Type{Unitary}, c::Circuit, v::VecOrQubitSet, m::Matrix{ComplexF64}) = add_instruction!(c, Instruction{Unitary}(Unitary(m), v)) -apply_gate!(::Val{0}, ::IR.NoControl, ::IR.MultiTarget, ::Type{Unitary}, c::Circuit, args...) = add_instruction!(c, Instruction{Unitary}(Unitary(args[end]), [args[1:end-1]...])) +apply_gate!(::Type{Unitary}, c::Circuit, v::VecOrQubitSet, m::Matrix{ComplexF64}) = add_instruction!(c, Instruction{Unitary}(Unitary(m), v)) +apply_gate!(::Type{Unitary}, c::Circuit, args...) = add_instruction!(c, Instruction{Unitary}(Unitary(args[end]), [args[1:end-1]...])) diff --git a/src/gates.jl b/src/gates.jl index 645b5a9b..0da98726 100644 --- a/src/gates.jl +++ b/src/gates.jl @@ -1,4 +1,4 @@ -export Gate, AngledGate, H, I, X, Y, Z, S, Si, T, Ti, V, Vi, CNot, Swap, ISwap, CV, CY, CZ, ECR, CCNot, CSwap, Unitary, Rx, Ry, Rz, PhaseShift, PSwap, XY, CPhaseShift, CPhaseShift00, CPhaseShift01, CPhaseShift10, XX, YY, ZZ, GPi, GPi2, MS, PRx +export Gate, AngledGate, H, I, X, Y, Z, S, Si, T, Ti, V, Vi, CNot, Swap, ISwap, CV, CY, CZ, ECR, CCNot, CSwap, Unitary, Rx, Ry, Rz, PhaseShift, PSwap, XY, CPhaseShift, CPhaseShift00, CPhaseShift01, CPhaseShift10, XX, YY, ZZ, GPi, GPi2, MS, PRx, U, GPhase """ Gate <: QuantumOperator @@ -6,7 +6,7 @@ Abstract type representing a quantum gate. """ abstract type Gate <: QuantumOperator end StructTypes.StructType(::Type{Gate}) = StructTypes.AbstractType() -StructTypes.subtypes(::Type{Gate}) = (angledgate=AngledGate, h=H, i=I, x=X, y=Y, z=Z, s=S, si=Si, t=T, ti=Ti, v=V, vi=Vi, cnot=CNot, swap=Swap, iswap=ISwap, cv=CV, cy=CY, cz=CZ, ecr=ECR, ccnot=CCNot, cswap=CSwap, unitary=Unitary, rx=Rx, ry=Ry, rz=Rz, phaseshift=PhaseShift, pswap=PSwap, xy=XY, cphaseshift=CPhaseShift, cphaseshift00=CPhaseShift00, cphaseshift01=CPhaseShift01, cphaseshift10=CPhaseShift10, xx=XX, yy=YY, zz=ZZ, gpi=GPi, gpi2=GPi2, ms=MS, prx=PRx) +StructTypes.subtypes(::Type{Gate}) = (angledgate=AngledGate, h=H, i=I, x=X, y=Y, z=Z, s=S, si=Si, t=T, ti=Ti, v=V, vi=Vi, cnot=CNot, swap=Swap, iswap=ISwap, cv=CV, cy=CY, cz=CZ, ecr=ECR, ccnot=CCNot, cswap=CSwap, unitary=Unitary, rx=Rx, ry=Ry, rz=Rz, phaseshift=PhaseShift, pswap=PSwap, xy=XY, cphaseshift=CPhaseShift, cphaseshift00=CPhaseShift00, cphaseshift01=CPhaseShift01, cphaseshift10=CPhaseShift10, xx=XX, yy=YY, zz=ZZ, gpi=GPi, gpi2=GPi2, ms=MS, prx=PRx, u=U, gphase=GPhase) """ AngledGate{NA} <: Gate @@ -20,25 +20,26 @@ n_angles(::Type{<:AngledGate{N}}) where {N} = N n_angles(g::G) where {G<:Gate} = n_angles(G) for gate_def in ( - (:Rx, :(IR.Rx), :1, :1, ("Rx(ang)",), "rx"), - (:Ry, :(IR.Ry), :1, :1, ("Ry(ang)",), "ry"), - (:Rz, :(IR.Rz), :1, :1, ("Rz(ang)",), "rz"), - (:PSwap, :(IR.PSwap), :1, :2, ("PSWAP(ang)", "PSWAP(ang)"), "pswap"), - (:PhaseShift, :(IR.PhaseShift), :1, :1, ("PHASE(ang)",), "phaseshift"), - (:CPhaseShift, :(IR.CPhaseShift), :1, :2, ("C", "PHASE(ang)"), "cphaseshift"), - (:CPhaseShift00, :(IR.CPhaseShift00), :1, :2, ("C", "PHASE00(ang)"), "cphaseshift00"), - (:CPhaseShift01, :(IR.CPhaseShift01), :1, :2, ("C", "PHASE01(ang)"), "cphaseshift01"), - (:CPhaseShift10, :(IR.CPhaseShift10), :1, :2, ("C", "PHASE10(ang)"), "cphaseshift10"), - (:XX, :(IR.XX), :1, :2, ("XX(ang)", "XX(ang)"), "xx"), - (:XY, :(IR.XY), :1, :2, ("XY(ang)", "XY(ang)"), "xy"), - (:YY, :(IR.YY), :1, :2, ("YY(ang)", "YY(ang)"), "yy"), - (:ZZ, :(IR.ZZ), :1, :2, ("ZZ(ang)", "ZZ(ang)"), "zz"), - (:GPi, :(IR.GPi), :1, :1, ("GPi(ang)",), "gpi"), - (:GPi2, :(IR.GPi2), :1, :1, ("GPi2(ang)",), "gpi2"), - (:MS, :(IR.MS), :3, :2, ("MS(ang)", "MS(ang)"), "ms"), - (:PRx, :(IR.PRx), :2, :1, ("PRx(ang)", "PRx(ang)"), "prx"), + (:Rx, :(IR.Rx), :1, :1, ("Rx(ang)",), "rx", :0, :1), + (:Ry, :(IR.Ry), :1, :1, ("Ry(ang)",), "ry", :0, :1), + (:Rz, :(IR.Rz), :1, :1, ("Rz(ang)",), "rz", :0, :1), + (:PSwap, :(IR.PSwap), :1, :2, ("PSWAP(ang)", "PSWAP(ang)"), "pswap", :0, :2), + (:PhaseShift, :(IR.PhaseShift), :1, :1, ("PHASE(ang)",), "phaseshift", :0, :1), + (:CPhaseShift, :(IR.CPhaseShift), :1, :2, ("C", "PHASE(ang)"), "cphaseshift", :1, :1), + (:CPhaseShift00, :(IR.CPhaseShift00), :1, :2, ("C", "PHASE00(ang)"), "cphaseshift00", :1, :1), + (:CPhaseShift01, :(IR.CPhaseShift01), :1, :2, ("C", "PHASE01(ang)"), "cphaseshift01", :1, :1), + (:CPhaseShift10, :(IR.CPhaseShift10), :1, :2, ("C", "PHASE10(ang)"), "cphaseshift10", :1, :1), + (:XX, :(IR.XX), :1, :2, ("XX(ang)", "XX(ang)"), "xx", :0, :2), + (:XY, :(IR.XY), :1, :2, ("XY(ang)", "XY(ang)"), "xy", :0, :2), + (:YY, :(IR.YY), :1, :2, ("YY(ang)", "YY(ang)"), "yy", :0, :2), + (:ZZ, :(IR.ZZ), :1, :2, ("ZZ(ang)", "ZZ(ang)"), "zz", :0, :2), + (:GPi, :(IR.GPi), :1, :1, ("GPi(ang)",), "gpi", :0, :1), + (:GPi2, :(IR.GPi2), :1, :1, ("GPi2(ang)",), "gpi2", :0, :1), + (:MS, :(IR.MS), :3, :2, ("MS(ang)", "MS(ang)"), "ms", :0, :2), + (:U, :(IR.UndefinedGate), :3, :1, ("U(ang)",), "U", :0, :1), + (:PRx, :(IR.UndefinedGate), :2, :1, ("PRx(ang)", "PRx(ang)"), "prx", :0, :1), ) - G, IR_G, n_angle, qc, c, lab_str = gate_def + G, IR_G, n_angle, qc, c, lab_str, n_ctrls, n_targs = gate_def @eval begin @doc """ $($G) <: AngledGate{$($n_angle)} @@ -47,41 +48,43 @@ for gate_def in ( $($G) gate. """ struct $G <: AngledGate{$n_angle} - angle::NTuple{$n_angle, Union{Float64, FreeParameter}} - $G(angle::T) where {T<:NTuple{$n_angle, Union{Float64, FreeParameter}}} = new(angle) + angle::NTuple{$n_angle, Union{Real, FreeParameter}} + $G(angle::T) where {T<:NTuple{$n_angle, Union{Real, FreeParameter}}} = new(angle) end - $G(angles::Vararg{Union{Float64, FreeParameter}}) = $G(tuple(angles...)) - $G(angles::Vararg{Number}) = $G((Float64(a) for a in angles)...) chars(::Type{$G}) = $c ir_typ(::Type{$G}) = $IR_G qubit_count(::Type{$G}) = $qc label(::Type{$G}) = $lab_str + n_controls(g::$G) = Val($n_ctrls) + n_targets(g::$G) = Val($n_targs) + n_controls(::Type{$G}) = Val($n_ctrls) + n_targets(::Type{$G}) = Val($n_targs) end end for gate_def in ( - (:H, :(IR.H), :1, ("H",), "h"), - (:I, :(IR.I), :1, ("I",), "i"), - (:X, :(IR.X), :1, ("X",), "x"), - (:Y, :(IR.Y), :1, ("Y",), "y"), - (:Z, :(IR.Z), :1, ("Z",), "z"), - (:S, :(IR.S), :1, ("S",), "s"), - (:Si, :(IR.Si), :1, ("Si",), "si"), - (:T, :(IR.T), :1, ("T",), "t"), - (:Ti, :(IR.Ti), :1, ("Ti",), "ti"), - (:V, :(IR.V), :1, ("V",), "v"), - (:Vi, :(IR.Vi), :1, ("Vi",), "vi"), - (:CNot, :(IR.CNot), :2, ("C", "X"), "cnot"), - (:Swap, :(IR.Swap), :2, ("SWAP", "SWAP"), "swap"), - (:ISwap, :(IR.ISwap), :2, ("ISWAP", "ISWAP"), "iswap"), - (:CV, :(IR.CV), :2, ("C", "V"), "cv"), - (:CY, :(IR.CY), :2, ("C", "Y"), "cy"), - (:CZ, :(IR.CZ), :2, ("C", "Z"), "cz"), - (:ECR, :(IR.ECR), :2, ("ECR", "ECR"), "ecr"), - (:CCNot, :(IR.CCNot), :3, ("C", "C", "X"), "ccnot"), - (:CSwap, :(IR.CSwap), :3, ("C", "SWAP", "SWAP"), "cswap"), + (:H, :(IR.H), :1, ("H",), "h", :0, :1), + (:I, :(IR.I), :1, ("I",), "i", :0, :1), + (:X, :(IR.X), :1, ("X",), "x", :0, :1), + (:Y, :(IR.Y), :1, ("Y",), "y", :0, :1), + (:Z, :(IR.Z), :1, ("Z",), "z", :0, :1), + (:S, :(IR.S), :1, ("S",), "s", :0, :1), + (:Si, :(IR.Si), :1, ("Si",), "si", :0, :1), + (:T, :(IR.T), :1, ("T",), "t", :0, :1), + (:Ti, :(IR.Ti), :1, ("Ti",), "ti", :0, :1), + (:V, :(IR.V), :1, ("V",), "v", :0, :1), + (:Vi, :(IR.Vi), :1, ("Vi",), "vi", :0, :1), + (:CNot, :(IR.CNot), :2, ("C", "X"), "cnot", :1, :1), + (:Swap, :(IR.Swap), :2, ("SWAP", "SWAP"), "swap", :0, :2), + (:ISwap, :(IR.ISwap), :2, ("ISWAP", "ISWAP"), "iswap", :0, :2), + (:CV, :(IR.CV), :2, ("C", "V"), "cv", :1, :1), + (:CY, :(IR.CY), :2, ("C", "Y"), "cy", :1, :1), + (:CZ, :(IR.CZ), :2, ("C", "Z"), "cz", :1, :1), + (:ECR, :(IR.ECR), :2, ("ECR", "ECR"), "ecr", :0, :2), + (:CCNot, :(IR.CCNot), :3, ("C", "C", "X"), "ccnot", :2, :1), + (:CSwap, :(IR.CSwap), :3, ("C", "SWAP", "SWAP"), "cswap", :1, :2), ) - G, IR_G, qc, c, lab_str = gate_def + G, IR_G, qc, c, lab_str, n_ctrls, n_targs = gate_def @eval begin @doc """ $($G) <: Gate @@ -94,27 +97,43 @@ for gate_def in ( ir_typ(::Type{$G}) = $IR_G qubit_count(::Type{$G}) = $qc label(::Type{$G}) = $lab_str + n_controls(g::$G) = Val($n_ctrls) + n_targets(g::$G) = Val($n_targs) + n_controls(::Type{$G}) = Val($n_ctrls) + n_targets(::Type{$G}) = Val($n_targs) end end (::Type{G})(x::Tuple{}) where {G<:Gate} = G() (::Type{G})(x::Tuple{}) where {G<:AngledGate} = throw(ArgumentError("angled gate must be constructed with at least one angle.")) (::Type{G})(x::AbstractVector) where {G<:AngledGate} = G(x...) -(::Type{G})(x::T) where {G<:AngledGate{1}, T<:Union{Float64, FreeParameter}} = G((x,)) +(::Type{G})(angle::T) where {G<:AngledGate{1}, T<:Union{Real, FreeParameter}} = G((angle,)) +(::Type{G})(angle1::T1, angle2::T2) where {T1<:Union{Real, FreeParameter}, T2<:Union{Real, FreeParameter}, G<:AngledGate{2}} = G((angle1, angle2,)) +(::Type{G})(angle1::T1, angle2::T2, angle3::T3) where {T1<:Union{Real, FreeParameter}, T2<:Union{Real, FreeParameter}, T3<:Union{Real, FreeParameter}, G<:AngledGate{3}} = G((angle1, angle2, angle3,)) qubit_count(g::G) where {G<:Gate} = qubit_count(G) angles(g::G) where {G<:Gate} = () angles(g::AngledGate{N}) where {N} = g.angle chars(g::G) where {G<:Gate} = map(char->replace(string(char), "ang"=>join(string.(angles(g)), ", ")), chars(G)) ir_typ(g::G) where {G<:Gate} = ir_typ(G) -label(g::G) where {G<:Gate} = label(G) +label(g::G) where {G<:Gate} = label(G) ir_str(g::G) where {G<:AngledGate} = label(g) * "(" * join(string.(angles(g)), ", ") * ")" ir_str(g::G) where {G<:Gate} = label(g) -targets_and_controls(g::G, target::QubitSet) where {G<:Gate} = IR._generate_control_and_target(IR.ControlAndTarget(ir_typ(g))..., target) +targets_and_controls(g::G, target::QubitSet) where {G<:Gate} = targets_and_controls(n_controls(g), n_targets(g), target) +targets_and_controls(::Val{0}, ::Val{1}, target::QubitSet) = ((), target[1]) +targets_and_controls(::Val{0}, ::Val{N}, target::QubitSet) where {N} = ((), collect(target)) +targets_and_controls(::Val{1}, ::Val{1}, target::QubitSet) = (target[1], target[2]) +targets_and_controls(::Val{1}, ::Val{N}, target::QubitSet) where {N} = (target[1], target[2:end]) +targets_and_controls(::Val{NC}, ::Val{1}, target::QubitSet) where {NC} = (target[1:NC], target[NC+1]) +targets_and_controls(::Val{NC}, ::Val{NT}, target::QubitSet) where {NC, NT} = (target[1:NC], target[NC+1:NC+NT]) function ir(g::G, target::QubitSet, ::Val{:JAQCD}; kwargs...) where {G<:Gate} t_c = targets_and_controls(g, target) - return ir_typ(g)(angles(g)..., t_c..., label(g)) + if isempty(t_c[1]) + return ir_typ(g)(angles(g)..., t_c[2], label(g)) + else + return ir_typ(g)(angles(g)..., t_c[1], t_c[2], label(g)) + end end function ir(g::G, target::QubitSet, ::Val{:OpenQASM}; serialization_properties=OpenQASMSerializationProperties()) where {G<:Gate} - t = format_qubits(targets_and_controls(g, target), serialization_properties) + t = format_qubits(target, serialization_properties) ir_string = ir_str(g) * " " * t if occursin("#pragma", ir_string) return ir_string @@ -138,23 +157,43 @@ qubit_count(g::Unitary) = convert(Int, log2(size(g.matrix, 1))) chars(g::Unitary) = ntuple(i->"U", qubit_count(g)) ir_typ(::Type{Unitary}) = IR.Unitary label(::Type{Unitary}) = "unitary" +n_targets(g::Unitary) = qubit_count(g) +n_controls(g::Unitary) = 0 -targets_and_controls(g::Unitary, target::QubitSet) = target[1:convert(Int, log2(size(g.matrix, 1)))] ir_str(g::Unitary) = "#pragma braket unitary(" * format_matrix(g.matrix) * ")" function ir(g::Unitary, target::QubitSet, ::Val{:JAQCD}; kwargs...) - t_c = targets_and_controls(g, target) mat = complex_matrix_to_ir(g.matrix) - return IR.Unitary(t_c, mat, "unitary") + return IR.Unitary(collect(target), mat, "unitary") +end + +""" + GPhase <: Gate + GPhase(ϕ::Union{Real, FreeParameter}) -> GPhase + +Global phase gate. +""" +struct GPhase <: Gate + angle::NTuple{1, Union{Real, FreeParameter}} + GPhase(angle::T) where {T<:NTuple{1, Union{Real, FreeParameter}}} = new(angle) end +Base.:(==)(g1::GPhase, g2::GPhase) = g1.angle == g2.angle +qubit_count(g::GPhase) = 0 +chars(g::GPhase) = ("gphase(ang)",) +ir_typ(::Type{GPhase}) = IR.UndefinedGate +label(::Type{GPhase}) = "gphase" +n_targets(g::GPhase) = 0 +n_controls(g::GPhase) = 0 +ir(g::GPhase, target::QubitSet, ::Val{:JAQCD}; kwargs...) = throw(MethodError(ir, (g, target, Val(:JAQCD)))) +targets_and_controls(g::GPhase, target::QubitSet) = ((), tuple(target...)) StructTypes.StructType(::Type{<:Gate}) = StructTypes.Struct() Parametrizable(g::AngledGate) = Parametrized() Parametrizable(g::Gate) = NonParametrized() parameters(g::AngledGate) = collect(filter(a->a isa FreeParameter, angles(g))) parameters(g::Gate) = FreeParameter[] -bind_value!(g::G, params::Dict{Symbol, Number}) where {G<:Gate} = bind_value!(Parametrizable(g), g, params) -bind_value!(::NonParametrized, g::G, params::Dict{Symbol, Number}) where {G<:Gate} = g -function bind_value!(::Parametrized, g::G, params::Dict{Symbol, Number}) where {G<:AngledGate} +bind_value!(g::G, params::Dict{Symbol, <:Number}) where {G<:Gate} = bind_value!(Parametrizable(g), g, params) +bind_value!(::NonParametrized, g::G, params::Dict{Symbol, <:Number}) where {G<:Gate} = g +function bind_value!(::Parametrized, g::G, params::Dict{Symbol, <:Number}) where {G<:AngledGate} new_angles = map(angles(g)) do angle angle isa FreeParameter || return angle return get(params, angle.name, angle) diff --git a/src/local_simulator.jl b/src/local_simulator.jl index 2bd4e5ae..245e9ce3 100644 --- a/src/local_simulator.jl +++ b/src/local_simulator.jl @@ -96,9 +96,8 @@ function simulate(d::LocalSimulator, task_specs::Vector{T}, args...; shots::Int= if is_single_input if is_single_task inputs = inputs isa Vector ? first(inputs) : inputs - results = [d(task_specs[1], args...; shots=shots, inputs=inputs, kwargs...)] - - return LocalQuantumTaskBatch([local_result.result.task_metadata.id for local_result in results], results) + local_task = d(task_specs[1], args...; shots=shots, inputs=inputs, kwargs...) + return LocalQuantumTaskBatch([local_task.result.task_metadata.id], [local_task.result]) elseif inputs isa Dict{String, Float64} inputs = [deepcopy(inputs) for ix in 1:length(task_specs)] else diff --git a/src/noise_applicators.jl b/src/noise_applicators.jl index 1c94d5d0..99bf5e03 100644 --- a/src/noise_applicators.jl +++ b/src/noise_applicators.jl @@ -1,16 +1,18 @@ -for (N, IRN) in zip((:Kraus, :BitFlip, :PhaseFlip, :PauliChannel, :AmplitudeDamping, :PhaseDamping, :Depolarizing, :TwoQubitDephasing, :TwoQubitDepolarizing, :GeneralizedAmplitudeDamping), (:(IR.Kraus), :(IR.BitFlip), :(IR.PhaseFlip), :(IR.PauliChannel), :(IR.AmplitudeDamping), :(IR.PhaseDamping), :(IR.Depolarizing), :(IR.TwoQubitDephasing), :(IR.TwoQubitDepolarizing), :(IR.GeneralizedAmplitudeDamping))) - @eval begin - $N(c::Circuit, args...) = apply_noise!(IR.Target($IRN), IR.ProbabilityCount($IRN), $N, c, args...) - apply_noise!(::Type{$N}, c::Circuit, args...) = apply_noise!(IR.Target($IRN), IR.ProbabilityCount($IRN), $N, c, args...) - end +for N in (:Kraus, :BitFlip, :PhaseFlip, :PauliChannel, :AmplitudeDamping, :PhaseDamping, :Depolarizing, :TwoQubitDephasing, :TwoQubitDepolarizing, :GeneralizedAmplitudeDamping, :MultiQubitPauliChannel) + @eval $N(c::Circuit) = throw(ArgumentError("noise applied to a circuit must have targets and arguments.")) end -apply_noise!(::IR.SingleTarget, ::IR.SingleProbability, ::Type{N}, c::Circuit, arg::IntOrQubit, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), arg)) -apply_noise!(::IR.SingleTarget, ::IR.DoubleProbability, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b), arg)) -apply_noise!(::IR.SingleTarget, ::IR.TripleProbability, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64, prob_c::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b, prob_c), arg)) -apply_noise!(::IR.SingleTarget, ::IR.DoubleProbability, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg)) -apply_noise!(::IR.SingleTarget, ::IR.TripleProbability, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg)) -apply_noise!(::IR.SingleTarget, ::IR.ProbabilityCount, ::Type{N}, c::Circuit, probs::Vector{Float64}) where {N<:Noise} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c) -apply_noise!(::IR.SingleTarget, ::IR.ProbabilityCount, ::Type{N}, c::Circuit, probs::Vararg{Float64}) where {N<:Noise} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c) -apply_noise!(::IR.DoubleTarget, ::IR.SingleProbability, ::Type{N}, c::Circuit, targ_a::IntOrQubit, targ_b::Int, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), [targ_a, targ_b])) -apply_noise!(::IR.DoubleTarget, ::IR.SingleProbability, ::Type{N}, c::Circuit, args...) where {N<:Noise} = add_instruction!(c, Instruction(N(args[end]), args[1:end-1])) -apply_noise!(::IR.MultiTarget, ::IR.MultiProbability, ::Type{N}, c::Circuit, args...) where {N<:Noise} = add_instruction!(c, Instruction(N(args[end]), args[1:end-1])) +MultiQubitPauliChannel{N}(c::Circuit) where {N} = throw(ArgumentError("noise applied to a circuit must have targets and arguments.")) +(::Type{N})(c::Circuit, args...) where {N<:Noise} = apply_noise!(n_targets(N), n_probabilities(N), N, c, args...) +apply_noise!(::Type{N}, c::Circuit, args...) where {N<:Noise} = apply_noise!(n_targets(N), n_probabilities(N), N, c, args...) +Kraus(c::Circuit, args...) = apply_noise!(Kraus, c, args...) + +apply_noise!(::Val{1}, ::Val{1}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), arg)) +apply_noise!(::Val{1}, ::Val{2}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b), arg)) +apply_noise!(::Val{1}, ::Val{3}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64, prob_c::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b, prob_c), arg)) +apply_noise!(::Val{1}, ::Val{2}, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg)) +apply_noise!(::Val{1}, ::Val{3}, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg)) +apply_noise!(::Val{1}, ::Val{NP}, ::Type{N}, c::Circuit, probs::Vector{Float64}) where {N<:Noise, NP} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c) +apply_noise!(::Val{1}, ::Val{NP}, ::Type{N}, c::Circuit, probs::Vararg{Float64}) where {N<:Noise, NP} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c) +apply_noise!(::Val{2}, ::Val{1}, ::Type{N}, c::Circuit, targ_a::IntOrQubit, targ_b::Int, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), [targ_a, targ_b])) +apply_noise!(::Val{2}, ::Val{1}, ::Type{N}, c::Circuit, args...) where {N<:Noise} = add_instruction!(c, Instruction(N(args[end]), args[1:end-1])) +apply_noise!(::Type{Kraus}, c::Circuit, args...) = add_instruction!(c, Instruction(Kraus(args[end]), args[1:end-1])) diff --git a/src/noises.jl b/src/noises.jl index ca86ce22..17f9a2d7 100644 --- a/src/noises.jl +++ b/src/noises.jl @@ -8,6 +8,8 @@ abstract type Noise <: QuantumOperator end StructTypes.StructType(::Type{Noise}) = StructTypes.AbstractType() StructTypes.subtypes(::Type{Noise}) = (noise=Noise, kraus=Kraus, bit_flip=BitFlip, phase_flip=PhaseFlip, pauli_channel=PauliChannel, amplitude_damping=AmplitudeDamping, phase_damping=PhaseDamping, depolarizing=Depolarizing, two_qubit_dephasing=TwoQubitDephasing, two_qubit_depolarizing=TwoQubitDepolarizing, generalized_amplitude_damping=GeneralizedAmplitudeDamping, multi_qubit_pauli_channel=MultiQubitPauliChannel) +const ProbabilityType = Union{Float64, FreeParameter} + """ Kraus <: Noise @@ -16,17 +18,11 @@ Kraus noise operation. struct Kraus <: Noise matrices::Vector{Matrix{ComplexF64}} end - Kraus(mats::Vector{Vector{Vector{Vector{Float64}}}}) = Kraus(complex_matrix_from_ir.(mats)) Base.:(==)(k1::Kraus, k2::Kraus) = k1.matrices == k2.matrices -function ir(g::Kraus, target::QubitSet, ::Val{:JAQCD}; kwargs...) - mats = complex_matrix_to_ir.(g.matrices) - t_c = collect(target[1:convert(Int, log2(size(g.matrices[1], 1)))]) - return IR.Kraus(t_c, mats, "kraus") -end +ir(g::Kraus, target::QubitSet, ::Val{:JAQCD}; kwargs...) = IR.Kraus(collect(target), [complex_matrix_to_ir(mat) for mat in g.matrices], "kraus") function ir(g::Kraus, target::QubitSet, ::Val{:OpenQASM}; serialization_properties::SerializationProperties=OpenQASMSerializationProperties()) - t_c = target[1:convert(Int, log2(size(g.matrices[1], 1)))] - t = format_qubits(t_c, serialization_properties) + t = format_qubits(collect(target), serialization_properties) ms = join(format_matrix.(g.matrices), ", ") return "#pragma braket noise kraus($ms) $t" end @@ -39,12 +35,15 @@ chars(n::Kraus) = ntuple(i->"KR", qubit_count(n)) BitFlip noise operation. """ struct BitFlip <: Noise - probability::Union{Float64, FreeParameter} + probability::ProbabilityType end - Parametrizable(g::BitFlip) = Parametrized() +n_targets(g::BitFlip) = Val(1) +n_targets(::Type{BitFlip}) = Val(1) qubit_count(g::BitFlip) = 1 chars(n::BitFlip) = map(char->replace(string(char), "prob"=>string(n.probability)), ("BF(prob)",)) +n_probabilities(::BitFlip) = Val(1) +n_probabilities(::Type{BitFlip}) = Val(1) """ PhaseFlip <: Noise @@ -52,12 +51,15 @@ chars(n::BitFlip) = map(char->replace(string(char), "prob"=>string(n.probability PhaseFlip noise operation. """ struct PhaseFlip <: Noise - probability::Union{Float64, FreeParameter} + probability::ProbabilityType end - Parametrizable(g::PhaseFlip) = Parametrized() qubit_count(g::PhaseFlip) = 1 chars(n::PhaseFlip) = map(char->replace(string(char), "prob"=>string(n.probability)), ("PF(prob)",)) +n_targets(g::PhaseFlip) = Val(1) +n_targets(::Type{PhaseFlip}) = Val(1) +n_probabilities(::PhaseFlip) = Val(1) +n_probabilities(::Type{PhaseFlip}) = Val(1) """ PauliChannel <: Noise @@ -65,11 +67,15 @@ chars(n::PhaseFlip) = map(char->replace(string(char), "prob"=>string(n.probabili PauliChannel noise operation. """ struct PauliChannel <: Noise - probX::Union{Float64, FreeParameter} - probY::Union{Float64, FreeParameter} - probZ::Union{Float64, FreeParameter} -end - + probX::ProbabilityType + probY::ProbabilityType + probZ::ProbabilityType + PauliChannel(probX::TX, probY::TY, probZ::TZ) where {TX<:ProbabilityType, TY<:ProbabilityType, TZ<:ProbabilityType} = new(probX, probY, probZ) +end +n_targets(g::PauliChannel) = Val(1) +n_targets(::Type{PauliChannel}) = Val(1) +n_probabilities(::PauliChannel) = Val(3) +n_probabilities(::Type{PauliChannel}) = Val(3) Parametrizable(g::PauliChannel) = Parametrized() qubit_count(g::PauliChannel) = 1 chars(n::PauliChannel) = map(char->replace(string(char), "prob"=>join([string(n.probX), string(n.probY), string(n.probX)], ", ")), ("PC(prob)",)) @@ -80,9 +86,12 @@ chars(n::PauliChannel) = map(char->replace(string(char), "prob"=>join([string(n. AmplitudeDamping noise operation. """ struct AmplitudeDamping <: Noise - gamma::Union{Float64, FreeParameter} + gamma::ProbabilityType end - +n_targets(g::AmplitudeDamping) = Val(1) +n_targets(::Type{AmplitudeDamping}) = Val(1) +n_probabilities(::AmplitudeDamping) = Val(1) +n_probabilities(::Type{AmplitudeDamping}) = Val(1) Parametrizable(g::AmplitudeDamping) = Parametrized() qubit_count(g::AmplitudeDamping) = 1 chars(n::AmplitudeDamping) = map(char->replace(string(char), "prob"=>string(n.gamma)), ("AD(prob)",)) @@ -93,9 +102,12 @@ chars(n::AmplitudeDamping) = map(char->replace(string(char), "prob"=>string(n.ga PhaseDamping noise operation. """ struct PhaseDamping <: Noise - gamma::Union{Float64, FreeParameter} + gamma::ProbabilityType end - +n_targets(g::PhaseDamping) = Val(1) +n_targets(::Type{PhaseDamping}) = Val(1) +n_probabilities(::PhaseDamping) = Val(1) +n_probabilities(::Type{PhaseDamping}) = Val(1) Parametrizable(g::PhaseDamping) = Parametrized() qubit_count(g::PhaseDamping) = 1 chars(n::PhaseDamping) = map(char->replace(string(char), "prob"=>string(n.gamma)), ("PD(prob)",)) @@ -106,9 +118,12 @@ chars(n::PhaseDamping) = map(char->replace(string(char), "prob"=>string(n.gamma) Depolarizing noise operation. """ struct Depolarizing <: Noise - probability::Union{Float64, FreeParameter} + probability::ProbabilityType end - +n_targets(g::Depolarizing) = Val(1) +n_targets(::Type{Depolarizing}) = Val(1) +n_probabilities(::Depolarizing) = Val(1) +n_probabilities(::Type{Depolarizing}) = Val(1) Parametrizable(g::Depolarizing) = Parametrized() qubit_count(g::Depolarizing) = 1 chars(n::Depolarizing) = map(char->replace(string(char), "prob"=>string(n.probability)), ("DEPO(prob)",)) @@ -119,9 +134,12 @@ chars(n::Depolarizing) = map(char->replace(string(char), "prob"=>string(n.probab TwoQubitDephasing noise operation. """ struct TwoQubitDephasing <: Noise - probability::Union{Float64, FreeParameter} + probability::ProbabilityType end - +n_targets(g::TwoQubitDephasing) = Val(2) +n_targets(::Type{TwoQubitDephasing}) = Val(2) +n_probabilities(::TwoQubitDephasing) = Val(1) +n_probabilities(::Type{TwoQubitDephasing}) = Val(1) Parametrizable(g::TwoQubitDephasing) = Parametrized() qubit_count(g::TwoQubitDephasing) = 2 chars(n::TwoQubitDephasing) = map(char->replace(string(char), "prob"=>string(n.probability)), ("DEPH(prob)", "DEPH(prob)")) @@ -132,9 +150,12 @@ chars(n::TwoQubitDephasing) = map(char->replace(string(char), "prob"=>string(n.p TwoQubitDepolarizing noise operation. """ struct TwoQubitDepolarizing <: Noise - probability::Union{Float64, FreeParameter} + probability::ProbabilityType end - +n_targets(g::TwoQubitDepolarizing) = Val(2) +n_targets(::Type{TwoQubitDepolarizing}) = Val(2) +n_probabilities(::TwoQubitDepolarizing) = Val(1) +n_probabilities(::Type{TwoQubitDepolarizing}) = Val(1) Parametrizable(g::TwoQubitDepolarizing) = Parametrized() qubit_count(g::TwoQubitDepolarizing) = 2 chars(n::TwoQubitDepolarizing) = map(char->replace(string(char), "prob"=>string(n.probability)), ("DEPO(prob)", "DEPO(prob)")) @@ -145,10 +166,14 @@ chars(n::TwoQubitDepolarizing) = map(char->replace(string(char), "prob"=>string( GeneralizedAmplitudeDamping noise operation. """ struct GeneralizedAmplitudeDamping <: Noise - probability::Union{Float64, FreeParameter} - gamma::Union{Float64, FreeParameter} -end - + probability::ProbabilityType + gamma::ProbabilityType + GeneralizedAmplitudeDamping(probability::TP, gamma::TG) where {TP<:ProbabilityType, TG<:ProbabilityType} = new(probability, gamma) +end +n_targets(g::GeneralizedAmplitudeDamping) = Val(1) +n_targets(::Type{GeneralizedAmplitudeDamping}) = Val(1) +n_probabilities(::GeneralizedAmplitudeDamping) = Val(2) +n_probabilities(::Type{GeneralizedAmplitudeDamping}) = Val(2) Parametrizable(g::GeneralizedAmplitudeDamping) = Parametrized() qubit_count(g::GeneralizedAmplitudeDamping) = 1 chars(n::GeneralizedAmplitudeDamping) = map(char->replace(string(char), "prob"=>join([string(n.gamma), string(n.probability)], ", ")), ("GAD(prob)",)) @@ -169,26 +194,24 @@ Pauli channel noise operation on two qubits. TwoQubitPauliChannel = MultiQubitPauliChannel{2} qubit_count(g::MultiQubitPauliChannel{N}) where {N} = N Parametrizable(g::MultiQubitPauliChannel) = Parametrized() -function ir(g::MultiQubitPauliChannel{N}, target::QubitSet, ::Val{:JAQCD}; kwargs...) where {N} - t_c = collect(target[1:N]) - return IR.MultiQubitPauliChannel(g.probabilities, t_c, "multi_qubit_pauli_channel") -end +ir(g::MultiQubitPauliChannel{N}, target::QubitSet, ::Val{:JAQCD}; kwargs...) where {N} = IR.MultiQubitPauliChannel(g.probabilities, collect(target), "multi_qubit_pauli_channel") function MultiQubitPauliChannel(probabilities::Dict{String, <:Union{Float64, FreeParameter}}) N = length(first(keys(probabilities))) return MultiQubitPauliChannel{N}(probabilities) end Base.:(==)(c1::MultiQubitPauliChannel{N}, c2::MultiQubitPauliChannel{M}) where {N,M} = N == M && c1.probabilities == c2.probabilities chars(n::TwoQubitPauliChannel) = ("PC2", "PC2") +n_controls(n::Noise) = Val(0) +targets_and_controls(n::N, target::QubitSet) where {N<:Noise} = targets_and_controls(n_controls(n), n_targets(n), target) for (N, IRN, label) in zip((:BitFlip, :PhaseFlip, :PauliChannel, :AmplitudeDamping, :PhaseDamping, :Depolarizing, :TwoQubitDephasing, :TwoQubitDepolarizing, :GeneralizedAmplitudeDamping), (:(IR.BitFlip), :(IR.PhaseFlip), :(IR.PauliChannel), :(IR.AmplitudeDamping), :(IR.PhaseDamping), :(IR.Depolarizing), :(IR.TwoQubitDephasing), :(IR.TwoQubitDepolarizing), :(IR.GeneralizedAmplitudeDamping)), ("bit_flip", "phase_flip", "pauli_channel", "amplitude_damping", "phase_damping", "depolarizing", "two_qubit_dephasing", "two_qubit_depolarizing", "generalized_amplitude_damping")) @eval begin function ir(n::$N, target::QubitSet, ::Val{:JAQCD}; kwargs...) - t_c = IR._generate_control_and_target(IR.ControlAndTarget($IRN)..., target) + t_c = targets_and_controls(n, target) ir_args = (getproperty(n, fn) for fn in fieldnames($N)) - return $IRN(ir_args..., t_c..., $label) + return $IRN(ir_args..., t_c[2], $label) end function ir(n::$N, target::QubitSet, ::Val{:OpenQASM}; serialization_properties=OpenQASMSerializationProperties()) - t_c = IR._generate_control_and_target(IR.ControlAndTarget($IRN)..., target) - t = format_qubits(t_c, serialization_properties) + t = format_qubits(target, serialization_properties) ir_args = join([repr(getproperty(n, fn)) for fn in fieldnames($N)], ", ") return "#pragma braket noise " * $label * "($ir_args) $t" end diff --git a/src/raw_schema.jl b/src/raw_schema.jl index 0d31a0d2..d9f48bba 100644 --- a/src/raw_schema.jl +++ b/src/raw_schema.jl @@ -168,7 +168,7 @@ export Program, AHSProgram, AbstractIR, AbstractProgramResult, CompilerDirective abstract type AbstractIR end StructTypes.StructType(::Type{AbstractIR}) = StructTypes.AbstractType() -StructTypes.subtypes(::Type{AbstractIR}) = (z=Z, sample=Sample, cphaseshift01=CPhaseShift01, phase_damping=PhaseDamping, rz=Rz, generalized_amplitude_damping=GeneralizedAmplitudeDamping, xx=XX, zz=ZZ, phase_flip=PhaseFlip, vi=Vi, depolarizing=Depolarizing, variance=Variance, two_qubit_depolarizing=TwoQubitDepolarizing, densitymatrix=DensityMatrix, cphaseshift00=CPhaseShift00, ecr=ECR, ccnot=CCNot, unitary=Unitary, bit_flip=BitFlip, y=Y, swap=Swap, cz=CZ, cnot=CNot, adjoint_gradient=AdjointGradient, cswap=CSwap, ry=Ry, i=I, si=Si, amplitude_damping=AmplitudeDamping, statevector=StateVector, iswap=ISwap, h=H, xy=XY, yy=YY, t=T, ahsprogram=AHSProgram, two_qubit_dephasing=TwoQubitDephasing, x=X, ti=Ti, cv=CV, pauli_channel=PauliChannel, pswap=PSwap, expectation=Expectation, probability=Probability, phaseshift=PhaseShift, v=V, cphaseshift=CPhaseShift, s=S, rx=Rx, kraus=Kraus, amplitude=Amplitude, cphaseshift10=CPhaseShift10, multi_qubit_pauli_channel=MultiQubitPauliChannel, cy=CY, ms=MS, gpi=GPi, gpi2=GPi2, prx=PRx) +StructTypes.subtypes(::Type{AbstractIR}) = (z=Z, sample=Sample, cphaseshift01=CPhaseShift01, phase_damping=PhaseDamping, rz=Rz, generalized_amplitude_damping=GeneralizedAmplitudeDamping, xx=XX, zz=ZZ, phase_flip=PhaseFlip, vi=Vi, depolarizing=Depolarizing, variance=Variance, two_qubit_depolarizing=TwoQubitDepolarizing, densitymatrix=DensityMatrix, cphaseshift00=CPhaseShift00, ecr=ECR, ccnot=CCNot, unitary=Unitary, bit_flip=BitFlip, y=Y, swap=Swap, cz=CZ, cnot=CNot, adjoint_gradient=AdjointGradient, cswap=CSwap, ry=Ry, i=I, si=Si, amplitude_damping=AmplitudeDamping, statevector=StateVector, iswap=ISwap, h=H, xy=XY, yy=YY, t=T, ahsprogram=AHSProgram, two_qubit_dephasing=TwoQubitDephasing, x=X, ti=Ti, cv=CV, pauli_channel=PauliChannel, pswap=PSwap, expectation=Expectation, probability=Probability, phaseshift=PhaseShift, v=V, cphaseshift=CPhaseShift, s=S, rx=Rx, kraus=Kraus, amplitude=Amplitude, cphaseshift10=CPhaseShift10, multi_qubit_pauli_channel=MultiQubitPauliChannel, cy=CY, undefinedgate=UndefinedGate) const IRObservable = Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} Base.convert(::Type{IRObservable}, v::Vector{String}) = convert(Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, v) @@ -320,14 +320,6 @@ end StructTypes.StructType(::Type{PSwap}) = StructTypes.UnorderedStruct() StructTypes.defaults(::Type{PSwap}) = Dict{Symbol, Any}(:type => "pswap") -struct GPi <: AbstractIR - angle::Float64 - target::Vector{Int} - type::String -end -StructTypes.StructType(::Type{GPi}) = StructTypes.UnorderedStruct() -StructTypes.defaults(::Type{GPi}) = Dict{Symbol, Any}(:type => "gpi") - struct AmplitudeDamping <: AbstractIR gamma::Float64 target::Int @@ -352,14 +344,6 @@ end StructTypes.StructType(::Type{Expectation}) = StructTypes.UnorderedStruct() StructTypes.defaults(::Type{Expectation}) = Dict{Symbol, Any}(:type => "expectation") -struct GPi2 <: AbstractIR - angle::Float64 - target::Vector{Int} - type::String -end -StructTypes.StructType(::Type{GPi2}) = StructTypes.UnorderedStruct() -StructTypes.defaults(::Type{GPi2}) = Dict{Symbol, Any}(:type => "gpi2") - struct BitFlip <: AbstractIR probability::Float64 target::Int @@ -469,25 +453,14 @@ end StructTypes.StructType(::Type{GeneralizedAmplitudeDamping}) = StructTypes.UnorderedStruct() StructTypes.defaults(::Type{GeneralizedAmplitudeDamping}) = Dict{Symbol, Any}(:type => "generalized_amplitude_damping") -struct MS <: AbstractIR - angle1::Float64 - angle2::Float64 - angle3::Float64 +struct UndefinedGate <: AbstractIR + angles + controls::Vector{Int} targets::Vector{Int} type::String end -StructTypes.StructType(::Type{MS}) = StructTypes.UnorderedStruct() -StructTypes.defaults(::Type{MS}) = Dict{Symbol, Any}(:type => "ms") - -struct PRx <: AbstractIR - angle1::Float64 - angle2::Float64 - target::Int - type::String -end -StructTypes.StructType(::Type{PRx}) = StructTypes.UnorderedStruct() -StructTypes.defaults(::Type{PRx}) = Dict{Symbol, Any}(:type => "prx") - +StructTypes.StructType(::Type{UndefinedGate}) = StructTypes.UnorderedStruct() +StructTypes.defaults(::Type{UndefinedGate}) = Dict{Symbol, Any}(:type => "undefined_gate") struct ECR <: AbstractIR targets::Vector{Int} @@ -706,109 +679,6 @@ end StructTypes.StructType(::Type{Variance}) = StructTypes.UnorderedStruct() StructTypes.defaults(::Type{Variance}) = Dict{Symbol, Any}(:type => "variance") - - -abstract type Control end -struct SingleControl <: Control end -for g in [:CPhaseShift, :CPhaseShift00, :CPhaseShift01, :CPhaseShift10, :CNot, :CV, :CY, :CZ, :CSwap] - @eval begin - Control(::Type{$g}) = SingleControl() - end -end -struct DoubleControl <: Control end -for g in [:CCNot] - @eval begin - Control(::Type{$g}) = DoubleControl() - end -end -struct NoControl <: Control end -Control(::Type{G}) where {G<:AbstractIR} = NoControl() -abstract type Target end -struct DoubleTarget <: Target end -for g in [:Swap, :CSwap, :ISwap, :PSwap, :XY, :ECR, :XX, :YY, :ZZ, :TwoQubitDepolarizing, :TwoQubitDephasing, :MS] - @eval begin - Target(::Type{$g}) = DoubleTarget() - end -end -struct SingleTarget <: Target end -for g in [:H, :I, :X, :Y, :Z, :Rx, :Ry, :Rz, :S, :T, :Si, :Ti, :PhaseShift, :CPhaseShift, :CPhaseShift00, :CPhaseShift01, :CPhaseShift10, :CNot, :CCNot, :CV, :CY, :CZ, :V, :Vi, :BitFlip, :PhaseFlip, :PauliChannel, :Depolarizing, :AmplitudeDamping, :GeneralizedAmplitudeDamping, :PhaseDamping, :GPi, :GPi2, :PRx] - @eval begin - Target(::Type{$g}) = SingleTarget() - end -end -struct OptionalNestedMultiTarget <: Target end -for g in [:AdjointGradient] - @eval begin - Target(::Type{$g}) = OptionalNestedMultiTarget() - end -end -struct OptionalMultiTarget <: Target end -for g in [:Expectation, :Sample, :Variance, :DensityMatrix, :Probability] - @eval begin - Target(::Type{$g}) = OptionalMultiTarget() - end -end -struct MultiTarget <: Target end -for g in [:Unitary, :MultiQubitPauliChannel, :Kraus] - @eval begin - Target(::Type{$g}) = MultiTarget() - end -end -abstract type Angle end -struct Angled <: Angle end -for g in [:Rx, :Ry, :Rz, :PhaseShift, :CPhaseShift, :CPhaseShift00, :CPhaseShift01, :CPhaseShift10, :PSwap, :XY, :XX, :YY, :ZZ, :GPi, :GPi2] - @eval begin - Angle(::Type{$g}) = Angled() - end -end -struct DoubleAngled <: Angle end -for g in [:PRx] - @eval begin - Angle(::Type{$g}) = DoubleAngled() - end -end -struct TripleAngled <: Angle end -for g in [:MS] - @eval begin - Angle(::Type{$g}) = TripleAngled() - end -end -struct NonAngled <: Angle end -Angle(::Type{G}) where {G<:AbstractIR} = NonAngled() -abstract type ProbabilityCount end -struct TripleProbability <: ProbabilityCount end -for g in [:PauliChannel] - @eval begin - ProbabilityCount(::Type{$g}) = TripleProbability() - end -end -struct MultiProbability <: ProbabilityCount end -for g in [:MultiQubitPauliChannel, :Kraus] - @eval begin - ProbabilityCount(::Type{$g}) = MultiProbability() - end -end -struct DoubleProbability <: ProbabilityCount end -for g in [:GeneralizedAmplitudeDamping] - @eval begin - ProbabilityCount(::Type{$g}) = DoubleProbability() - end -end -struct SingleProbability <: ProbabilityCount end -for g in [:BitFlip, :PhaseFlip, :Depolarizing, :TwoQubitDephasing, :TwoQubitDepolarizing, :AmplitudeDamping] - @eval begin - ProbabilityCount(::Type{$g}) = SingleProbability() - end -end -ControlAndTarget(T) = (Control(T), Target(T)) -_generate_control_and_target(::NoControl, ::SingleTarget, q) = q[1] -_generate_control_and_target(::NoControl, ::DoubleTarget, q) = ([q[1], q[2]],) -_generate_control_and_target(::NoControl, ::MultiTarget, q) = (q,) -_generate_control_and_target(::SingleControl, ::SingleTarget, q) = (q[1], q[2]) -_generate_control_and_target(::SingleControl, ::DoubleTarget, q) = (q[1], [q[2], q[3]]) -_generate_control_and_target(::DoubleControl, ::SingleTarget, q) = ([q[1], q[2]], q[3]) - - Base.:(==)(o1::T, o2::T) where {T<:AbstractIR} = all(getproperty(o1, fn) == getproperty(o2, fn) for fn in fieldnames(T)) end # module diff --git a/src/schemas.jl b/src/schemas.jl index f1eb17c5..d5a0fc7a 100644 --- a/src/schemas.jl +++ b/src/schemas.jl @@ -35,10 +35,10 @@ StructTypes.lower(x::Instruction{O}) where {O<:Operator} = isempty(x.target) ? i ir(x::Instruction{O}, ::Val{:OpenQASM}; kwargs...) where {O<:Operator} = isempty(x.target) ? ir(x.operator, Val(:OpenQASM); kwargs...) : ir(x.operator, x.target, Val(:OpenQASM); kwargs...) conc_types = filter(Base.isconcretetype, vcat(subtypes(AbstractIR), subtypes(CompilerDirective))) -nt_dict = merge([Dict(zip(fieldnames(t), (Union{Nothing, x} for x in fieldtypes(t)))) for t in conc_types]...) -ks = tuple(:angles, keys(nt_dict)...) -vs = Tuple{Union{Nothing, Vector{Float64}}, values(nt_dict)...} -inst_typ = NamedTuple{ks, vs} +nt_dict = merge([Dict(zip(fieldnames(t), (Union{Nothing, x} for x in fieldtypes(t)))) for t in conc_types]...) +ks = tuple(keys(nt_dict)...) +vs = Tuple{values(nt_dict)...} +inst_typ = NamedTuple{ks, vs} StructTypes.lowertype(::Type{Instruction{O}}) where {O} = inst_typ StructTypes.lowertype(::Type{Instruction}) = inst_typ Instruction(x::Instruction{O}) where {O<:Braket.Operator} = x diff --git a/test/gates.jl b/test/gates.jl index 56ff36a5..51daa64f 100644 --- a/test/gates.jl +++ b/test/gates.jl @@ -32,30 +32,11 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= c = g(c, [0, 1, 2]) @test c.instructions == [Instruction(g(), 0), Instruction(g(), 1), Instruction(g(), 2)] end - angle = rand() - @testset for g in (Rx(angle), Ry(angle), Rz(angle), PhaseShift(angle)) - @test qubit_count(g) == 1 - ix = Instruction(g, 0) - @test JSON3.read(JSON3.write(ix), Instruction) == ix - @test Braket.Parametrizable(g) == Braket.Parametrized() - @test Braket.parameters(g) == Braket.FreeParameter[] - end - @testset for g in (Rx, Ry, Rz, PhaseShift) - @test qubit_count(g) == 1 - c = Circuit() - c = g(c, 0, angle) - @test c.instructions == [Instruction(g(angle), 0)] - c = Circuit() - c = g(c, [0, 1, 2], angle) - @test c.instructions == [Instruction(g(angle), 0), Instruction(g(angle), 1), Instruction(g(angle), 2)] - α = FreeParameter(:alpha) - pg = g(α) - @test Braket.parameters(pg) == [α] - end @testset for g in (CNot(), Swap(), ISwap(), CV(), CY(), CZ(), ECR()) @test qubit_count(g) == 2 ix = Instruction(g, [0, 1]) @test JSON3.read(JSON3.write(ix), Instruction) == ix + @test Braket.Parametrizable(g) == Braket.NonParametrized() @test Braket.parameters(g) == Braket.FreeParameter[] end @testset for g in (CNot, Swap, ISwap, CV, CY, CZ, ECR) @@ -67,55 +48,6 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= c = g(c, 10, 1) @test c.instructions == [Instruction(g(), [10, 1])] end - @testset for g in (PSwap(angle), XY(angle), CPhaseShift(angle), CPhaseShift00(angle), CPhaseShift01(angle), CPhaseShift10(angle), XX(angle), YY(angle), ZZ(angle)) - @test qubit_count(g) == 2 - ix = Instruction(g, [0, 1]) - @test JSON3.read(JSON3.write(ix), Instruction) == ix - @test Braket.Parametrizable(g) == Braket.Parametrized() - @test Braket.parameters(g) == Braket.FreeParameter[] - end - @testset for g in (PSwap, XY, CPhaseShift, CPhaseShift00, CPhaseShift01, CPhaseShift10, XX, YY, ZZ) - @test qubit_count(g) == 2 - c = Circuit() - c = g(c, 0, 1, angle) - @test c.instructions == [Instruction(g(angle), [0, 1])] - c = Circuit() - c = g(c, 10, 1, angle) - @test c.instructions == [Instruction(g(angle), [10, 1])] - α = FreeParameter(:alpha) - pg = g(α) - @test Braket.parameters(pg) == [α] - end - @testset for g in (MS(angle, angle, angle),) - @test qubit_count(g) == 2 - ix = Instruction(g, [0, 1]) - @test JSON3.read(JSON3.write(ix), Instruction) == ix - @test Braket.Parametrizable(g) == Braket.Parametrized() - @test Braket.parameters(g) == Braket.FreeParameter[] - end - @testset for g in (PRx(angle, angle),) - @test qubit_count(g) == 1 - ix = Instruction(g, [0]) - @test JSON3.read(JSON3.write(ix), Instruction) == ix - @test Braket.Parametrizable(g) == Braket.Parametrized() - @test Braket.parameters(g) == Braket.FreeParameter[] - end - @testset for g in (MS,) - @test qubit_count(g) == 2 - c = Circuit() - c = g(c, 0, 1, angle, angle, angle) - @test c.instructions == [Instruction(g(angle, angle, angle), [0, 1])] - c = Circuit() - c = g(c, 10, 1, angle, angle, angle) - @test c.instructions == [Instruction(g(angle, angle, angle), [10, 1])] - α = FreeParameter(:alpha) - β = FreeParameter(:beta) - γ = FreeParameter(:gamma) - pg = g(α, β, γ) - @test Braket.parameters(pg) == [α, β, γ] - pg = Braket.bind_value!(Braket.Parametrized(), pg, Dict{Symbol, Number}(:α=>0.1, :β=>0.5, :γ=>0.2)) - #@test pg == g(0.1, 0.5, 0.2) - end @testset for g in (CCNot(), CSwap()) @test qubit_count(g) == 3 ix = Instruction(g, [0, 1, 2]) @@ -132,6 +64,129 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= c = g(c, 5, 1, 2) @test c.instructions == [Instruction(g(), [5, 1, 2])] end + angle = rand() + α = FreeParameter(:alpha) + β = FreeParameter(:beta) + γ = FreeParameter(:gamma) + @testset for (angle1, angle2, angle3) in ((rand(), rand(), rand()), (π, rand(), rand())) + @testset for g in (Rx(angle1), Ry(angle1), Rz(angle1), PhaseShift(angle1)) + @test qubit_count(g) == 1 + ix = Instruction(g, 0) + @test Braket.Parametrizable(g) == Braket.Parametrized() + @test Braket.parameters(g) == Braket.FreeParameter[] + end + @testset for g in (Rx, Ry, Rz, PhaseShift) + @test qubit_count(g) == 1 + c = Circuit() + c = g(c, 0, angle1) + @test c.instructions == [Instruction(g(angle1), 0)] + c = Circuit() + c = g(c, [0, 1, 2], angle1) + @test c.instructions == [Instruction(g(angle1), 0), Instruction(g(angle1), 1), Instruction(g(angle1), 2)] + pg = g(α) + @test Braket.parameters(pg) == [α] + ix = Instruction(g(angle1), 0) + @test JSON3.read(JSON3.write(ix), Instruction) == Instruction(g(Float64(angle1)), 0) + end + @testset for g in (PSwap(angle1), XY(angle1), CPhaseShift(angle1), CPhaseShift00(angle1), CPhaseShift01(angle1), CPhaseShift10(angle1), XX(angle1), YY(angle1), ZZ(angle1)) + @test qubit_count(g) == 2 + @test Braket.Parametrizable(g) == Braket.Parametrized() + @test Braket.parameters(g) == Braket.FreeParameter[] + end + @testset for g in (PSwap, XY, CPhaseShift, CPhaseShift00, CPhaseShift01, CPhaseShift10, XX, YY, ZZ) + @test qubit_count(g) == 2 + c = Circuit() + c = g(c, 0, 1, angle1) + @test c.instructions == [Instruction(g(angle1), [0, 1])] + c = Circuit() + c = g(c, 10, 1, angle1) + @test c.instructions == [Instruction(g(angle1), [10, 1])] + pg = g(α) + @test Braket.parameters(pg) == [α] + ix = Instruction(g(angle1), [0, 1]) + @test JSON3.read(JSON3.write(ix), Instruction) == Instruction(g(Float64(angle1)), [0, 1]) + end + @testset for g in (PRx(angle1, angle2),) + @test qubit_count(g) == 1 + @test Braket.Parametrizable(g) == Braket.Parametrized() + @test Braket.parameters(g) == Braket.FreeParameter[] + end + @testset for g in (PRx,) + @test qubit_count(g) == 1 + c = Circuit() + c = g(c, 0, angle1, angle2) + @test c.instructions == [Instruction(g(angle1, angle2), 0)] + c = Circuit() + c = g(c, 10, angle1, angle2) + @test c.instructions == [Instruction(g(angle1, angle2), 10)] + pg = g(α, β) + @test Braket.parameters(pg) == [α, β] + pg = Braket.bind_value!(Braket.Parametrized(), pg, Dict(:alpha=>angle1, :beta=>angle2)) + @test pg == g(angle1, angle2) + end + @testset for g in (MS(angle1, angle2, angle3),) + @test qubit_count(g) == 2 + @test Braket.Parametrizable(g) == Braket.Parametrized() + @test Braket.parameters(g) == Braket.FreeParameter[] + end + @testset for g in (MS,) + @test qubit_count(g) == 2 + c = Circuit() + c = g(c, 0, 1, angle1, angle2, angle3) + @test c.instructions == [Instruction(g(angle1, angle2, angle3), [0, 1])] + c = Circuit() + c = g(c, 10, 1, angle1, angle2, angle3) + @test c.instructions == [Instruction(g(angle1, angle2, angle3), [10, 1])] + pg = g(α, β, γ) + @test Braket.parameters(pg) == [α, β, γ] + pg = Braket.bind_value!(Braket.Parametrized(), pg, Dict(:alpha=>angle1, :beta=>angle2, :gamma=>angle3)) + @test pg == g(angle1, angle2, angle3) + end + @testset for g in (U(angle1, angle2, angle3),) + @test qubit_count(g) == 1 + @test Braket.Parametrizable(g) == Braket.Parametrized() + @test Braket.parameters(g) == Braket.FreeParameter[] + end + @testset for g in (U,) + @test qubit_count(g) == 1 + c = Circuit() + c = g(c, 0, angle1, angle2, angle3) + @test c.instructions == [Instruction(g(angle1, angle2, angle3), 0)] + c = Circuit() + c = g(c, [0, 1, 2], angle1, angle2, angle3) + @test c.instructions == [Instruction(g(angle1, angle2, angle3), 0), Instruction(g(angle1, angle2, angle3), 1), Instruction(g(angle1, angle2, angle3), 2)] + c = Circuit() + c = g(c, 0, 1, 2, angle1, angle2, angle3) + @test c.instructions == [Instruction(g(angle1, angle2, angle3), 0), Instruction(g(angle1, angle2, angle3), 1), Instruction(g(angle1, angle2, angle3), 2)] + pg = g(α, β, γ) + @test Braket.parameters(pg) == [α, β, γ] + pg = Braket.bind_value!(Braket.Parametrized(), pg, Dict(:alpha=>angle1, :beta=>angle2, :gamma=>angle3)) + @test pg == g(angle1, angle2, angle3) + end + @testset "Angled 3 qubit gates" begin + # build some "fake" (for now) 3 qubit gates to test gate applicators + struct CCPhaseShift <: Braket.AngledGate{1} + angle::NTuple{1, Union{Real, FreeParameter}} + CCPhaseShift(angle::T) where {T<:NTuple{1, Union{Real, FreeParameter}}} = new(angle) + end + struct CXX <: Braket.AngledGate{1} + angle::NTuple{1, Union{Real, FreeParameter}} + CXX(angle::T) where {T<:NTuple{1, Union{Real, FreeParameter}}} = new(angle) + end + c = Circuit() + c = Braket.apply_gate!(Val(1), Val(2), Val(1), CCPhaseShift, c, 0, 1, 2, angle1) + @test c.instructions == [Instruction(CCPhaseShift(angle1), [0, 1, 2])] + c = Circuit() + c = Braket.apply_gate!(Val(1), Val(2), Val(1), CCPhaseShift, c, [0, 1, 2], angle1) + @test c.instructions == [Instruction(CCPhaseShift(angle1), [0, 1, 2])] + c = Circuit() + c = Braket.apply_gate!(Val(1), Val(1), Val(2), CXX, c, 0, 1, 2, angle1) + @test c.instructions == [Instruction(CXX(angle1), [0, 1, 2])] + c = Circuit() + c = Braket.apply_gate!(Val(1), Val(1), Val(2), CXX, c, [0, 1, 2], angle1) + @test c.instructions == [Instruction(CXX(angle1), [0, 1, 2])] + end + end @testset "g = Unitary" begin X = complex([0. 1.; 1. 0.]) Y = [0. -im; im 0.] @@ -154,38 +209,19 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= c = Unitary(c, 0, 1, kron(X, Y)) @test c.instructions == [Instruction(Unitary(kron(X, Y)), [0, 1])] end - @testset "Angled 3 qubit gates" begin - # build some "fake" (for now) 3 qubit gates to test gate applicators - struct CCPhaseShift <: Braket.AngledGate{1} - angle::NTuple{1, Union{Float64, Braket.FreeParameter}} - end - CCPhaseShift(angles::Vararg{Union{Float64, FreeParameter}}) = CCPhaseShift(tuple(angles...)) - struct CXX <: Braket.AngledGate{1} - angle::NTuple{1, Union{Float64, Braket.FreeParameter}} - end - CXX(angles::Vararg{Union{Float64, FreeParameter}}) = CXX(tuple(angles...)) - angle = rand() - c = Circuit() - c = Braket.apply_gate!(Val(1), Braket.IR.DoubleControl(), Braket.IR.SingleTarget(), CCPhaseShift, c, 0, 1, 2, angle) - @test c.instructions == [Instruction(CCPhaseShift((angle,)), [0, 1, 2])] - c = Circuit() - c = Braket.apply_gate!(Val(1), Braket.IR.DoubleControl(), Braket.IR.SingleTarget(), CCPhaseShift, c, [0, 1, 2], angle) - @test c.instructions == [Instruction(CCPhaseShift((angle,)), [0, 1, 2])] - c = Circuit() - c = Braket.apply_gate!(Val(1), Braket.IR.SingleControl(), Braket.IR.DoubleTarget(), CXX, c, 0, 1, 2, angle) - @test c.instructions == [Instruction(CXX((angle,)), [0, 1, 2])] - c = Circuit() - c = Braket.apply_gate!(Val(1), Braket.IR.SingleControl(), Braket.IR.DoubleTarget(), CXX, c, [0, 1, 2], angle) - @test c.instructions == [Instruction(CXX((angle,)), [0, 1, 2])] - end @testset "OpenQASM IR" begin fp = FreeParameter(:alpha) fp2 = FreeParameter(:beta) + fp3 = FreeParameter(:gamma) @testset for ir_bolus in [ (Rx(0.17), [Qubit(4)], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "rx(0.17) q[4];",), (Rx(0.17), [Qubit(4)], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "rx(0.17) \$4;",), (Rx(0.17), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "rx(0.17) q[4];",), (Rx(0.17), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "rx(0.17) \$4;",), + (PRx(0.17, 3.45), [Qubit(4)], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "prx(0.17, 3.45) q[4];",), + (PRx(0.17, 3.45), [Qubit(4)], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "prx(0.17, 3.45) \$4;",), + (PRx(0.17, 3.45), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "prx(0.17, 3.45) q[4];",), + (PRx(0.17, 3.45), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "prx(0.17, 3.45) \$4;",), (X(), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "x q[4];",), (X(), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "x \$4;",), (Z(), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "z q[4];",), @@ -208,6 +244,10 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= (Rz(0.17), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "rz(0.17) \$4;",), (Rz(fp), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "rz(alpha) q[4];",), (Rz(fp), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "rz(alpha) \$4;",), + (U(0.17, 0.2, 0.1), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "U(0.17, 0.2, 0.1) q[4];",), + (U(0.17, 0.2, 0.1), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "U(0.17, 0.2, 0.1) \$4;",), + (U(fp, fp2, fp3), [4], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "U(alpha, beta, gamma) q[4];",), + (U(fp, fp2, fp3), [4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "U(alpha, beta, gamma) \$4;",), (XX(0.17), [4, 5], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "xx(0.17) q[4], q[5];",), (XX(0.17), [4, 5], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "xx(0.17) \$4, \$5;",), (XX(fp), [4, 5], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "xx(alpha) q[4], q[5];",), @@ -317,6 +357,5 @@ T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits= end @test StructTypes.StructType(X) == StructTypes.Struct() @test StructTypes.StructType(Gate) == StructTypes.AbstractType() - ##@test StructTypes.StructType(DoubleAngledGate) == StructTypes.AbstractType() @test StructTypes.StructType(AngledGate) == StructTypes.AbstractType() end diff --git a/test/runtests.jl b/test/runtests.jl index c682b6ca..91807f74 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,7 @@ using Pkg, Test, Aqua, Braket in_ci = tryparse(Bool, get(ENV, "BRAKET_CI", "false")) -Aqua.test_all(Braket, ambiguities=false, unbound_args=false, piracies=false, stale_deps=!in_ci, deps_compat=!in_ci, persistent_tasks=false) +Aqua.test_all(Braket, ambiguities=false, piracies=false, stale_deps=!in_ci, deps_compat=!in_ci, persistent_tasks=!in_ci) Aqua.test_ambiguities(Braket) Aqua.test_piracies(Braket, treat_as_own=[Braket.DecFP.Dec128]) diff --git a/test/schemas_misc.jl b/test/schemas_misc.jl index c7f1a59a..34be8898 100644 --- a/test/schemas_misc.jl +++ b/test/schemas_misc.jl @@ -106,7 +106,6 @@ using Braket, Braket.IR, Test, JSON3, StructTypes @test read_T isa T @test read_T.targets == targs @test read_T.observable == obs - @test Braket.IR.Target(T) == Braket.IR.OptionalMultiTarget() @test JSON3.read(JSON3.write(read_T), Braket.IR.AbstractIR) == read_T end for T in (IR.Probability, IR.DensityMatrix) @@ -115,7 +114,6 @@ using Braket, Braket.IR, Test, JSON3, StructTypes read_T = JSON3.read(raw_str, T) @test read_T isa T @test read_T.targets == targs - @test Braket.IR.Target(T) == Braket.IR.OptionalMultiTarget() @test JSON3.read(JSON3.write(read_T), Braket.IR.AbstractIR) == read_T end for T in (IR.StateVector,)