From 89be3546e21d17f65b4c0635f7aaec65f39590c5 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt <67932820+kshyatt-aws@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:12:55 -0400 Subject: [PATCH] Change: Make Braket.jl an optional dependency with package extension (#36) * change: Remove Braket.jl dependency * change: More tests * fix: More cleanup * fix: lock GIL appropriately for multiple Python specs * fix: No more QBP hang * fix: Working with Python multithreading * test docs in runtests, use GIL lock * fix: Remove extranous verify * fix: Make reset a no-op, close #37 --- .github/workflows/CI.yml | 10 +- Project.toml | 29 +- coverage.jl | 8 + docs/Project.toml | 1 - docs/make.jl | 9 +- docs/src/circuits.md | 22 + docs/src/custom_gates.md | 6 +- docs/src/gates.md | 52 ++ docs/src/index.md | 27 +- docs/src/noises.md | 24 + docs/src/observables.md | 13 + docs/src/results.md | 14 + docs/src/sims.md | 4 +- .../BraketSimulatorBraketExt.jl | 164 ++++++ .../BraketSimulatorPythonExt.jl | 78 +-- ext/BraketSimulatorPythonExt/translation.jl | 59 --- src/BraketSimulator.jl | 468 +++++++++-------- src/Quasar.jl | 171 ++++--- src/builtin_functions.jl | 11 +- src/builtin_gates.jl | 96 ++-- src/circuit.jl | 250 +++++++++ src/custom_gates.jl | 131 ++--- src/dm_simulator.jl | 15 +- src/gate_kernels.jl | 292 +++++++---- src/gates.jl | 130 +++++ src/inverted_gates.jl | 41 -- src/noise_kernels.jl | 8 +- src/noises.jl | 157 ++++++ src/observables.jl | 246 ++++++++- src/operators.jl | 67 +++ src/pow_gates.jl | 89 +--- src/precompile.jl | 275 ---------- src/properties.jl | 277 +++++----- src/qubit_set.jl | 115 +++++ src/raw_schema.jl | 253 +++++++++ src/result_types.jl | 55 +- src/results.jl | 191 +++++++ src/schemas.jl | 28 + src/sv_simulator.jl | 33 +- src/validation.jl | 12 +- test/Project.toml | 2 + test/runtests.jl | 10 +- test/test_braket_integration.jl | 212 ++++---- test/test_custom_gates.jl | 111 ++-- test/test_dm_simulator.jl | 148 +++--- test/test_gate_operations.jl | 177 +++++-- test/test_gates.jl | 257 ++++++++++ test/test_noises.jl | 60 +++ test/test_observables.jl | 55 +- test/test_openqasm3.jl | 478 +++++++----------- test/test_python_ext.jl | 139 +---- test/test_qubit_set.jl | 40 ++ test/test_result_types.jl | 47 +- test/test_sv_simulator.jl | 384 ++++++++++---- test/test_validation.jl | 14 +- 55 files changed, 3910 insertions(+), 2155 deletions(-) create mode 100644 docs/src/circuits.md create mode 100644 docs/src/gates.md create mode 100644 docs/src/noises.md create mode 100644 docs/src/observables.md create mode 100644 docs/src/results.md create mode 100644 ext/BraketSimulatorBraketExt/BraketSimulatorBraketExt.jl delete mode 100644 ext/BraketSimulatorPythonExt/translation.jl create mode 100644 src/circuit.jl create mode 100644 src/gates.jl delete mode 100644 src/inverted_gates.jl create mode 100644 src/noises.jl create mode 100644 src/operators.jl delete mode 100644 src/precompile.jl create mode 100644 src/qubit_set.jl create mode 100644 src/raw_schema.jl create mode 100644 src/results.jl create mode 100644 src/schemas.jl create mode 100644 test/test_gates.jl create mode 100644 test/test_noises.jl create mode 100644 test/test_qubit_set.jl diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f0ef288..c31abce 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -40,6 +40,11 @@ jobs: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - uses: julia-actions/cache@v2 + - name: Update registry + shell: julia --project=. --color=yes {0} + run: | + using Pkg + Pkg.Registry.update() - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - uses: julia-actions/julia-processcoverage@v1 @@ -65,6 +70,7 @@ jobs: 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 @@ -75,6 +81,6 @@ jobs: shell: julia --project=docs --color=yes {0} run: | using Documenter: DocMeta, doctest - using Braket, BraketSimulator - DocMeta.setdocmeta!(BraketSimulator, :DocTestSetup, :(using Braket, BraketSimulator); recursive=true) + using BraketSimulator + DocMeta.setdocmeta!(BraketSimulator, :DocTestSetup, :(using BraketSimulator, BraketSimulator.Observables; using BraketSimulator: Program, Circuit, qubits, CNot, H, Rx, FreeParameter, QubitSet, AdjointGradient, BitFlip, qubit_count, Qubit, StateVector, Measure, Probability, Ry, Amplitude, Instruction, DensityMatrix, add_instruction!); recursive=true) doctest(BraketSimulator) diff --git a/Project.toml b/Project.toml index 0db9261..6142c7d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,56 +1,65 @@ name = "BraketSimulator" uuid = "76d27892-9a0b-406c-98e4-7c178e9b3dff" authors = ["Katharine Hyatt and contributors"] -version = "0.0.1" +version = "0.0.2" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Automa = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b" -Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [weakdeps] +Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" +JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" [extensions] -BraketSimulatorPythonExt = "PythonCall" +BraketSimulatorBraketExt = "Braket" +BraketSimulatorPythonExt = ["JSON3", "PythonCall"] [compat] AbstractTrees = "=0.4.5" Aqua = "=0.8" -Automa = "=1.0.3" -Braket = "=0.9.1" +Automa = "=1.0.4" +Braket = "=0.9.4" Combinatorics = "=1.0.2" DataStructures = "=0.18.20" Dates = "1.6" +Documenter = "=1.5.0" +InteractiveUtils = "1.6" JSON3 = "=1.14.0" LinearAlgebra = "1.6" Logging = "1.6" -Pkg = "1.6" +OrderedCollections = "=1.6.3" PrecompileTools = "=1.2.1" -PythonCall = "=0.9.20" +PythonCall = "=0.9.22" Random = "1.6" StaticArrays = "1.9" StatsBase = "0.34" +StructTypes = "=1.10.0" Test = "1.6" UUIDs = "1.6" julia = "1.9" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Aqua", "Test", "Logging", "PythonCall"] +test = ["Aqua", "Braket", "JSON3", "Test", "Logging", "PythonCall"] diff --git a/coverage.jl b/coverage.jl index b6f4691..b2f694d 100644 --- a/coverage.jl +++ b/coverage.jl @@ -2,6 +2,7 @@ using Coverage # process '*.cov' files coverage = process_folder() coverage = append!(coverage, process_folder("ext/BraketSimulatorPythonExt/")) +coverage = append!(coverage, process_folder("ext/BraketSimulatorBraketExt/")) coverage = merge_coverage_counts(coverage) # Get total coverage for all Julia files covered_lines, total_lines = get_summary(coverage) @@ -11,6 +12,13 @@ open("lcov.info", "w") do io LCOV.write(io, coverage) end +for fi in readdir("src") + if endswith(fi, ".jl") + println("Coverage for file $fi") + @show get_summary(process_file(joinpath("src", fi))) + end +end + # uncomment this if you have `genhtml` installed # to generate HTML coverage info #run(`genhtml -o .coverage/ lcov.info`) diff --git a/docs/Project.toml b/docs/Project.toml index 2f3e875..616411d 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,4 +1,3 @@ [deps] -Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" BraketSimulator = "76d27892-9a0b-406c-98e4-7c178e9b3dff" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/make.jl b/docs/make.jl index 6480d6e..0153d30 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,7 +1,7 @@ -using Braket, BraketSimulator +using BraketSimulator using Documenter -DocMeta.setdocmeta!(BraketSimulator, :DocTestSetup, :(using Braket, BraketSimulator); recursive=true) +DocMeta.setdocmeta!(BraketSimulator, :DocTestSetup, :(using BraketSimulator, BraketSimulator.Observables; using BraketSimulator: Program, Circuit, qubits, CNot, H, Rx, FreeParameter, QubitSet, AdjointGradient, BitFlip, qubit_count, Qubit, StateVector, Measure, Probability, Ry, Amplitude, Instruction, DensityMatrix, add_instruction!); recursive=true) makedocs(; modules=[BraketSimulator], @@ -15,6 +15,11 @@ makedocs(; pages=[ "Home" => "index.md", "Simulators" => "sims.md", + "Gates" => "gates.md", + "Custom Gates" => "custom_gates.md", + "Noises" => "noises.md", + "Observables" => "observables.md", + "Results" => "results.md", ], ) diff --git a/docs/src/circuits.md b/docs/src/circuits.md new file mode 100644 index 0000000..965edd1 --- /dev/null +++ b/docs/src/circuits.md @@ -0,0 +1,22 @@ +```@meta +CurrentModule = BraketSimulator +``` + +# Circuits + +Circuits are made up of *instructions* (operations to apply to the qubits -- [gates](gates.md) and [noises](noises.md)) and *result types* ([results](results.md)). +OpenQASM3 programs are parsed to circuits which are then run on the simulator. + +```@docs +BraketSimulator.Circuit +BraketSimulator.Operator +BraketSimulator.QuantumOperator +BraketSimulator.FreeParameter +BraketSimulator.Measure +BraketSimulator.Instruction +BraketSimulator.QubitSet +BraketSimulator.Qubit +BraketSimulator.qubit_count +BraketSimulator.qubits +BraketSimulator.basis_rotation_instructions! +``` diff --git a/docs/src/custom_gates.md b/docs/src/custom_gates.md index caaca2a..7cdfaf6 100644 --- a/docs/src/custom_gates.md +++ b/docs/src/custom_gates.md @@ -4,10 +4,8 @@ CurrentModule = BraketSimulator # Custom gates -`BraketSimulator.jl` defines some custom gates to extend what `Braket.jl` provides. These include the OpenQASM3 built-in gates `gphase` (as `MultiQubitPhaseShift`) and `U` (the single qubit three angle unitary). +`BraketSimulator.jl` defines some custom gates to extend what `Braket.jl` provides. ```@docs -U -MultiQubitPhaseShift -MultiRZ +BraketSimulator.MultiRZ ``` diff --git a/docs/src/gates.md b/docs/src/gates.md new file mode 100644 index 0000000..4edc03a --- /dev/null +++ b/docs/src/gates.md @@ -0,0 +1,52 @@ +```@meta +CurrentModule = BraketSimulator +``` + +# Gates + +`BraketSimulators.jl` provides many pre-implemented gates which can be used to build up circuits. For gates with angle parameters, you can supply `Irrational`s like `π` as arguments. + +```@docs +BraketSimulator.Gate +BraketSimulator.AngledGate +BraketSimulator.I +BraketSimulator.X +BraketSimulator.Y +BraketSimulator.Z +BraketSimulator.H +BraketSimulator.Rx +BraketSimulator.Ry +BraketSimulator.Rz +BraketSimulator.V +BraketSimulator.Vi +BraketSimulator.T +BraketSimulator.Ti +BraketSimulator.S +BraketSimulator.Si +BraketSimulator.U +BraketSimulator.Unitary +BraketSimulator.PhaseShift +BraketSimulator.MultiQubitPhaseShift +BraketSimulator.PRx +BraketSimulator.GPi +BraketSimulator.GPi2 +BraketSimulator.XX +BraketSimulator.XY +BraketSimulator.YY +BraketSimulator.ZZ +BraketSimulator.ECR +BraketSimulator.MS +BraketSimulator.CPhaseShift +BraketSimulator.CPhaseShift00 +BraketSimulator.CPhaseShift01 +BraketSimulator.CPhaseShift10 +BraketSimulator.CNot +BraketSimulator.CY +BraketSimulator.CZ +BraketSimulator.CV +BraketSimulator.Swap +BraketSimulator.PSwap +BraketSimulator.ISwap +BraketSimulator.CCNot +BraketSimulator.CSwap +``` diff --git a/docs/src/index.md b/docs/src/index.md index b1f9731..1c58d37 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,5 +1,5 @@ ```@meta -DocTestSetup = quote using Braket, BraketSimulator end +DocTestSetup = quote using BraketSimulator, BraketSimulator.Observables; using BraketSimulator: Program, Circuit, qubits, CNot, H, Rx, FreeParameter, QubitSet, AdjointGradient, BitFlip, qubit_count, Qubit, StateVector, Measure, Probability, Ry, Amplitude, Instruction, DensityMatrix, add_instruction! end CurrentModule = BraketSimulator ``` @@ -31,29 +31,28 @@ Pkg.add("BraketSimulator") Then you can run a simulation of a simple [GHZ state](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) preparation circuit. -!!! note - To simulate OpenQASM3 programs, you will need to load the Python extension `BraketSimulatorPythonExt` like so: `using PythonCall, BraketSimulator`. If - you prefer not to install or use Python, make sure to set the default `IRType` for `Braket.jl` to JAQCD: `Braket.IRType[] = :JAQCD`. - ```jldoctest -julia> using Braket, BraketSimulator +julia> using BraketSimulator + +julia> using BraketSimulator: Circuit, H, CNot, Amplitude julia> n_qubits = 10; julia> c = Circuit(); -julia> H(c, 0); +julia> add_instruction!(c, Instruction(H(), 0)); -julia> foreach(q->CNot(c, 0, q), 1:n_qubits-1); +julia> foreach(q->add_instruction!(c, Instruction(CNot(), [0, q])), 1:n_qubits-1); -julia> Amplitude(c, [repeat("0", n_qubits), repeat("1", n_qubits)]); +julia> push!(c.result_types, Amplitude([repeat("0", n_qubits), repeat("1", n_qubits)])); -julia> sim = LocalSimulator("braket_sv_v2"); # use the state vector simulator (without noise) +julia> sim = StateVectorSimulator(n_qubits, 0); # use the state vector simulator (without noise) -julia> res = result(simulate(sim, ir(c, Val(:JAQCD)), shots=0)); +julia> res = simulate(sim, Program(c), n_qubits, 0); -julia> res.values -1-element Vector{Any}: - Dict{String, ComplexF64}("0000000000" => 0.7071067811865475 + 0.0im, "1111111111" => 0.7071067811865475 + 0.0im) +julia> res.resultTypes[1].value +Dict{String, ComplexF64} with 2 entries: + "0000000000" => 0.707107+0.0im + "1111111111" => 0.707107+0.0im ``` diff --git a/docs/src/noises.md b/docs/src/noises.md new file mode 100644 index 0000000..38a73b8 --- /dev/null +++ b/docs/src/noises.md @@ -0,0 +1,24 @@ +```@meta +CurrentModule = BraketSimulator +``` + +# Noises + +`BraketSimulators.jl` provides many pre-implemented noise channels which can be applied to circuits. +Noisy circuits can be simulated used the density matrix simulator. + +```@docs +BraketSimulator.Noise +BraketSimulator.Kraus +BraketSimulator.BitFlip +BraketSimulator.PhaseFlip +BraketSimulator.PauliChannel +BraketSimulator.TwoQubitPauliChannel +BraketSimulator.MultiQubitPauliChannel +BraketSimulator.Depolarizing +BraketSimulator.PhaseDamping +BraketSimulator.AmplitudeDamping +BraketSimulator.GeneralizedAmplitudeDamping +BraketSimulator.TwoQubitDepolarizing +BraketSimulator.TwoQubitDephasing +``` diff --git a/docs/src/observables.md b/docs/src/observables.md new file mode 100644 index 0000000..f61efe2 --- /dev/null +++ b/docs/src/observables.md @@ -0,0 +1,13 @@ +# Observables + +```@docs +BraketSimulator.Observables.Observable +BraketSimulator.Observables.X +BraketSimulator.Observables.Y +BraketSimulator.Observables.Z +BraketSimulator.Observables.H +BraketSimulator.Observables.I +BraketSimulator.Observables.TensorProduct +BraketSimulator.Observables.HermitianObservable +BraketSimulator.Observables.Sum +``` diff --git a/docs/src/results.md b/docs/src/results.md new file mode 100644 index 0000000..0970617 --- /dev/null +++ b/docs/src/results.md @@ -0,0 +1,14 @@ +# Results + + +```@docs +BraketSimulator.Result +BraketSimulator.AdjointGradient +BraketSimulator.Expectation +BraketSimulator.Variance +BraketSimulator.Sample +BraketSimulator.Amplitude +BraketSimulator.Probability +BraketSimulator.DensityMatrix +BraketSimulator.StateVector +``` diff --git a/docs/src/sims.md b/docs/src/sims.md index e2c420f..9598ab4 100644 --- a/docs/src/sims.md +++ b/docs/src/sims.md @@ -8,7 +8,7 @@ CurrentModule = BraketSimulator Each type is [parameterized](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types) by an **element type** (which should be a Julia `Complex` type, such as `ComplexF64`) and an **array type** (so that we can specialize for GPU arrays, for example). -Each simulator can be initialized with a `qubit_count` and `shots` value. You may query the [`properties`](@ref Braket.properties) of a simulator to learn what gate types, result types, and other operations it supports. +Each simulator can be initialized with a `qubit_count` and `shots` value. You may query the [`properties`](@ref BraketSimulator.properties) of a simulator to learn what gate types, result types, and other operations it supports. ```@docs StateVectorSimulator @@ -17,5 +17,5 @@ evolve! simulate expectation probabilities -Braket.properties +BraketSimulator.properties ``` diff --git a/ext/BraketSimulatorBraketExt/BraketSimulatorBraketExt.jl b/ext/BraketSimulatorBraketExt/BraketSimulatorBraketExt.jl new file mode 100644 index 0000000..1c15207 --- /dev/null +++ b/ext/BraketSimulatorBraketExt/BraketSimulatorBraketExt.jl @@ -0,0 +1,164 @@ +module BraketSimulatorBraketExt + +using PrecompileTools + +@recompile_invalidations begin + using BraketSimulator, Braket +end + +Braket.name(d::BraketSimulator.AbstractSimulator) = BraketSimulator.name(d) +Braket.properties(d::BraketSimulator.AbstractSimulator) = BraketSimulator.properties(d) +Braket.simulate(d::BraketSimulator.AbstractSimulator, program::Braket.OpenQasmProgram, args...; kwargs...) = convert(Braket.GateModelTaskResult, BraketSimulator.simulate(d, convert(BraketSimulator.OpenQasmProgram, program), args...; kwargs...)) +Braket.simulate(d::BraketSimulator.AbstractSimulator, program::Braket.Program, args...; kwargs...) = convert(Braket.GateModelTaskResult, BraketSimulator.simulate(d, convert(BraketSimulator.Program, program), args...; kwargs...)) + +Base.convert(::Type{Braket.TaskMetadata}, tm::BraketSimulator.TaskMetadata) = Braket.TaskMetadata(Braket.braketSchemaHeader("braket.task_result.task_metadata", "1"), tm.id, tm.shots, tm.deviceId, tm.deviceParameters, tm.createdAt, tm.endedAt, tm.status, tm.failureReason) +Base.convert(::Type{Braket.AdditionalMetadata}, am::BraketSimulator.AdditionalMetadata) = Braket.AdditionalMetadata(convert(Braket.AbstractProgram, am.action), nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing) +Base.convert(::Type{Braket.ResultTypeValue}, rtv::BraketSimulator.ResultTypeValue) = Braket.ResultTypeValue(convert(Braket.AbstractProgramResult, rtv.type), rtv.value) + +# nosemgrep +function Base.convert(::Type{Braket.GateModelTaskResult}, r::BraketSimulator.GateModelTaskResult) + task_meta = convert(Braket.TaskMetadata, r.taskMetadata) + addl_meta = convert(Braket.AdditionalMetadata, r.additionalMetadata) + rts = !isnothing(r.resultTypes) ? Braket.ResultTypeValue[convert(Braket.ResultTypeValue, rt) for rt in r.resultTypes] : nothing + + return Braket.GateModelTaskResult(Braket.braketSchemaHeader("braket.task_result.gate_model_task_result", "1"), + r.measurements, + r.measurementProbabilities, + rts, + r.measuredQubits, + task_meta, + addl_meta) +end + +Braket.qubit_count(o::O) where {O<:BraketSimulator.Operator} = BraketSimulator.qubit_count(o) +Braket.qubit_count(o::O) where {O<:BraketSimulator.Observables.Observable} = BraketSimulator.qubit_count(o) +Braket.qubit_count(::Type{O}) where {O<:BraketSimulator.Operator} = BraketSimulator.qubit_count(O) + +for (braket_sim, simulator_sym) in ((:(Braket.X), :(BraketSimulator.X)), + (:(Braket.Y), :(BraketSimulator.Y)), + (:(Braket.Z), :(BraketSimulator.Z)), + (:(Braket.I), :(BraketSimulator.I)), + (:(Braket.H), :(BraketSimulator.H)), + (:(Braket.V), :(BraketSimulator.V)), + (:(Braket.Vi), :(BraketSimulator.Vi)), + (:(Braket.S), :(BraketSimulator.S)), + (:(Braket.Si), :(BraketSimulator.Si)), + (:(Braket.T), :(BraketSimulator.T)), + (:(Braket.Ti), :(BraketSimulator.Ti)), + (:(Braket.ECR), :(BraketSimulator.ECR)), + (:(Braket.CNot), :(BraketSimulator.CNot)), + (:(Braket.CY), :(BraketSimulator.CY)), + (:(Braket.CZ), :(BraketSimulator.CZ)), + (:(Braket.CV), :(BraketSimulator.CV)), + (:(Braket.CCNot), :(BraketSimulator.CCNot)), + (:(Braket.Swap), :(BraketSimulator.Swap)), + (:(Braket.ISwap), :(BraketSimulator.ISwap)), + (:(Braket.CSwap), :(BraketSimulator.CSwap)), + ) + @eval Base.convert(::Type{BraketSimulator.Operator}, g::$braket_sim) = $simulator_sym() + @eval Base.convert(::Type{Braket.Operator}, g::$simulator_sym) = $braket_sim() +end + +for (braket_sim, simulator_sym) in ((:(Braket.Rx), :(BraketSimulator.Rx)), + (:(Braket.Ry), :(BraketSimulator.Ry)), + (:(Braket.Rz), :(BraketSimulator.Rz)), + (:(Braket.GPi), :(BraketSimulator.GPi)), + (:(Braket.GPi2), :(BraketSimulator.GPi2)), + (:(Braket.XX), :(BraketSimulator.XX)), + (:(Braket.XY), :(BraketSimulator.XY)), + (:(Braket.YY), :(BraketSimulator.YY)), + (:(Braket.ZZ), :(BraketSimulator.ZZ)), + (:(Braket.PSwap), :(BraketSimulator.PSwap)), + (:(Braket.PhaseShift), :(BraketSimulator.PhaseShift)), + (:(Braket.CPhaseShift), :(BraketSimulator.CPhaseShift)), + (:(Braket.CPhaseShift00), :(BraketSimulator.CPhaseShift00)), + (:(Braket.CPhaseShift01), :(BraketSimulator.CPhaseShift01)), + (:(Braket.CPhaseShift10), :(BraketSimulator.CPhaseShift10)), + ) + @eval Base.convert(::Type{BraketSimulator.Operator}, g::$braket_sim) = $simulator_sym(convert(Union{BraketSimulator.FreeParameter, Real}, g.angle[1])) + @eval Base.convert(::Type{Braket.Operator}, g::$simulator_sym) = $braket_sim(convert(Union{Braket.FreeParameter, Real}, g.angle[1])) +end +for (braket_sim, simulator_sym) in ((:(Braket.BitFlip), :(BraketSimulator.BitFlip)), + (:(Braket.PhaseFlip), :(BraketSimulator.PhaseFlip)), + (:(Braket.Depolarizing), :(BraketSimulator.Depolarizing)), + (:(Braket.TwoQubitDephasing), :(BraketSimulator.TwoQubitDephasing)), + (:(Braket.TwoQubitDepolarizing), :(BraketSimulator.TwoQubitDepolarizing)), + ) + @eval Base.convert(::Type{BraketSimulator.Operator}, g::$braket_sim) = $simulator_sym(convert(Union{BraketSimulator.FreeParameter, Real}, g.probability)) + @eval Base.convert(::Type{Braket.Operator}, g::$simulator_sym) = $braket_sim(convert(Union{Braket.FreeParameter, Real}, g.probability)) +end +for (braket_sim, simulator_sym) in ((:(Braket.IR.Expectation), :(BraketSimulator.IR.Expectation)), + (:(Braket.IR.Variance), :(BraketSimulator.IR.Variance)), + (:(Braket.IR.Sample), :(BraketSimulator.IR.Sample)), + ) + @eval Base.convert(::Type{Braket.AbstractProgramResult}, rt::$simulator_sym) = $braket_sim(rt.observable, rt.targets, rt.type) + @eval Base.convert(::Type{BraketSimulator.AbstractProgramResult}, rt::$braket_sim) = $simulator_sym(rt.observable, rt.targets, rt.type) +end +for (braket_sim, simulator_sym) in ((:(Braket.IR.DensityMatrix), :(BraketSimulator.IR.DensityMatrix)), + (:(Braket.IR.Probability), :(BraketSimulator.IR.Probability)), + ) + @eval Base.convert(::Type{Braket.AbstractProgramResult}, rt::$simulator_sym) = $braket_sim(rt.targets, rt.type) + @eval Base.convert(::Type{BraketSimulator.AbstractProgramResult}, rt::$braket_sim) = $simulator_sym(rt.targets, rt.type) +end +Base.convert(::Type{Braket.AbstractProgramResult}, rt::BraketSimulator.IR.StateVector) = Braket.IR.StateVector(rt.type) +Base.convert(::Type{BraketSimulator.AbstractProgramResult}, rt::Braket.IR.StateVector) = BraketSimulator.IR.StateVector(rt.type) +Base.convert(::Type{Braket.AbstractProgramResult}, rt::BraketSimulator.IR.Amplitude) = Braket.IR.Amplitude(rt.states, rt.type) +Base.convert(::Type{BraketSimulator.AbstractProgramResult}, rt::Braket.IR.Amplitude) = BraketSimulator.IR.Amplitude(rt.states, rt.type) +Base.convert(::Type{BraketSimulator.Operator}, m::Braket.Measure) = BraketSimulator.Measure(m.index) +Base.convert(::Type{Braket.Operator}, m::BraketSimulator.Measure) = Braket.Measure(m.index) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.MS) = BraketSimulator.MS(ntuple(i->convert(Union{FreeParameter, Real}, g.angle[i]), 3)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.MS) = Braket.MS(ntuple(i->convert(Union{Braket.FreeParameter, Real}, g.angle[i]), 3)) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.U) = BraketSimulator.U(ntuple(i->convert(Union{FreeParameter, Real}, g.angle[i]), 3)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.U) = Braket.U(ntuple(i->convert(Union{Braket.FreeParameter, Real}, g.angle[i]), 3)) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.PRx) = BraketSimulator.PRx(ntuple(i->convert(Union{FreeParameter, Real}, g.angle[i]), 2)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.PRx) = Braket.PRx(ntuple(i->convert(Union{Braket.FreeParameter, Real}, g.angle[i]), 2)) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.Unitary) = BraketSimulator.Unitary(g.matrix) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.Unitary) = Braket.Unitary(g.matrix) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.Kraus) = BraketSimulator.Kraus(g.matrices) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.Kraus) = Braket.Kraus(g.matrices) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.PauliChannel) = BraketSimulator.PauliChannel(convert(Union{BraketSimulator.FreeParameter,Real}, g.probX), convert(Union{BraketSimulator.FreeParameter,Real}, g.probY), convert(Union{BraketSimulator.FreeParameter,Real}, g.probZ)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.PauliChannel) = Braket.PauliChannel(convert(Union{Braket.FreeParameter,Real}, g.probX), convert(Union{Braket.FreeParameter,Real}, g.probY), convert(Union{Braket.FreeParameter,Real}, g.probZ)) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.GeneralizedAmplitudeDamping) = BraketSimulator.GeneralizedAmplitudeDamping(convert(Union{BraketSimulator.FreeParameter,Real}, g.probability), convert(Union{BraketSimulator.FreeParameter,Real}, g.gamma)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.GeneralizedAmplitudeDamping) = Braket.GeneralizedAmplitudeDamping(convert(Union{Braket.FreeParameter,Real}, g.probability), convert(Union{Braket.FreeParameter,Real}, g.gamma)) + +Base.convert(::Type{BraketSimulator.Operator}, g::Braket.MultiQubitPauliChannel{N}) where {N} = BraketSimulator.MultiQubitPauliChannel{N}(Dict(k=>convert(Union{BraketSimulator.FreeParameter,Float64}, v) for (k,v) in g.probabilities)) +Base.convert(::Type{Braket.Operator}, g::BraketSimulator.MultiQubitPauliChannel{N}) where {N} = Braket.MultiQubitPauliChannel{N}(Dict(k=>convert(Union{Braket.FreeParameter,Real}, v) for (k,v) in g.probabilities)) + +Base.convert(::Type{BraketSimulator.Instruction}, ix::Braket.Instruction) = BraketSimulator.Instruction(convert(BraketSimulator.Operator, ix.operator), convert(BraketSimulator.QubitSet, ix.target)) +Base.convert(::Type{Braket.Instruction}, ix::BraketSimulator.Instruction) = Braket.Instruction(convert(Braket.Operator, ix.operator), convert(Braket.QubitSet, ix.target)) + +Base.convert(::Type{BraketSimulator.OpenQasmProgram}, p::Braket.OpenQasmProgram) = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), p.source, p.inputs) + +# have to handle the special case of 2-qubit Hermitians carefully due to endianness +# nosemgrep +function Base.convert(::Type{BraketSimulator.Program}, p::Braket.Program) + ixs = [convert(BraketSimulator.Instruction, ix) for ix in p.instructions] + rts = [convert(BraketSimulator.AbstractProgramResult, rt) for rt in p.results] + bris = map(p.basis_rotation_instructions) do bri + if bri.operator isa Unitary && length(bri.target) == 2 + return BraketSimulator.Instruction(BraketSimulator.Unitary(BraketSimulator.fix_endianness(bri.operator.matrix)), bri.target) + else + return convert(BraketSimulator.Instruction, bri) + end + end + p = BraketSimulator.Program(BraketSimulator.braketSchemaHeader("braket.ir.jaqcd.program", "1"), ixs, rts, bris) + return p +end +Base.convert(::Type{Braket.AbstractProgram}, p::BraketSimulator.Program) = Braket.Program(Braket.braketSchemaHeader("braket.ir.jaqcd.program", "1"), [convert(Braket.Instruction, ix) for ix in p.instructions],[convert(Braket.AbstractProgramResult, rt) for rt in p.results], [convert(Braket.Instruction, ix) for ix in p.basis_rotation_instructions]) +Base.convert(::Type{Braket.AbstractProgram}, p::BraketSimulator.OpenQasmProgram) = Braket.OpenQasmProgram(Braket.braketSchemaHeader("braket.ir.openqasm.program", "1"), p.source, p.inputs) + +function __init__() + Braket._simulator_devices[]["braket_dm_v2"] = + DensityMatrixSimulator{ComplexF64,Matrix{ComplexF64}} + Braket._simulator_devices[]["braket_sv_v2"] = + StateVectorSimulator{ComplexF64,Vector{ComplexF64}} +end + +end diff --git a/ext/BraketSimulatorPythonExt/BraketSimulatorPythonExt.jl b/ext/BraketSimulatorPythonExt/BraketSimulatorPythonExt.jl index 5d2c945..089d905 100644 --- a/ext/BraketSimulatorPythonExt/BraketSimulatorPythonExt.jl +++ b/ext/BraketSimulatorPythonExt/BraketSimulatorPythonExt.jl @@ -3,76 +3,22 @@ module BraketSimulatorPythonExt using PrecompileTools @recompile_invalidations begin - using BraketSimulator, BraketSimulator.Braket, PythonCall, BraketSimulator.Dates + using BraketSimulator, PythonCall, JSON3 end -import BraketSimulator.Braket: - LocalSimulator, - qubit_count, - Instruction, - Observables, - AbstractProgramResult, - ResultTypeValue, - format_result, - GateModelQuantumTaskResult, - GateModelTaskResult, - Program, - Gate, - AngledGate, - AbstractIR, - AbstractProgram, - IRObservable -import BraketSimulator: - AbstractSimulator, - simulate, - parse_program, - DoubleExcitation, - SingleExcitation, - Control, - MultiQubitPhaseShift, - MultiRZ +using BraketSimulator: simulate -const numpy = Ref{Py}() -const braket = Ref{Py}() -const sympy = Ref{Py}() - -include("translation.jl") - -function __init__() - # must set these when this code is actually loaded - braket[] = pyimport("braket") - numpy[] = pyimport("numpy") - pyimport("braket.ir.openqasm.program_v1") - pyimport("braket.task_result.task_metadata_v1") - pyimport("braket.task_result.additional_metadata") +function BraketSimulator.simulate(simulator, task_spec::String, inputs::Dict{String, Any}, shots::Int; kwargs...) + jl_specs = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), task_spec, inputs) + jl_results = simulate(simulator, jl_specs, shots; kwargs...) + json = JSON3.write(jl_results) + return json end - -@recompile_invalidations begin - function simulate(simulator::AbstractSimulator, - task_specs::PyList{Any}, - args...; - max_parallel::Int=-1, - inputs::Union{PyDict{Any, Any}, PyList{Any}, Nothing} = nothing, - shots::Int=0, - kwargs... - ) - PythonCall.GC.disable() - jl_specs = convert(Vector{Union{Braket.OpenQasmProgram, Braket.Program}}, task_specs) - if !isnothing(inputs) - py_inputs = inputs isa PyDict ? [inputs] : inputs - n_inputs = length(py_inputs) - jl_inputs = Vector{Dict{String, Float64}}(undef, n_inputs) - for input_ix in 1:n_inputs - jl_inputs[input_ix] = Dict{String, Float64}(pyconvert(String, k)=>pyconvert(Float64, v) for (k,v) in py_inputs[input_ix]) - end - jl_kwargs = (max_parallel=max_parallel, inputs=jl_inputs) - else - jl_kwargs = (max_parallel=max_parallel,) - end - jl_results = simulate(simulator, jl_specs, shots; jl_kwargs...) - PythonCall.GC.enable() - return map(Py, jl_results) - end +function BraketSimulator.simulate(simulator, task_specs::Vector{String}, inputs::Vector{Dict{String, Any}}, shots::Int; kwargs...) + jl_specs = [BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), task_spec, input) for (task_spec, input) in zip(task_specs, inputs)] + jl_results = simulate(simulator, jl_specs, shots; kwargs...) + jsons = [JSON3.write(r) for r in jl_results] + return jsons end end diff --git a/ext/BraketSimulatorPythonExt/translation.jl b/ext/BraketSimulatorPythonExt/translation.jl deleted file mode 100644 index d832fed..0000000 --- a/ext/BraketSimulatorPythonExt/translation.jl +++ /dev/null @@ -1,59 +0,0 @@ -convert_targets(::Nothing) = PythonCall.pybuiltins.None -convert_targets(ts::Vector{Int}) = pylist(ts) - -function inputs_to_jl(x) - pyis(x, pybuiltins.None) && return nothing - jl_inputs = map(x.items()) do x_ - k, v = x_ - jl_k = pyconvert(String, k) - jl_v = pyisinstance(v, pybuiltins.int) ? pyconvert(Int, v) : pyconvert(Float64, v) - return jl_k=>jl_v - end - return Dict(jl_inputs) -end - -py_obs(o::String) = pylist([pystr(o)]) -function py_obs(obs::Vector) - raw_obs = map(obs) do o - o isa String ? pystr(o) : pylist(pylist(pylist(o__) for o__ in o_) for o_ in o) - end - return pylist(raw_obs) -end -Py(r::Braket.IR.Sample) = braket[].ir.jaqcd.results.Sample(targets=convert_targets(r.targets), observable=py_obs(r.observable), type=pystr("sample")) -Py(r::Braket.IR.Expectation) = braket[].ir.jaqcd.results.Expectation(targets=convert_targets(r.targets), observable=py_obs(r.observable), type=pystr("expectation")) -Py(r::Braket.IR.Variance) = braket[].ir.jaqcd.results.Variance(observable=py_obs(r.observable), targets=convert_targets(r.targets), type=pystr("variance")) -Py(r::Braket.IR.Amplitude) = braket[].ir.jaqcd.results.Amplitude(states=pylist(pystr(s) for s in r.states), type=pystr("amplitude")) -Py(r::Braket.IR.StateVector) = braket[].ir.jaqcd.results.StateVector(type=pystr("statevector")) -Py(r::Braket.IR.DensityMatrix) = braket[].ir.jaqcd.results.DensityMatrix(targets=convert_targets(r.targets), type=pystr("densitymatrix")) -Py(r::Braket.IR.Probability) = braket[].ir.jaqcd.results.Probability(targets=convert_targets(r.targets), type=pystr("probability")) -# exclude adjoint gradient translation from coverage for now -# as we don't yet implement this, so don't have a test for it -# COV_EXCL_START -Py(r::Braket.IR.AdjointGradient) = braket[].ir.jaqcd.results.AdjointGradient(targets=convert_targets(r.targets), observable=pylist(r.observable), parameters=pylist(pystr(p) for p in r.parameters), type=pystr("adjoint_gradient")) -# COV_EXCL_STOP - -function Py(rt::Braket.ResultTypeValue) - py_typ = Py(rt.type) - py_val = if rt.value isa Dict - pydict(rt.value) - elseif rt.value isa Float64 - rt.value - elseif rt.value isa Vector{Vector{Vector{Float64}}} - pylist(pylist(pycomplex(v_...) for v_ in v) for v in rt.value) - else - pylist(rt.value) - end - return braket[].task_result.gate_model_task_result_v1.ResultTypeValue(type=py_typ, value=py_val) -end - -function Py(r::GateModelTaskResult) - py_measurements = (isnothing(r.measurements) || isempty(r.measurements)) ? PythonCall.pybuiltins.None : pyrowlist(transpose(reduce(hcat, r.measurements))) - py_probabilities = !isnothing(r.measurementProbabilities) ? pydict(Dict(pystr(k)=>v for (k,v) in r.measurementProbabilities)) : PythonCall.pybuiltins.None - py_qubits = !isnothing(r.measuredQubits) ? pylist(r.measuredQubits) : PythonCall.pybuiltins.None - py_results = pylist(Py(rtv) for rtv in r.resultTypes) - py_task_mtd = braket[].task_result.task_metadata_v1.TaskMetadata(id=pystr(r.taskMetadata.id), shots=Py(r.taskMetadata.shots), deviceId=pystr(r.taskMetadata.deviceId)) - # we create a placeholder OpenQASM3 Program here -- this is replaced by the "true" action in the Python wrapper - dummy_action = braket[].ir.openqasm.program_v1.Program(source=pystr("")) - py_addl_mtd = braket[].task_result.additional_metadata.AdditionalMetadata(action=dummy_action) - return braket[].task_result.GateModelTaskResult(measurements=py_measurements, measurementProbabilities=py_probabilities, resultTypes=py_results, measuredQubits=py_qubits, taskMetadata=py_task_mtd, additionalMetadata=py_addl_mtd) -end diff --git a/src/BraketSimulator.jl b/src/BraketSimulator.jl index 238a58c..d2cdd43 100644 --- a/src/BraketSimulator.jl +++ b/src/BraketSimulator.jl @@ -2,61 +2,81 @@ module BraketSimulator using Dates, + Combinatorics, LinearAlgebra, StaticArrays, StatsBase, - Combinatorics, UUIDs, - JSON3, + StructTypes, Random, PrecompileTools -#PrecompileTools.verbose[] = true - -using Braket, Braket.Observables - -import Braket: - Instruction, - AbstractBraketSimulator, - Program, - OpenQasmProgram, - ir_typ, - apply_gate!, - apply_noise!, - qubit_count, - I, - simulate, - device_id, - bind_value! +export StateVectorSimulator, DensityMatrixSimulator, evolve!, simulate, ValidationError -export StateVectorSimulator, DensityMatrixSimulator, evolve!, simulate, U, MultiQubitPhaseShift, MultiRZ, ValidationError - -const StateVector{T} = Vector{T} -const DensityMatrix{T} = Matrix{T} const AbstractStateVector{T} = AbstractVector{T} const AbstractDensityMatrix{T} = AbstractMatrix{T} -abstract type AbstractSimulator <: Braket.AbstractBraketSimulator end -Braket.name(s::AbstractSimulator) = device_id(s) +abstract type AbstractSimulator end ap_size(shots::Int, qubit_count::Int) = (shots > 0 && qubit_count < 30) ? 2^qubit_count : 0 +""" + FreeParameter + FreeParameter(name::Symbol) -> FreeParameter + +Struct representing a free parameter, which may be used to initialize +to a parametrized [`Gate`](@ref) or [`Noise`](@ref) and then given a +fixed value later by supplying a mapping to a [`Circuit`](@ref). +""" +struct FreeParameter + name::Symbol + FreeParameter(name::Symbol) = new(name) + FreeParameter(name::String) = new(Symbol(name)) +end +Base.copy(fp::FreeParameter) = fp +Base.show(io::IO, fp::FreeParameter) = print(io, string(fp.name)) + +function complex_matrix_from_ir(mat::Vector{Vector{Vector{T}}}) where {T<:Number} + m = zeros(complex(T), length(mat), length(mat)) + for ii in 1:length(mat), jj in 1:length(mat) + m[ii,jj] = complex(mat[ii][jj][1], mat[ii][jj][2]) + end + return m +end + +function complex_matrix_to_ir(m::Matrix{T}) where {T<:Complex} + mat = Vector{Vector{Vector{real(T)}}}(undef, size(m, 1)) + for row in 1:size(m, 1) + mat[row] = Vector{Vector{T}}(undef, size(m, 2)) + for col in 1:size(m, 2) + mat[row][col] = [real(m[row, col]), imag(m[row, col])] + end + end + return mat +end + + + +include("raw_schema.jl") +include("qubit_set.jl") +include("operators.jl") +include("gates.jl") +include("noises.jl") +include("schemas.jl") +include("observables.jl") +using .Observables +include("results.jl") +include("circuit.jl") include("validation.jl") include("custom_gates.jl") -include("inverted_gates.jl") include("pow_gates.jl") include("gate_kernels.jl") include("noise_kernels.jl") include("Quasar.jl") - using .Quasar -const BuiltinGates = merge(Braket.StructTypes.subtypes(Braket.Gate), custom_gates) - const OBS_LIST = (Observables.X(), Observables.Y(), Observables.Z()) const CHUNK_SIZE = 2^10 -parse_program(d, program, shots::Int) = throw(MethodError(parse_program, (d, program, shots))) - function _index_to_endian_bits(ix::Int, qubit_count::Int) bits = Vector{Int}(undef, qubit_count) for qubit = 0:qubit_count-1 @@ -74,13 +94,13 @@ function _formatted_measurements(simulator::D, measured_qubits::Vector{Int}=coll end function _bundle_results( - results::Vector{Braket.ResultTypeValue}, + results::Vector{ResultTypeValue}, circuit_ir::Program, simulator::D, measured_qubits::Vector{Int} = collect(0:qubit_count(simulator)-1) ) where {D<:AbstractSimulator} - task_mtd = Braket.TaskMetadata( - Braket.header_dict[Braket.TaskMetadata], + task_mtd = TaskMetadata( + braketSchemaHeader("braket.task_result.task_metadata", "1"), string(uuid4()), simulator.shots, device_id(simulator), @@ -90,7 +110,7 @@ function _bundle_results( nothing, nothing, ) - addl_mtd = Braket.AdditionalMetadata( + addl_mtd = AdditionalMetadata( circuit_ir, nothing, nothing, @@ -100,9 +120,9 @@ function _bundle_results( nothing, nothing, ) - formatted_samples = simulator.shots > 0 ? _formatted_measurements(simulator, measured_qubits) : Vector{Int}[] - return Braket.GateModelTaskResult( - Braket.header_dict[Braket.GateModelTaskResult], + formatted_samples = simulator.shots > 0 ? _formatted_measurements(simulator, measured_qubits) : nothing + return GateModelTaskResult( + braketSchemaHeader("braket.task_result.gate_model_task_result", "1"), formatted_samples, nothing, results, @@ -113,13 +133,13 @@ function _bundle_results( end function _bundle_results( - results::Vector{Braket.ResultTypeValue}, + results::Vector{ResultTypeValue}, circuit_ir::OpenQasmProgram, simulator::D, measured_qubits = Set{Int}(0:qubit_count(simulator)-1) ) where {D<:AbstractSimulator} - task_mtd = Braket.TaskMetadata( - Braket.header_dict[Braket.TaskMetadata], + task_mtd = TaskMetadata( + braketSchemaHeader("braket.task_result.task_metadata", "1"), string(uuid4()), simulator.shots, device_id(simulator), @@ -129,7 +149,7 @@ function _bundle_results( nothing, nothing, ) - addl_mtd = Braket.AdditionalMetadata( + addl_mtd = AdditionalMetadata( circuit_ir, nothing, nothing, @@ -140,9 +160,9 @@ function _bundle_results( nothing, ) sorted_qubits = sort(collect(measured_qubits)) - formatted_samples = simulator.shots > 0 ? _formatted_measurements(simulator, sorted_qubits) : Vector{Int}[] - return Braket.GateModelTaskResult( - Braket.header_dict[Braket.GateModelTaskResult], + formatted_samples = simulator.shots > 0 ? _formatted_measurements(simulator, sorted_qubits) : nothing + return GateModelTaskResult( + braketSchemaHeader("braket.task_result.gate_model_task_result", "1"), formatted_samples, nothing, results, @@ -153,50 +173,38 @@ function _bundle_results( end function _generate_results( - results::Vector{<:Braket.AbstractProgramResult}, + results::Vector{<:AbstractProgramResult}, result_types::Vector, simulator::D, ) where {D<:AbstractSimulator} result_values = map(result_type -> calculate(result_type, simulator), result_types) result_values = - [val isa Matrix ? Braket.complex_matrix_to_ir(val) : val for val in result_values] - final_results = Vector{Braket.ResultTypeValue}(undef, length(result_values)) + [val isa Matrix ? complex_matrix_to_ir(val) : val for val in result_values] + final_results = Vector{ResultTypeValue}(undef, length(result_values)) for r_ix in 1:length(final_results) - final_results[r_ix] = Braket.ResultTypeValue(results[r_ix], result_values[r_ix]) + final_results[r_ix] = ResultTypeValue(results[r_ix], result_values[r_ix]) end return final_results end -_translate_result_type(r::Braket.IR.Amplitude, qc::Int) = Braket.Amplitude(r.states) -_translate_result_type(r::Braket.IR.StateVector, qc::Int) = Braket.StateVector() +_translate_result_type(r::IR.Amplitude, qc::Int) = Amplitude(r.states) +_translate_result_type(r::IR.StateVector, qc::Int) = StateVector() # The IR result types support `nothing` as a valid option for the `targets` field, -# however `Braket.jl`'s `Result`s represent this with an empty `QubitSet` for type +# however `Result`s represent this with an empty `QubitSet` for type # stability reasons. Here we take a `nothing` value for `targets` and translate it # to apply to all qubits. -_translate_result_type(r::Braket.IR.DensityMatrix, qc::Int) = isnothing(r.targets) ? Braket.DensityMatrix(collect(0:qc-1)) : Braket.DensityMatrix(r.targets) -_translate_result_type(r::Braket.IR.Probability, qc::Int) = isnothing(r.targets) ? Braket.Probability(collect(0:qc-1)) : Braket.Probability(r.targets) -function _translate_result_type(r::Braket.IR.Expectation, qc::Int) - targets = isnothing(r.targets) ? collect(0:qc-1) : r.targets - obs = Braket.StructTypes.constructfrom(Braket.Observables.Observable, r.observable) - Braket.Expectation(obs, QubitSet(targets)) -end -function _translate_result_type(r::Braket.IR.Variance, qc::Int) - targets = isnothing(r.targets) ? collect(0:qc-1) : r.targets - obs = Braket.StructTypes.constructfrom(Braket.Observables.Observable, r.observable) - Braket.Variance(obs, QubitSet(targets)) -end -function _translate_result_type(r::Braket.IR.Sample, qc::Int) - targets = isnothing(r.targets) ? collect(0:qc-1) : r.targets - obs = Braket.StructTypes.constructfrom(Braket.Observables.Observable, r.observable) - Braket.Sample(obs, QubitSet(targets)) -end - -function _translate_result_types( - results::Vector{Braket.AbstractProgramResult}, - qubit_count::Int, -) - return map(result->_translate_result_type(result, qubit_count), results) +_translate_result_type(r::IR.DensityMatrix, qc::Int) = isnothing(r.targets) ? DensityMatrix(collect(0:qc-1)) : DensityMatrix(r.targets) +_translate_result_type(r::IR.Probability, qc::Int) = isnothing(r.targets) ? Probability(collect(0:qc-1)) : Probability(r.targets) +for (RT, IRT) in ((:Expectation, :(IR.Expectation)), (:Variance, :(IR.Variance)), (:Sample, :(IR.Sample))) + @eval begin + function _translate_result_type(r::$IRT, qc::Int) + targets = isnothing(r.targets) ? collect(0:qc-1) : r.targets + obs = StructTypes.constructfrom(Observables.Observable, r.observable) + $RT(obs, QubitSet(targets)) + end + end end +_translate_result_types(results::Vector{AbstractProgramResult}, qubit_count::Int) = map(result->_translate_result_type(result, qubit_count), results) function _compute_exact_results(d::AbstractSimulator, program::Program, qc::Int) result_types = _translate_result_types(program.results, qc) @@ -214,15 +222,14 @@ function _verify_openqasm_shots_observables(circuit::Circuit) # must ensure observable is the same typeof(previously_measured) != typeof(observable) && throw(ValidationError("Conflicting result types applied to a single qubit", "ValueError")) # including matrix value for Hermitians - observable isa Braket.Observables.HermitianObservable && !isapprox(previously_measured.matrix, observable.matrix) && throw(ValidationError("Conflicting result types applied to a single qubit", "ValueError")) + observable isa Observables.HermitianObservable && !isapprox(previously_measured.matrix, observable.matrix) && throw(ValidationError("Conflicting result types applied to a single qubit", "ValueError")) end end observable_map[qubits] = observable end - for result in filter(rt->rt isa Braket.ObservableResult, circuit.result_types) - result.observable isa Braket.Observables.I && continue - observable_qubits = result.targets - if result.observable isa Braket.Observables.TensorProduct + for result in filter(rt->rt isa ObservableResult, circuit.result_types) + result.observable isa Observables.I && continue + if result.observable isa Observables.TensorProduct result_targets = collect(result.targets) for observable in result.observable.factors obs_targets = splice!(result_targets, 1:qubit_count(observable)) @@ -235,170 +242,158 @@ function _verify_openqasm_shots_observables(circuit::Circuit) return end -@recompile_invalidations begin - """ - simulate(simulator::AbstractSimulator, circuit_ir; shots::Int = 0, kwargs...) -> GateModelTaskResult - - Simulate the evolution of a statevector or density matrix using the passed in `simulator`. - The instructions to apply (gates and noise channels) and measurements to make are - encoded in `circuit_ir`. Supported IR formats are `OpenQASMProgram` (OpenQASM3) - and `Program` (JAQCD). Returns a `GateModelTaskResult` containing the individual shot - measurements (if `shots > 0`), final calculated results, circuit IR, and metadata - about the task. - """ - function simulate( - simulator::AbstractSimulator, - circuit_ir::OpenQasmProgram, - shots::Int = 0; - kwargs..., - ) - ir_inputs = isnothing(circuit_ir.inputs) || isempty(circuit_ir.inputs) ? Dict{String, Float64}() : circuit_ir.inputs - inputs = get(kwargs, :inputs, ir_inputs) - inputs = isnothing(inputs) || isempty(inputs) ? ir_inputs : Dict{String, Any}(k=>v for (k,v) in inputs) - circuit = Circuit(circuit_ir.source, inputs) - measure_ixs = splice!(circuit.instructions, findall(ix->ix.operator isa Measure, circuit.instructions)) - measure_targets = (convert(Vector{Int}, measure.target) for measure in measure_ixs) - measured_qubits = convert(Vector{Int}, unique(reduce(vcat, measure_targets, init=Int[])))::Vector{Int} - if shots > 0 - _verify_openqasm_shots_observables(circuit) - Braket.basis_rotation_instructions!(circuit) - end - program = Program(circuit) - program_qc = qubit_count(program) - n_qubits = max(program_qc, max(measured_qubits..., 0)+1)::Int - _validate_ir_results_compatibility(simulator, program.results, Val(:JAQCD)) - _validate_ir_instructions_compatibility(simulator, program, Val(:JAQCD)) - _validate_shots_and_ir_results(shots, program.results, n_qubits) - operations = program.instructions - if shots > 0 && !isempty(program.basis_rotation_instructions) - operations = vcat(operations, program.basis_rotation_instructions) - end - _validate_operation_qubits(vcat(operations, measure_ixs)) - reinit!(simulator, n_qubits, shots) - simulator = evolve!(simulator, operations) - analytic_results = shots == 0 && !isnothing(program.results) && !isempty(program.results) - results = if analytic_results - _compute_exact_results(simulator, program, n_qubits) - elseif isnothing(program.results) || isempty(program.results) - Braket.ResultTypeValue[] +""" + simulate(simulator::AbstractSimulator, circuit_ir; shots::Int = 0, kwargs...) -> GateModelTaskResult + +Simulate the evolution of a statevector or density matrix using the passed in `simulator`. +The instructions to apply (gates and noise channels) and measurements to make are +encoded in `circuit_ir`. Supported IR formats are `OpenQASMProgram` (OpenQASM3) +and `Program` (JAQCD). Returns a `GateModelTaskResult` containing the individual shot +measurements (if `shots > 0`), final calculated results, circuit IR, and metadata +about the task. +""" +function simulate( + simulator::AbstractSimulator, + circuit_ir::OpenQasmProgram, + shots::Int = 0; + kwargs..., +) + ir_inputs = isnothing(circuit_ir.inputs) || isempty(circuit_ir.inputs) ? Dict{String, Float64}() : circuit_ir.inputs + inputs = get(kwargs, :inputs, ir_inputs) + inputs = isnothing(inputs) || isempty(inputs) ? ir_inputs : Dict{String, Any}(k=>v for (k,v) in inputs) + circuit = Circuit(circuit_ir.source, inputs) + if shots > 0 + _verify_openqasm_shots_observables(circuit) + basis_rotation_instructions!(circuit) + end + measure_ixs = splice!(circuit.instructions, findall(ix->ix.operator isa Measure, circuit.instructions)) + measure_targets = (convert(Vector{Int}, measure.target) for measure in measure_ixs) + measured_qubits = convert(Vector{Int}, unique(reduce(vcat, measure_targets, init=Int[])))::Vector{Int} + program = Program(circuit) + program_qc = qubit_count(program) + n_qubits = max(program_qc, max(measured_qubits..., 0)+1)::Int + _validate_ir_results_compatibility(simulator, program.results, Val(:JAQCD)) + _validate_ir_instructions_compatibility(simulator, program, Val(:JAQCD)) + _validate_shots_and_ir_results(shots, program.results, n_qubits) + operations = program.instructions + if shots > 0 && !isempty(program.basis_rotation_instructions) + operations = vcat(operations, program.basis_rotation_instructions) + end + _validate_operation_qubits(vcat(operations, measure_ixs)) + reinit!(simulator, n_qubits, shots) + simulator = evolve!(simulator, operations) + analytic_results = shots == 0 && !isnothing(program.results) && !isempty(program.results) + results = if analytic_results + _compute_exact_results(simulator, program, n_qubits) + elseif isnothing(program.results) || isempty(program.results) + ResultTypeValue[] + else + ResultTypeValue[ResultTypeValue(result_type, 0.0) for result_type in program.results] + end + isempty(measured_qubits) && (measured_qubits = collect(0:n_qubits-1)) + return _bundle_results(results, circuit_ir, simulator, measured_qubits) +end +function simulate(simulator::AbstractSimulator, + task_specs::Vector{<:Union{Program, OpenQasmProgram}}, + shots::Int=0; + max_parallel::Int=-1, + inputs = Dict{String, Float64}(), + kwargs... + ) + is_single_task = length(task_specs) == 1 + is_single_input = inputs isa Dict || length(inputs) == 1 + if is_single_input && is_single_task + if inputs isa Vector + return [simulate(simulator, only(task_specs), shots; inputs=only(inputs), kwargs...)] else - Braket.ResultTypeValue[Braket.ResultTypeValue(result_type, 0.0) for result_type in program.results] + return [simulate(simulator, only(task_specs), shots; inputs=inputs, kwargs...)] end - isempty(measured_qubits) && (measured_qubits = collect(0:n_qubits-1)) - res = _bundle_results(results, circuit_ir, simulator, measured_qubits) - return res end - - function simulate( - simulator::AbstractSimulator, - circuit_ir::Program, - qubit_count::Int, - shots::Int; - kwargs..., - ) - _validate_ir_results_compatibility(simulator, circuit_ir.results, Val(:JAQCD)) - _validate_ir_instructions_compatibility(simulator, circuit_ir, Val(:JAQCD)) - _validate_shots_and_ir_results(shots, circuit_ir.results, qubit_count) - operations::Vector{Instruction} = circuit_ir.instructions - if shots > 0 && !isnothing(circuit_ir.basis_rotation_instructions) && !isempty(circuit_ir.basis_rotation_instructions) - operations = vcat(operations, circuit_ir.basis_rotation_instructions) - end - inputs = get(kwargs, :inputs, Dict{String,Float64}()) - symbol_inputs = Dict{Symbol,Number}(Symbol(k) => v for (k, v) in inputs) - operations = [bind_value!(Instruction(operation), symbol_inputs) for operation in operations] - _validate_operation_qubits(operations) - reinit!(simulator, qubit_count, shots) - simulator = evolve!(simulator, operations) - analytic_results = shots == 0 && !isnothing(circuit_ir.results) && !isempty(circuit_ir.results) - results = if analytic_results - _compute_exact_results(simulator, circuit_ir, qubit_count) + if is_single_input + if inputs isa Dict + inputs = [deepcopy(inputs) for ix in 1:length(task_specs)] else - Braket.ResultTypeValue[] + inputs = [deepcopy(only(inputs)) for ix in 1:length(task_specs)] end - measured_qubits = get(kwargs, :measured_qubits, collect(0:qubit_count-1)) - isempty(measured_qubits) && (measured_qubits = collect(0:qubit_count-1)) - res = _bundle_results(results, circuit_ir, simulator, measured_qubits) - return res end - simulate(simulator::AbstractSimulator, circuit_ir::Program, shots::Int; kwargs...) = simulate(simulator, circuit_ir, qubit_count(circuit_ir), shots; kwargs...) - function simulate(simulator::AbstractSimulator, - task_specs::Vector{<:Union{Program, OpenQasmProgram}}, - shots::Int=0; - max_parallel::Int=-1, - inputs::Union{Vector{Dict{String, Float64}}, Dict{String, Float64}} = Dict{String, Float64}(), - kwargs... - ) - is_single_task = length(task_specs) == 1 - is_single_input = inputs isa Dict || length(inputs) == 1 - if is_single_input && is_single_task - if inputs isa Vector - return [simulate(simulator, only(task_specs), shots; inputs=only(inputs), kwargs...)] - else - return [simulate(simulator, only(task_specs), shots; inputs=inputs, kwargs...)] - end - end - if is_single_input - if inputs isa Dict - inputs = [deepcopy(inputs) for ix in 1:length(task_specs)] - else - inputs = [deepcopy(only(inputs)) for ix in 1:length(task_specs)] - end - end - !is_single_task && !is_single_input && (length(task_specs) != length(inputs)) && throw(ArgumentError("number of inputs ($(length(inputs))), and task specifications ($(length(task_specs))) must be equal.")) - n_tasks = length(task_specs) - - todo_tasks_ch = Channel{Int}(ch->foreach(ix->put!(ch, ix), 1:n_tasks), n_tasks) - - max_parallel_threads = max_parallel > 0 ? max_parallel : min(32, Threads.nthreads()) - n_task_threads = min(max_parallel_threads, n_tasks) - - results = Vector{Braket.GateModelTaskResult}(undef, n_tasks) - function process_work(my_sim) - while isready(todo_tasks_ch) - my_ix = -1 - # need to lock the channel as it may become empty - # and "unready" in between the while-loop call - # and the call to take! - lock(todo_tasks_ch) do - my_ix = isready(todo_tasks_ch) ? take!(todo_tasks_ch) : -1 - end - # if my_ix is still -1, the channel is empty and - # there's no more work to do - my_ix == -1 && break - spec = task_specs[my_ix] - input = inputs[my_ix] - results[my_ix] = simulate(my_sim, spec, shots; inputs=input) + !is_single_task && !is_single_input && (length(task_specs) != length(inputs)) && throw(ArgumentError("number of inputs ($(length(inputs))), and task specifications ($(length(task_specs))) must be equal.")) + n_tasks = length(task_specs) + + todo_tasks_ch = Channel{Int}(ch->foreach(ix->put!(ch, ix), 1:n_tasks), n_tasks) + + max_parallel_threads = max_parallel > 0 ? max_parallel : min(32, Threads.nthreads()) + n_task_threads = min(max_parallel_threads, n_tasks) + + results = Vector{GateModelTaskResult}(undef, n_tasks) + function process_work(my_sim) + while isready(todo_tasks_ch) + my_ix = -1 + # need to lock the channel as it may become empty + # and "unready" in between the while-loop call + # and the call to take! + lock(todo_tasks_ch) do + my_ix = isready(todo_tasks_ch) ? take!(todo_tasks_ch) : -1 end - return - end - tasks = Vector{Task}(undef, n_task_threads) - # need sync here to ensure all the spawns launch - @sync for worker in 1:n_task_threads - tasks[worker] = Threads.@spawn process_work(similar(simulator)) + # if my_ix is still -1, the channel is empty and + # there's no more work to do + my_ix == -1 && break + spec = task_specs[my_ix] + input = inputs[my_ix] + results[my_ix] = simulate(my_sim, spec, shots; inputs=input) end - # tasks don't return anything so we can wait rather than fetch - wait.(tasks) - # check to ensure all the results were in fact populated - for r_ix in 1:n_tasks - @assert isassigned(results, r_ix) - end - return results + return + end + tasks = Vector{Task}(undef, n_task_threads) + # need sync here to ensure all the spawns launch + @sync for worker in 1:n_task_threads + tasks[worker] = Threads.@spawn process_work(similar(simulator)) end + # tasks don't return anything so we can wait rather than fetch + wait.(tasks) + # check to ensure all the results were in fact populated + for r_ix in 1:n_tasks + @assert isassigned(results, r_ix) + end + return results end -include("observables.jl") +function simulate( + simulator::AbstractSimulator, + circuit_ir::Program, + qubit_count::Int, + shots::Int; + kwargs..., +) + _validate_ir_results_compatibility(simulator, circuit_ir.results, Val(:JAQCD)) + _validate_ir_instructions_compatibility(simulator, circuit_ir, Val(:JAQCD)) + _validate_shots_and_ir_results(shots, circuit_ir.results, qubit_count) + operations::Vector{Instruction} = circuit_ir.instructions + if shots > 0 && !isnothing(circuit_ir.basis_rotation_instructions) && !isempty(circuit_ir.basis_rotation_instructions) + operations = vcat(operations, circuit_ir.basis_rotation_instructions) + end + inputs = get(kwargs, :inputs, Dict{String,Float64}()) + symbol_inputs = Dict(Symbol(k) => v for (k, v) in inputs) + operations = [bind_value!(Instruction(operation), symbol_inputs) for operation in operations] + _validate_operation_qubits(operations) + reinit!(simulator, qubit_count, shots) + simulator = evolve!(simulator, operations) + analytic_results = shots == 0 && !isnothing(circuit_ir.results) && !isempty(circuit_ir.results) + results = if analytic_results + _compute_exact_results(simulator, circuit_ir, qubit_count) + else + ResultTypeValue[] + end + measured_qubits = get(kwargs, :measured_qubits, collect(0:qubit_count-1)) + isempty(measured_qubits) && (measured_qubits = collect(0:qubit_count-1)) + return _bundle_results(results, circuit_ir, simulator, measured_qubits) +end +simulate(simulator::AbstractSimulator, circuit_ir::Program, shots::Int; kwargs...) = simulate(simulator, circuit_ir, qubit_count(circuit_ir), shots; kwargs...) + include("result_types.jl") include("properties.jl") include("sv_simulator.jl") include("dm_simulator.jl") -function __init__() - Braket._simulator_devices[]["braket_dm_v2"] = - DensityMatrixSimulator{ComplexF64,DensityMatrix{ComplexF64}} - Braket._simulator_devices[]["braket_sv_v2"] = - StateVectorSimulator{ComplexF64,StateVector{ComplexF64}} -end - @setup_workload begin custom_qasm = """ int[8] two = 2; @@ -511,25 +506,24 @@ end #pragma braket result probability b """ @compile_workload begin - using Braket, BraketSimulator, BraketSimulator.Quasar + using BraketSimulator, BraketSimulator.Quasar simulator = StateVectorSimulator(5, 0) - oq3_program = Braket.OpenQasmProgram(Braket.header_dict[Braket.OpenQasmProgram], custom_qasm, nothing) + oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), custom_qasm, nothing) simulate(simulator, oq3_program, 100) - + simulator = DensityMatrixSimulator(2, 0) - oq3_program = Braket.OpenQasmProgram(Braket.header_dict[Braket.OpenQasmProgram], noise_qasm, nothing) + oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), noise_qasm, nothing) simulate(simulator, oq3_program, 100) simulate(simulator, [oq3_program, oq3_program], 100) - + simulator = StateVectorSimulator(3, 0) - oq3_program = Braket.OpenQasmProgram(Braket.header_dict[Braket.OpenQasmProgram], unitary_qasm, nothing) + oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), unitary_qasm, nothing) simulate(simulator, oq3_program, 100) simulate(simulator, [oq3_program, oq3_program], 100) - + simulator = StateVectorSimulator(6, 0) - oq3_program = Braket.OpenQasmProgram(Braket.header_dict[Braket.OpenQasmProgram], sv_adder_qasm, Dict("a_in"=>3, "b_in"=>7)) + oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), sv_adder_qasm, Dict("a_in"=>3, "b_in"=>7)) simulate(simulator, oq3_program, 0) end end - end # module BraketSimulator diff --git a/src/Quasar.jl b/src/Quasar.jl index 2114766..fc65899 100644 --- a/src/Quasar.jl +++ b/src/Quasar.jl @@ -1,13 +1,11 @@ module Quasar using ..BraketSimulator -using Automa, AbstractTrees, DataStructures, Braket -using PrecompileTools: @setup_workload, @compile_workload +using Automa, AbstractTrees, DataStructures using DataStructures: Stack -using Braket: Instruction, bind_value!, remap -using BraketSimulator: Control +using BraketSimulator: Control, Instruction, Result, bind_value!, remap, qubit_count, Circuit -export parse_qasm, QasmProgramVisitor +export parse_qasm, QasmProgramVisitor, Circuit struct QasmParseError <: Exception message::String @@ -67,6 +65,7 @@ const qasm_tokens = [ :power_mod => re"pow", :measure => re"measure", :arrow_token => re"->", + :reset_token => re"reset", :void => re"void", :const_token => re"const", :assignment => re"=|-=|\+=|\*=|/=|^=|&=|\|=|<<=|>>=", @@ -104,7 +103,7 @@ const qasm_tokens = [ :newline => re"\r?\n", :spaces => re"[\t ]+", :classical_type => re"bool|uint|int|float|angle|complex|array|bit", - :forbidden_keyword => re"cal|defcal|duration|durationof|stretch|reset|delay|barrier|extern", + :forbidden_keyword => re"cal|defcal|duration|durationof|stretch|delay|barrier|extern", ] @eval @enum Token error $(first.(qasm_tokens)...) @@ -291,28 +290,40 @@ end struct SizedBitVector <: AbstractArray{Bool, 1} size::QasmExpression + SizedBitVector(size::QasmExpression) = new(size) + SizedBitVector(sbv::SizedBitVector) = new(sbv.size) end Base.length(s::SizedBitVector) = s.size Base.size(s::SizedBitVector) = (s.size,) Base.show(io::IO, s::SizedBitVector) = print(io, "SizedBitVector{$(s.size.args[end])}") struct SizedInt <: Integer size::QasmExpression + SizedInt(size::QasmExpression) = new(size) + SizedInt(sint::SizedInt) = new(sint.size) end Base.show(io::IO, s::SizedInt) = print(io, "SizedInt{$(s.size.args[end])}") struct SizedUInt <: Unsigned size::QasmExpression + SizedUInt(size::QasmExpression) = new(size) + SizedUInt(suint::SizedUInt) = new(suint.size) end Base.show(io::IO, s::SizedUInt) = print(io, "SizedUInt{$(s.size.args[end])}") struct SizedFloat <: AbstractFloat size::QasmExpression + SizedFloat(size::QasmExpression) = new(size) + SizedFloat(sfloat::SizedFloat) = new(sfloat.size) end Base.show(io::IO, s::SizedFloat) = print(io, "SizedFloat{$(s.size.args[end])}") struct SizedAngle <: AbstractFloat size::QasmExpression + SizedAngle(size::QasmExpression) = new(size) + SizedAngle(sangle::SizedAngle) = new(sangle.size) end Base.show(io::IO, s::SizedAngle) = print(io, "SizedAngle{$(s.size.args[end])}") struct SizedComplex <: Number size::QasmExpression + SizedComplex(size::QasmExpression) = new(size) + SizedComplex(scomplex::SizedComplex) = new(scomplex.size) end Base.show(io::IO, s::SizedComplex) = print(io, "SizedComplex{$(s.size.args[end])}") @@ -396,7 +407,7 @@ const binary_assignment_ops = Dict{String, Symbol}( ) function parse_assignment_op(op_token, qasm) op_string = parse_identifier(op_token, qasm) - return binary_assignment_ops[op_string.args[1]] + return binary_assignment_ops[op_string.args[1]::String] end parse_string_literal(token, qasm) = QasmExpression(:string_literal, String(qasm[token[1]:token[1]+token[2]-1])) @@ -983,9 +994,14 @@ function parse_qasm(clean_tokens::Vector{Tuple{Int64, Int32, Token}}, qasm::Stri elseif token == box @warn "box expression encountered -- currently boxed and delayed expressions are not supported" box_expr = QasmExpression(:box) - # handle condition parse_block_body(box_expr, clean_tokens, stack, start, qasm) push!(stack, box_expr) + elseif token == reset_token + @warn "reset expression encountered -- currently `reset` is a no-op" + eol = findfirst(triplet->triplet[end] == semicolon, clean_tokens) + reset_tokens = splice!(clean_tokens, 1:eol) + targets = parse_expression(reset_tokens, stack, start, qasm) + push!(stack, QasmExpression(:reset, targets)) elseif token == end_token push!(stack, QasmExpression(:end)) elseif token == identifier || token == builtin_gate @@ -1062,7 +1078,7 @@ mutable struct QasmProgramVisitor <: AbstractVisitor qubit_count::Int instructions::Vector{Instruction} results::Vector{Result} - function QasmProgramVisitor(inputs = Dict{String, Any}()) + function QasmProgramVisitor(inputs::Dict{String, <:Any} = Dict{String, Any}()) new(inputs, Dict{String, ClassicalVariable}(), Dict{String, FunctionDefinition}(), @@ -1078,7 +1094,7 @@ end mutable struct QasmGateDefVisitor <: AbstractVisitor parent::AbstractVisitor - params::Dict{String, FreeParameter} + params::Dict{String, BraketSimulator.FreeParameter} qubit_defs::Dict{String, Qubit} qubit_mapping::Dict{String, Vector{Int}} qubit_count::Int @@ -1103,7 +1119,8 @@ mutable struct QasmFunctionVisitor <: AbstractVisitor qubit_mapping::Dict{String, Vector{Int}} qubit_count::Int instructions::Vector{Instruction} - function QasmFunctionVisitor(parent::AbstractVisitor, declared_arguments::Vector{QasmExpression}, provided_arguments::Vector{QasmExpression}) + # nosemgrep + function QasmFunctionVisitor(@nospecialize(parent::AbstractVisitor), declared_arguments::Vector{QasmExpression}, provided_arguments::Vector{QasmExpression}) v = new(parent, classical_defs(parent), deepcopy(parent.qubit_defs), @@ -1156,10 +1173,10 @@ qubit_mapping(v::QasmProgramVisitor) = v.qubit_mapping qubit_mapping(v::QasmFunctionVisitor) = v.qubit_mapping qubit_mapping(v::QasmGateDefVisitor) = v.qubit_mapping -Braket.qubit_count(v::AbstractVisitor) = qubit_count(parent(v)) -Braket.qubit_count(v::QasmProgramVisitor) = v.qubit_count -Braket.qubit_count(v::QasmFunctionVisitor) = v.qubit_count -Braket.qubit_count(v::QasmGateDefVisitor) = v.qubit_count +BraketSimulator.qubit_count(v::AbstractVisitor) = qubit_count(parent(v)) +BraketSimulator.qubit_count(v::QasmProgramVisitor) = v.qubit_count +BraketSimulator.qubit_count(v::QasmFunctionVisitor) = v.qubit_count +BraketSimulator.qubit_count(v::QasmGateDefVisitor) = v.qubit_count classical_defs(v::AbstractVisitor) = classical_defs(parent(v)) classical_defs(v::QasmProgramVisitor) = v.classical_defs @@ -1178,11 +1195,9 @@ Base.push!(v::QasmProgramVisitor, rts::Vector{<:Result}) = append!(v.results, rt Base.push!(v::AbstractVisitor, @nospecialize(rt::Result)) = push!(parent(v), rt) Base.push!(v::QasmProgramVisitor, @nospecialize(rt::Result)) = push!(v.results, rt) -function generate_gate_body(v::AbstractVisitor, argument_names::Vector{String}, qubits::Vector{String}, raw_expressions::QasmExpression) - params = Dict{String, FreeParameter}() - for arg in argument_names - params[arg] = FreeParameter(arg) - end +# nosemgrep +function generate_gate_body(@nospecialize(v::AbstractVisitor), argument_names::Vector{String}, qubits::Vector{String}, raw_expressions::QasmExpression) + params = Dict{String, BraketSimulator.FreeParameter}(arg=>BraketSimulator.FreeParameter(arg) for arg in argument_names) qubit_defs = Dict(q=>Qubit(q, 1) for q in qubits) qubit_mapping = Dict(qubits[ix+1]=>[ix] for ix in 0:length(qubits)-1) for ix in 0:length(qubits)-1 @@ -1241,12 +1256,13 @@ function name(expr::QasmExpression)::String throw(QasmVisitorError("name not defined for expressions of type $(head(expr))")) end -evaluate(v::AbstractVisitor, i::Number) = i -evaluate(v::AbstractVisitor, i::String) = i -evaluate(v::AbstractVisitor, i::BitVector) = i -evaluate(v::AbstractVisitor, i::NTuple{N,<:Number}) where {N} = i -evaluate(v::AbstractVisitor, i::Vector{<:Number}) = i -function evaluate(v::AbstractVisitor, expr::QasmExpression) +evaluate(@nospecialize(v::AbstractVisitor), i::Number) = i +evaluate(@nospecialize(v::AbstractVisitor), i::String) = i +evaluate(@nospecialize(v::AbstractVisitor), i::BitVector) = i +evaluate(@nospecialize(v::AbstractVisitor), i::NTuple{N,<:Number}) where {N} = i +evaluate(@nospecialize(v::AbstractVisitor), i::Vector{<:Number}) = i +# nosemgrep +function evaluate(@nospecialize(v::AbstractVisitor), expr::QasmExpression) if head(expr) == :identifier id_name = name(expr) haskey(classical_defs(v), id_name) && return classical_defs(v)[id_name].val @@ -1293,20 +1309,20 @@ function evaluate(v::AbstractVisitor, expr::QasmExpression) raw_obs = expr.args[1]::QasmExpression if head(raw_obs) == :array_literal new_obs = map(arg->evaluate(v, QasmExpression(:observable, arg)), convert(Vector{QasmExpression}, raw_obs.args)) - return Braket.Observables.TensorProduct(convert(Vector{Braket.Observables.Observable}, new_obs)) + return BraketSimulator.Observables.TensorProduct(convert(Vector{BraketSimulator.Observables.Observable}, new_obs)) elseif head(raw_obs) == :identifier obs_name = raw_obs.args[1]::String - obs_name == "x" && return Braket.Observables.X() - obs_name == "y" && return Braket.Observables.Y() - obs_name == "z" && return Braket.Observables.Z() - obs_name == "i" && return Braket.Observables.I() - obs_name == "h" && return Braket.Observables.H() + obs_name == "x" && return BraketSimulator.Observables.X() + obs_name == "y" && return BraketSimulator.Observables.Y() + obs_name == "z" && return BraketSimulator.Observables.Z() + obs_name == "i" && return BraketSimulator.Observables.I() + obs_name == "h" && return BraketSimulator.Observables.H() elseif head(raw_obs) == :hermitian h_mat = similar(raw_obs.args[1], ComplexF64)::Matrix{ComplexF64} for ii in eachindex(h_mat) h_mat[ii] = convert(ComplexF64, evaluate(v, raw_obs.args[1][ii]))::ComplexF64 end - return Braket.Observables.HermitianObservable(h_mat) + return BraketSimulator.Observables.HermitianObservable(h_mat) end elseif head(expr) == :power_mod pow_expr = QasmExpression(:pow, evaluate(v, expr.args[1]::QasmExpression)) @@ -1352,7 +1368,7 @@ function evaluate(v::AbstractVisitor, expr::QasmExpression) end elseif head(expr) == :measure qubits_to_measure = evaluate_qubits(v, expr.args[1]) - push!(v, [Instruction(Measure(), q) for q in qubits_to_measure]) + push!(v, [Instruction(BraketSimulator.Measure(), q) for q in qubits_to_measure]) return false elseif head(expr) == :function_call function_name = name(expr) @@ -1422,7 +1438,7 @@ end evaluate(v::AbstractVisitor, exprs::Vector{QasmExpression}) = [evaluate(v, expr) for expr in exprs] function evaluate_qubits(v::AbstractVisitor, qubit_targets::Vector{QasmExpression})::Vector{Int} - mapping = qubit_mapping(v) + mapping = qubit_mapping(v)::Dict{String, Vector{Int}} final_qubits = Int[] for qubit_expr in qubit_targets if head(qubit_expr) == :identifier @@ -1457,34 +1473,31 @@ function process_gate_arguments(v::AbstractVisitor, gate_name::String, defined_a def_has_arguments && throw(QasmVisitorError("gate $gate_name requires arguments but none were provided.")) call_has_arguments && throw(QasmVisitorError("gate $gate_name does not accept arguments but arguments were provided.")) end - if !isempty(called_arguments) - evaled_args = map(Float64, Iterators.flatten(evaluate(v, called_arguments))) - argument_values = Dict{Symbol, Number}(Symbol(arg_name)=>argument for (arg_name, argument) in zip(defined_arguments, evaled_args)) + if def_has_arguments + evaled_args = only(evaluate(v, called_arguments)) + argument_values = Dict{Symbol, Real}(Symbol(arg_name)=>argument for (arg_name, argument) in zip(defined_arguments, evaled_args)) + return [bind_value!(ix, argument_values) for ix in gate_body] else - argument_values = Dict{Symbol, Number}() + return deepcopy(gate_body) end - applied_arguments = Vector{Instruction}(undef, length(gate_body)) - for (ii, ix) in enumerate(gate_body) - applied_arguments[ii] = def_has_arguments ? bind_value!(ix, argument_values) : ix - end - return applied_arguments end -function handle_gate_modifiers(ixs::Vector{Instruction}, mods::Vector{QasmExpression}, control_qubits::Vector{Int}, is_gphase::Bool) +# nosemgrep +function handle_gate_modifiers(@nospecialize(ixs::Vector{<:Instruction}), mods::Vector{QasmExpression}, control_qubits::Vector{Int}, is_gphase::Bool) for mod in Iterators.reverse(mods) control_qubit = (head(mod) ∈ (:negctrl, :ctrl) && !is_gphase) ? pop!(control_qubits) : -1 for (ii, ix) in enumerate(ixs) if head(mod) == :pow - ixs[ii] = Instruction(ix.operator ^ mod.args[1], ix.target) + ixs[ii].operator.pow_exponent *= mod.args[1] elseif head(mod) == :inv - ixs[ii] = Instruction(inv(ix.operator), ix.target) + ixs[ii].operator.pow_exponent *= -1 # need to handle "extra" target elseif head(mod) ∈ (:negctrl, :ctrl) bit = head(mod) == :ctrl ? (1,) : (0,) if is_gphase ixs[ii] = Instruction(Control(ix.operator, bit), ix.target) else - ixs[ii] = Instruction(Control(ix.operator, bit), vcat(control_qubit, ix.target...)) + ixs[ii] = Instruction(Control(ix.operator, bit), BraketSimulator.QubitSet(control_qubit::Int, ix.target...)) end end end @@ -1517,7 +1530,7 @@ function visit_gphase_call(v::AbstractVisitor, program_expr::QasmExpression) gate_targets::Vector{Int} = collect(0:n_called_with-1) provided_arg::QasmExpression = only(program_expr.args[2].args) evaled_arg = Float64(evaluate(v, provided_arg)) - applied_arguments = Instruction[Instruction(MultiQubitPhaseShift{n_called_with}(evaled_arg), gate_targets)] + applied_arguments = Instruction[Instruction(BraketSimulator.MultiQubitPhaseShift{n_called_with}(evaled_arg), gate_targets)] mods::Vector{QasmExpression} = length(program_expr.args) == 4 ? program_expr.args[4].args : QasmExpression[] applied_arguments = handle_gate_modifiers(applied_arguments, mods, Int[], true) target_mapper = Dict{Int, Int}(g_ix=>gate_targets[g_ix+1][1] for g_ix in 0:n_called_with-1) @@ -1528,7 +1541,7 @@ function visit_gphase_call(v::AbstractVisitor, program_expr::QasmExpression) end function visit_gate_call(v::AbstractVisitor, program_expr::QasmExpression) - gate_name = name(program_expr)::String + gate_name = name(program_expr)::String raw_call_targets = program_expr.args[3]::QasmExpression call_targets::Vector{QasmExpression} = convert(Vector{QasmExpression}, head(raw_call_targets.args[1]) == :array_literal ? raw_call_targets.args[1].args : raw_call_targets.args)::Vector{QasmExpression} provided_args::Vector{QasmExpression} = convert(Vector{QasmExpression}, program_expr.args[2].args)::Vector{QasmExpression} @@ -1558,10 +1571,10 @@ function visit_gate_call(v::AbstractVisitor, program_expr::QasmExpression) return end -function _check_observable_targets(observable::Braket.Observables.HermitianObservable, targets) +function _check_observable_targets(observable::BraketSimulator.Observables.HermitianObservable, targets) qubit_count(observable) == 1 && (isempty(targets) || length(targets) == 1) && return qubit_count(observable) == length(targets) && return - matrix_ir = Braket.complex_matrix_to_ir(observable.matrix) + matrix_ir = BraketSimulator.complex_matrix_to_ir(observable.matrix) throw(QasmVisitorError("Invalid observable specified: $matrix_ir, targets: $targets", "ValueError")) end _check_observable_targets(observable, targets) = nothing @@ -1582,6 +1595,8 @@ function (v::AbstractVisitor)(program_expr::QasmExpression) end elseif head(program_expr) == :version return v + elseif head(program_expr) == :reset + return v elseif head(program_expr) == :input var_name = name(program_expr) var_type = program_expr.args[1].args[1] @@ -1798,51 +1813,51 @@ function (v::AbstractVisitor)(program_expr::QasmExpression) if pragma_type == :result result_type = program_expr.args[2] if result_type == :state_vector - push!(v, Braket.StateVector()) + push!(v, BraketSimulator.StateVector()) elseif result_type == :probability has_targets = !isempty(program_expr.args[3].args) - targets = has_targets ? evaluate_qubits(v, program_expr.args[3].args[1]) : QubitSet() - push!(v, Probability(targets)) + targets = has_targets ? evaluate_qubits(v, program_expr.args[3].args[1]) : BraketSimulator.QubitSet() + push!(v, BraketSimulator.Probability(targets)) elseif result_type == :density_matrix has_targets = !isempty(program_expr.args[3].args) - targets = has_targets ? evaluate_qubits(v, program_expr.args[3].args[1]) : QubitSet() - push!(v, DensityMatrix(targets)) + targets = has_targets ? evaluate_qubits(v, program_expr.args[3].args[1]) : BraketSimulator.QubitSet() + push!(v, BraketSimulator.DensityMatrix(targets)) elseif result_type == :amplitude states = head(program_expr.args[3]) == :array_literal ? program_expr.args[3].args : program_expr.args[3] clean_states = map(states) do state return replace(state.args[1], "\""=>"", "\'"=>"") end - push!(v, Amplitude(clean_states)) + push!(v, BraketSimulator.Amplitude(clean_states)) elseif result_type == :expectation raw_obs, raw_targets = program_expr.args[3:end] has_targets = !isempty(raw_targets.args) - targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : QubitSet() + targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : BraketSimulator.QubitSet() observable = evaluate(v, raw_obs) - if observable isa Braket.Observables.StandardObservable && length(targets) > 1 + if observable isa BraketSimulator.Observables.StandardObservable && length(targets) > 1 throw(QasmVisitorError("Standard observable target must be exactly 1 qubit.", "ValueError")) end _check_observable_targets(observable, targets) - push!(v, Expectation(observable, targets)) + push!(v, BraketSimulator.Expectation(observable, targets)) elseif result_type == :variance raw_obs, raw_targets = program_expr.args[3:end] has_targets = !isempty(raw_targets.args) - targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : QubitSet() + targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : BraketSimulator.QubitSet() observable = evaluate(v, raw_obs) - if observable isa Braket.Observables.StandardObservable && length(targets) > 1 + if observable isa BraketSimulator.Observables.StandardObservable && length(targets) > 1 throw(QasmVisitorError("Standard observable target must be exactly 1 qubit.", "ValueError")) end _check_observable_targets(observable, targets) - push!(v, Variance(observable, targets)) + push!(v, BraketSimulator.Variance(observable, targets)) elseif result_type == :sample raw_obs, raw_targets = program_expr.args[3:end] has_targets = !isempty(raw_targets.args) - targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : QubitSet() + targets = has_targets ? evaluate_qubits(v, raw_targets.args[1]) : BraketSimulator.QubitSet() observable = evaluate(v, raw_obs) - if observable isa Braket.Observables.StandardObservable && length(targets) > 1 + if observable isa BraketSimulator.Observables.StandardObservable && length(targets) > 1 throw(QasmVisitorError("Standard observable target must be exactly 1 qubit.", "ValueError")) end _check_observable_targets(observable, targets) - push!(v, Sample(observable, targets)) + push!(v, BraketSimulator.Sample(observable, targets)) elseif result_type == :adjoint_gradient throw(QasmVisitorError("Result type adjoint_gradient is not supported.", "TypeError")) end @@ -1853,7 +1868,7 @@ function (v::AbstractVisitor)(program_expr::QasmExpression) unitary_matrix[ii] = evaluate(v, raw_mat[ii]) end targets = evaluate_qubits(v, program_expr.args[end].args[1]) - push!(v, Instruction(Unitary(unitary_matrix), targets)) + push!(v, Instruction(BraketSimulator.Unitary(unitary_matrix), targets)) elseif pragma_type == :noise noise_type::String = program_expr.args[2].args[1] raw_args::QasmExpression = program_expr.args[3].args[1] @@ -1868,7 +1883,7 @@ function (v::AbstractVisitor)(program_expr::QasmExpression) end kraus_matrix end - push!(v, Instruction(Kraus(kraus_matrices), targets)) + push!(v, Instruction(BraketSimulator.Kraus(kraus_matrices), targets)) else braket_noise_type = noise_types[noise_type] args = map(Float64, evaluate(v, raw_args)) @@ -1886,15 +1901,15 @@ function (v::AbstractVisitor)(program_expr::QasmExpression) return v end -function Braket.Circuit(v::QasmProgramVisitor) - c = Circuit() - foreach(ix->Braket.add_instruction!(c, ix), v.instructions) +function BraketSimulator.Circuit(v::QasmProgramVisitor) + c = BraketSimulator.Circuit() + foreach(ix->BraketSimulator.add_instruction!(c, ix), v.instructions) for rt in v.results - obs = Braket.extract_observable(rt) - if !isnothing(obs) && c.observables_simultaneously_measureable && !(rt isa AdjointGradient) - Braket.add_to_qubit_observable_mapping!(c, obs, rt.targets) + obs = BraketSimulator.extract_observable(rt) + if !isnothing(obs) && c.observables_simultaneously_measureable && !(rt isa BraketSimulator.AdjointGradient) + BraketSimulator.add_to_qubit_observable_mapping!(c, obs, rt.targets) end - Braket.add_to_qubit_observable_set!(c, rt) + BraketSimulator.add_to_qubit_observable_set!(c, rt) push!(c.result_types, rt) end return c @@ -1902,7 +1917,7 @@ end # semgrep rules can't handle this macro properly yet # nosemgrep -function Braket.Circuit(qasm_source::String, @nospecialize(inputs::Dict{String, <:Any}=Dict{String, Any}())) +function BraketSimulator.Circuit(qasm_source::String, @nospecialize(inputs::Dict{String, <:Any}=Dict{String, Any}())) input_qasm = if endswith(qasm_source, ".qasm") && isfile(qasm_source) read(qasm_source, String) else @@ -1912,7 +1927,7 @@ function Braket.Circuit(qasm_source::String, @nospecialize(inputs::Dict{String, parsed = parse_qasm(input_qasm) visitor = QasmProgramVisitor(inputs) visitor(parsed) - return Circuit(visitor) + return BraketSimulator.Circuit(visitor) end end # module Quasar diff --git a/src/builtin_functions.jl b/src/builtin_functions.jl index d6244a4..bc40476 100644 --- a/src/builtin_functions.jl +++ b/src/builtin_functions.jl @@ -1,9 +1,10 @@ -popcount(s::String) = count(c->c=='1', s) -popcount(c::Char...) = count(c_->c_=='1', c) +popcount() = 0 +popcount(s::String) = count(c->c=='1', s) +popcount(c::Char...) = count(c_->c_=='1', c) popcount(bv::BitVector) = count(bv) -popcount(b::Bool...) = count(b) -popcount(i::Integer) = count_ones(i) -popcount(u::Unsigned) = count_ones(u) +popcount(b::Bool...) = count(b) +popcount(i::Integer) = count_ones(i) +popcount(u::Unsigned) = count_ones(u) const builtin_functions = Dict{String, Function}( "sizeof" => size, diff --git a/src/builtin_gates.jl b/src/builtin_gates.jl index 480b993..195d887 100644 --- a/src/builtin_gates.jl +++ b/src/builtin_gates.jl @@ -1,92 +1,92 @@ # OpenQASM 3 Braket Standard Gates builtin_gates() = Dict{String, GateDefinition}( # identity gate - "i"=>GateDefinition("i", String[], ["a"], [Instruction(Braket.I(), 0)]), + "i"=>GateDefinition("i", String[], ["a"], Instruction(BraketSimulator.I(), 0)), # phase gate - "phaseshift"=>GateDefinition("phaseshift", ["λ"], ["a"], [Instruction(PhaseShift(FreeParameter(:λ)), 0)]), + "phaseshift"=>GateDefinition("phaseshift", ["λ"], ["a"], Instruction(BraketSimulator.PhaseShift(BraketSimulator.FreeParameter(:λ)), 0)), # pauli X gate - "x"=>GateDefinition("x", String[], ["a"], [Instruction(X(), 0)]), + "x"=>GateDefinition("x", String[], ["a"], Instruction(BraketSimulator.X(), 0)), # pauli Y gate - "y"=>GateDefinition("y", String[], ["a"], [Instruction(Y(), 0)]), + "y"=>GateDefinition("y", String[], ["a"], Instruction(BraketSimulator.Y(), 0)), # pauli Z gate - "z"=>GateDefinition("z", String[], ["a"], [Instruction(Z(), 0)]), + "z"=>GateDefinition("z", String[], ["a"], Instruction(BraketSimulator.Z(), 0)), # Hadamard gate - "h"=>GateDefinition("h", String[], ["a"], [Instruction(H(), 0)]), + "h"=>GateDefinition("h", String[], ["a"], Instruction(BraketSimulator.H(), 0)), # S gate - "s"=>GateDefinition("s", String[], ["a"], [Instruction(S(), 0)]), + "s"=>GateDefinition("s", String[], ["a"], Instruction(BraketSimulator.S(), 0)), # Si gate - "si"=>GateDefinition("si", String[], ["a"], [Instruction(Si(), 0)]), + "si"=>GateDefinition("si", String[], ["a"], Instruction(BraketSimulator.Si(), 0)), # T gate - "t"=>GateDefinition("t", String[], ["a"], [Instruction(T(), 0)]), + "t"=>GateDefinition("t", String[], ["a"], Instruction(BraketSimulator.T(), 0)), # Ti gate - "ti"=>GateDefinition("ti", String[], ["a"], [Instruction(Ti(), 0)]), + "ti"=>GateDefinition("ti", String[], ["a"], Instruction(BraketSimulator.Ti(), 0)), # V gate - "v"=>GateDefinition("v", String[], ["a"], [Instruction(V(), 0)]), + "v"=>GateDefinition("v", String[], ["a"], Instruction(BraketSimulator.V(), 0)), # Vi gate - "vi"=>GateDefinition("vi", String[], ["a"], [Instruction(Vi(), 0)]), + "vi"=>GateDefinition("vi", String[], ["a"], Instruction(BraketSimulator.Vi(), 0)), # RotX gate - "rx"=>GateDefinition("rx", ["θ"], ["a"], [Instruction(Rx(FreeParameter(:θ)), 0)]), + "rx"=>GateDefinition("rx", ["θ"], ["a"], Instruction(BraketSimulator.Rx(BraketSimulator.FreeParameter(:θ)), 0)), # RotY gate - "ry"=>GateDefinition("ry", ["θ"], ["a"], [Instruction(Ry(FreeParameter(:θ)), 0)]), + "ry"=>GateDefinition("ry", ["θ"], ["a"], Instruction(BraketSimulator.Ry(BraketSimulator.FreeParameter(:θ)), 0)), # RotZ gate - "rz"=>GateDefinition("rz", ["θ"], ["a"], [Instruction(Rz(FreeParameter(:θ)), 0)]), + "rz"=>GateDefinition("rz", ["θ"], ["a"], Instruction(BraketSimulator.Rz(BraketSimulator.FreeParameter(:θ)), 0)), # CNot gate - "cnot"=>GateDefinition("cnot", String[], ["a", "b"], [Instruction(CNot(), QubitSet(0, 1))]), + "cnot"=>GateDefinition("cnot", String[], ["a", "b"], Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(0, 1))), # CY gate - "cy"=>GateDefinition("cy", String[], ["a", "b"], [Instruction(CY(), QubitSet(0, 1))]), + "cy"=>GateDefinition("cy", String[], ["a", "b"], Instruction(BraketSimulator.CY(), BraketSimulator.QubitSet(0, 1))), # CZ gate - "cz"=>GateDefinition("cz", String[], ["a", "b"], [Instruction(CZ(), QubitSet(0, 1))]), + "cz"=>GateDefinition("cz", String[], ["a", "b"], Instruction(BraketSimulator.CZ(), BraketSimulator.QubitSet(0, 1))), # CV gate - "cv"=>GateDefinition("cv", String[], ["a", "b"], [Instruction(CV(), QubitSet(0, 1))]), + "cv"=>GateDefinition("cv", String[], ["a", "b"], Instruction(BraketSimulator.CV(), BraketSimulator.QubitSet(0, 1))), # controlled-phase - "cphaseshift"=>GateDefinition("cphaseshift", ["λ"], ["a", "b"], [Instruction(CPhaseShift(FreeParameter(:λ)), QubitSet(0, 1))]), + "cphaseshift"=>GateDefinition("cphaseshift", ["λ"], ["a", "b"], Instruction(BraketSimulator.CPhaseShift(BraketSimulator.FreeParameter(:λ)), BraketSimulator.QubitSet(0, 1))), # controlled-phase-00 - "cphaseshift00"=>GateDefinition("cphaseshift00", ["λ"], ["a", "b"], [Instruction(CPhaseShift00(FreeParameter(:λ)), QubitSet(0, 1))]), + "cphaseshift00"=>GateDefinition("cphaseshift00", ["λ"], ["a", "b"], Instruction(BraketSimulator.CPhaseShift00(BraketSimulator.FreeParameter(:λ)), BraketSimulator.QubitSet(0, 1))), # controlled-phase-01 - "cphaseshift01"=>GateDefinition("cphaseshift01", ["λ"], ["a", "b"], [Instruction(CPhaseShift01(FreeParameter(:λ)), QubitSet(0, 1))]), + "cphaseshift01"=>GateDefinition("cphaseshift01", ["λ"], ["a", "b"], Instruction(BraketSimulator.CPhaseShift01(BraketSimulator.FreeParameter(:λ)), BraketSimulator.QubitSet(0, 1))), # controlled-phase-10 - "cphaseshift10"=>GateDefinition("cphaseshift10", ["λ"], ["a", "b"], [Instruction(CPhaseShift10(FreeParameter(:λ)), QubitSet(0, 1))]), + "cphaseshift10"=>GateDefinition("cphaseshift10", ["λ"], ["a", "b"], Instruction(BraketSimulator.CPhaseShift10(BraketSimulator.FreeParameter(:λ)), BraketSimulator.QubitSet(0, 1))), # Swap gate - "swap"=>GateDefinition("swap", String[], ["a", "b"], [Instruction(Swap(), QubitSet(0, 1))]), + "swap"=>GateDefinition("swap", String[], ["a", "b"], Instruction(BraketSimulator.Swap(), BraketSimulator.QubitSet(0, 1))), # ISwap gate - "iswap"=>GateDefinition("iswap", String[], ["a", "b"], [Instruction(ISwap(), QubitSet(0, 1))]), + "iswap"=>GateDefinition("iswap", String[], ["a", "b"], Instruction(BraketSimulator.ISwap(), BraketSimulator.QubitSet(0, 1))), # ISwap gate - "pswap"=>GateDefinition("pswap", ["θ"], ["a", "b"], [Instruction(PSwap(FreeParameter(:θ)), QubitSet(0, 1))]), + "pswap"=>GateDefinition("pswap", ["θ"], ["a", "b"], Instruction(BraketSimulator.PSwap(BraketSimulator.FreeParameter(:θ)), BraketSimulator.QubitSet(0, 1))), # controlled-swap gate - "cswap"=>GateDefinition("cswap", String[], ["a", "b", "c"], [Instruction(CSwap(), QubitSet(0, 1, 2))]), + "cswap"=>GateDefinition("cswap", String[], ["a", "b", "c"], Instruction(BraketSimulator.CSwap(), BraketSimulator.QubitSet(0, 1, 2))), # ccnot/Toffoli gate - "ccnot"=>GateDefinition("ccnot", String[], ["a", "b", "c"], [Instruction(CCNot(), QubitSet(0, 1, 2))]), + "ccnot"=>GateDefinition("ccnot", String[], ["a", "b", "c"], Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(0, 1, 2))), # XX gate - "xx"=>GateDefinition("xx", ["θ"], ["a", "b"], [Instruction(XX(FreeParameter(:θ)), QubitSet(0, 1))]), + "xx"=>GateDefinition("xx", ["θ"], ["a", "b"], Instruction(BraketSimulator.XX(BraketSimulator.FreeParameter(:θ)), BraketSimulator.QubitSet(0, 1))), # XY gate - "xy"=>GateDefinition("xy", ["θ"], ["a", "b"], [Instruction(XY(FreeParameter(:θ)), QubitSet(0, 1))]), + "xy"=>GateDefinition("xy", ["θ"], ["a", "b"], Instruction(BraketSimulator.XY(BraketSimulator.FreeParameter(:θ)), BraketSimulator.QubitSet(0, 1))), # YY gate - "yy"=>GateDefinition("yy", ["θ"], ["a", "b"], [Instruction(YY(FreeParameter(:θ)), QubitSet(0, 1))]), + "yy"=>GateDefinition("yy", ["θ"], ["a", "b"], Instruction(BraketSimulator.YY(BraketSimulator.FreeParameter(:θ)), BraketSimulator.QubitSet(0, 1))), # ZZ gate - "zz"=>GateDefinition("zz", ["θ"], ["a", "b"], [Instruction(ZZ(FreeParameter(:θ)), QubitSet(0, 1))]), + "zz"=>GateDefinition("zz", ["θ"], ["a", "b"], Instruction(BraketSimulator.ZZ(BraketSimulator.FreeParameter(:θ)), BraketSimulator.QubitSet(0, 1))), # ECR gate - "ecr"=>GateDefinition("ecr", String[], ["a", "b"], [Instruction(ECR(), QubitSet(0, 1))]), + "ecr"=>GateDefinition("ecr", String[], ["a", "b"], Instruction(BraketSimulator.ECR(), BraketSimulator.QubitSet(0, 1))), # MS gate - "ms"=>GateDefinition("ms", ["ϕ", "θ", "λ"], ["a", "b"], [Instruction(MS(FreeParameter(:ϕ), FreeParameter(:θ), FreeParameter(:λ)), QubitSet(0, 1))]), + "ms"=>GateDefinition("ms", ["ϕ", "θ", "λ"], ["a", "b"], Instruction(BraketSimulator.MS(BraketSimulator.FreeParameter(:ϕ), BraketSimulator.FreeParameter(:θ), BraketSimulator.FreeParameter(:λ)), BraketSimulator.QubitSet(0, 1))), # GPi gate - "gpi"=>GateDefinition("gpi", ["θ"], ["a"], [Instruction(GPi(FreeParameter(:θ)), 0)]), + "gpi"=>GateDefinition("gpi", ["θ"], ["a"], Instruction(BraketSimulator.GPi(BraketSimulator.FreeParameter(:θ)), 0)), # GPi2 gate - "gpi2"=>GateDefinition("gpi2", ["θ"], ["a"], [Instruction(GPi2(FreeParameter(:θ)), 0)]), + "gpi2"=>GateDefinition("gpi2", ["θ"], ["a"], Instruction(BraketSimulator.GPi2(BraketSimulator.FreeParameter(:θ)), 0)), # PRx gate - "prx"=>GateDefinition("prx", ["θ", "ϕ"], ["a"], [Instruction(PRx(FreeParameter(:θ), FreeParameter(:ϕ)), 0)]), + "prx"=>GateDefinition("prx", ["θ", "ϕ"], ["a"], Instruction(BraketSimulator.PRx(BraketSimulator.FreeParameter(:θ), BraketSimulator.FreeParameter(:ϕ)), 0)), # 3-angle U gate - "U"=>GateDefinition("U", ["θ", "ϕ", "λ"], ["a"], [Instruction(U(FreeParameter(:θ), FreeParameter(:ϕ), FreeParameter(:λ)), 0)]), + "U"=>GateDefinition("U", ["θ", "ϕ", "λ"], ["a"], Instruction(BraketSimulator.U(BraketSimulator.FreeParameter(:θ), BraketSimulator.FreeParameter(:ϕ), BraketSimulator.FreeParameter(:λ)), 0)), ) const noise_types = Dict{String, Type}( - "bit_flip"=>BitFlip, - "phase_flip"=>PhaseFlip, - "pauli_channel"=>PauliChannel, - "depolarizing"=>Depolarizing, - "two_qubit_depolarizing"=>TwoQubitDepolarizing, - "two_qubit_dephasing"=>TwoQubitDephasing, - "amplitude_damping"=>AmplitudeDamping, - "generalized_amplitude_damping"=>GeneralizedAmplitudeDamping, - "phase_damping"=>PhaseDamping, - "kraus"=>Kraus, + "bit_flip"=>BraketSimulator.BitFlip, + "phase_flip"=>BraketSimulator.PhaseFlip, + "pauli_channel"=>BraketSimulator.PauliChannel, + "depolarizing"=>BraketSimulator.Depolarizing, + "two_qubit_depolarizing"=>BraketSimulator.TwoQubitDepolarizing, + "two_qubit_dephasing"=>BraketSimulator.TwoQubitDephasing, + "amplitude_damping"=>BraketSimulator.AmplitudeDamping, + "generalized_amplitude_damping"=>BraketSimulator.GeneralizedAmplitudeDamping, + "phase_damping"=>BraketSimulator.PhaseDamping, + "kraus"=>BraketSimulator.Kraus, ) diff --git a/src/circuit.jl b/src/circuit.jl new file mode 100644 index 0000000..21ff029 --- /dev/null +++ b/src/circuit.jl @@ -0,0 +1,250 @@ +const ALL_QUBITS = -1 + +""" + Circuit + +A representation of a quantum circuit that contains the instructions to be performed on a +quantum device and the requested result types. + +See: + - [Gates](@ref) for all of the supported gates. + - [Noises](@ref) for all of the supported noise operations. + - [Results](@ref) for all of the supported result types. +""" +mutable struct Circuit + instructions::Vector{Instruction{<:Operator}} + result_types::Vector{Result} + basis_rotation_instructions::Vector{Instruction{<:Operator}} + qubit_observable_mapping::Dict{Int, Observables.Observable} + qubit_observable_target_mapping::Dict{Int, Tuple} + qubit_observable_set::Set{Int} + parameters::Set{FreeParameter} + observables_simultaneously_measureable::Bool + measure_targets::Vector{Int} + + @doc """ + Circuit() + + Construct an empty `Circuit`. + """ + Circuit() = new([], [], [], Dict(), Dict(), Set{Int}(), Set{FreeParameter}(), true, Int[]) +end + +""" + qubits(c::Circuit) -> QubitSet + +Returns a [`QubitSet`](@ref) containing all qubits +that `c` is defined on. + +# Examples +```jldoctest +julia> c = Circuit(); + +julia> add_instruction!(c, Instruction(H(), 0)); + +julia> add_instruction!(c, Instruction(CNot(), [0, 1])); + +julia> qubits(c) +QubitSet with 2 elements: + 0 + 1 +``` +""" +qubits(c::Circuit) = (qs = union!(mapreduce(ix->ix.target, union, c.instructions, init=Set{Int}()), c.qubit_observable_set); QubitSet(qs)) +function qubits(p::Program) + inst_qubits = mapreduce(ix->ix.target, union, p.instructions, init=Set{Int}()) + bri_qubits = mapreduce(ix->ix.target, union, p.basis_rotation_instructions, init=Set{Int}()) + res_qubits = mapreduce(ix->(hasproperty(ix, :targets) && !isnothing(ix.targets)) ? reduce(vcat, ix.targets) : Set{Int}(), union, p.results, init=Set{Int}()) + return union(inst_qubits, bri_qubits, res_qubits) +end +""" + qubit_count(c::Circuit) -> Int + +Returns the number of qubits that `c` is defined on. + +# Examples +```jldoctest +julia> c = Circuit(); + +julia> add_instruction!(c, Instruction(H(), 0)); + +julia> add_instruction!(c, Instruction(CNot(), [0, 1])); + +julia> qubit_count(c) +2 +``` +""" +qubit_count(c::Circuit) = length(qubits(c)) +qubit_count(p::Program) = length(qubits(p)) + +Base.convert(::Type{Program}, c::Circuit) = (basis_rotation_instructions!(c); return Program(braketSchemaHeader("braket.ir.jaqcd.program" ,"1"), c.instructions, ir.(c.result_types, Val(:JAQCD)), c.basis_rotation_instructions)) +Program(c::Circuit) = convert(Program, c) + +extract_observable(rt::ObservableResult) = rt.observable +extract_observable(p::Probability) = Observables.Z() +extract_observable(rt::Result) = nothing + +function _encounter_noncommuting_observable!(c::Circuit) + c.observables_simultaneously_measureable = false + empty!(c.qubit_observable_mapping) + empty!(c.qubit_observable_target_mapping) + return c +end + +function tensor_product_index_dict(o::Observables.TensorProduct, obs_targets::QubitSet) + factors = copy(o.factors) + total = qubit_count(first(factors)) + obj_dict = Dict{Int, Any}() + i = 0 + while length(factors) > 0 + if i >= total + popfirst!(factors) + if !isempty(factors) + total += qubit_count(first(factors)) + end + end + if !isempty(factors) + front = total - qubit_count(first(factors)) + obj_dict[i] = (first(factors), tuple([obs_targets[ii] for ii in front+1:total]...)) + end + i += 1 + end + return obj_dict +end + +basis_rotation_gates(o::Observables.H) = (Ry(-π/4),) +basis_rotation_gates(o::Observables.X) = (H(),) +basis_rotation_gates(o::Observables.I) = () +basis_rotation_gates(o::Observables.Z) = () +basis_rotation_gates(o::Observables.Y) = (Z(), S(), H()) +basis_rotation_gates(o::Observables.TensorProduct) = tuple(reduce(vcat, basis_rotation_gates.(o.factors))...) +basis_rotation_gates(o::Observables.HermitianObservable) = (Unitary(Matrix(adjoint(eigvecs(o.matrix)))),) + +function fix_endianness(mat::Matrix) + size(mat) != (4, 4) && return mat + new_mat = copy(mat) + for row in axes(new_mat, 1) + idata = new_mat[row, 2] + new_mat[row, 2] = new_mat[row, 3] + new_mat[row, 3] = idata + end + for col in axes(new_mat, 2) + idata = new_mat[2, col] + new_mat[2, col] = new_mat[3, col] + new_mat[3, col] = idata + end + return new_mat +end + +function _observable_to_instruction(observable::Observables.Observable, target_list)::Vector{Instruction{<:Operator}} + rotation_gates = collect(basis_rotation_gates(observable)) + return map(rotation_gates) do gate + if gate isa Unitary && length(target_list) == 2 + return Instruction(Unitary(fix_endianness(gate.matrix)), target_list) + else + return Instruction(gate, target_list) + end + end +end + +""" + basis_rotation_instructions!(c::Circuit) + +Gets a list of basis rotation instructions and stores them in the circuit `c`. +These basis rotation instructions are added if result types are requested for +an observable other than Pauli-Z. + +This only makes sense if all observables are simultaneously measurable; +if not, this method will return an empty list. +""" +function basis_rotation_instructions!(c::Circuit) + basis_rotation_instructions = Instruction[] + all_qubit_observable = get(c.qubit_observable_mapping, ALL_QUBITS, nothing) + if !isnothing(all_qubit_observable) + c.basis_rotation_instructions = reduce(vcat, _observable_to_instruction(all_qubit_observable, target) for target in qubits(c)) + return c + end + unsorted = collect(Set(values(c.qubit_observable_target_mapping))) + target_lists = sort(unsorted) + for target_list in target_lists + observable = c.qubit_observable_mapping[first(target_list)] + append!(basis_rotation_instructions, _observable_to_instruction(observable, target_list)) + end + c.basis_rotation_instructions = basis_rotation_instructions + return c +end + +function add_to_qubit_observable_mapping!(c::Circuit, o::Observables.Observable, obs_targets::QubitSet) + targets = length(obs_targets) > 0 ? obs_targets : collect(c.qubit_observable_set) + all_qubits_observable = get(c.qubit_observable_mapping, ALL_QUBITS, nothing) + id = Observables.I() + for ii in 1:length(targets) + target = targets[ii] + new_observable = o + current_observable = !isnothing(all_qubits_observable) ? all_qubits_observable : get(c.qubit_observable_mapping, target, nothing) + add_observable = isnothing(current_observable) || (current_observable == id && new_observable != id) + !add_observable && current_observable != id && new_observable != id && new_observable != current_observable && return _encounter_noncommuting_observable!(c) + if !isempty(obs_targets) + new_targets = tuple(obs_targets...) + if add_observable + c.qubit_observable_target_mapping[target] = new_targets + c.qubit_observable_mapping[target] = new_observable + elseif qubit_count(new_observable) > 1 + current_target = get(c.qubit_observable_target_mapping, target, nothing) + !isnothing(current_target) && current_target != new_targets && _encounter_noncommuting_observable!(c) + end + end + end + if isempty(obs_targets) + !isnothing(all_qubits_observable) && all_qubits_observable != o && return _encounter_noncommuting_observable!(c) + c.qubit_observable_mapping[ALL_QUBITS] = o + end + return c +end + +function add_to_qubit_observable_mapping!(c::Circuit, o::Observables.TensorProduct, obs_targets::QubitSet) + targets = length(obs_targets) != 0 ? obs_targets : collect(c.qubit_observable_set) + all_qubits_observable = get(c.qubit_observable_mapping, ALL_QUBITS, nothing) + tensor_product_dict = length(targets) > 0 ? tensor_product_index_dict(o, QubitSet(targets)) : Dict() + id = Observables.I() + for ii in 1:length(targets) + target = targets[ii] + new_observable = tensor_product_dict[ii-1][1] + current_observable = !isnothing(all_qubits_observable) ? all_qubits_observable : get(c.qubit_observable_mapping, target, nothing) + add_observable = isnothing(current_observable) || (current_observable == id && new_observable != id) + !add_observable && current_observable != id && new_observable != id && new_observable != current_observable && return _encounter_noncommuting_observable!(c) + if !isempty(obs_targets) + new_targets = tensor_product_dict[ii-1][2] + if add_observable + c.qubit_observable_target_mapping[target] = new_targets + c.qubit_observable_mapping[target] = new_observable + elseif qubit_count(new_observable) > 1 + current_target = get(c.qubit_observable_target_mapping, target, nothing) + !isnothing(current_target) && current_target != new_targets && return _encounter_noncommuting_observable!(c) + end + end + end + return c +end +add_to_qubit_observable_set!(c::Circuit, rt::ObservableResult) = union!(c.qubit_observable_set, Set(rt.targets)) +add_to_qubit_observable_set!(c::Circuit, rt::AdjointGradient) = union!(c.qubit_observable_set, Set(reduce(union, rt.targets))) +add_to_qubit_observable_set!(c::Circuit, rt::Result) = c.qubit_observable_set + +function _check_if_qubit_measured(c::Circuit, qubit::Int) + isempty(c.measure_targets) && return + # check if there is a measure instruction on the targeted qubit(s) + isempty(intersect(c.measure_targets, qubit)) || error("cannot apply instruction to measured qubits.") +end +_check_if_qubit_measured(c::Circuit, qubits) = foreach(q->_check_if_qubit_measured(c, Int(q)), qubits) + +function add_instruction!(c::Circuit, ix::Instruction{O}) where {O<:Operator} + _check_if_qubit_measured(c, ix.target) + to_add = [ix] + if ix.operator isa QuantumOperator && Parametrizable(ix.operator) == Parametrized() + for param in parameters(ix.operator) + union!(c.parameters, (param,)) + end + end + push!(c.instructions, ix) + return c +end diff --git a/src/custom_gates.jl b/src/custom_gates.jl index 920f2ac..f3664ad 100644 --- a/src/custom_gates.jl +++ b/src/custom_gates.jl @@ -1,12 +1,11 @@ -struct DoubleExcitation <: AngledGate{1} - angle::NTuple{1,Union{Float64,FreeParameter}} - DoubleExcitation(angle::T) where {T<:NTuple{1,Union{Float64,FreeParameter}}} = - new(angle) +mutable struct DoubleExcitation <: AngledGate{1} + angle::NTuple{1,Union{Real,FreeParameter}} + pow_exponent::Float64 + DoubleExcitation(angle::T, pow_exponent=1.0) where {T<:NTuple{1,Union{Real,FreeParameter}}} = + new(angle, Float64(pow_exponent)) end -Braket.chars(::Type{DoubleExcitation}) = "G2(ang)" -Braket.qubit_count(::Type{DoubleExcitation}) = 4 -Base.inv(g::DoubleExcitation) = DoubleExcitation(-g.angle[1]) -function matrix_rep(g::DoubleExcitation) +qubit_count(::Type{DoubleExcitation}) = 4 +function matrix_rep_raw(g::DoubleExcitation) cosϕ = cos(g.angle[1] / 2.0) sinϕ = sin(g.angle[1] / 2.0) @@ -18,15 +17,14 @@ function matrix_rep(g::DoubleExcitation) return SMatrix{16,16,ComplexF64}(mat) end -struct SingleExcitation <: AngledGate{1} - angle::NTuple{1,Union{Float64,FreeParameter}} - SingleExcitation(angle::T) where {T<:NTuple{1,Union{Float64,FreeParameter}}} = - new(angle) +mutable struct SingleExcitation <: AngledGate{1} + angle::NTuple{1,Union{Real,FreeParameter}} + pow_exponent::Float64 + SingleExcitation(angle::T, pow_exponent=1.0) where {T<:NTuple{1,Union{Real,FreeParameter}}} = + new(angle, Float64(pow_exponent)) end -Braket.chars(::Type{SingleExcitation}) = "G(ang)" -Braket.qubit_count(::Type{SingleExcitation}) = 2 -Base.inv(g::SingleExcitation) = SingleExcitation(-g.angle[1]) -function matrix_rep(g::SingleExcitation) +qubit_count(::Type{SingleExcitation}) = 2 +function matrix_rep_raw(g::SingleExcitation) cosϕ = cos(g.angle[1] / 2.0) sinϕ = sin(g.angle[1] / 2.0) return SMatrix{4,4,ComplexF64}([1.0 0 0 0; 0 cosϕ sinϕ 0; 0 -sinϕ cosϕ 0; 0 0 0 1.0]) @@ -38,32 +36,11 @@ Multi-qubit Z-rotation gate. The 2-qubit version is equivalent to the `ZZ` gate, and the single-qubit version is equivalent to the `Rz` gate. """ struct MultiRZ <: AngledGate{1} - angle::NTuple{1,Union{Float64,FreeParameter}} - MultiRZ(angle::T) where {T<:NTuple{1,Union{Float64,FreeParameter}}} = new(angle) + angle::NTuple{1,Union{Real,FreeParameter}} + pow_exponent::Float64 + MultiRZ(angle::T, pow_exponent::Float64=1.0) where {T<:NTuple{1,Union{Real,FreeParameter}}} = new(angle, pow_exponent) end -Braket.chars(::Type{MultiRZ}) = "MultiRZ(ang)" -Braket.qubit_count(g::MultiRZ) = 1 -Base.inv(g::MultiRZ) = MultiRZ(-g.angle[1]) - -""" - U(θ, ϕ, λ) - -3-angle single qubit unitary gate. Equivalent to -the OpenQASM3 built-in [`U` gate](https://openqasm.com/language/gates.html#U). -""" -struct U <: AngledGate{3} - angle::NTuple{3,Union{Float64,FreeParameter}} - U(angle::T) where {T<:NTuple{3,Union{Float64,FreeParameter}}} = - new(angle) -end -U(θ::T, ϕ::T, λ::T) where {T<:Union{Float64,FreeParameter}} = U((θ, ϕ, λ)) -function matrix_rep(g::U) - θ, ϕ, λ = g.angle - return SMatrix{2, 2, ComplexF64}([cos(θ/2) -exp(im*λ)*sin(θ/2); exp(im*ϕ)*sin(θ/2) exp(im*(λ+ϕ))*cos(θ/2)]) -end -Braket.chars(::Type{U}) = "U(ang)" -Braket.qubit_count(g::U) = 1 -Base.inv(g::U) = U(-g.angle[1], -g.angle[3], -g.angle[2]) +qubit_count(g::MultiRZ) = 1 """ MultiQubitPhaseShift{N}(angle) @@ -74,19 +51,18 @@ Controls/negative controls applied to this gate control which states are rotated, so that `Control(g::MultiQubitPhaseShift{2})` will apply the rotation to the `|11>` state. """ -struct MultiQubitPhaseShift{N} <: AngledGate{1} +mutable struct MultiQubitPhaseShift{N} <: AngledGate{1} angle::NTuple{1,Union{Float64,FreeParameter}} - MultiQubitPhaseShift{N}(angle::NTuple{1,<:Union{Float64,FreeParameter}}) where {N} = new(angle) + pow_exponent::Float64 + MultiQubitPhaseShift{N}(angle::T, pow_exponent::Float64=1.0) where {N, T<:NTuple{1,Union{Real,FreeParameter}}} = new(angle, pow_exponent) end -matrix_rep(g::MultiQubitPhaseShift{N}) where {N} = Diagonal(SVector{2^N, ComplexF64}(exp(im*g.angle[1]) for _ in 1:2^N)) -Braket.chars(::Type{MultiQubitPhaseShift}) = "GPhase(ang)" -Braket.qubit_count(g::MultiQubitPhaseShift{N}) where {N} = N -Base.inv(g::MultiQubitPhaseShift{N}) where {N} = MultiQubitPhaseShift{N}((-g.angle[1],)) +matrix_rep_raw(g::MultiQubitPhaseShift{N}) where {N} = Diagonal(SVector{2^N, ComplexF64}(exp(im*g.angle[1]) for _ in 1:2^N)) +qubit_count(g::MultiQubitPhaseShift{N}) where {N} = N function apply_gate!( factor::ComplexF64, - diagonal::Braket.PauliEigenvalues{N}, - state_vec::StateVector{T}, + diagonal::PauliEigenvalues{N}, + state_vec::AbstractStateVector{T}, ts::Vararg{Int,N}, ) where {T<:Complex,N} g_mat = Diagonal(SVector{2^N,ComplexF64}(exp(factor * diagonal[i]) for i = 1:2^N)) @@ -94,7 +70,7 @@ function apply_gate!( end function apply_gate!( factor::ComplexF64, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, ts::Vararg{Int,N}, ) where {T<:Complex,N} g_mat = Diagonal(SVector{2^N,ComplexF64}(factor for i = 1:2^N)) @@ -102,32 +78,16 @@ function apply_gate!( end for (V, f) in ((true, :conj), (false, :identity)) @eval begin - apply_gate!( - ::Val{$V}, - g::MultiRZ, - state_vec::StateVector{T}, - t::Int, - ) where {T<:Complex} = apply_gate!(Val($V), Rz(g.angle), state_vec, t) - apply_gate!( - ::Val{$V}, - g::MultiRZ, - state_vec::StateVector{T}, - t1::Int, - t2::Int, - ) where {T<:Complex} = apply_gate!(Val($V), ZZ(g.angle), state_vec, t1, t2) - apply_gate!( - ::Val{$V}, - g::MultiRZ, - state_vec::StateVector{T}, - ts::Vararg{Int,N}, - ) where {T<:Complex,N} = apply_gate!($f(-im * g.angle[1] / 2.0), Braket.PauliEigenvalues(Val(N)), state_vec, ts...) - apply_gate!(::Val{$V}, g::MultiQubitPhaseShift{N}, state_vec::StateVector{T}, ts::Vararg{Int,N}) where {T<:Complex, N} = apply_gate!($f(exp(im*g.angle[1])), state_vec, ts...) + apply_gate!(::Val{$V}, g::MultiRZ, state_vec::AbstractStateVector{T}, t::Int) where {T<:Complex} = apply_gate!(Val($V), Rz(g.angle, g.pow_exponent), state_vec, t) + apply_gate!(::Val{$V}, g::MultiRZ, state_vec::AbstractStateVector{T}, t1::Int,t2::Int,) where {T<:Complex} = apply_gate!(Val($V), ZZ(g.angle, g.pow_exponent), state_vec, t1, t2) + apply_gate!(::Val{$V}, g::MultiRZ, state_vec::AbstractStateVector{T}, ts::Vararg{Int,N}) where {T<:Complex,N} = apply_gate!($f(-im * g.angle[1] / 2.0), PauliEigenvalues(Val(N)), state_vec, ts...) + apply_gate!(::Val{$V}, g::MultiQubitPhaseShift{N}, state_vec::AbstractStateVector{T}, ts::Vararg{Int,N}) where {T<:Complex, N} = apply_gate!($f(exp(im*g.angle[1]*g.pow_exponent)), state_vec, ts...) end end function apply_gate!( g::DoubleExcitation, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, t1::Int, t2::Int, t3::Int, @@ -151,21 +111,23 @@ function apply_gate!( end return end -apply_gate!(::Val{true}, g::DoubleExcitation, state_vec::StateVector{T}, t1::Int, t2::Int, t3::Int, t4::Int) where {T<:Complex} = apply_gate!(g, state_vec, t1, t2, t3, t4) -apply_gate!(::Val{false}, g::DoubleExcitation, state_vec::StateVector{T}, t1::Int, t2::Int, t3::Int, t4::Int) where {T<:Complex} = apply_gate!(g, state_vec, t1, t2, t3, t4) +apply_gate!(::Val{true}, g::DoubleExcitation, state_vec::AbstractStateVector{T}, t1::Int, t2::Int, t3::Int, t4::Int) where {T<:Complex} = apply_gate!(g, state_vec, t1, t2, t3, t4) +apply_gate!(::Val{false}, g::DoubleExcitation, state_vec::AbstractStateVector{T}, t1::Int, t2::Int, t3::Int, t4::Int) where {T<:Complex} = apply_gate!(g, state_vec, t1, t2, t3, t4) -struct Control{G<:Gate, B} <: Gate +mutable struct Control{G<:Gate, B} <: Gate g::G bitvals::NTuple{B, Int} - Control{G, B}(g::G, bitvals::NTuple{B, Int}) where {B, G} = new(g, bitvals) + pow_exponent::Float64 + Control{G, B}(g::G, bitvals::NTuple{B, Int}, pow_exponent::Float64=1.0) where {B, G} = new(g, bitvals, pow_exponent) end -Control(g::G, bitvals::NTuple{B, Int}) where {G<:Gate, B} = Control{G, B}(g, bitvals) -Control(g::Control{G, BC}, bitvals::NTuple{B, Int}) where {G<:Gate, BC, B} = Control(g.g, (g.bitvals..., bitvals...)) -Control(g::G, bitvals::NTuple{0, Int}) where {G<:Gate} = g -Base.copy(c::Control{G, B}) where {G<:Gate, B} = Control(copy(c.g), c.bitvals) -Braket.qubit_count(c::Control{G, B}) where {G<:Gate, B} = qubit_count(c.g) + B -Braket.qubit_count(c::Control{MultiQubitPhaseShift{N}, B}) where {N, B} = N -function matrix_rep(c::Control{G, B}) where {G<:Gate, B} +Control(g::G, bitvals::NTuple{B, Int}, pow_exponent::Float64=1.0) where {G<:Gate, B} = Control{G, B}(g, bitvals, pow_exponent) +Control(g::Control{G, BC}, bitvals::NTuple{B, Int}, pow_exponent::Float64=1.0) where {G<:Gate, BC, B} = Control(g.g, (g.bitvals..., bitvals...), g.pow_exponent * pow_exponent) +Control(g::Control{G, BC}, bitvals::NTuple{0, Int}, pow_exponent::Float64=1.0) where {G<:Gate, BC} = g +Control(g::G, bitvals::NTuple{0, Int}, pow_exponent::Float64=1.0) where {G<:Gate} = g +Base.copy(c::Control{G, B}) where {G<:Gate, B} = Control(copy(c.g), c.bitvals, c.pow_exponent) +qubit_count(c::Control{G, B}) where {G<:Gate, B} = qubit_count(c.g) + B +qubit_count(c::Control{MultiQubitPhaseShift{N}, B}) where {N, B} = N +function matrix_rep_raw(c::Control{G, B}) where {G<:Gate, B} inner_mat = matrix_rep(c.g) inner_qc = qubit_count(c.g) total_qc = qubit_count(c.g) + B @@ -179,7 +141,7 @@ function matrix_rep(c::Control{G, B}) where {G<:Gate, B} end return full_mat end -function matrix_rep(c::Control{MultiQubitPhaseShift{N}, B}) where {N, B} +function matrix_rep_raw(c::Control{MultiQubitPhaseShift{N}, B}) where {N, B} g_mat = matrix_rep(c.g) qc = N ctrl_ix = 0 @@ -192,6 +154,3 @@ function matrix_rep(c::Control{MultiQubitPhaseShift{N}, B}) where {N, B} end return Diagonal(SVector{2^N, ComplexF64}(full_mat)) end - -const custom_gates = (doubleexcitation=DoubleExcitation, singleexcitation=SingleExcitation, multirz=MultiRZ, u=U,) - diff --git a/src/dm_simulator.jl b/src/dm_simulator.jl index a42ceb1..f55fb31 100644 --- a/src/dm_simulator.jl +++ b/src/dm_simulator.jl @@ -60,24 +60,24 @@ end Create a `DensityMatrixSimulator` with `2^qubit_count x 2^qubit_count` elements and `shots` shots to be measured. The default element type is `ComplexF64`. """ DensityMatrixSimulator(::Type{T}, qubit_count::Int, shots::Int) where {T<:Number} = - DensityMatrixSimulator{T,DensityMatrix{T}}(qubit_count, shots) + DensityMatrixSimulator{T,Matrix{T}}(qubit_count, shots) DensityMatrixSimulator(qubit_count::Int, shots::Int) = DensityMatrixSimulator(ComplexF64, qubit_count, shots) -Braket.qubit_count(dms::DensityMatrixSimulator) = dms.qubit_count +qubit_count(dms::DensityMatrixSimulator) = dms.qubit_count """ properties(svs::DensityMatrixSimulator) -> GateModelSimulatorDeviceCapabilities Query the properties and capabilities of a `DensityMatrixSimulator`, including which gates and result types are supported and the minimum and maximum shot and qubit counts. """ -Braket.properties(d::DensityMatrixSimulator) = dm_props +properties(d::DensityMatrixSimulator) = dm_props supported_operations(d::DensityMatrixSimulator, ::Val{:OpenQASM}) = dm_props.action["braket.ir.openqasm.program"].supportedOperations supported_operations(d::DensityMatrixSimulator, ::Val{:JAQCD}) = dm_props.action["braket.ir.jaqcd.program"].supportedOperations supported_operations(d::DensityMatrixSimulator) = supported_operations(d::DensityMatrixSimulator, Val(:OpenQASM)) supported_result_types(d::DensityMatrixSimulator, ::Val{:OpenQASM}) = dm_props.action["braket.ir.openqasm.program"].supportedResultTypes supported_result_types(d::DensityMatrixSimulator, ::Val{:JAQCD}) = dm_props.action["braket.ir.jaqcd.program"].supportedResultTypes supported_result_types(d::DensityMatrixSimulator) = supported_result_types(d::DensityMatrixSimulator, Val(:OpenQASM)) -Braket.device_id(dms::DensityMatrixSimulator) = "braket_dm_v2" -Braket.name(dms::DensityMatrixSimulator) = "DensityMatrixSimulator" +device_id(dms::DensityMatrixSimulator) = "braket_dm_v2" +name(dms::DensityMatrixSimulator) = "DensityMatrixSimulator" Base.show(io::IO, dms::DensityMatrixSimulator) = print(io, "DensityMatrixSimulator(qubit_count=$(qubit_count(dms)), shots=$(dms.shots))") Base.similar( @@ -181,8 +181,8 @@ function apply_observable!( return dm end function apply_observable!( - observable::Braket.Observables.HermitianObservable, - dm::DensityMatrix{T}, + observable::Observables.HermitianObservable, + dm::AbstractDensityMatrix{T}, targets::Int..., ) where {T<:Complex} n_amps = size(dm, 1) @@ -251,7 +251,6 @@ function expectation( dm_copy = apply_observable(observable, dms.density_matrix, targets...) return real(sum(diag(dm_copy))) end -state_vector(dms::DensityMatrixSimulator) = diag(dms.density_matrix) density_matrix(dms::DensityMatrixSimulator) = copy(dms.density_matrix) probabilities(dms::DensityMatrixSimulator) = real.(diag(dms.density_matrix)) diff --git a/src/gate_kernels.jl b/src/gate_kernels.jl index 751be8c..6f7b507 100644 --- a/src/gate_kernels.jl +++ b/src/gate_kernels.jl @@ -29,40 +29,165 @@ end return n_amps, endian_qubits(n_qubits, qubits...) end -matrix_rep(::H) = SMatrix{2,2}(complex((1 / √2) * [1.0 1.0; 1.0 -1.0])) -matrix_rep(::X) = SMatrix{2,2}(complex([0.0 1.0; 1.0 0.0])) -matrix_rep(::Y) = SMatrix{2,2}(complex([0.0 -im; im 0.0])) -matrix_rep(::Z) = SMatrix{2,2}(complex([1.0 0.0; 0.0 -1.0])) -matrix_rep(::I) = SMatrix{2,2}(complex([1.0 0.0; 0.0 1.0])) -matrix_rep(::V) = SMatrix{2,2}(0.5 * [1.0+im 1.0-im; 1.0-im 1.0+im]) -matrix_rep(::Vi) = SMatrix{2,2}(0.5 * [1.0-im 1.0+im; 1.0+im 1.0-im]) -matrix_rep(::S) = SMatrix{2,2}([1.0 0.0; 0.0 im]) -matrix_rep(::Si) = SMatrix{2,2}([1.0 0.0; 0.0 -im]) -matrix_rep(::T) = SMatrix{2,2}([1.0 0.0; 0.0 exp(im * π / 4.0)]) -matrix_rep(::Ti) = SMatrix{2,2}([1.0 0.0; 0.0 exp(-im * π / 4.0)]) +matrix_rep_raw(::H) = SMatrix{2,2}(complex((1 / √2) * [1.0 1.0; 1.0 -1.0])) +matrix_rep_raw(::X) = SMatrix{2,2}(complex([0.0 1.0; 1.0 0.0])) +matrix_rep_raw(::Y) = SMatrix{2,2}(complex([0.0 -im; im 0.0])) +matrix_rep_raw(::Z) = SMatrix{2,2}(complex([1.0 0.0; 0.0 -1.0])) +matrix_rep_raw(g::I, qc::Int=1) = SMatrix{2^qc,2^qc}(complex(diagm(ones(2^qc)))) +matrix_rep_raw(::V) = SMatrix{2,2}(0.5 * [1.0+im 1.0-im; 1.0-im 1.0+im]) +matrix_rep_raw(::Vi) = SMatrix{2,2}(0.5 * [1.0-im 1.0+im; 1.0+im 1.0-im]) +matrix_rep_raw(::S) = SMatrix{2,2}([1.0 0.0; 0.0 im]) +matrix_rep_raw(::Si) = SMatrix{2,2}([1.0 0.0; 0.0 -im]) +matrix_rep_raw(::T) = SMatrix{2,2}([1.0 0.0; 0.0 exp(im * π / 4.0)]) +matrix_rep_raw(::Ti) = SMatrix{2,2}([1.0 0.0; 0.0 exp(-im * π / 4.0)]) +matrix_rep_raw(g::CNot) = SMatrix{4,4}(complex([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 1.0; 0.0 0.0 1.0 0.0])) +matrix_rep_raw(g::CY) = SMatrix{4,4}([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 -im; 0.0 0.0 im 0.0]) +matrix_rep_raw(g::CZ) = SMatrix{4,4}(complex([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 -1.0])) +matrix_rep_raw(g::CCNot) = SMatrix{8,8}(complex([1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0])) +matrix_rep_raw(g::CSwap) = SMatrix{8,8}(complex([1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0])) -matrix_rep(::CNot) = SMatrix{4,4}(complex([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 1.0; 0.0 0.0 1.0 0.0])) -matrix_rep(::CY) = SMatrix{4,4}([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 -im; 0.0 0.0 im 0.0]) -matrix_rep(::CZ) = SMatrix{4,4}(complex([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 -1.0])) -matrix_rep(::CV) = SMatrix{4,4}([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.5+0.5im 0.5-0.5im; 0.0 0.0 0.5-0.5im 0.5+0.5im]) -matrix_rep(::CCNot) = SMatrix{8,8}(complex([1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0])) -matrix_rep(::CSwap) = SMatrix{8,8}(complex([1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0])) +matrix_rep(g::I) = matrix_rep_raw(g) +for G in (:Y, :H, :Swap, :CNot, :CY, :CZ, :CCNot, :CSwap, :GPi, :ECR) + @eval begin + function matrix_rep(g::$G) + iseven(g.pow_exponent) && return matrix_rep_raw(I(), qubit_count(g)) + isodd(g.pow_exponent) && return matrix_rep_raw(g) + # this path is taken if n == 2.1, for example + return SMatrix{2^qubit_count($G), 2^qubit_count($G)}(matrix_rep_raw(g)^g.pow_exponent) + end + end +end + +for (G, G2) in ((:X, :V), (:Z, :S)) + @eval begin + function matrix_rep(g::$G) + iseven(g.pow_exponent) && return matrix_rep_raw(I(), qubit_count(g)) + isodd(g.pow_exponent) && return matrix_rep_raw(g) + g.pow_exponent == 0.5 && return matrix_rep_raw($G2()) + # this path is taken if n == 2.1, for example + return SMatrix{2, 2}(matrix_rep_raw(g)^g.pow_exponent) + end + end +end + +function matrix_rep(g::ISwap) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return SMatrix{4, 4}([1.0 0.0 0.0 0.0; 0.0 0.0 -im 0.0; 0.0 -im 0.0 0.0; 0.0 0.0 0.0 1.0]) + return SMatrix{4, 4}(matrix_rep_raw(g)^n) +end + +function matrix_rep(g::PSwap) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + isodd(n) && return matrix_rep_raw(PSwap(g.angle[1]*n)) + iseven(n) && return SMatrix{4,4}(diagm([1.0, exp(im*g.angle[1]*n), exp(im*g.angle[1]*n), 1.0])) + return SMatrix{4, 4}(matrix_rep_raw(g)^n) +end + +function matrix_rep(g::PRx) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return matrix_rep_raw(PRx(-g.angle[1], g.angle[2])) + return SMatrix{2, 2}(matrix_rep_raw(g)^n) +end + +for G in (:Rx, :Ry, :Rz, :PhaseShift, :CPhaseShift, :CPhaseShift00, :CPhaseShift01, :CPhaseShift10, :XX, :YY, :ZZ, :XY, :SingleExcitation, :DoubleExcitation, :MultiRZ) + @eval function matrix_rep(g::$G) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + isinteger(n) && return matrix_rep_raw($G(g.angle[1]*n)) + return SMatrix{2^qubit_count(g),2^qubit_count(g)}(matrix_rep_raw($G(g.angle[1])) ^ n) + end +end + +function matrix_rep(g::CV) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return SMatrix{4, 4}(complex(ComplexF64[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.5-0.5im 0.5+0.5im; 0.0 0.0 0.5+0.5im 0.5-0.5im])) + return SMatrix{4, 4}(matrix_rep_raw(g)^n) +end + +function matrix_rep(g::MS) + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return matrix_rep_raw(MS(g.angle[1] + π, g.angle[2], g.angle[3])) + return SMatrix{4, 4}(matrix_rep_raw(g)^n) +end + +for (G, Gi, G2) in ((:V, :Vi, :X), (:S, :Si, :Z)) + @eval begin + function matrix_rep(g::$G) + n = g.pow_exponent + mod(n, 4) == 0 && return matrix_rep_raw(I(), qubit_count(g)) + mod(n, 4) == 1 && return matrix_rep_raw($G()) + mod(n, 4) == 2 && return matrix_rep_raw($G2()) + mod(n, 4) == 3 && return matrix_rep_raw($Gi()) + # this path is taken if n == 2.1, for example + return SMatrix{2, 2}(matrix_rep_raw(g)^n) + end + function matrix_rep(g::$Gi) + n = g.pow_exponent + mod(n, 4) == 0 && return matrix_rep_raw(I(), qubit_count(g)) + mod(n, 4) == 1 && return matrix_rep_raw($Gi()) + mod(n, 4) == 2 && return matrix_rep_raw($G2()) + mod(n, 4) == 3 && return matrix_rep_raw($G()) + # this path is taken if n == 2.1, for example + return SMatrix{2, 2}(matrix_rep_raw(g)^n) + end + end +end -matrix_rep(g::PRx) = SMatrix{2,2}( +function matrix_rep_raw(g::U)::SMatrix{2, 2, ComplexF64} + θ, ϕ, λ = g.angle + return SMatrix{2, 2, ComplexF64}([cos(θ/2) -exp(im*λ)*sin(θ/2); exp(im*ϕ)*sin(θ/2) exp(im*(λ+ϕ))*cos(θ/2)]) +end + +function matrix_rep(g::U)::SMatrix{2, 2, ComplexF64} + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return matrix_rep_raw(U(-g.angle[1], -g.angle[3], -g.angle[2])) + return SMatrix{2, 2}(matrix_rep_raw(g) ^ n) +end +function matrix_rep(g::T)::SMatrix{2, 2, ComplexF64} + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return matrix_rep_raw(Ti()) + return matrix_rep(PhaseShift(n*π/4)) +end +function matrix_rep(g::Ti)::SMatrix{2, 2, ComplexF64} + n = g.pow_exponent + iszero(n) && return matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == -1 && return matrix_rep_raw(T()) + return matrix_rep(PhaseShift(-n*π/4)) +end + +matrix_rep_raw(g::CV) = SMatrix{4,4}([1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 0.5+0.5im 0.5-0.5im; 0.0 0.0 0.5-0.5im 0.5+0.5im]) + +matrix_rep_raw(g::PRx) = SMatrix{2,2}( [ cos(g.angle[1] / 2.0) -im*exp(-im*g.angle[2])*sin(g.angle[1]/2.0) -im*exp(im*g.angle[2])*sin(g.angle[1]/2.0) cos(g.angle[1] / 2.0) ], ) -matrix_rep(g::Rz) = +matrix_rep_raw(g::Rz) = SMatrix{2,2}([exp(-im * g.angle[1] / 2.0) 0.0; 0.0 exp(im * g.angle[1] / 2.0)]) -matrix_rep(g::Rx) = SMatrix{2,2}( +matrix_rep_raw(g::Rx) = SMatrix{2,2}( [ cos(g.angle[1] / 2.0) -im*sin(g.angle[1] / 2.0) -im*sin(g.angle[1] / 2.0) cos(g.angle[1] / 2.0) ], ) -matrix_rep(g::Ry) = SMatrix{2,2}( +matrix_rep_raw(g::Ry) = SMatrix{2,2}( complex( [ cos(g.angle[1] / 2.0) -sin(g.angle[1] / 2.0) @@ -70,27 +195,28 @@ matrix_rep(g::Ry) = SMatrix{2,2}( ], ), ) -matrix_rep(g::GPi) = +matrix_rep_raw(g::GPi) = SMatrix{2,2}(complex([0 exp(-im * g.angle[1]); exp(im * g.angle[1]) 0])) -matrix_rep(g::GPi2) = + +matrix_rep_raw(g::GPi2) = SMatrix{2,2}(1/√2 * complex([1.0 -im*exp(-im * g.angle[1]); -im*exp(im * g.angle[1]) 1.0])) -matrix_rep(g::MS) = SMatrix{4,4}( +matrix_rep_raw(g::MS) = SMatrix{4,4}( complex( [ - cos(g.angle[3] / 2.0) 0.0 0.0 -im*exp(-im * (g.angle[1] + g.angle[2]))*sin(g.angle[3] / 2) - 0.0 cos(g.angle[3] / 2) -im*exp(-im * (g.angle[1] - g.angle[2]))*sin(g.angle[3] / 2) 0.0 - 0.0 -im*exp(im * (g.angle[1] - g.angle[2]))*sin(g.angle[3] / 2) cos(g.angle[3] / 2) 0.0 - -im*exp(im * (g.angle[1] + g.angle[2]))*sin(g.angle[3] / 2) 0.0 0.0 cos(g.angle[3] / 2) + cos(g.angle[3] / 2.0) 0.0 0.0 -im*exp(-im * (g.angle[1] + g.angle[2]))*sin(g.angle[3] / 2); + 0.0 cos(g.angle[3] / 2.0) -im*exp(-im * (g.angle[1] - g.angle[2]))*sin(g.angle[3] / 2.0) 0.0; + 0.0 -im*exp(im * (g.angle[1] - g.angle[2]))*sin(g.angle[3] / 2) cos(g.angle[3] / 2.0) 0.0; + -im*exp(im * (g.angle[1] + g.angle[2]))*sin(g.angle[3] / 2.0) 0.0 0.0 cos(g.angle[3] / 2.0); ], ), ) -matrix_rep(g::PhaseShift) = SMatrix{2,2}([1.0 0.0; 0.0 exp(im * g.angle[1])]) +matrix_rep_raw(g::PhaseShift) = SMatrix{2,2}([1.0 0.0; 0.0 exp(im * g.angle[1])]) # controlled unitaries for (cph, ind) in ((:CPhaseShift, 4), (:CPhaseShift00, 1), (:CPhaseShift01, 3), (:CPhaseShift10, 2)) @eval begin - matrix_rep(g::$cph) = Diagonal( + matrix_rep_raw(g::$cph) = Diagonal( SVector{4,ComplexF64}( setindex!(ones(ComplexF64, 4), exp(im * g.angle[1]), $ind), ), @@ -100,12 +226,12 @@ end for (sw, factor) in ((:Swap, 1.0), (:ISwap, im), (:PSwap, :(exp(im * g.angle[1])))) @eval begin - matrix_rep(g::$sw) = SMatrix{4,4,ComplexF64}( + matrix_rep_raw(g::$sw) = SMatrix{4,4,ComplexF64}( [1.0 0.0 0.0 0.0 0.0 0.0 $factor 0.0 0.0 $factor 0.0 0.0 0.0 0.0 0.0 1.0], ) end end -matrix_rep(g::XX) = SMatrix{4,4}( +matrix_rep_raw(g::XX) = SMatrix{4,4}( [ cos(g.angle[1] / 2.0) 0.0 0.0 -im*sin(g.angle[1] / 2) 0.0 cos(g.angle[1] / 2.0) -im*sin(g.angle[1] / 2.0) 0.0 @@ -113,7 +239,7 @@ matrix_rep(g::XX) = SMatrix{4,4}( -im*sin(g.angle[1] / 2.0) 0.0 0.0 cos(g.angle[1] / 2.0) ], ) -matrix_rep(g::XY) = SMatrix{4,4}( +matrix_rep_raw(g::XY) = SMatrix{4,4}( [ 1.0 0.0 0.0 0.0 0.0 cos(g.angle[1] / 2.0) im*sin(g.angle[1] / 2.0) 0.0 @@ -121,7 +247,7 @@ matrix_rep(g::XY) = SMatrix{4,4}( 0.0 0.0 0.0 1.0 ], ) -matrix_rep(g::YY) = SMatrix{4,4}( +matrix_rep_raw(g::YY) = SMatrix{4,4}( [ cos(g.angle[1] / 2.0) 0.0 0.0 im*sin(g.angle[1] / 2) 0.0 cos(g.angle[1] / 2.0) -im*sin(g.angle[1] / 2.0) 0.0 @@ -129,7 +255,7 @@ matrix_rep(g::YY) = SMatrix{4,4}( im*sin(g.angle[1] / 2.0) 0.0 0.0 cos(g.angle[1] / 2.0) ], ) -matrix_rep(g::ZZ) = SMatrix{4,4}( +matrix_rep_raw(g::ZZ) = SMatrix{4,4}( diagm([ exp(-im * g.angle[1] / 2.0), exp(im * g.angle[1] / 2.0), @@ -138,17 +264,25 @@ matrix_rep(g::ZZ) = SMatrix{4,4}( ]), ) # 1/√2 * (IX - XY) -matrix_rep(g::ECR) = SMatrix{4,4}(1/√2 * [0 1 0 im; 1 0 -im 0; 0 im 0 1; -im 0 1 0]) -matrix_rep(g::Unitary) = g.matrix +matrix_rep_raw(g::ECR) = SMatrix{4,4}(1/√2 * [0 1 0 im; 1 0 -im 0; 0 im 0 1; -im 0 1 0]) +matrix_rep_raw(g::Unitary) = g.matrix +function matrix_rep(g::Gate) + n = g.pow_exponent + iszero(n) && matrix_rep_raw(I(), qubit_count(g)) + isone(n) && return matrix_rep_raw(g) + n == 0.5 && return √matrix_rep_raw(g) + n == -0.5 && return inv(√matrix_rep_raw(g)) + return SMatrix{2^qubit_count(g),2^qubit_count(g)}( matrix_rep_raw(g)^n ) +end -apply_gate!(::Val{false}, g::I, state_vec::StateVector{T}, qubits::Int...) where {T<:Complex} = +apply_gate!(::Val{false}, g::I, state_vec::AbstractStateVector{T}, qubits::Int...) where {T<:Complex} = return -apply_gate!(::Val{true}, g::I, state_vec::StateVector{T}, qubits::Int...) where {T<:Complex} = +apply_gate!(::Val{true}, g::I, state_vec::AbstractStateVector{T}, qubits::Int...) where {T<:Complex} = return function apply_gate!( g_matrix::Union{SMatrix{2,2,T}, Diagonal{T,SVector{2,T}}}, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, qubit::Int, ) where {T<:Complex} n_amps, endian_qubit = get_amps_and_qubits(state_vec, qubit) @@ -198,7 +332,7 @@ end # generic two-qubit non controlled unitaries function apply_gate!( g_mat::M, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, t1::Int, t2::Int, ) where {T<:Complex,M<:Union{SMatrix{4,4,T},Diagonal{T,SVector{4,T}}}} @@ -232,30 +366,10 @@ function apply_gate!( end end -for (V, f) in ((false, :identity), (true, :conj)) - @eval begin - apply_gate!(::Val{$V}, - g::G, - state_vec::StateVector{T}, - qubits::Int...) where {G<:Gate,T<:Complex} = apply_gate!($f(matrix_rep(g)), state_vec, qubits...) - apply_gate!(::Val{$V}, - g::Unitary, - state_vec::StateVector{T}, - qubit::Int) where {T<:Complex} = apply_gate!(SMatrix{2,2,T}($f(matrix_rep(g))), state_vec, qubit) - apply_gate!(::Val{$V}, - g::Unitary, - state_vec::StateVector{T}, - q1::Int, - q2::Int) where {T<:Complex} = apply_gate!(SMatrix{4,4,T}($f(matrix_rep(g))), state_vec, q2, q1) - end -end - -apply_gate!(g::G, args...) where {G<:Gate} = apply_gate!(Val(false), g, args...) - function apply_controlled_gate!( g_matrix::Union{SMatrix{2,2,T}, Diagonal{T,SVector{2,T}}, Matrix{T}}, c_bit::Bool, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control::Int, target::Int, ) where {T<:Complex} @@ -283,7 +397,7 @@ end function apply_controlled_gate!( g_matrix::Union{SMatrix{4, 4, T}, Diagonal{T, SVector{4, T}}, Matrix{T}}, c_bit::Bool, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control::Int, target_1::Int, target_2::Int, @@ -312,7 +426,7 @@ function apply_controlled_gate!( g_matrix::Union{SMatrix{2, 2, T}, Diagonal{T, SVector{2, T}}, Matrix{T}}, c1_bit::Bool, c2_bit::Bool, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control_1::Int, control_2::Int, target::Int, @@ -343,6 +457,10 @@ function apply_controlled_gate!( end for (V, f) in ((true, :conj), (false, :identity)) @eval begin + apply_gate!(::Val{$V}, gate::Control{G, B}, state_vec::AbstractStateVector{T}, qubits::Int...) where {T<:Complex, G<:Gate, B} = apply_controlled_gate!(Val($V), Val(B), gate, gate.g ^ gate.pow_exponent, state_vec, gate.bitvals, qubits...) + apply_gate!(::Val{$V}, gate::Control{MultiQubitPhaseShift{N}, B}, state_vec::AbstractStateVector{T}, qubits::Int...) where {T<:Complex, N, B} = apply_gate!($f(im), gate, state_vec, qubits...) + apply_gate!(::Val{$V}, gate::Unitary, state_vec::AbstractStateVector{T}, targets::Vararg{Int,NQ}) where {T<:Complex,NQ} = apply_gate!($f(SMatrix{2^NQ, 2^NQ, ComplexF64}(matrix_rep(gate))), state_vec, targets...) + apply_gate!(::Val{$V}, g::G, state_vec::AbstractStateVector{T}, qubits::Int...) where {G<:Gate,T<:Complex} = apply_gate!($f(matrix_rep(g)), state_vec, qubits...) apply_controlled_gate!( ::Val{$V}, ::Val{1}, @@ -350,7 +468,7 @@ for (V, f) in ((true, :conj), (false, :identity)) gate::G, # gate on *target* qubit bits only (e.g. V) target_gate::TG, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control_bits::NTuple{1,Int}, control::Int, target::Int, @@ -360,7 +478,7 @@ for (V, f) in ((true, :conj), (false, :identity)) ::Val{1}, gate::G, target_gate::TG, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control_bits::NTuple{1,Int}, control::Int, target_1::Int, @@ -372,7 +490,7 @@ for (V, f) in ((true, :conj), (false, :identity)) ::Val{2}, gate::G, target_gate::TG, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, control_bits::NTuple{2,Int}, control_1::Int, control_2::Int, @@ -380,6 +498,7 @@ for (V, f) in ((true, :conj), (false, :identity)) ) where {G<:Gate,TG<:Gate,T<:Complex} = apply_controlled_gate!($f(matrix_rep(target_gate)), control_bits[1] == 1, control_bits[2] == 1, state_vec, control_1, control_2, target) end end +apply_gate!(g::G, args...) where {G<:Gate} = apply_gate!(Val(false), g, args...) for (control_gate, target_gate, n_controls) in ( (:CNot, :X, 1), @@ -391,13 +510,7 @@ for (control_gate, target_gate, n_controls) in ( ), Vc in (false, true) @eval begin - apply_gate!( - ::Val{$Vc}, - gate::$control_gate, - state_vec::StateVector{T}, - qubits::Int..., - ) where {T<:Complex} = - apply_controlled_gate!(Val($Vc), Val($n_controls), gate, $target_gate(), state_vec, ntuple(control_bit->1, Val($n_controls)), qubits...) + apply_gate!(::Val{$Vc}, gate::$control_gate, state_vec::AbstractStateVector{T}, qubits::Int...,) where {T<:Complex} = apply_controlled_gate!(Val($Vc), Val($n_controls), gate, $target_gate() ^ gate.pow_exponent, state_vec, ntuple(control_bit->1, Val($n_controls)), qubits...) end end @@ -405,7 +518,7 @@ end function apply_gate!( factor::Complex, gate::Control{MultiQubitPhaseShift{N}, B}, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, qubits::Int..., ) where {T<:Complex, N, B} bit_values = gate.bitvals @@ -415,38 +528,13 @@ function apply_gate!( for (bit_index, bit_value) in enumerate(bit_values) phase_index += bit_value << (bit_index - 1) end - g_matrix[phase_index] = exp(factor*gate.g.angle[1]) + g_matrix[phase_index] = exp(factor*gate.g.angle[1]*gate.g.pow_exponent * gate.pow_exponent) apply_gate!(Diagonal(SVector{2^N, ComplexF64}(g_matrix)), state_vec, qubits...) end -# arbitrary number of targets -for (V, f) in ((false, :identity), (true, :conj)) - @eval begin - apply_gate!( - ::Val{$V}, - gate::Control{G, B}, - state_vec::StateVector{T}, - qubits::Int..., - ) where {T<:Complex, G<:Gate, B} = - apply_controlled_gate!(Val($V), Val(B), gate, gate.g, state_vec, gate.bitvals, qubits...) - apply_gate!( - ::Val{$V}, - gate::Control{MultiQubitPhaseShift{N}, B}, - state_vec::StateVector{T}, - qubits::Int..., - ) where {T<:Complex, N, B} = apply_gate!($f(im), gate, state_vec, qubits...) - apply_gate!( - ::Val{$V}, - gate::Unitary, - state_vec::StateVector{T}, - targets::Vararg{Int,NQ}, - ) where {T<:Complex,NQ} = - apply_gate!($f(SMatrix{2^NQ, 2^NQ, ComplexF64}(matrix_rep(gate))), state_vec, targets...) - end -end function apply_gate!( g_matrix::Union{SMatrix{N, N, T}, Diagonal{T, SVector{N, T}}}, - state_vec::StateVector{T}, + state_vec::AbstractStateVector{T}, targets::Vararg{Int,NQ}, ) where {T<:Complex,NQ,N} n_amps, endian_ts = get_amps_and_qubits(state_vec, targets...) diff --git a/src/gates.jl b/src/gates.jl new file mode 100644 index 0000000..024ac71 --- /dev/null +++ b/src/gates.jl @@ -0,0 +1,130 @@ +""" + Gate <: QuantumOperator + +Abstract type representing a quantum gate. +""" +abstract type Gate <: QuantumOperator end + +""" + AngledGate{NA} <: Gate + +Parametric type representing a quantum gate with `NA` `angle` parameters. +""" +abstract type AngledGate{NA} <: Gate end +n_angles(::Type{<:Gate}) = 0 +n_angles(::Type{<:AngledGate{N}}) where {N} = N +n_angles(g::G) where {G<:Gate} = n_angles(G) + +for gate_def in ( + (:Rx, :1, :1, :0, :1), + (:Ry, :1, :1, :0, :1), + (:Rz, :1, :1, :0, :1), + (:PSwap, :1, :2, :0, :2), + (:PhaseShift, :1, :1, :0, :1), + (:CPhaseShift, :1, :2, :1, :1), + (:CPhaseShift00, :1, :2, :1, :1), + (:CPhaseShift01, :1, :2, :1, :1), + (:CPhaseShift10, :1, :2, :1, :1), + (:XX, :1, :2, :0, :2), + (:XY, :1, :2, :0, :2), + (:YY, :1, :2, :0, :2), + (:ZZ, :1, :2, :0, :2), + (:GPi, :1, :1, :0, :1), + (:GPi2, :1, :1, :0, :1), + (:MS, :3, :2, :0, :2), + (:U, :3, :1, :0, :1), + (:PRx, :2, :1, :0, :1), + ) + G, n_angle, qc, n_controls, n_targets = gate_def + @eval begin + @doc """ + $($G) <: AngledGate{$($n_angle)} + $($G)(angles) -> $($G) + + $($G) gate. + """ + mutable struct $G <: AngledGate{$n_angle} + angle::NTuple{$n_angle, Union{Real, FreeParameter}} + pow_exponent::Float64 + $G(angle::T, pow_exponent::Float64=1.0) where {T<:NTuple{$n_angle, Union{Real, FreeParameter}}} = new(angle, pow_exponent) + end + qubit_count(::Type{$G}) = $qc + end +end +Base.:(==)(g1::G, g2::G) where {G<:AngledGate} = g1.pow_exponent == g2.pow_exponent && g1.angle == g2.angle + +for gate_def in ( + (:H, :1, :0, :1), + (:I, :1, :0, :1), + (:X, :1, :0, :1), + (:Y, :1, :0, :1), + (:Z, :1, :0, :1), + (:S, :1, :0, :1), + (:Si, :1, :0, :1), + (:T, :1, :0, :1), + (:Ti, :1, :0, :1), + (:V, :1, :0, :1), + (:Vi, :1, :0, :1), + (:CNot, :2, :1, :1), + (:Swap, :2, :0, :2), + (:ISwap, :2, :0, :2), + (:CV, :2, :1, :1), + (:CY, :2, :1, :1), + (:CZ, :2, :1, :1), + (:ECR, :2, :0, :2), + (:CCNot, :3, :2, :1), + (:CSwap, :3, :1, :2), + ) + G, qc, n_controls, n_targets = gate_def + @eval begin + @doc """ + $($G) <: Gate + $($G)() -> $($G) + + $($G) gate. + """ + mutable struct $G <: Gate + pow_exponent::Float64 + $G(pow_exponent::Float64=1.0) = new(pow_exponent) + end + qubit_count(::Type{$G}) = $qc + end +end +(::Type{G})(angle::T, pow_exponent=1.0) where {G<:AngledGate{1}, T<:Union{Real, FreeParameter}} = G((angle,), Float64(pow_exponent)) +(::Type{G})(angle1::T1, angle2::T2, pow_exponent=1.0) where {T1<:Union{Real, FreeParameter}, T2<:Union{Real, FreeParameter}, G<:AngledGate{2}} = G((angle1, angle2,), Float64(pow_exponent)) +(::Type{G})(angle1::T1, angle2::T2, angle3::T3, pow_exponent=1.0) where {T1<:Union{Real, FreeParameter}, T2<:Union{Real, FreeParameter}, T3<:Union{Real, FreeParameter}, G<:AngledGate{3}} = G((angle1, angle2, angle3,), Float64(pow_exponent)) +Base.:(==)(g1::G, g2::G) where {G<:Gate} = g1.pow_exponent == g2.pow_exponent +qubit_count(g::G) where {G<:Gate} = qubit_count(G) +angles(g::G) where {G<:Gate} = () +angles(g::AngledGate{N}) where {N} = g.angle + +""" + Unitary <: Gate + Unitary(matrix::Matrix{ComplexF64}) -> Unitary + +Arbitrary unitary gate. +""" +mutable struct Unitary <: Gate + matrix::Matrix{ComplexF64} + pow_exponent::Float64 + Unitary(matrix::Matrix{<:Number}, pow_exponent=1.0) = new(ComplexF64.(matrix), Float64(pow_exponent)) +end +Base.:(==)(u1::Unitary, u2::Unitary) = u1.matrix == u2.matrix && u1.pow_exponent == u2.pow_exponent +qubit_count(g::Unitary) = convert(Int, log2(size(g.matrix, 1))) + +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, <:Real}) where {G<:Gate} = bind_value!(Parametrizable(g), g, params) +bind_value!(::NonParametrized, g::G, params::Dict{Symbol, <:Real}) where {G<:Gate} = g +# nosemgrep +function bind_value!(::Parametrized, g::G, params::Dict{Symbol, <:Real}) where {G<:AngledGate} + new_angles = map(angles(g)) do angle + angle isa FreeParameter || return angle + return get(params, angle.name, angle) + end + return G(new_angles...) +end +Base.copy(g::G) where {G<:Gate} = G((copy(getproperty(g, fn)) for fn in fieldnames(G))...) +Base.copy(g::G) where {G<:AngledGate} = G(angles(g), g.pow_exponent) diff --git a/src/inverted_gates.jl b/src/inverted_gates.jl deleted file mode 100644 index 2dbd9df..0000000 --- a/src/inverted_gates.jl +++ /dev/null @@ -1,41 +0,0 @@ -for G in (:X, :Y, :Z, :H, :I, :Swap, :CNot, :CY, :CZ, :CCNot, :CSwap, :GPi, :ECR) - @eval Base.inv(g::$G) = g -end -for G in ( - :Rx, - :Ry, - :Rz, - :PhaseShift, - :PSwap, - :CPhaseShift, - :CPhaseShift00, - :CPhaseShift01, - :CPhaseShift10, - :XX, - :YY, - :ZZ, - :XY, -) - @eval Base.inv(g::$G) = $G(-g.angle[1]) -end -for (G, Gi) in ((:V, :Vi), (:S, :Si), (:T, :Ti)) - @eval begin - Base.inv(g::$G) = $Gi() - Base.inv(g::$Gi) = $G() - end -end -Base.inv(g::Unitary) = Unitary(inv(g.matrix)) -Base.inv(g::PRx) = PRx(-g.angle[1], g.angle[2]) -Base.inv(g::GPi2) = GPi2(g.angle[1] + π) -Base.inv(g::MS) = MS(g.angle[1] + π, g.angle[2], g.angle[3]) - -const iswap_inv = ComplexF64[1.0 0.0 0.0 0.0; - 0.0 0.0 -im 0.0; - 0.0 -im 0.0 0.0; - 0.0 0.0 0.0 1.0] -Base.inv(::ISwap) = Unitary(iswap_inv) -const cv_inv = ComplexF64[1.0 0.0 0.0 0.0; - 0.0 1.0 0.0 0.0; - 0.0 0.0 0.5-0.5im 0.5+0.5im; - 0.0 0.0 0.5+0.5im 0.5-0.5im] -Base.inv(::CV) = Unitary(cv_inv) diff --git a/src/noise_kernels.jl b/src/noise_kernels.jl index 52abf1a..4ea7b49 100644 --- a/src/noise_kernels.jl +++ b/src/noise_kernels.jl @@ -4,7 +4,7 @@ return n_amps, endian_qubits(n_qubits, qubits...) end -function apply_noise!(n::PhaseFlip, dm::DensityMatrix{T}, qubit::Int) where {T} +function apply_noise!(n::PhaseFlip, dm::AbstractDensityMatrix{T}, qubit::Int) where {T} # K₀ = √(1.0 - n.probability) * I # K₁ = √(n.probability) * Z # ρ = ∑ᵢ Kᵢ ρ Kᵢ\^† @@ -102,7 +102,7 @@ end apply_noise!(n::N, dm::S, qubits::Int...) where {T,S<:AbstractDensityMatrix{T},N<:Noise} = apply_noise!(kraus_rep(n), dm, qubits...) -function apply_noise!(n::Kraus, dm::DensityMatrix{T}, qubit::Int) where {T} +function apply_noise!(n::Kraus, dm::AbstractDensityMatrix{T}, qubit::Int) where {T} k_mats = ntuple(ix -> SMatrix{2,2,ComplexF64}(n.matrices[ix]), length(n.matrices)) k_mats_conj = ntuple(ix -> SMatrix{2,2,ComplexF64}(adjoint(n.matrices[ix])), length(n.matrices)) @@ -132,7 +132,7 @@ function apply_noise!(n::Kraus, dm::DensityMatrix{T}, qubit::Int) where {T} end end -function apply_noise!(n::Kraus, dm::DensityMatrix{T}, target1::Int, target2::Int) where {T} +function apply_noise!(n::Kraus, dm::AbstractDensityMatrix{T}, target1::Int, target2::Int) where {T} k_mats = ntuple(ix -> SMatrix{4,4,ComplexF64}(n.matrices[ix]), length(n.matrices)) k_mats_conj = ntuple(ix -> SMatrix{4,4,ComplexF64}(adjoint(n.matrices[ix])), length(n.matrices)) @@ -167,7 +167,7 @@ function apply_noise!(n::Kraus, dm::DensityMatrix{T}, target1::Int, target2::Int end end -function apply_noise!(n::Kraus, dm::DensityMatrix{T}, targets::Int...) where {T} +function apply_noise!(n::Kraus, dm::AbstractDensityMatrix{T}, targets::Int...) where {T} k_mats = n.matrices k_mats_conj = ntuple(ix -> adjoint(n.matrices[ix]), length(n.matrices)) # ρ = ∑ᵢ Kᵢ ρ Kᵢ\^† diff --git a/src/noises.jl b/src/noises.jl new file mode 100644 index 0000000..46258fe --- /dev/null +++ b/src/noises.jl @@ -0,0 +1,157 @@ +""" + Noise <: QuantumOperator + +Abstract type representing a quantum noise operation. +""" +abstract type Noise <: QuantumOperator end + +""" + Kraus <: Noise + +Kraus noise operation. +""" +struct Kraus <: Noise + matrices::Vector{Matrix{ComplexF64}} +end +Base.:(==)(k1::Kraus, k2::Kraus) = k1.matrices == k2.matrices +qubit_count(g::Kraus) = convert(Int, log2(size(g.matrices[1], 1))) + +""" + BitFlip <: Noise + +BitFlip noise operation. +""" +struct BitFlip <: Noise + probability::Union{Float64, FreeParameter} +end +Parametrizable(g::BitFlip) = Parametrized() +qubit_count(g::BitFlip) = 1 + +""" + PhaseFlip <: Noise + +PhaseFlip noise operation. +""" +struct PhaseFlip <: Noise + probability::Union{Float64, FreeParameter} +end +Parametrizable(g::PhaseFlip) = Parametrized() +qubit_count(g::PhaseFlip) = 1 + +""" + PauliChannel <: Noise + +PauliChannel noise operation. +""" +struct PauliChannel <: Noise + probX::Union{Float64, FreeParameter} + probY::Union{Float64, FreeParameter} + probZ::Union{Float64, FreeParameter} +end +Parametrizable(g::PauliChannel) = Parametrized() +qubit_count(g::PauliChannel) = 1 + +""" + AmplitudeDamping <: Noise + +AmplitudeDamping noise operation. +""" +struct AmplitudeDamping <: Noise + gamma::Union{Float64, FreeParameter} +end +Parametrizable(g::AmplitudeDamping) = Parametrized() +qubit_count(g::AmplitudeDamping) = 1 + +""" + PhaseDamping <: Noise + +PhaseDamping noise operation. +""" +struct PhaseDamping <: Noise + gamma::Union{Float64, FreeParameter} +end +Parametrizable(g::PhaseDamping) = Parametrized() +qubit_count(g::PhaseDamping) = 1 + +""" + Depolarizing <: Noise + +Depolarizing noise operation. +""" +struct Depolarizing <: Noise + probability::Union{Float64, FreeParameter} +end +Parametrizable(g::Depolarizing) = Parametrized() +qubit_count(g::Depolarizing) = 1 + +""" + TwoQubitDephasing <: Noise + +TwoQubitDephasing noise operation. +""" +struct TwoQubitDephasing <: Noise + probability::Union{Float64, FreeParameter} +end +Parametrizable(g::TwoQubitDephasing) = Parametrized() +qubit_count(g::TwoQubitDephasing) = 2 + +""" + TwoQubitDepolarizing <: Noise + +TwoQubitDepolarizing noise operation. +""" +struct TwoQubitDepolarizing <: Noise + probability::Union{Float64, FreeParameter} +end +Parametrizable(g::TwoQubitDepolarizing) = Parametrized() +qubit_count(g::TwoQubitDepolarizing) = 2 + +""" + GeneralizedAmplitudeDamping <: Noise + +GeneralizedAmplitudeDamping noise operation. +""" +struct GeneralizedAmplitudeDamping <: Noise + probability::Union{Float64, FreeParameter} + gamma::Union{Float64, FreeParameter} +end +Parametrizable(g::GeneralizedAmplitudeDamping) = Parametrized() +qubit_count(g::GeneralizedAmplitudeDamping) = 1 + +""" + MultiQubitPauliChannel{N} <: Noise + +Pauli channel noise operation on `N` qubits. +""" +struct MultiQubitPauliChannel{N} <: Noise + probabilities::Dict{String, Union{Float64, FreeParameter}} +end +""" + TwoQubitPauliChannel <: Noise + +Pauli channel noise operation on two qubits. +""" +TwoQubitPauliChannel = MultiQubitPauliChannel{2} +qubit_count(g::MultiQubitPauliChannel{N}) where {N} = N +Parametrizable(g::MultiQubitPauliChannel) = Parametrized() +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 + +Parametrizable(g::Noise) = NonParametrized() +parameters(g::Noise) = parameters(Parametrizable(g), g) +parameters(::Parametrized, g::N) where {N<:Noise} = filter(x->x isa FreeParameter, [getproperty(g, fn) for fn in fieldnames(N)]) +parameters(::NonParametrized, g::Noise) = FreeParameter[] +bind_value!(n::N, params::Dict{Symbol, <:Real}) where {N<:Noise} = bind_value!(Parametrizable(n), n, params) +bind_value!(::NonParametrized, n::N, params::Dict{Symbol, <:Real}) where {N<:Noise} = n + +# nosemgrep +function bind_value!(::Parametrized, g::N, params::Dict{Symbol, <:Real}) where {N<:Noise} + new_args = OrderedDict(zip(fieldnames(N), (getproperty(g, fn) for fn in fieldnames(N)))) + for fp in findall(v->v isa FreeParameter, new_args) + new_args[fp] = get(params, getproperty(g, fp).name, new_args[fp]) + end + return N(values(new_args)...) +end diff --git a/src/observables.jl b/src/observables.jl index 614beb2..1319cdf 100644 --- a/src/observables.jl +++ b/src/observables.jl @@ -1,22 +1,242 @@ -diagonalizing_gates(g::Braket.Observables.I, targets) = Braket.Instruction[] -diagonalizing_gates(g::Braket.Observables.H, targets) = - [Braket.Instruction(Ry(-π / 4.0), t) for t in targets] -diagonalizing_gates(g::Braket.Observables.X, targets) = - [Braket.Instruction(H(), t) for t in targets] -diagonalizing_gates(g::Braket.Observables.Y, targets) = - [Braket.Instruction(Unitary(1 / √2 * [1.0 -im; 1.0 im]), t) for t in targets] -diagonalizing_gates(g::Braket.Observables.Z, targets) = Braket.Instruction[] -function diagonalizing_gates(g::Braket.Observables.HermitianObservable, targets) +module Observables + +using StructTypes, LinearAlgebra + +import ..BraketSimulator: qubit_count, complex_matrix_to_ir, complex_matrix_from_ir, Operator, QubitSet, Qubit, IntOrQubit, IRObservable, PauliEigenvalues +export Observable, TensorProduct, HermitianObservable, Sum + +""" + Observable <: Operator + +Abstract type representing an observable to be measured. All `Observable`s +have `eigvals` defined. + +See also: [`H`](@ref), [`I`](@ref), [`X`](@ref), [`Y`](@ref), [`Z`](@ref), [`TensorProduct`](@ref), [`HermitianObservable`](@ref). +""" +abstract type Observable <: Operator end +abstract type NonCompositeObservable <: Observable end +abstract type StandardObservable <: NonCompositeObservable end + +LinearAlgebra.ishermitian(o::Observable) = true + +coef(o::O) where {O<:Observable} = o.coefficient + +for (typ, label, super) in ((:H, "h", :StandardObservable), (:X, "x", :StandardObservable), (:Y, "y", :StandardObservable), (:Z, "z", :StandardObservable), (:I, "i", :NonCompositeObservable)) + @eval begin + @doc """ + $($typ) <: Observable + $($typ)([coeff::Float64]) -> $($typ) + + Struct representing a `$($typ)` observable in a measurement. The observable + may be scaled by `coeff`. + """ + struct $typ <: $super + coefficient::Float64 + $typ(coef::Float64=1.0) = new(coef) + end + StructTypes.lower(x::$typ) = Union{String, Vector{Vector{Vector{Float64}}}}[$label] + qubit_count(::Type{$typ}) = 1 + qubit_count(o::$typ) = qubit_count($typ) + unscaled(o::$typ) = $typ() + Base.copy(o::$typ) = $typ(o.coefficient) + Base.:(*)(o::$typ, n::Real) = $typ(Float64(n*o.coefficient)) + Base.:(==)(o1::$typ, o2::$typ) = (o1.coefficient ≈ o2.coefficient) + Base.show(io::IO, o::$typ) = print(io, (isone(o.coefficient) ? "" : string(o.coefficient) * " * ") * uppercase($label)) + end +end +LinearAlgebra.eigvals(o::I) = [o.coefficient, o.coefficient] +LinearAlgebra.eigvals(o::StandardObservable) = [o.coefficient, -o.coefficient] + +""" + HermitianObservable <: Observable + HermitianObservable(matrix::Matrix) -> HermitianObservable + +Struct representing an observable of an arbitrary complex Hermitian matrix. + +# Examples +```jldoctest +julia> ho = BraketSimulator.Observables.HermitianObservable([0 1; 1 0]) +HermitianObservable((2, 2)) +``` +""" +struct HermitianObservable <: NonCompositeObservable + matrix::Matrix{<:Complex} + coefficient::Float64 + function HermitianObservable(mat::Matrix{<:Number}) + ishermitian(mat) || throw(ArgumentError("input matrix to HermitianObservable must be Hermitian.")) + new(complex(mat), 1.0) + end +end +HermitianObservable(v::Vector{Vector{Vector{T}}}) where {T<:Number} = HermitianObservable(complex_matrix_from_ir(v)) +Base.copy(o::HermitianObservable) = HermitianObservable(copy(o.matrix)) +StructTypes.lower(x::HermitianObservable) = Union{String, Vector{Vector{Vector{Float64}}}}[complex_matrix_to_ir(ComplexF64.(x.matrix))] +Base.:(==)(h1::HermitianObservable, h2::HermitianObservable) = (size(h1.matrix) == size(h2.matrix) && h1.matrix ≈ h2.matrix) +qubit_count(o::HermitianObservable) = convert(Int, log2(size(o.matrix, 1))) +LinearAlgebra.eigvals(o::HermitianObservable) = eigvals(Hermitian(o.matrix)) +unscaled(o::HermitianObservable) = o +Base.:(*)(o::HermitianObservable, n::Real) = HermitianObservable(Float64(n) .* o.matrix) +Base.show(io::IO, ho::HermitianObservable) = print(io, "HermitianObservable($(size(ho.matrix)))") + +""" + TensorProduct <: Observable + TensorProduct(factors::Vector{<:Observable}) -> TensorProduct + TensorProduct(factors::Vector{String}) -> TensorProduct + +Struct representing a tensor product of smaller observables. + +# Examples +```jldoctest +julia> BraketSimulator.Observables.TensorProduct(["x", "h"]) +X @ H + +julia> ho = BraketSimulator.Observables.HermitianObservable([0 1; 1 0]); + +julia> BraketSimulator.Observables.TensorProduct([ho, BraketSimulator.Observables.Z()]) +HermitianObservable((2, 2)) @ Z +``` +""" +struct TensorProduct{O} <: Observable where {O<:Observable} + factors::Vector{O} + coefficient::Float64 + function TensorProduct{O}(v::Vector{O}, coefficient::Float64=1.0) where {O<:NonCompositeObservable} + coeff = coefficient + flattened_v = Vector{O}(undef, length(v)) + for (oi, o) in enumerate(v) + flattened_v[oi] = unscaled(o) + coeff *= coef(o) + end + return new(flattened_v, coeff) + end + function TensorProduct{O}(v::Vector{O}, coefficient::Float64=1.0) where {O<:Observable} + any(v_->v_ isa Sum, v) && throw(ArgumentError("Sum observable not allowed in TensorProduct.")) + coeff = prod(coef, v, init=coefficient) + flattened_v = Iterators.flatmap(v) do o + return o isa TensorProduct ? (unscaled(o) for o in o.factors) : (unscaled(o),) + end + flat_v = collect(flattened_v) + return new(flat_v, coeff) + end +end +TensorProduct(o::Vector{T}, coefficient::Float64=1.0) where {T<:Union{String, Observable}} = TensorProduct{T}(o, coefficient) +TensorProduct(o::Vector{String}, coefficient::Float64=1.0) = TensorProduct([StructTypes.constructfrom(Observable, s) for s in o], coefficient) + +Base.:(*)(o::TensorProduct, n::Real) = TensorProduct(deepcopy(o.factors), Float64(n*o.coefficient)) +unscaled(o::TensorProduct) = TensorProduct(o.factors, 1.0) +qubit_count(o::TensorProduct) = sum(qubit_count.(o.factors)) +StructTypes.lower(x::TensorProduct{O}) where {O<:Observable} = Union{String, Vector{Vector{Vector{Float64}}}}[convert(Union{String, Vector{Vector{Vector{Float64}}}}, o) for o in mapreduce(StructTypes.lower, vcat, x.factors)] +Base.:(==)(t1::TensorProduct, t2::TensorProduct) = t1.factors == t2.factors && t1.coefficient ≈ t2.coefficient +Base.copy(t::TensorProduct) = TensorProduct(deepcopy(t.factors), t.coefficient) +_evs(os::Vector{O}, coeff::Float64=1.0) where {O<:StandardObservable} = PauliEigenvalues(Val(length(os)), coeff) +_evs(os::Vector{O}, coeff::Float64=1.0) where {O<:Observable} = mapfoldl(eigvals, kron, os, init=[coeff])::Vector{Float64} +LinearAlgebra.eigvals(o::TensorProduct{O}) where {O} = return _evs(o.factors, o.coefficient) +function Base.show(io::IO, o::TensorProduct) + coef_str = isone(o.coefficient) ? "" : string(o.coefficient) * " * " + print(io, coef_str) + for f in o.factors[1:end-1] + print(io, f) + print(io, " @ ") + end + print(io, o.factors[end]) + return +end + + +# exclude Sum from coverage for now +# as we don't yet implement this, so don't have a test for it +# COV_EXCL_START +""" + Sum <: Observable + Sum(summands::Vector{<:Observable}) -> Sum + +Struct representing the sum of observables. + +# Examples +```jldoctest +julia> o1 = 2.0 * BraketSimulator.Observables.I() * BraketSimulator.Observables.Z(); + +julia> o2 = 3.0 * BraketSimulator.Observables.X() * BraketSimulator.Observables.X(); + +julia> o = o1 + o2 +Sum(2.0 * I @ Z, 3.0 * X @ X) +``` +""" +struct Sum <: Observable + summands::Vector{Observable} + coefficient::Float64 + function Sum(v) + flattened_v = Iterators.flatmap(obs->obs isa Sum ? obs.summands : (obs,), v) + new(collect(flattened_v), 1.0) + end +end +Base.length(s::Sum) = length(s.summands) +Base.:(*)(s::Sum, n::Real) = Sum(Float64(n) .* deepcopy(s.summands)) +function Base.:(==)(s1::Sum, s2::Sum) + length(s1) != length(s2) && return false + are_eq = true + for (summand1, summand2) in zip(s1.summands, s2.summands) + are_eq &= (summand1 == summand2) + are_eq || return false + end + return true +end +function Base.:(==)(s::Sum, o::Observable) + length(s) == 1 || return false + return first(s.summands) == o +end +Base.:(==)(o::Observable, s::Sum) = s == o +function Base.show(io::IO, s::Sum) + print(io, "Sum(") + for summand in s.summands[1:end-1] + print(io, summand) + print(io, ", ") + end + print(io, s.summands[end]) + print(io, ")") + return +end +StructTypes.lower(s::Sum) = [StructTypes.lower(summand) for summand in s.summands] + +Base.:(*)(o1::O1, o2::O2) where {O1<:Observable, O2<:Observable} = TensorProduct([o1, o2], 1.0) +Base.:(*)(n::Real, o::Observable) = o*n +Base.:(+)(o1::Observable, o2::Observable) = Sum([o1, o2]) +Base.:(-)(o1::Observable, o2::Observable) = Sum([o1, -1.0 * o2]) +# COV_EXCL_STOP + +# nosemgrep +function StructTypes.constructfrom(::Type{Observable}, obj::String) + (obj == "i" || obj == "I") && return I() + (obj == "x" || obj == "X") && return X() + (obj == "y" || obj == "Y") && return Y() + (obj == "z" || obj == "Z") && return Z() + (obj == "h" || obj == "H") && return H() + throw(ArgumentError("Observable of type \"$obj\" provided, only \"i\", \"x\", \"y\", \"z\", and \"h\" are valid.")) +end +StructTypes.constructfrom(::Type{Observable}, obj::Vector{String}) = length(obj) == 1 ? StructTypes.constructfrom(Observable, first(obj)) : TensorProduct(obj) +StructTypes.constructfrom(::Type{Observable}, obj::Vector{Vector{Vector{Float64}}}) = HermitianObservable(obj) +StructTypes.constructfrom(::Type{Observable}, obj::Vector{Vector{Vector{Vector{Float64}}}}) = length(obj) == 1 ? HermitianObservable(obj[1]) : TensorProduct(obj) +StructTypes.constructfrom(::Type{Observable}, obj::Vector{T}) where {T} = length(obj) == 1 ? StructTypes.constructfrom(Observable, obj[1]) : TensorProduct([StructTypes.constructfrom(Observable, o) for o in obj]) + +end + +diagonalizing_gates(g::Observables.I, targets) = Instruction[] +diagonalizing_gates(g::Observables.H, targets) = + [Instruction(Ry(-π / 4.0), t) for t in targets] +diagonalizing_gates(g::Observables.X, targets) = + [Instruction(H(), t) for t in targets] +diagonalizing_gates(g::Observables.Y, targets) = + [Instruction(Unitary(1 / √2 * [1.0 -im; 1.0 im]), t) for t in targets] +diagonalizing_gates(g::Observables.Z, targets) = Instruction[] +function diagonalizing_gates(g::Observables.HermitianObservable, targets) size(g.matrix, 1) == 2^length(targets) && - return [Braket.Instruction(Unitary(eigvecs(g.matrix)), targets)] + return [Instruction(Unitary(eigvecs(g.matrix)), targets)] size(g.matrix, 1) == 2 && length(targets) > 1 && return [ - Braket.Instruction(Unitary(eigvecs(g.matrix)), target) for target in targets + Instruction(Unitary(eigvecs(g.matrix)), target) for target in targets ] end -diagonalizing_gates(g::Braket.Observables.TensorProduct, targets) = reduce( +diagonalizing_gates(g::Observables.TensorProduct, targets) = reduce( vcat, [diagonalizing_gates(f, t) for (f, t) in zip(g.factors, targets)], - init = Braket.Instruction[], + init = Instruction[], ) diff --git a/src/operators.jl b/src/operators.jl new file mode 100644 index 0000000..d9654c2 --- /dev/null +++ b/src/operators.jl @@ -0,0 +1,67 @@ +""" + Operator + +Abstract type representing operations that can be applied to a [`Circuit`](@ref). +Subtypes include [`Gate`](@ref), [`Noise`](@ref), [`Observable`](@ref BraketSimulator.Observables.Observable). +""" +abstract type Operator end + +""" + QuantumOperator < Operator + +Abstract type representing *quantum* operations that can be applied to a [`Circuit`](@ref). +Subtypes include [`Gate`](@ref) and [`Noise`](@ref). +""" +abstract type QuantumOperator <: Operator end + +abstract type Parametrizable end +struct Parametrized end +struct NonParametrized end + +struct PauliEigenvalues{N} + coeff::Float64 + PauliEigenvalues{N}(coeff::Float64=1.0) where {N} = new(coeff) +end +PauliEigenvalues(::Val{N}, coeff::Float64=1.0) where {N} = PauliEigenvalues{N}(coeff) +Base.length(p::PauliEigenvalues{N}) where {N} = 2^N +function Base.iterate(p::PauliEigenvalues{N}, ix::Int=1) where {N} + return ix <= length(p) ? (p[ix], ix+1) : nothing +end + +Base.getindex(p::PauliEigenvalues{1}, i::Int)::Float64 = getindex((p.coeff, -p.coeff), i) +function Base.getindex(p::PauliEigenvalues{N}, i::Int)::Float64 where N + i_block = div(i-1, 2) + split = div(2^(N-1)-1, 2) + if N < 5 + total_evs = 2^N + is_front = !isodd(mod(i-1, 2)) + ev = is_front ? p.coeff : -p.coeff + mi = mod(i_block, 2) + di = div(i_block, 2) + if i_block <= split + return isodd(mi) ⊻ isodd(di) ? -ev : ev + else + mi = mod(i_block - split - 1, 2) + di = div(i_block - split - 1, 2) + return isodd(mi) ⊻ isodd(di) ? ev : -ev + end + else + new_i = i > 2^(N-1) ? i - 2^(N-1) : i + one_down_pe = PauliEigenvalues(Val(N-1)) + one_down = one_down_pe[new_i] + return i_block <= split ? one_down : -one_down + end +end +Base.getindex(p::PauliEigenvalues{N}, ix::Vector{Int}) where {N} = [p[i] for i in ix] + +""" + Measure(index) <: QuantumOperator + +Represents a measurement operation on targeted qubit, stored in the classical register at `index`. +""" +struct Measure <: QuantumOperator + index::Int +end +Measure() = Measure(-1) +Parametrizable(m::Measure) = NonParametrized() +qubit_count(::Type{Measure}) = 1 diff --git a/src/pow_gates.jl b/src/pow_gates.jl index 071528a..5d6f600 100644 --- a/src/pow_gates.jl +++ b/src/pow_gates.jl @@ -1,81 +1,8 @@ -function Base.:(^)(g::Gate, n::Real) - iszero(n) && return I() - isone(n) && return g - return Unitary(Matrix(Matrix(matrix_rep(g))^n)) -end - -Base.:(^)(g::I, n::Real) = I() -for G in (:X, :Y, :Z, :H, :Swap, :CNot, :CY, :CZ, :CCNot, :CSwap, :GPi, :ECR) - @eval begin - function Base.:(^)(g::$G, n::Real) - iseven(n) && return I() - isodd(n) && return g - # this path is taken if n == 2.1, for example - return Unitary(Matrix(matrix_rep(g)^n)) - end - end -end -for G in ( - :Rx, - :Ry, - :Rz, - :PhaseShift, - :CPhaseShift, - :CPhaseShift00, - :CPhaseShift01, - :CPhaseShift10, - :XX, - :YY, - :ZZ, - :XY, -) - @eval function Base.:(^)(g::$G, n::Real) - iszero(n) && return I() - isone(n) && return g - return $G(g.angle[1]*n) - end -end - -function Base.:(^)(g::PSwap, n::Real) - iszero(n) && return I() - isone(n) && return g - isodd(n) && return PSwap(g.angle[1]*n) - iseven(n) && return Unitary(diagm([1.0, exp(im*g.angle[1]*n), exp(im*g.angle[1]*n), 1.0])) - return Unitary(Matrix(matrix_rep(g)^n)) -end - -function Base.:(^)(g::MS, n::Real) - iszero(n) && return I() - isone(n) && return g - isinteger(n) && return MS(g.angle[1], g.angle[2], n*g.angle[3]) - return Unitary(Matrix(matrix_rep(g)^n)) -end - -for (G, Gi, G2) in ((:V, :Vi, :X), (:S, :Si, :Z)) - @eval begin - function Base.:(^)(g::$G, n::Real) - mod(n, 4) == 0 && return I() - mod(n, 4) == 1 && return $G() - mod(n, 4) == 2 && return $G2() - mod(n, 4) == 3 && return $Gi() - # this path is taken if n == 2.1, for example - return Unitary(Matrix(matrix_rep(g)^n)) - end - function Base.:(^)(g::$Gi, n::Real) - mod(n, 4) == 0 && return I() - mod(n, 4) == 1 && return $Gi() - mod(n, 4) == 2 && return $G2() - mod(n, 4) == 3 && return $G() - # this path is taken if n == 2.1, for example - return Unitary(Matrix(matrix_rep(g)^n)) - end - end -end - -Base.:(^)(g::MultiQubitPhaseShift{N}, n::Real) where {N} = MultiQubitPhaseShift{N}((g.angle[1]*n,)) -function Base.:(^)(g::Control{<:Gate, B}, n::Real) where {B} - iszero(n) && return Braket.I() - isone(n) && return g - return Control(g.g ^ n, g.bitvals) -end -Base.:(^)(g::Control{MultiQubitPhaseShift{N}, B}, n::Real) where {N, B} = Control{MultiQubitPhaseShift{N}, B}(g.g ^ n, g.bitvals) +Base.:(^)(@nospecialize(g::G), n::Real) where {G<:Gate} = G(g.pow_exponent * n)::G +Base.inv(@nospecialize(g::G)) where {G<:Gate} = G(-g.pow_exponent)::G +Base.:(^)(@nospecialize(g::G), n::Real) where {G<:AngledGate} = G(g.angle, g.pow_exponent * n)::G +Base.inv(@nospecialize(g::G)) where {G<:AngledGate} = G(g.angle, -g.pow_exponent)::G +Base.:(^)(g::Unitary, n::Real) = Unitary(g.matrix, g.pow_exponent * n)::Unitary +Base.inv(g::Unitary) = Unitary(g.matrix, -g.pow_exponent)::Unitary +Base.:(^)(@nospecialize(g::Control{<:Gate, B}), n::Real) where {B} = Control(g.g ^ n, g.bitvals) +Base.inv(@nospecialize(g::Control{<:Gate, B})) where {B} = Control(inv(g.g), g.bitvals) \ No newline at end of file diff --git a/src/precompile.jl b/src/precompile.jl deleted file mode 100644 index 2a615fe..0000000 --- a/src/precompile.jl +++ /dev/null @@ -1,275 +0,0 @@ -# exclude precompilation from coverage -# COV_EXCL_START -function _precompile_() - ccall(:jl_generating_output, Cint, ()) == 1 || return nothing - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{HermitianObservable, Vector{Int64}}}}) # time: 2.3760564 - Base.precompile(Tuple{var"#556#threadsfor_fun#215"{var"#556#threadsfor_fun#211#216"{Matrix{ComplexF64}, Int64, Vector{Vector{Int64}}, Vector{Int64}, Transpose{ComplexF64, Matrix{ComplexF64}}, UnitRange{Int64}}},Int64}) # time: 0.14115863 - Base.precompile(Tuple{var"#357#threadsfor_fun#123"{var"#357#threadsfor_fun#120#124"{16, ComplexF64, SMatrix{16, 16, ComplexF64, 256}, Vector{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.12406683 - Base.precompile(Tuple{var"#403#threadsfor_fun#143"{var"#403#threadsfor_fun#140#144"{Matrix{ComplexF64}, Int64, Int64, Int64, Int64, Tuple{SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}}, Tuple{SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}}, UnitRange{Int64}}},Int64}) # time: 0.11665836 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{HermitianObservable, Vector{Int64}}}}) # time: 0.08039276 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},DoubleExcitation,Int64,Vararg{Int64}}) # time: 0.0797019 - Base.precompile(Tuple{var"#536#threadsfor_fun#204"{var"#536#threadsfor_fun#201#205"{Vector{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, Matrix{ComplexF64}, UnitRange{Int64}}},Int64}) # time: 0.07728745 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Kraus,Int64,Vararg{Int64}}) # time: 0.06592051 - Base.precompile(Tuple{var"#403#threadsfor_fun#143"{var"#403#threadsfor_fun#140#144"{Matrix{ComplexF64}, Int64, Int64, Int64, Int64, Tuple{SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}}, Tuple{SMatrix{4, 4, ComplexF64, 16}, SMatrix{4, 4, ComplexF64, 16}}, UnitRange{Int64}}},Int64}) # time: 0.062411573 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots,), Tuple{Int64}},typeof(simulate),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},OpenQasmProgram}) # time: 0.06121916 - Base.precompile(Tuple{var"#403#threadsfor_fun#143"{var"#403#threadsfor_fun#140#144"{Matrix{ComplexF64}, Int64, Int64, Int64, Int64, NTuple{16, SMatrix{4, 4, ComplexF64, 16}}, NTuple{16, SMatrix{4, 4, ComplexF64, 16}}, UnitRange{Int64}}},Int64}) # time: 0.052433595 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.X, Int64}}}) # time: 0.050354417 - Base.precompile(Tuple{typeof(calculate),Braket.DensityMatrix,StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.047030203 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Int64}) # time: 0.045860793 - Base.precompile(Tuple{typeof(calculate),Amplitude,StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.04560804 - isdefined(BraketSimulator, Symbol("#60#64")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#60#64")),Instruction{BitFlip}}) # time: 0.045065258 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{HermitianObservable},Int64,Int64,Vararg{Int64}}) # time: 0.044758502 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TwoQubitDepolarizing,Int64,Vararg{Int64}}) # time: 0.044507124 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.StandardObservable}, Tuple{Int64, Int64}}}}) # time: 0.04418025 - Base.precompile(Tuple{typeof(calculate),Probability,StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.041471716 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.NonCompositeObservable}, Vector{Int64}}}}) # time: 0.0414185 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.StandardObservable}, Vector{Int64}}}}) # time: 0.04043337 - Base.precompile(Tuple{typeof(^),CCNot,Int64}) # time: 0.03875475 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiQubitPhaseShift{2},Int64,Vararg{Int64}}) # time: 0.03686717 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.StandardObservable, Vector{Int64}}}}) # time: 0.03636653 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiQubitPauliChannel{2},Int64,Vararg{Int64}}) # time: 0.035675667 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots,), Tuple{Int64}},typeof(simulate),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},OpenQasmProgram}) # time: 0.03539539 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.NonCompositeObservable}, NTuple{4, Int64}}}}) # time: 0.034470204 - isdefined(BraketSimulator, Symbol("#162#163")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#162#163")),Tuple{Braket.Observables.Y, Int64}}) # time: 0.03252417 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),D<:BraketSimulator.AbstractSimulator,Union{Circuit, Program},Val{:OpenQASM}}) # time: 0.031343497 - Base.precompile(Tuple{typeof(apply_gate!),DoubleExcitation,Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.030710414 - Base.precompile(Tuple{typeof(apply_gate!),Unitary,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.030677125 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiQubitPhaseShift{4},Int64,Vararg{Int64}}) # time: 0.029619085 - Base.precompile(Tuple{var"#403#threadsfor_fun#143"{var"#403#threadsfor_fun#140#144"{Matrix{ComplexF64}, Int64, Int64, Int64, Int64, NTuple{4, SMatrix{4, 4, ComplexF64, 16}}, NTuple{4, SMatrix{4, 4, ComplexF64, 16}}, UnitRange{Int64}}},Int64}) # time: 0.028585028 - Base.precompile(Tuple{typeof(matrix_rep),DoubleExcitation}) # time: 0.027744127 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},SingleExcitation,Int64,Vararg{Int64}}) # time: 0.026039707 - Base.precompile(Tuple{var"#388#threadsfor_fun#136"{var"#388#threadsfor_fun#133#137"{Matrix{ComplexF64}, Int64, NTuple{4, SMatrix{2, 2, ComplexF64, 4}}, NTuple{4, SMatrix{2, 2, ComplexF64, 4}}, UnitRange{Int64}}},Int64}) # time: 0.025726128 - Base.precompile(Tuple{typeof(apply_gate!),MultiQubitPhaseShift{4},Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.025318487 - Base.precompile(Tuple{typeof(apply_gate!),MultiRZ,Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.024543203 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.StandardObservable}, Tuple{Int64, Int64}}}}) # time: 0.024210926 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.NonCompositeObservable}, Tuple{Int64, Int64}}}}) # time: 0.02415638 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{HermitianObservable},Int64,Int64,Vararg{Int64}}) # time: 0.023168875 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Unitary,Int64,Vararg{Int64}}) # time: 0.022914968 - Base.precompile(Tuple{typeof(apply_gate!),Control{X, 2},Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.022110343 - Base.precompile(Tuple{var"#357#threadsfor_fun#123"{var"#357#threadsfor_fun#120#124"{8, ComplexF64, SMatrix{8, 8, ComplexF64, 64}, Vector{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.022048157 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Int64}}}) # time: 0.021454116 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Braket.DensityMatrix},DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.021367287 - Base.precompile(Tuple{typeof(apply_gate!),MultiQubitPhaseShift{3},Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.0211587 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.H, Int64}}}) # time: 0.021102335 - Base.precompile(Tuple{var"#357#threadsfor_fun#123"{var"#357#threadsfor_fun#120#124"{8, ComplexF64, Diagonal{ComplexF64, SVector{8, ComplexF64}}, Vector{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.02088434 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiQubitPhaseShift{3},Int64,Vararg{Int64}}) # time: 0.020738542 - Base.precompile(Tuple{typeof(apply_gate!),Val{true},MultiRZ,Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.018903581 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),D<:BraketSimulator.AbstractSimulator,Union{Circuit, Program},Val{:JAQCD}}) # time: 0.01855247 - Base.precompile(Tuple{typeof(samples),StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.018172288 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.X, Vector{Int64}}}}) # time: 0.018068293 - Base.precompile(Tuple{typeof(apply_gate!),MultiRZ,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.01697871 - Base.precompile(Tuple{var"#357#threadsfor_fun#123"{var"#357#threadsfor_fun#120#124"{16, ComplexF64, Diagonal{ComplexF64, SVector{16, ComplexF64}}, Vector{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.016731136 - Base.precompile(Tuple{typeof(apply_gate!),MultiQubitPhaseShift{2},Vector{ComplexF64},Int64,Int64}) # time: 0.015248993 - Base.precompile(Tuple{typeof(apply_gate!),Val{true},Unitary,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.014217445 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Tuple{Int64}}}}) # time: 0.0140325 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.X, Vector{Int64}}}}) # time: 0.014004589 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.Z, Vector{Int64}}}}) # time: 0.013751209 - Base.precompile(Tuple{typeof(_validate_ir_results_compatibility),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{NamedTuple{(:type,), Tuple{String}}},Val{:OpenQASM}}) # time: 0.013238872 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},CNot,Int64,Vararg{Int64}}) # time: 0.013133743 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Tuple{Int64}}}}) # time: 0.012980301 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.H, Vector{Int64}}}}) # time: 0.012828214 - Base.precompile(Tuple{var"#419#threadsfor_fun#151"{var"#419#threadsfor_fun#147#152"{Matrix{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, Tuple{Adjoint{ComplexF64, Matrix{ComplexF64}}}, Vector{Matrix{ComplexF64}}, UnitRange{Int64}}},Int64}) # time: 0.012743572 - Base.precompile(Tuple{var"#506#threadsfor_fun#195"{var"#506#threadsfor_fun#194#196"{Vector{ComplexF64}, Int64, Matrix{ComplexF64}, UnitRange{Int64}}},Int64}) # time: 0.012427671 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.H, Vector{Int64}}}}) # time: 0.012073245 - Base.precompile(Tuple{typeof(_validate_ir_results_compatibility),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{NamedTuple{(:type,), Tuple{String}}},Val{:JAQCD}}) # time: 0.011608869 - Base.precompile(Tuple{typeof(apply_gate!),Unitary,Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.011561283 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Int64}}}) # time: 0.011552837 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.H, Int64}}}) # time: 0.011530246 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.X, Int64}}}) # time: 0.01139113 - Base.precompile(Tuple{typeof(expectation),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},HermitianObservable,Int64}) # time: 0.011389514 - Base.precompile(Tuple{typeof(matrix_rep),MultiQubitPhaseShift{4}}) # time: 0.011219284 - Base.precompile(Tuple{typeof(apply_gate!),Val{true},MultiRZ,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.010829912 - Base.precompile(Tuple{var"#441#threadsfor_fun#171"{var"#441#threadsfor_fun#170#172"{Vector{Float64}, Vector{Vector{Int64}}, Vector{Float64}, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.010822869 - Base.precompile(Tuple{var"#220#threadsfor_fun#75"{var"#220#threadsfor_fun#74#76"{ComplexF64, SMatrix{4, 4, ComplexF64, 16}, Vector{ComplexF64}, Vector{UnitRange{Int64}}, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.009974208 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.Z, Vector{Int64}}}}) # time: 0.009941416 - Base.precompile(Tuple{var"#521#threadsfor_fun#198"{var"#521#threadsfor_fun#197#199"{Vector{ComplexF64}, Int64, Int64, Matrix{ComplexF64}, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.009609202 - Base.precompile(Tuple{typeof(apply_noise!),Kraus,Matrix{ComplexF64},Int64,Int64,Int64,Int64,Int64}) # time: 0.009606712 - Base.precompile(Tuple{var"#321#threadsfor_fun#91"{var"#321#threadsfor_fun#87#92"{ComplexF64, Vector{ComplexF64}, Bool, SMatrix{4, 4, ComplexF64, 16}, Int64, Int64, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.009529764 - Base.precompile(Tuple{var"#472#threadsfor_fun#181"{var"#472#threadsfor_fun#178#182"{Matrix{ComplexF64}, Int64, Vector{Int64}, Matrix{ComplexF64}, UnitRange{Int64}}},Int64}) # time: 0.009195421 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots, :inputs), Tuple{Int64, Dict{String, Float64}}},typeof(simulate),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Program,Int64}) # time: 0.009151381 - Base.precompile(Tuple{typeof(apply_gate!),CNot,Vector{ComplexF64},Int64,Int64}) # time: 0.009115913 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots, :inputs), Tuple{Int64, Dict{String, Float64}}},typeof(simulate),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Program,Int64}) # time: 0.008724961 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Result},StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.008643294 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots, :inputs), Tuple{Int64, Dict{String, Float64}}},typeof(simulate),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},OpenQasmProgram}) # time: 0.008624748 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Vector{Int64}}}}) # time: 0.008502583 - Base.precompile(Tuple{typeof(calculate),Expectation,StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.008263838 - Base.precompile(Tuple{typeof(^),CNot,Int64}) # time: 0.008205919 - Base.precompile(Tuple{typeof(Core.kwcall),NamedTuple{(:shots, :inputs), Tuple{Int64, Dict{String, Float64}}},typeof(simulate),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},OpenQasmProgram}) # time: 0.008148667 - Base.precompile(Tuple{typeof(apply_gate!),H,Vector{ComplexF64},Int64}) # time: 0.008035914 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},BitFlip,Int64}) # time: 0.007911752 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Int64}) # time: 0.00772037 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},HermitianObservable,Int64,Int64,Vararg{Int64}}) # time: 0.007329834 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{HermitianObservable, Int64}}}) # time: 0.00700907 - Base.precompile(Tuple{var"#457#threadsfor_fun#175"{var"#457#threadsfor_fun#173#176"{Vector{Float64}, Int64, Vector{Int64}, Vector{Float64}, UnitRange{Int64}}},Int64}) # time: 0.00699316 - Base.precompile(Tuple{typeof(expectation),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},HermitianObservable,Int64,Vararg{Int64}}) # time: 0.006969504 - Base.precompile(Tuple{typeof(matrix_rep),MultiQubitPhaseShift{3}}) # time: 0.006872365 - Base.precompile(Tuple{typeof(marginal_probability),Vector{Float64},Int64,Int64}) # time: 0.006763912 - Base.precompile(Tuple{typeof(marginal_probability),Vector{Float64},Int64,Tuple{Int64, Int64}}) # time: 0.006747198 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.I, Vector{Int64}}}}) # time: 0.006616665 - Base.precompile(Tuple{Type{StateVectorSimulator},Int64,Int64}) # time: 0.00658437 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.Z, Int64}}}) # time: 0.006555793 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.I, Int64}}}) # time: 0.006480999 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CSwap}}}) # time: 0.006389134 - Base.precompile(Tuple{typeof(marginal_probability),Vector{Float64},Int64,Tuple{Int64}}) # time: 0.006313712 - Base.precompile(Tuple{typeof(probabilities),StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.006088001 - Base.precompile(Tuple{typeof(apply_observables!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Tuple{Braket.Observables.StandardObservable, Vector{Int64}}}}) # time: 0.006057755 - Base.precompile(Tuple{var"#220#threadsfor_fun#75"{var"#220#threadsfor_fun#74#76"{ComplexF64, Diagonal{ComplexF64, SVector{4, ComplexF64}}, Vector{ComplexF64}, Vector{UnitRange{Int64}}, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.005851834 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},HermitianObservable,Int64,Int64}) # time: 0.005848543 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiRZ,Int64,Vararg{Int64}}) # time: 0.005818084 - Base.precompile(Tuple{typeof(apply_gate!),MultiQubitPhaseShift{1},Vector{ComplexF64},Int64}) # time: 0.005786125 - isdefined(BraketSimulator, Symbol("#60#64")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#60#64")),Instruction{Rx}}) # time: 0.00568604 - Base.precompile(Tuple{var"#388#threadsfor_fun#136"{var"#388#threadsfor_fun#133#137"{Matrix{ComplexF64}, Int64, Tuple{SMatrix{2, 2, ComplexF64, 4}, SMatrix{2, 2, ComplexF64, 4}}, Tuple{SMatrix{2, 2, ComplexF64, 4}, SMatrix{2, 2, ComplexF64, 4}}, UnitRange{Int64}}},Int64}) # time: 0.005640168 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{HermitianObservable, Int64}}}) # time: 0.005586166 - Base.precompile(Tuple{typeof(probabilities),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.005552664 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.Z},Int64,Int64}) # time: 0.005303585 - Base.precompile(Tuple{typeof(evolve!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Instruction}}) # time: 0.005119041 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CZ}}}) # time: 0.005095164 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},H,Int64}) # time: 0.005078246 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CY}}}) # time: 0.005051496 - isdefined(BraketSimulator, Symbol("#60#64")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#60#64")),Instruction{Ry}}) # time: 0.004877292 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Control{X, 1},Int64,Vararg{Int64}}) # time: 0.004856696 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},CSwap,Int64,Vararg{Int64}}) # time: 0.004838249 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.I, Vector{Int64}}}}) # time: 0.004632425 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.Z, Int64}}}) # time: 0.004622792 - Base.precompile(Tuple{typeof(matrix_rep),MultiQubitPhaseShift{2}}) # time: 0.00461696 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.I, Int64}}}) # time: 0.004577912 - Base.precompile(Tuple{var"#336#threadsfor_fun#93"{var"#336#threadsfor_fun#88#94"{Vector{ComplexF64}, Tuple{Int64, Int64}, ComplexF64, ComplexF64, ComplexF64, ComplexF64, Int64, Int64, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.004202628 - Base.precompile(Tuple{typeof(matrix_rep),Control{MultiQubitPhaseShift{2}, 2}}) # time: 0.004102118 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{Braket.Observables.Y, Vector{Int64}}}}) # time: 0.004091999 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},MultiQubitPhaseShift{1},Int64}) # time: 0.004060454 - Base.precompile(Tuple{typeof(evolve!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Instruction{Kraus}}}) # time: 0.004041914 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Circuit,Val{:OpenQASM}}) # time: 0.004018167 - Base.precompile(Tuple{typeof(matrix_rep),SingleExcitation}) # time: 0.004016366 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Probability},DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.003991788 - Base.precompile(Tuple{typeof(expectation),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{HermitianObservable},Int64,Vararg{Int64}}) # time: 0.00398108 - Base.precompile(Tuple{typeof(calculate),Expectation,DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.003972124 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Int64,Vararg{Int64}}) # time: 0.003953711 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Result},DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.00392808 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},CY,Int64,Vararg{Int64}}) # time: 0.003895222 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},CZ,Int64,Vararg{Int64}}) # time: 0.003787091 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},HermitianObservable,Int64,Int64}) # time: 0.003721872 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Probability},StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.003683374 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Circuit,Val{:JAQCD}}) # time: 0.00366429 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Int64,Vararg{Int64}}) # time: 0.003664 - Base.precompile(Tuple{var"#251#threadsfor_fun#82"{var"#251#threadsfor_fun#78#83"{ComplexF64, Vector{ComplexF64}, Bool, SMatrix{4, 4, ComplexF64, 16}, Int64, Int64, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.003619081 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Expectation},DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.003612213 - Base.precompile(Tuple{typeof(apply_observables!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Tuple{TensorProduct{Braket.Observables.NonCompositeObservable}, Tuple{Int64, Int64}}}}) # time: 0.003567337 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{HermitianObservable},Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.003555792 - Base.precompile(Tuple{typeof(_generate_results),Vector{Braket.IR.AbstractProgramResult},Vector{Expectation},StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.003515872 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Control{X, 2},Int64,Vararg{Int64}}) # time: 0.003494703 - Base.precompile(Tuple{typeof(apply_gate!),MultiRZ,Vector{ComplexF64},Int64,Int64}) # time: 0.003429628 - Base.precompile(Tuple{typeof(matrix_rep),MultiQubitPhaseShift{1}}) # time: 0.003388248 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Int64}) # time: 0.003384418 - Base.precompile(Tuple{typeof(calculate),Variance,DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.003176043 - Base.precompile(Tuple{typeof(calculate),Variance,StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.003117915 - isdefined(BraketSimulator, Symbol("#162#163")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#162#163")),Tuple{Braket.Observables.H, Int64}}) # time: 0.003023545 - Base.precompile(Tuple{typeof(_validate_input_provided),Circuit}) # time: 0.003010547 - isdefined(BraketSimulator, Symbol("#207#208")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#207#208")),Tuple{Braket.Observables.H, Vector{Int64}}}) # time: 0.003008123 - isdefined(BraketSimulator, Symbol("#162#163")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#162#163")),Tuple{Braket.Observables.X, Int64}}) # time: 0.002941127 - Base.precompile(Tuple{typeof(apply_gate!),Rz,Vector{ComplexF64},Int64}) # time: 0.002940584 - Base.precompile(Tuple{var"#419#threadsfor_fun#151"{var"#419#threadsfor_fun#147#152"{Matrix{ComplexF64}, Vector{Vector{Int64}}, Vector{Int64}, Tuple{Adjoint{ComplexF64, Matrix{ComplexF64}}, Adjoint{ComplexF64, Matrix{ComplexF64}}}, Vector{Matrix{ComplexF64}}, UnitRange{Int64}}},Int64}) # time: 0.002931998 - Base.precompile(Tuple{typeof(calculate),Variance,AbstractSimulator}) # time: 0.002875833 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},CCNot,Int64,Vararg{Int64}}) # time: 0.002809754 - Base.precompile(Tuple{typeof(^),PSwap,Int64}) # time: 0.002741585 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Unitary}}}) # time: 0.002696421 - Base.precompile(Tuple{typeof(apply_gate!),CCNot,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.002666251 - Base.precompile(Tuple{typeof(apply_observable!),HermitianObservable,Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.002656832 - Base.precompile(Tuple{typeof(expectation),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Vararg{Int64}}) # time: 0.002642792 - Base.precompile(Tuple{typeof(expectation),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Vararg{Int64}}) # time: 0.002624209 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction}}) # time: 0.002521376 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Control{MultiQubitPhaseShift{2}, 2},Int64,Vararg{Int64}}) # time: 0.002457497 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{YY}}}) # time: 0.002411541 - Base.precompile(Tuple{typeof(matrix_rep),Control{MultiQubitPhaseShift{1}, 1}}) # time: 0.002357129 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{HermitianObservable},Matrix{ComplexF64},Int64,Int64,Int64}) # time: 0.002340128 - Base.precompile(Tuple{typeof(expectation),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.NonCompositeObservable},Int64,Vararg{Int64}}) # time: 0.002331834 - Base.precompile(Tuple{typeof(expectation),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Vararg{Int64}}) # time: 0.002299791 - Base.precompile(Tuple{typeof(apply_observable!),HermitianObservable,Matrix{ComplexF64},Int64,Int64,Int64}) # time: 0.0022985 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},HermitianObservable,Int64,Int64,Vararg{Int64}}) # time: 0.00229296 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{H}}}) # time: 0.002282665 - Base.precompile(Tuple{typeof(apply_gate!),Control{X, 1},Vector{ComplexF64},Int64,Int64}) # time: 0.002236294 - Base.precompile(Tuple{typeof(apply_gate!),Control{I, 1},Vector{ComplexF64},Int64,Int64}) # time: 0.00222787 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},HermitianObservable,Int64}) # time: 0.002189707 - Base.precompile(Tuple{typeof(^),X,Int64}) # time: 0.002178541 - Base.precompile(Tuple{typeof(apply_gate!),Val{true},Unitary,Vector{ComplexF64},Int64,Int64,Int64,Int64}) # time: 0.002167166 - Base.precompile(Tuple{typeof(matrix_rep),XY}) # time: 0.002118794 - Base.precompile(Tuple{typeof(matrix_rep),XX}) # time: 0.002106209 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{ECR}}}) # time: 0.002103711 - isdefined(BraketSimulator, Symbol("#188#190")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#188#190")),HermitianObservable}) # time: 0.002097624 - Base.precompile(Tuple{typeof(apply_gate!),CV,Vector{ComplexF64},Int64,Int64}) # time: 0.00209163 - Base.precompile(Tuple{typeof(matrix_rep),YY}) # time: 0.002058165 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CCNot}}}) # time: 0.002057918 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{V}}}) # time: 0.002049661 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Vi}}}) # time: 0.002040998 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},PhaseFlip,Int64}) # time: 0.002026789 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{ZZ}}}) # time: 0.002024126 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{XY}}}) # time: 0.002018045 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Int64,Vararg{Int64}}) # time: 0.002012294 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{PSwap}}}) # time: 0.002007076 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},HermitianObservable,Int64}) # time: 0.002006084 - Base.precompile(Tuple{var"#266#threadsfor_fun#84"{var"#266#threadsfor_fun#79#85"{Vector{ComplexF64}, Tuple{Int64, Int64}, ComplexF64, ComplexF64, ComplexF64, ComplexF64, Int64, Int64, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.001982498 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CPhaseShift10}}}) # time: 0.001980336 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{MS}}}) # time: 0.001973913 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CPhaseShift}}}) # time: 0.001968584 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CPhaseShift00}}}) # time: 0.001967121 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Z}}}) # time: 0.001953294 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{I}}}) # time: 0.001952793 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CNot}}}) # time: 0.001940213 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{U}}}) # time: 0.00193508 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Y}}}) # time: 0.001934711 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{CPhaseShift01}}}) # time: 0.001930041 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Swap}}}) # time: 0.001927331 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{GPi}}}) # time: 0.001898796 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{XX}}}) # time: 0.001895626 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{GPi2}}}) # time: 0.001883828 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Rz}}}) # time: 0.001863544 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{X}}}) # time: 0.001833085 - Base.precompile(Tuple{var"#53#threadsfor_fun#40"{var"#53#threadsfor_fun#39#41"{Vector{ComplexF64}, Int64, Int64, Int64, Int64, Float64, Float64, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.001826791 - Base.precompile(Tuple{typeof(permute_probability),Vector{Float64},Int64,Vector{Int64}}) # time: 0.001820791 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{PhaseShift}}}) # time: 0.001816795 - Base.precompile(Tuple{typeof(expectation_op_squared),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Int64}) # time: 0.001796248 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Ry}}}) # time: 0.001789662 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Circuit,Val{:OpenQASM}}) # time: 0.001764041 - Base.precompile(Tuple{var"#204#threadsfor_fun#72"{var"#204#threadsfor_fun#71#73"{Vector{ComplexF64}, ComplexF64, ComplexF64, ComplexF64, ComplexF64, Bool, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.001741707 - Base.precompile(Tuple{typeof(apply_gate!),Control{MultiQubitPhaseShift{2}, 2},Vector{ComplexF64},Int64,Int64}) # time: 0.001721957 - Base.precompile(Tuple{typeof(expectation_op_squared),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},TensorProduct{Braket.Observables.StandardObservable},Int64,Int64,Vararg{Int64}}) # time: 0.001721418 - isdefined(BraketSimulator, Symbol("#51#54")) && Base.precompile(Tuple{getfield(BraketSimulator, Symbol("#51#54")),Tuple{Braket.IR.AbstractProgramResult, Any}}) # time: 0.001702045 - Base.precompile(Tuple{typeof(evolve!),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Vector{Instruction{Rx}}}) # time: 0.001694167 - Base.precompile(Tuple{typeof(samples),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.00169363 - Base.precompile(Tuple{typeof(matrix_rep),Rx}) # time: 0.001682583 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},TwoQubitDephasing,Int64,Vararg{Int64}}) # time: 0.001661709 - Base.precompile(Tuple{typeof(inv),MS}) # time: 0.001660417 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Depolarizing,Int64}) # time: 0.00160096 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.NonCompositeObservable},Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.001573957 - Base.precompile(Tuple{typeof(index_to_endian_bits),Int64,Int64}) # time: 0.001559832 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.StandardObservable},Matrix{ComplexF64},Int64,Int64,Int64}) # time: 0.0015475 - Base.precompile(Tuple{typeof(apply_gate!),Ry,Vector{ComplexF64},Int64}) # time: 0.001546374 - Base.precompile(Tuple{typeof(matrix_rep),I}) # time: 0.001544544 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Control{MultiQubitPhaseShift{1}, 1},Int64}) # time: 0.001539502 - Base.precompile(Tuple{typeof(_validate_operation_qubits),Vector{Instruction{Rx}}}) # time: 0.00153604 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.NonCompositeObservable},Matrix{ComplexF64},Int64,Int64,Int64}) # time: 0.001534041 - Base.precompile(Tuple{var"#306#threadsfor_fun#89"{var"#306#threadsfor_fun#86#90"{Vector{ComplexF64}, ComplexF64, ComplexF64, ComplexF64, ComplexF64, Bool, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.001509835 - Base.precompile(Tuple{typeof(apply_gate!),Control{MultiQubitPhaseShift{1}, 1},Vector{ComplexF64},Int64}) # time: 0.001500166 - Base.precompile(Tuple{typeof(apply_gate!),Val{true},Control{MultiQubitPhaseShift{2}, 2},Vector{ComplexF64},Int64,Int64}) # time: 0.00148471 - Base.precompile(Tuple{typeof(matrix_rep),PhaseShift}) # time: 0.001484083 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.StandardObservable},Vector{ComplexF64},Int64,Int64,Int64}) # time: 0.001468376 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.NonCompositeObservable},Matrix{ComplexF64},Int64,Int64}) # time: 0.001460708 - Base.precompile(Tuple{typeof(expectation),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},HermitianObservable,Int64}) # time: 0.001454329 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.StandardObservable},Matrix{ComplexF64},Int64,Int64}) # time: 0.001452959 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},GeneralizedAmplitudeDamping,Int64}) # time: 0.001450046 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.NonCompositeObservable},Vector{ComplexF64},Int64,Int64}) # time: 0.001447251 - Base.precompile(Tuple{typeof(_validate_ir_instructions_compatibility),StateVectorSimulator{ComplexF64, Vector{ComplexF64}},Circuit,Val{:JAQCD}}) # time: 0.001447165 - Base.precompile(Tuple{typeof(apply_observable!),TensorProduct{Braket.Observables.StandardObservable},Vector{ComplexF64},Int64,Int64}) # time: 0.001421333 - Base.precompile(Tuple{typeof(^),MS,Int64}) # time: 0.001409875 - Base.precompile(Tuple{typeof(matrix_rep),Control{I, 1}}) # time: 0.001371751 - Base.precompile(Tuple{typeof(matrix_rep),Control{X, 1}}) # time: 0.001291998 - Base.precompile(Tuple{var"#373#threadsfor_fun#127"{var"#373#threadsfor_fun#126#128"{PhaseFlip, Matrix{ComplexF64}, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.00128375 - Base.precompile(Tuple{typeof(copy),StateVectorSimulator{ComplexF64, Vector{ComplexF64}}}) # time: 0.001264997 - Base.precompile(Tuple{typeof(calculate),Probability,DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}}}) # time: 0.001251415 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},AmplitudeDamping,Int64}) # time: 0.001234916 - Base.precompile(Tuple{var"#73#threadsfor_fun#43"{var"#73#threadsfor_fun#42#44"{Vector{ComplexF64}, Int64, Int64, Int64, Int64, Float64, Float64, Vector{Int64}, UnitRange{Int64}}},Int64}) # time: 0.001232541 - Base.precompile(Tuple{var"#236#threadsfor_fun#80"{var"#236#threadsfor_fun#77#81"{Vector{ComplexF64}, ComplexF64, ComplexF64, ComplexF64, ComplexF64, Bool, Int64, Int64, Int64, Int64, UnitRange{Int64}}},Int64}) # time: 0.001212125 - Base.precompile(Tuple{typeof(_evolve_op!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},PauliChannel,Int64}) # time: 0.001116707 - Base.precompile(Tuple{Type{DensityMatrixSimulator},Int64,Int64}) # time: 0.001066707 - Base.precompile(Tuple{typeof(evolve!),DensityMatrixSimulator{ComplexF64, Matrix{ComplexF64}},Vector{Instruction{XX}}}) # time: 0.001022039 -end -# COV_EXCL_STOP diff --git a/src/properties.jl b/src/properties.jl index b4f0c17..77616d4 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -2,25 +2,25 @@ const sv_qubit_count = 28 const sv_max_shots = 1_000_000 const sv_observables = ["x", "y", "z", "h", "i", "hermitian"] const sv_props_dict = Dict( - "braketSchemaHeader" => Dict( - "name" => "braket.device_schema.simulators.gate_model_simulator_device_capabilities", - "version" => "1", + :braketSchemaHeader => Dict( + :name => "braket.device_schema.simulators.gate_model_simulator_device_capabilities", + :version => "1", ), - "service" => Dict( - "executionWindows" => [ + :service => Dict( + :executionWindows => [ Dict( - "executionDay" => "Everyday", - "windowStartHour" => "00:00", - "windowEndHour" => "23:59:59", + :executionDay => "Everyday", + :windowStartHour => "00:00", + :windowEndHour => "23:59:59", ), ], - "shotsRange" => [0, sv_max_shots], + :shotsRange => [0, sv_max_shots], ), - "action" => Dict( + :action => Dict( "braket.ir.jaqcd.program" => Dict( - "actionType" => "braket.ir.jaqcd.program", - "version" => ["1"], - "supportedOperations" => [ + :actionType => "braket.ir.jaqcd.program", + :version => ["1"], + :supportedOperations => [ "ccnot", "cnot", "cphaseshift", @@ -57,41 +57,41 @@ const sv_props_dict = Dict( "z", "zz", ], - "supportedResultTypes" => [ + :supportedResultTypes => [ Dict( - "name" => "Sample", - "observables" => sv_observables, - "minShots" => 1, - "maxShots" => sv_max_shots, + :name => "Sample", + :observables => sv_observables, + :minShots => 1, + :maxShots => sv_max_shots, ), Dict( - "name" => "Expectation", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => sv_max_shots, + :name => "Expectation", + :observables => sv_observables, + :minShots => 0, + :maxShots => sv_max_shots, ), Dict( - "name" => "Variance", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => sv_max_shots, + :name => "Variance", + :observables => sv_observables, + :minShots => 0, + :maxShots => sv_max_shots, ), Dict( - "name" => "Adjoint_Gradient", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => 0, + :name => "Adjoint_Gradient", + :observables => sv_observables, + :minShots => 0, + :maxShots => 0, ), - Dict("name" => "Probability", "minShots" => 0, "maxShots" => sv_max_shots), - Dict("name" => "StateVector", "minShots" => 0, "maxShots" => 0), - Dict("name" => "DensityMatrix", "minShots" => 0, "maxShots" => 0), - Dict("name" => "Amplitude", "minShots" => 0, "maxShots" => 0), + Dict(:name => "Probability", :minShots => 0, :maxShots => sv_max_shots), + Dict(:name => "StateVector", :minShots => 0, :maxShots => 0), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), + Dict(:name => "Amplitude", :minShots => 0, :maxShots => 0), ], ), "braket.ir.openqasm.program" => Dict( - "actionType" => "braket.ir.openqasm.program", - "version" => ["1"], - "supportedOperations" => [ + :actionType => "braket.ir.openqasm.program", + :version => ["1"], + :supportedOperations => [ "U", "GPhase", "ccnot", @@ -133,13 +133,13 @@ const sv_props_dict = Dict( "z", "zz", ], - "supportedModifiers" => [ - Dict("name" => "ctrl"), - Dict("name" => "negctrl"), - Dict("name" => "pow", "exponent_types" => ["int", "float"]), - Dict("name" => "inv"), + :supportedModifiers => [ + Dict(:name => "ctrl"), + Dict(:name => "negctrl"), + Dict(:name => "pow", :exponent_types => ["int", "float"]), + Dict(:name => "inv"), ], - "supportedPragmas" => [ + :supportedPragmas => [ "braket_unitary_matrix", "braket_result_type_state_vector", "braket_result_type_density_matrix", @@ -149,7 +149,7 @@ const sv_props_dict = Dict( "braket_result_type_probability", "braket_result_type_amplitude", ], - "forbiddenPragmas" => [ + :forbiddenPragmas => [ "braket_noise_amplitude_damping", "braket_noise_bit_flip", "braket_noise_depolarizing", @@ -162,74 +162,74 @@ const sv_props_dict = Dict( "braket_noise_two_qubit_depolarizing", "braket_result_type_adjoint_gradient", ], - "supportedResultTypes" => [ + :supportedResultTypes => [ Dict( - "name" => "Sample", - "observables" => sv_observables, - "minShots" => 1, - "maxShots" => sv_max_shots, + :name => "Sample", + :observables => sv_observables, + :minShots => 1, + :maxShots => sv_max_shots, ), Dict( - "name" => "Expectation", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => sv_max_shots, + :name => "Expectation", + :observables => sv_observables, + :minShots => 0, + :maxShots => sv_max_shots, ), Dict( - "name" => "Variance", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => sv_max_shots, + :name => "Variance", + :observables => sv_observables, + :minShots => 0, + :maxShots => sv_max_shots, ), - Dict("name" => "Probability", "minShots" => 0, "maxShots" => sv_max_shots), - Dict("name" => "StateVector", "minShots" => 0, "maxShots" => 0), - Dict("name" => "DensityMatrix", "minShots" => 0, "maxShots" => 0), - Dict("name" => "Amplitude", "minShots" => 0, "maxShots" => 0), + Dict(:name => "Probability", :minShots => 0, :maxShots => sv_max_shots), + Dict(:name => "StateVector", :minShots => 0, :maxShots => 0), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), + Dict(:name => "Amplitude", :minShots => 0, :maxShots => 0), Dict( - "name" => "Adjoint_Gradient", - "observables" => sv_observables, - "minShots" => 0, - "maxShots" => 0, + :name => "Adjoint_Gradient", + :observables => sv_observables, + :minShots => 0, + :maxShots => 0, ), ], - "supportPhysicalQubits" => false, - "supportsPartialVerbatimBox" => false, - "requiresContiguousQubitIndices" => true, - "requiresAllQubitsMeasurement" => true, - "supportsUnassignedMeasurements" => true, - "disabledQubitRewiringSupported" => false, + :supportPhysicalQubits => false, + :supportsPartialVerbatimBox => false, + :requiresContiguousQubitIndices => true, + :requiresAllQubitsMeasurement => true, + :supportsUnassignedMeasurements => true, + :disabledQubitRewiringSupported => false, ), ), - "paradigm" => Dict("qubitCount" => sv_qubit_count), - "deviceParameters" => - Dict("paradigmParameters" => Dict("qubitCount" => sv_qubit_count)), + :paradigm => Dict(:qubitCount => sv_qubit_count), + :deviceParameters => + Dict(:paradigmParameters => Dict(:qubitCount => sv_qubit_count)), ) -const sv_props = Braket.parse_raw_schema(JSON3.write(sv_props_dict)) +const sv_props = StructTypes.constructfrom(GateModelSimulatorDeviceCapabilities, sv_props_dict) const dm_qubit_count = 14 const dm_max_shots = 1_000_000 const dm_observables = ["x", "y", "z", "h", "i", "hermitian"] const dm_props_dict = Dict( - "braketSchemaHeader" => Dict( - "name" => "braket.device_schema.simulators.gate_model_simulator_device_capabilities", - "version" => "1", + :braketSchemaHeader => Dict( + :name => "braket.device_schema.simulators.gate_model_simulator_device_capabilities", + :version => "1", ), - "service" => Dict( - "executionWindows" => [ + :service => Dict( + :executionWindows => [ Dict( - "executionDay" => "Everyday", - "windowStartHour" => "00:00", - "windowEndHour" => "23:59:59", + :executionDay => "Everyday", + :windowStartHour => "00:00", + :windowEndHour => "23:59:59", ), ], - "shotsRange" => [0, dm_max_shots], + :shotsRange => [0, dm_max_shots], ), - "action" => Dict( + :action => Dict( "braket.ir.openqasm.program" => Dict( - "actionType" => "braket.ir.openqasm.program", - "version" => ["1"], - "supportedOperations" => [ + :actionType => "braket.ir.openqasm.program", + :version => ["1"], + :supportedOperations => [ "U", "GPhase", "ccnot", @@ -281,15 +281,14 @@ const dm_props_dict = Dict( "phase_damping", "kraus", ], - "supportedModifiers" => [ - Dict("name" => "ctrl"), - Dict("name" => "negctrl"), - Dict("name" => "pow", "exponent_types" => ["int", "float"]), - Dict("name" => "inv"), + :supportedModifiers => [ + Dict(:name => "ctrl"), + Dict(:name => "negctrl"), + Dict(:name => "pow", :exponent_types => ["int", "float"]), + Dict(:name => "inv"), ], - "supportedPragmas" => [ + :supportedPragmas => [ "braket_unitary_matrix", - "braket_result_type_state_vector", "braket_result_type_density_matrix", "braket_result_type_sample", "braket_result_type_expectation", @@ -307,40 +306,40 @@ const dm_props_dict = Dict( "braket_noise_two_qubit_dephasing", "braket_noise_two_qubit_depolarizing", ], - "forbiddenPragmas" => ["braket_result_type_adjoint_gradient"], - "supportedResultTypes" => [ + :forbiddenPragmas => ["braket_result_type_adjoint_gradient", "braket_result_type_state_vector"], + :supportedResultTypes => [ Dict( - "name" => "Sample", - "observables" => dm_observables, - "minShots" => 1, - "maxShots" => dm_max_shots, + :name => "Sample", + :observables => dm_observables, + :minShots => 1, + :maxShots => dm_max_shots, ), Dict( - "name" => "Expectation", - "observables" => dm_observables, - "minShots" => 0, - "maxShots" => dm_max_shots, + :name => "Expectation", + :observables => dm_observables, + :minShots => 0, + :maxShots => dm_max_shots, ), Dict( - "name" => "Variance", - "observables" => dm_observables, - "minShots" => 0, - "maxShots" => dm_max_shots, + :name => "Variance", + :observables => dm_observables, + :minShots => 0, + :maxShots => dm_max_shots, ), - Dict("name" => "Probability", "minShots" => 0, "maxShots" => dm_max_shots), - Dict("name" => "DensityMatrix", "minShots" => 0, "maxShots" => 0), + Dict(:name => "Probability", :minShots => 0, :maxShots => dm_max_shots), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), ], - "supportPhysicalQubits" => false, - "supportsPartialVerbatimBox" => false, - "requiresContiguousQubitIndices" => true, - "requiresAllQubitsMeasurement" => true, - "supportsUnassignedMeasurements" => true, - "disabledQubitRewiringSupported" => false, + :supportPhysicalQubits => false, + :supportsPartialVerbatimBox => false, + :requiresContiguousQubitIndices => true, + :requiresAllQubitsMeasurement => true, + :supportsUnassignedMeasurements => true, + :disabledQubitRewiringSupported => false, ), "braket.ir.jaqcd.program" => Dict( - "actionType" => "braket.ir.jaqcd.program", - "version" => ["1"], - "supportedOperations" => [ + :actionType => "braket.ir.jaqcd.program", + :version => ["1"], + :supportedOperations => [ "amplitude_damping", "bit_flip", "ccnot", @@ -388,32 +387,32 @@ const dm_props_dict = Dict( "z", "zz", ], - "supportedResultTypes" => [ + :supportedResultTypes => [ Dict( - "name" => "Sample", - "observables" => dm_observables, - "minShots" => 1, - "maxShots" => dm_max_shots, + :name => "Sample", + :observables => dm_observables, + :minShots => 1, + :maxShots => dm_max_shots, ), Dict( - "name" => "Expectation", - "observables" => dm_observables, - "minShots" => 0, - "maxShots" => dm_max_shots, + :name => "Expectation", + :observables => dm_observables, + :minShots => 0, + :maxShots => dm_max_shots, ), Dict( - "name" => "Variance", - "observables" => dm_observables, - "minShots" => 0, - "maxShots" => dm_max_shots, + :name => "Variance", + :observables => dm_observables, + :minShots => 0, + :maxShots => dm_max_shots, ), - Dict("name" => "Probability", "minShots" => 0, "maxShots" => dm_max_shots), - Dict("name" => "DensityMatrix", "minShots" => 0, "maxShots" => 0), + Dict(:name => "Probability", :minShots => 0, :maxShots => dm_max_shots), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), ], ), ), - "paradigm" => Dict("qubitCount" => dm_qubit_count), - "deviceParameters" => - Dict("paradigmParameters" => Dict("qubitCount" => dm_qubit_count)), + :paradigm => Dict(:qubitCount => dm_qubit_count), + :deviceParameters => + Dict(:paradigmParameters => Dict(:qubitCount => dm_qubit_count)), ) -const dm_props = Braket.parse_raw_schema(JSON3.write(dm_props_dict)) +const dm_props = StructTypes.constructfrom(GateModelSimulatorDeviceCapabilities, dm_props_dict) diff --git a/src/qubit_set.jl b/src/qubit_set.jl new file mode 100644 index 0000000..1dd26ce --- /dev/null +++ b/src/qubit_set.jl @@ -0,0 +1,115 @@ +using OrderedCollections + +""" + Qubit <: Integer + +Wrapper `struct` representing a qubit. + +# Examples +```jldoctest +julia> q = Qubit(0) +Qubit(0) + +julia> q == 0 +true +``` +""" +struct Qubit <: Integer + index::Int + Qubit(q::Integer) = new(q) + Qubit(q::AbstractFloat) = new(Int(q)) + Qubit(q::BigFloat) = new(Int(q)) +end +Qubit(q::Qubit) = q +Base.:(==)(q::Qubit, i::T) where {T<:Integer} = q.index==i +Base.:(==)(i::T, q::Qubit) where {T<:Integer} = q.index==i +Base.:(==)(i::BigInt, q::Qubit) = big(q.index)==i +Base.:(==)(q::Qubit, i::BigInt) = big(q.index)==i +Base.:(==)(q1::Qubit, q2::Qubit) = q1.index==q2.index + +Base.convert(::Type{Int}, q::Qubit) = q.index +Base.Int(q::Qubit) = q.index +Base.hash(q::Qubit, h::UInt) = hash(q.index, h) +Base.show(io::IO, q::Qubit) = print(io, "Qubit($(q.index))") +const IntOrQubit = Union{Int, Qubit} + +""" + QubitSet + +An `OrderedSet`-like object which represents the qubits a +[`Circuit`](@ref), [`Instruction`](@ref), or [`Result`](@ref) +acts on and their ordering. +Elements may be `Int`s or [`Qubit`](@ref)s. + +# Examples +```jldoctest +julia> QubitSet(1, Qubit(0)) +QubitSet with 2 elements: + 1 + Qubit(0) + +julia> QubitSet([2, 1]) +QubitSet with 2 elements: + 2 + 1 + +julia> QubitSet() +QubitSet() + +julia> QubitSet(QubitSet(5, 1)) +QubitSet with 2 elements: + 5 + 1 +``` +""" +struct QubitSet <: AbstractSet{Int} + dict::OrderedDict{IntOrQubit, Nothing} + QubitSet() = new(OrderedDict{IntOrQubit, Nothing}()) + QubitSet(xs) = (v = foldl(vcat, xs, init=Int[]); return union!(new(OrderedDict{IntOrQubit,Nothing}()), v)) + QubitSet(qs::Vararg{IntOrQubit}) = QubitSet(collect(qs)) + QubitSet(qs::QubitSet) = qs + QubitSet(::Nothing) = QubitSet() +end +Base.convert(::Type{Vector{Int}}, qs::QubitSet) = convert.(Int, collect(qs)) +Base.length(qs::QubitSet) = length(qs.dict) +Base.lastindex(qs::QubitSet) = length(qs) +Base.isempty(qs::QubitSet) = isempty(qs.dict) +Base.in(q, qs::QubitSet) = haskey(qs.dict, q) +Base.push!(qs::QubitSet, q) = (qs.dict[q] = nothing; qs) +Base.copy(qs::QubitSet) = QubitSet(qs[ii] for ii in 1:length(qs)) +Base.popfirst!(qs::QubitSet) = (q = popfirst!(qs.dict); return q[1]) +function Base.iterate(qs::QubitSet)::Union{Nothing, Tuple{IntOrQubit, Int}} + qs.dict.ndel > 0 && OrderedCollections.rehash!(qs.dict) + length(qs.dict.keys) < 1 && return nothing + return (qs.dict.keys[1], 2) +end +function Base.iterate(qs::QubitSet, i)::Union{Nothing, Tuple{IntOrQubit, Int}} + length(qs.dict.keys) < i && return nothing + return (qs.dict.keys[i], i+1) +end +Base.:(==)(q1::QubitSet, q2::QubitSet) = (length(q1) == length(q2)) && all(q1[ii] == q2[ii] for ii in 1:length(q1)) + +function Base.getindex(qs::QubitSet, i::Int) + qs.dict.ndel > 0 && OrderedCollections.rehash!(qs.dict) + return qs.dict.keys[i] +end +Base.getindex(qs::QubitSet, ui::UnitRange) = QubitSet([qs[ii] for ii in ui]) + +function Base.intersect(qs1::QubitSet, qs2::QubitSet) + qs = QubitSet() + for q in qs1 + (q in qs2) && union!(qs, q) + end + return qs +end + +function Base.show(io::IO, qs::QubitSet) + print(io, "QubitSet(") + q_strs = map(q->sprint(show, q), collect(qs)) + print(io, join(q_strs, ", ")) + print(io, ")") +end +Base.convert(::Type{QubitSet}, v::Vector{<:Integer}) = QubitSet(v) +Base.sort(qs::QubitSet; kwargs...) = QubitSet(sort(collect(qs); kwargs...)) + +const VecOrQubitSet = Union{Vector, QubitSet} diff --git a/src/raw_schema.jl b/src/raw_schema.jl new file mode 100644 index 0000000..9fecd6c --- /dev/null +++ b/src/raw_schema.jl @@ -0,0 +1,253 @@ +using StructTypes + +abstract type BraketSchemaBase end + +@enum ExponentType int float +ExponentTypeDict = Dict(string(inst)=>inst for inst in instances(ExponentType)) + +struct braketSchemaHeader + name::String + version::String +end + +abstract type DeviceActionProperties <: BraketSchemaBase end + +abstract type AbstractProgram <: BraketSchemaBase end + +module IR +import ..BraketSimulator: braketSchemaHeader, BraketSchemaBase, AbstractProgram +using StructTypes + +export Program, AbstractIR, AbstractProgramResult, IRObservable + +abstract type AbstractIR end + +const IRObservable = Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} + +abstract type AbstractProgramResult <: AbstractIR end + +struct Program <: AbstractProgram + braketSchemaHeader::braketSchemaHeader + instructions::Vector{<:Any} + results::Union{Nothing, Vector{AbstractProgramResult}} + basis_rotation_instructions::Union{Nothing, Vector{<:Any}} +end + +struct Sample <: AbstractProgramResult + observable::Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} + targets::Union{Nothing, Vector{Int}} + type::String +end + +struct DensityMatrix <: AbstractProgramResult + targets::Union{Nothing, Vector{Int}} + type::String +end + +struct Expectation <: AbstractProgramResult + observable::Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} + targets::Union{Nothing, Vector{Int}} + type::String +end + +struct Amplitude <: AbstractProgramResult + states::Vector{String} + type::String +end + +struct Probability <: AbstractProgramResult + targets::Union{Nothing, Vector{Int}} + type::String +end + +struct AdjointGradient <: AbstractProgramResult + parameters::Union{Nothing, Vector{String}} + observable::Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} + targets::Union{Nothing, Vector{Vector{Int}}} + type::String +end + +struct StateVector <: AbstractProgramResult + type::String +end + +struct Variance <: AbstractProgramResult + observable::Union{Vector{Union{String, Vector{Vector{Vector{Float64}}}}}, String} + targets::Union{Nothing, Vector{Int}} + type::String +end + +end # module + +using .IR + +@enum DeviceActionType openqasm jaqcd +DeviceActionTypeDict = Dict(string(inst)=>inst for inst in instances(DeviceActionType)) + +struct ResultType + name::String + observables::Union{Nothing, Vector{String}} + minShots::Union{Nothing, Int} + maxShots::Union{Nothing, Int} +end + +struct AdditionalMetadata + action::AbstractProgram + dwaveMetadata::Nothing + ionqMetadata::Nothing + rigettiMetadata::Nothing + oqcMetadata::Nothing + xanaduMetadata::Nothing + queraMetadata::Nothing + simulatorMetadata::Nothing +end + +struct ResultTypeValue + type::AbstractProgramResult + value::Union{Vector, Float64, Dict} +end +# for custom lowering of ComplexF64 +StructTypes.StructType(::Type{ResultTypeValue}) = StructTypes.CustomStruct() +function StructTypes.lower(rtv::ResultTypeValue) + typ = rtv.type + function lower_complex(v::ComplexF64) + abs(imag(v)) < eps(real(v)) && return real(v) + return [real(v), imag(v)] + end + lower_complex(v) = v + if rtv.value isa Float64 + return (type=typ, value=rtv.value) + elseif rtv.value isa Vector + lowered_vec = [lower_complex(val) for val in rtv.value] + return (type=typ, value=lowered_vec) + elseif rtv.value isa Dict + lowered_dict = Dict(k=>lower_complex(v) for (k, v) in rtv.value) + return (type=typ, value=lowered_dict) + end +end + +struct JaqcdDeviceActionProperties <: DeviceActionProperties + version::Vector{String} + actionType::String + supportedOperations::Union{Nothing, Vector{String}} + supportedResultTypes::Union{Nothing, Vector{ResultType}} + disabledQubitRewiringSupported::Union{Nothing, Bool} +end + +struct ControlMod + name::String + max_qubits::Union{Nothing, Int} +end + +struct NegControlMod + name::String + max_qubits::Union{Nothing, Int} +end + +struct Power + name::String + exponent_types::Vector{ExponentType} +end + +struct Inverse + name::String +end + +struct OpenQASMDeviceActionProperties <: DeviceActionProperties + version::Vector{String} + actionType::String + supportedOperations::Union{Nothing, Vector{String}} + supportedModifiers::Vector{Union{ControlMod, NegControlMod, Power, Inverse}} + supportedPragmas::Vector{String} + forbiddenPragmas::Vector{String} + maximumQubitArrays::Union{Nothing, Int} + maximumClassicalArrays::Union{Nothing, Int} + forbiddenArrayOperations::Vector{String} + requiresAllQubitsMeasurement::Bool + supportPhysicalQubits::Bool + requiresContiguousQubitIndices::Bool + supportsPartialVerbatimBox::Bool + supportsUnassignedMeasurements::Bool + disabledQubitRewiringSupported::Bool + supportedResultTypes::Union{Nothing, Vector{ResultType}} +end + +struct GateModelParameters <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + qubitCount::Int + disableQubitRewiring::Bool +end + +struct OpenQasmProgram <: AbstractProgram + braketSchemaHeader::braketSchemaHeader + source::String + inputs::Union{Nothing, Dict{String, Union{String, Float64, Int, Vector{Union{String, Float64, Int}}}}} +end + +@enum ExecutionDay everyday weekdays weekends monday tuesday wednesday thursday friday saturday sunday +ExecutionDayDict = Dict(string(inst)=>inst for inst in instances(ExecutionDay)) + +struct DeviceExecutionWindow + executionDay::Union{ExecutionDay, String} + windowStartHour::Dates.Time + windowEndHour::Dates.Time +end + +struct DeviceServiceProperties <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + executionWindows::Vector{DeviceExecutionWindow} + shotsRange::Tuple{Int, Int} + deviceCost::Nothing + deviceDocumentation::Nothing + deviceLocation::Nothing + updatedAt::Nothing + getTaskPollIntervalMillis::Nothing +end +StructTypes.defaults(::Type{DeviceServiceProperties}) = Dict{Symbol, Any}(:braketSchemaHeader => braketSchemaHeader("braket.device_schema.device_service_properties", "1")) + +struct GateModelSimulatorParadigmProperties <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + qubitCount::Int +end +StructTypes.defaults(::Type{GateModelSimulatorParadigmProperties}) = Dict{Symbol, Any}(:braketSchemaHeader => braketSchemaHeader("braket.device_schema.simulators.gate_model_simulator_paradigm_properties", "1")) + +struct GateModelSimulatorDeviceCapabilities <: BraketSchemaBase + service::DeviceServiceProperties + action::Dict{Union{DeviceActionType, String}, Union{OpenQASMDeviceActionProperties, JaqcdDeviceActionProperties}} + deviceParameters::Dict + braketSchemaHeader::braketSchemaHeader + paradigm::GateModelSimulatorParadigmProperties +end +StructTypes.defaults(::Type{GateModelSimulatorDeviceCapabilities}) = Dict{Symbol, Any}(:braketSchemaHeader => braketSchemaHeader("braket.device_schema.simulators.gate_model_simulator_device_capabilities", "1")) + +struct GateModelSimulatorDeviceParameters <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + paradigmParameters::GateModelParameters +end + +struct TaskMetadata <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + id::String + shots::Int + deviceId::String + deviceParameters::Nothing + createdAt::Union{Nothing, String} + endedAt::Union{Nothing, String} + status::Union{Nothing, String} + failureReason::Union{Nothing, String} +end + +struct GateModelTaskResult <: BraketSchemaBase + braketSchemaHeader::braketSchemaHeader + measurements::Union{Nothing, Vector{Vector{Int}}} + measurementProbabilities::Union{Nothing, Dict{String, Float64}} + resultTypes::Union{Nothing, Vector{ResultTypeValue}} + measuredQubits::Union{Nothing, Vector{Int}} + taskMetadata::TaskMetadata + additionalMetadata::AdditionalMetadata +end + +struct GenericDeviceActionProperties <: DeviceActionProperties + version::Vector{String} + actionType::Union{DeviceActionType, String} +end diff --git a/src/result_types.jl b/src/result_types.jl index d0fcebd..20bae8d 100644 --- a/src/result_types.jl +++ b/src/result_types.jl @@ -79,8 +79,8 @@ function samples(simulator::AbstractSimulator) return simulator.shot_buffer end -calculate(sv::Braket.StateVector, sim::AbstractSimulator) = state_vector(sim) -function calculate(amplitude::Braket.Amplitude, sim::AbstractSimulator) +calculate(sv::StateVector, sim::AbstractSimulator) = state_vector(sim) +function calculate(amplitude::Amplitude, sim::AbstractSimulator) state = collect(state_vector(sim)) rev_states = reverse.(amplitude.states) state_ints = [ @@ -148,7 +148,7 @@ function permute_density_matrix(ρ::Matrix{T}, qubit_count::Int, targets) where return new_ρ end -function calculate(probability::Braket.Probability, sim::AbstractSimulator) +function calculate(probability::Probability, sim::AbstractSimulator) targets = probability.targets probs = probabilities(sim) n_qubits = qubit_count(sim) @@ -158,53 +158,53 @@ function calculate(probability::Braket.Probability, sim::AbstractSimulator) return marginal_probability(probs, n_qubits, targets) end -function calculate(expectation_result::Braket.Expectation, sim::AbstractSimulator) +function calculate(expectation_result::Expectation, sim::AbstractSimulator) obs = expectation_result.observable targets = isempty(expectation_result.targets) ? collect(0:qubit_count(sim)-1) : expectation_result.targets obs_qubit_count = qubit_count(obs) length(targets) == obs_qubit_count && return expectation(sim, obs, targets...) return [expectation(sim, obs, target) for target in targets] end -expectation_op_squared(sim, obs::Braket.Observables.StandardObservable, target::Int) = 1.0 -expectation_op_squared(sim, obs::Braket.Observables.I, target::Int) = 1.0 -function expectation_op_squared(sim, obs::Braket.Observables.TensorProduct, targets::Int...) +expectation_op_squared(sim, obs::Observables.StandardObservable, target::Int) = 1.0 +expectation_op_squared(sim, obs::Observables.I, target::Int) = 1.0 +function expectation_op_squared(sim, obs::Observables.TensorProduct, targets::Int...) all( - factor isa Braket.Observables.StandardObservable || factor isa Braket.Observables.I for + factor isa Observables.StandardObservable || factor isa Observables.I for factor in obs.factors ) && return 1.0 sq_factors = map(obs.factors) do factor - (factor isa Braket.Observables.StandardObservable || factor isa Braket.Observables.I) && - return Braket.Observables.I() - factor isa Braket.Observables.HermitianObservable && - return Braket.Observables.HermitianObservable(factor.matrix * factor.matrix) + (factor isa Observables.StandardObservable || factor isa Observables.I) && + return Observables.I() + factor isa Observables.HermitianObservable && + return Observables.HermitianObservable(factor.matrix * factor.matrix) end - sq_tensor_prod = Braket.Observables.TensorProduct(sq_factors) + sq_tensor_prod = Observables.TensorProduct(sq_factors) return expectation(sim, sq_tensor_prod, targets...) end function expectation_op_squared( sim, - obs::Braket.Observables.HermitianObservable, + obs::Observables.HermitianObservable, targets::Int..., ) return expectation( sim, - Braket.Observables.HermitianObservable(obs.matrix * obs.matrix), + Observables.HermitianObservable(obs.matrix * obs.matrix), targets..., ) end for (gate, obs) in ( - (:X, :(Braket.Observables.X)), - (:Y, :(Braket.Observables.Y)), - (:Z, :(Braket.Observables.Z)), - (:I, :(Braket.Observables.I)), - (:H, :(Braket.Observables.H)), + (:X, :(Observables.X)), + (:Y, :(Observables.Y)), + (:Z, :(Observables.Z)), + (:I, :(Observables.I)), + (:H, :(Observables.H)), ) @eval apply_observable!(::$obs, sv_or_dm::T, targets) where {T<:AbstractVecOrMat{<:Complex}} = apply_observable!($gate(), sv_or_dm, targets) end function apply_observable!( - observable::Braket.Observables.TensorProduct, + observable::Observables.TensorProduct, sv_or_dm::T, targets::Int..., ) where {T<:AbstractVecOrMat{<:Complex}} @@ -218,14 +218,9 @@ function apply_observable!( end return sv_or_dm end -apply_observable( - observable::O, - sv_or_dm, - target::Int..., -) where {O<:Braket.Observables.Observable} = - apply_observable!(observable, deepcopy(sv_or_dm), target...) - -function calculate(variance::Braket.Variance, sim::AbstractSimulator) +apply_observable(observable::O, sv_or_dm, target::Int...) where {O<:Observables.Observable} = apply_observable!(observable, deepcopy(sv_or_dm), target...) + +function calculate(variance::Variance, sim::AbstractSimulator) obs = variance.observable targets = isnothing(variance.targets) ? collect(0:qubit_count(sim)-1) : variance.targets obs_qubit_count = qubit_count(obs) @@ -242,7 +237,7 @@ function calculate(variance::Braket.Variance, sim::AbstractSimulator) end end -function calculate(dm::Braket.DensityMatrix, sim::AbstractSimulator) +function calculate(dm::DensityMatrix, sim::AbstractSimulator) ρ = density_matrix(sim) full_qubits = collect(0:qubit_count(sim)-1) (collect(dm.targets) == full_qubits || isempty(dm.targets)) && return ρ diff --git a/src/results.jl b/src/results.jl new file mode 100644 index 0000000..f8d3b89 --- /dev/null +++ b/src/results.jl @@ -0,0 +1,191 @@ +""" + Result + +Abstract type representing a measurement to perform on +a [`Circuit`](@ref). + +See also: [`Expectation`](@ref), [`Variance`](@ref), +[`Sample`](@ref), [`Probability`](@ref), +[`DensityMatrix`](@ref), and [`Amplitude`](@ref). +""" +abstract type Result end + +for (typ, ir_typ, label) in ((:Expectation, :(IR.Expectation), "expectation"), (:Variance, :(IR.Variance), "variance"), (:Sample, :(IR.Sample), "sample")) + @eval begin + @doc """ + $($typ) <: Result + + Struct which represents a $($label) measurement on a [`Circuit`](@ref). + """ + struct $typ <: Result + observable::Observables.Observable + targets::QubitSet + $typ(observable::Observables.Observable, targets::QubitSet) = new(observable, targets) + end + @doc """ + $($typ)(o, targets) -> $($typ) + $($typ)(o) -> $($typ) + + Constructs a $($typ) of an observable `o` on qubits `targets`. + + `o` may be one of: + - Any [`Observable`](@ref Observables.Observable) + - A `String` corresponding to an `Observable` (e.g. `\"x\"``) + - A `Vector{String}` in which each element corresponds to an `Observable` + + `targets` may be one of: + - A [`QubitSet`](@ref) + - A `Vector` of `Int`s and/or [`Qubit`](@ref)s + - An `Int` or `Qubit` + - Absent, in which case the observable `o` will be applied to all qubits provided it is a single qubit observable. + """ $typ(o, targets) = $typ(o, QubitSet(targets)) + StructTypes.lower(x::$typ) = $ir_typ(StructTypes.lower(x.observable), (isempty(x.targets) ? nothing : Int.(x.targets)), $label) + end +end + + +for (typ, ir_typ, label) in ((:Probability, :(IR.Probability), "probability"), (:DensityMatrix, :(IR.DensityMatrix), "densitymatrix")) + @eval begin + @doc """ + $($typ) <: Result + + Struct which represents a $($label) measurement on a [`Circuit`](@ref). + """ + struct $typ <: Result + targets::QubitSet + $typ(targets::QubitSet) = new(targets) + end + Base.:(==)(p1::$typ, p2::$typ) = (p1.targets == p2.targets) + $typ() = $typ(QubitSet()) + @doc """ + $($typ)(targets) -> $($typ) + $($typ)() -> $($typ) + + Constructs a $($typ) on qubits `targets`. + + `targets` may be one of: + - A [`QubitSet`](@ref) + - A `Vector` of `Int`s and/or [`Qubit`](@ref)s + - An `Int` or `Qubit` + - Absent, in which case the measurement will be applied to all qubits. + """ $typ(targets) = $typ(QubitSet(targets)) + $typ(targets::Vararg{IntOrQubit}) = $typ(QubitSet(targets...)) + StructTypes.lower(x::$typ) = $ir_typ(isempty(x.targets) ? nothing : Int.(x.targets), $label) + end +end + +# exclude adjoint gradient from coverage for now +# as we don't yet implement this, so don't have a test for it +# COV_EXCL_START +""" + AdjointGradient <: Result + +Struct which represents a gradient computation using the adjoint differentiation method on a [`Circuit`](@ref). +""" +struct AdjointGradient <: Result + observable::Observable + targets::Vector{QubitSet} + parameters::Vector{String} + function AdjointGradient(observable::Observable, targets::Vector{QubitSet}, parameters::Vector{String}=["all"]) + if observable isa Sum + length(targets) == length(observable) || throw(DimensionMismatch("length of targets ($(length(targets))) must be the same as number of summands ($(length(observable))).")) + all(length(term_target) == qubit_count(summand) for (term_target, summand) in zip(targets, observable.summands)) || throw(DimensionMismatch("each target must be the same size as the qubit count of its corresponding term.")) + else + (length(targets) == 1 && length(targets[1]) == qubit_count(observable)) || throw(DimensionMismatch("targets $targets must have only one element if adjoint gradient observable is not a Sum.")) + end + new(observable, targets, parameters) + end +end + +""" + AdjointGradient(o::Observable, targets, parameters::Vector) -> AdjointGradient + AdjointGradient(o::Observable, targets) -> AdjointGradient + +Constructs an `AdjointGradient` with respect to the expectation value of +an observable `o` on qubits `targets`. The gradient will be calculated by +computing partial derivatives with respect to `parameters`. If `parameters` +is not present, is empty, or is `["all"]`, all parameters in the circuit +will be used. + +`targets` may be one of: + - A [`QubitSet`](@ref) + - A `Vector` of `Int`s and/or [`Qubit`](@ref)s + - An `Int` or `Qubit` + +`AdjointGradient` supports using [`Sum`](@ref) observables. If `o` is a `Sum`, +`targets` should be a nested vector of target qubits, such that the `n`-th term of +`targets` has the same length as the `n`-th term of `o`. + +# Examples +```jldoctest +julia> α = FreeParameter(:alpha); + +julia> op = 2.0 * Observables.X() * Observables.X(); + +julia> AdjointGradient(op, [QubitSet(0, 1)], [α]); +``` + +Using a `Sum`: + +```jldoctest +julia> α = FreeParameter(:alpha); + +julia> op1 = 2.0 * Observables.X() * Observables.X(); + +julia> op2 = -3.0 * Observables.Y() * Observables.Y(); + +julia> AdjointGradient(op1 + op2, [QubitSet(0, 1), QubitSet(0, 2)], [α]); +``` +""" +function AdjointGradient(observable::Observable, targets::Vector{QubitSet}, parameters::Vector) + isempty(parameters) && return AdjointGradient(observable, targets, ["all"]) + return AdjointGradient(observable, targets, string.(parameters)) +end +AdjointGradient(observable::Observable, targets::QubitSet, parameters) = AdjointGradient(observable, [targets], parameters) +AdjointGradient(observable::Observable, targets::Vector{Vector{T}}, args...) where {T} = AdjointGradient(observable, [QubitSet(t) for t in targets], args...) +AdjointGradient(observable::Observable, targets::Vector{<:IntOrQubit}, args...) = AdjointGradient(observable, [QubitSet(targets)], args...) +AdjointGradient(observable::Observable, targets::IntOrQubit, args...) = AdjointGradient(observable, [QubitSet(targets)], args...) + +StructTypes.StructType(::Type{AdjointGradient}) = StructTypes.CustomStruct() +function StructTypes.lower(x::AdjointGradient) + lowered_obs = StructTypes.lower(x.observable) + lowered_targets = (isempty(x.targets) ? nothing : convert(Vector{Vector{Int}}, x.targets)) + IR.AdjointGradient(x.parameters, lowered_obs, lowered_targets, "adjoint_gradient") +end +# COV_EXCL_STOP + +""" + Amplitude <: Result + +Struct which represents an amplitude measurement on a [`Circuit`](@ref). +""" +struct Amplitude <: Result + states::Vector{String} +end +""" + Amplitude(states) -> Amplitude + +Constructs an Amplitude measurement of `states`. + +`states` may be one of: + - A `Vector{String}` + - A `String` +All elements of `states` must be `'0'` or `'1'`. +""" +Amplitude(s::String) = Amplitude([s]) +Base.:(==)(a1::Amplitude, a2::Amplitude) = (a1.states == a2.states) + +""" + StateVector <: Result + +Struct which represents a state vector measurement on a [`Circuit`](@ref). +""" +struct StateVector <: Result end +Base.:(==)(sv1::StateVector, sv2::StateVector) = true + +const ObservableResult = Union{Expectation, Variance, Sample} +const ObservableParameterResult = Union{AdjointGradient,} +StructTypes.lower(x::Amplitude) = IR.Amplitude(x.states, "amplitude") +StructTypes.lower(x::StateVector) = IR.StateVector("statevector") + +ir(r::Result, ::Val{:JAQCD}; kwargs...) = StructTypes.lower(r) diff --git a/src/schemas.jl b/src/schemas.jl new file mode 100644 index 0000000..c130e6b --- /dev/null +++ b/src/schemas.jl @@ -0,0 +1,28 @@ +""" + Instruction + Instruction(o::Operator, target) + +Represents a single operation applied to a [`Circuit`](@ref). +Contains an `operator`, which may be any subtype of [`Operator`](@ref), +and a `target` set of qubits to which the `operator` is applied. + +# Examples +```jldoctest +julia> Instruction(H(), 1) +Instruction{H}(H(1.0), QubitSet(1)) + +julia> Instruction(CNot(), [1, Qubit(4)]) +Instruction{CNot}(CNot(1.0), QubitSet(1, 4)) +``` +""" +struct Instruction{O<:Operator} + operator::O + target::QubitSet +end +Instruction(o::O, target) where {O<:Operator} = Instruction{O}(o, QubitSet(target...)) + +Instruction(x::Instruction{O}) where {O<:Operator} = x +Base.:(==)(ix1::Instruction{O}, ix2::Instruction{O}) where {O<:Operator} = (ix1.operator == ix2.operator && ix1.target == ix2.target) + +bind_value!(ix::Instruction{O}, param_values::Dict{Symbol, <:Real}) where {O<:Operator} = Instruction{O}(bind_value!(ix.operator, param_values), ix.target) +remap(@nospecialize(ix::Instruction{O}), mapping::Dict{<:Integer, <:Integer}) where {O} = Instruction{O}(copy(ix.operator), [mapping[q] for q in ix.target]) diff --git a/src/sv_simulator.jl b/src/sv_simulator.jl index 9ba5741..67bbbc3 100644 --- a/src/sv_simulator.jl +++ b/src/sv_simulator.jl @@ -63,24 +63,24 @@ end Create a `StateVectorSimulator` with `2^qubit_count` elements and `shots` shots to be measured. The default element type is `ComplexF64`. """ StateVectorSimulator(::Type{T}, qubit_count::Int, shots::Int) where {T<:Number} = - StateVectorSimulator{T,StateVector{T}}(qubit_count, shots) + StateVectorSimulator{T,Vector{T}}(qubit_count, shots) StateVectorSimulator(qubit_count::Int, shots::Int) = StateVectorSimulator(ComplexF64, qubit_count, shots) -Braket.qubit_count(svs::StateVectorSimulator) = svs.qubit_count +qubit_count(svs::StateVectorSimulator) = svs.qubit_count """ properties(svs::StateVectorSimulator) -> GateModelSimulatorDeviceCapabilities Query the properties and capabilities of a `StateVectorSimulator`, including which gates and result types are supported and the minimum and maximum shot and qubit counts. """ -Braket.properties(svs::StateVectorSimulator) = sv_props +properties(svs::StateVectorSimulator) = sv_props supported_operations(svs::StateVectorSimulator, ::Val{:OpenQASM}) = sv_props.action["braket.ir.openqasm.program"].supportedOperations supported_operations(svs::StateVectorSimulator) = supported_operations(svs::StateVectorSimulator, Val(:OpenQASM)) supported_operations(svs::StateVectorSimulator, ::Val{:JAQCD}) = sv_props.action["braket.ir.jaqcd.program"].supportedOperations supported_result_types(svs::StateVectorSimulator, ::Val{:OpenQASM}) = sv_props.action["braket.ir.openqasm.program"].supportedResultTypes supported_result_types(svs::StateVectorSimulator, ::Val{:JAQCD}) = sv_props.action["braket.ir.jaqcd.program"].supportedResultTypes supported_result_types(svs::StateVectorSimulator) = supported_result_types(svs::StateVectorSimulator, Val(:OpenQASM)) -Braket.device_id(svs::StateVectorSimulator) = "braket_sv_v2" -Braket.name(svs::StateVectorSimulator) = "StateVectorSimulator" +device_id(svs::StateVectorSimulator) = "braket_sv_v2" +name(svs::StateVectorSimulator) = "StateVectorSimulator" Base.show(io::IO, svs::StateVectorSimulator) = print(io, "StateVectorSimulator(qubit_count=$(qubit_count(svs)), shots=$(svs.shots))") Base.similar(svs::StateVectorSimulator{T,S}; shots::Int = svs.shots) where {T,S} = @@ -162,8 +162,8 @@ function apply_observable!( return sv end function apply_observable!( - observable::Braket.Observables.HermitianObservable, - sv::StateVector{T}, + observable::Observables.HermitianObservable, + sv::AbstractStateVector{T}, target::Int, ) where {T<:Complex} n_amps = length(sv) @@ -179,20 +179,17 @@ function apply_observable!( return sv end function apply_observable!( - observable::Braket.Observables.HermitianObservable, - sv::StateVector{T}, + observable::Observables.HermitianObservable, + sv::AbstractStateVector{T}, target_1::Int, target_2::Int, ) where {T<:Complex} - n_amps = length(sv) - n_qubits = Int(log2(n_amps)) - endian_t1 = n_qubits - 1 - target_1 - endian_t2 = n_qubits - 1 - target_2 - mat = observable.matrix - small_target, big_target = minmax(endian_t1, endian_t2) + n_amps, (endian_t1, endian_t2) = get_amps_and_qubits(sv, target_1, target_2) + small_t, big_t = minmax(endian_t1, endian_t2) + mat = observable.matrix Threads.@threads for ix = 0:div(n_amps, 4)-1 # bit shift to get indices - ix_00 = pad_bits(ix, (small_target, big_target)) + ix_00 = pad_bits(ix, (small_t, big_t)) ix_10 = flip_bit(ix_00, endian_t2) ix_01 = flip_bit(ix_00, endian_t1) ix_11 = flip_bit(ix_10, endian_t1) @@ -203,8 +200,8 @@ function apply_observable!( end function apply_observable!( - observable::Braket.Observables.HermitianObservable, - sv::StateVector{T}, + observable::Observables.HermitianObservable, + sv::AbstractStateVector{T}, target_1::Int, target_2::Int, targets::Int..., diff --git a/src/validation.jl b/src/validation.jl index abb9a99..ee4b322 100644 --- a/src/validation.jl +++ b/src/validation.jl @@ -77,7 +77,7 @@ function _validate_ir_instructions_compatibility( circuit::Union{Program,Circuit}, supported_operations, ) - circuit_instruction_names = map(ix->replace(lowercase(string(typeof(ix.operator))), "_"=>"", "braket."=>""), circuit.instructions) + circuit_instruction_names = map(ix->replace(lowercase(string(typeof(ix.operator))), "_"=>"", "braketsimulator."=>""), circuit.instructions) supported_instructions = Set(map(op->replace(lowercase(op), "_"=>""), supported_operations)) no_noise = true for name in circuit_instruction_names @@ -95,8 +95,11 @@ function _validate_ir_instructions_compatibility( end _validate_ir_instructions_compatibility(simulator::D, circuit::Union{Program,Circuit}, v::Val{V}) where {D<:AbstractSimulator, V} = _validate_ir_instructions_compatibility(circuit, supported_operations(simulator, v)) -_validate_result_type_qubits_exist(rt::Braket.StateVector, qubit_count::Int) = return -_validate_result_type_qubits_exist(rt::Braket.Amplitude, qubit_count::Int) = return +_validate_result_type_qubits_exist(rt::StateVector, qubit_count::Int) = return +_validate_result_type_qubits_exist(rt::Amplitude, qubit_count::Int) = return +# exclude adjoint gradient validation from coverage for now +# as we don't yet implement this, so don't have a test for it +# COV_EXCL_START function _validate_result_type_qubits_exist(rt::AdjointGradient, qubit_count::Int) isempty(rt.targets) && return targets = reduce(vcat, targets) @@ -106,7 +109,8 @@ function _validate_result_type_qubits_exist(rt::AdjointGradient, qubit_count::In ) return end -# don't need to check for `isnothing` here as the `Braket.QubitSet` being empty covers this +# COV_EXCL_STOP +# don't need to check for `isnothing` here as the `QubitSet` being empty covers this function _validate_result_type_qubits_exist(rt::RT, qubit_count::Int) where {RT<:Result} isempty(rt.targets) && return maximum(rt.targets) > qubit_count && diff --git a/test/Project.toml b/test/Project.toml index 76e0ee0..20d12d9 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,6 +3,8 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67" BraketSimulator = "76d27892-9a0b-406c-98e4-7c178e9b3dff" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" diff --git a/test/runtests.jl b/test/runtests.jl index 4aa524e..f08737e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,11 +1,15 @@ -using Test, Aqua, BraketSimulator - -Aqua.test_all(BraketSimulator, ambiguities=false, piracies=false, persistent_tasks = false) +using Test, Aqua, Documenter, BraketSimulator +Aqua.test_all(BraketSimulator, ambiguities=false) +Aqua.test_ambiguities(BraketSimulator) dir_list = filter(x-> startswith(x, "test_") && endswith(x, ".jl"), readdir(@__DIR__)) @testset "BraketSimulator" begin @testset "$test" for test in dir_list include(test) end + @testset "docs" begin + Documenter.DocMeta.setdocmeta!(BraketSimulator, :DocTestSetup, :(using BraketSimulator, BraketSimulator.Observables; using BraketSimulator: Program, Circuit, qubits, CNot, H, Rx, FreeParameter, QubitSet, AdjointGradient, BitFlip, qubit_count, Qubit, StateVector, Measure, Probability, Ry, Amplitude, Instruction, DensityMatrix, add_instruction!); recursive=true) + Documenter.doctest(BraketSimulator) + end end diff --git a/test/test_braket_integration.jl b/test/test_braket_integration.jl index b597034..3abbd4f 100644 --- a/test/test_braket_integration.jl +++ b/test/test_braket_integration.jl @@ -1,31 +1,46 @@ using Test, Statistics, LinearAlgebra, - Braket, - Braket.Observables, BraketSimulator +using Braket using Braket: I, name -@testset "Basic integration of local simulators with Braket.jl" begin +@testset "Basic integration of local simulators with BraketSimulator.jl" begin @testset "Simulator $sim_type" for (sim_type, rt) in ( ("braket_sv_v2", Braket.StateVector), ("braket_dm_v2", Braket.DensityMatrix), ) d = LocalSimulator(sim_type) @test d.backend == sim_type - c = Circuit() - H(c, 0, 1, 2) - Rx(c, 0, 1, 2, 0.5) + c = Braket.Circuit() + Braket.H(c, 0, 1, 2) + Braket.Rx(c, 0, 1, 2, 0.5) rt(c) if sim_type == "braket_sv_v2" - Amplitude(c, ["000", "111"]) + Braket.Amplitude(c, ["000", "111"]) end r = d(c, shots = 0) end end +@testset "Type conversions" begin + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.Measure(2))) == Braket.Measure(2) + angle1 = 0.2 + angle2 = 0.1 + angle3 = π + prob = 0.015 + prob2 = 0.1 + prob3 = 0.002 + gamma = 0.23 + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.MS(angle1, angle2, angle3))) == Braket.MS(angle1, angle2, angle3) + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.U(angle1, angle2, angle3))) == Braket.U(angle1, angle2, angle3) + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.PRx(angle1, angle2))) == Braket.PRx(angle1, angle2) + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.GeneralizedAmplitudeDamping(prob, gamma))) == Braket.GeneralizedAmplitudeDamping(prob, gamma) + @test convert(Braket.Operator, convert(BraketSimulator.Operator, Braket.PauliChannel(prob, prob3, prob3))) == Braket.PauliChannel(prob, prob3, prob3) + @test convert(Braket.AbstractProgramResult, convert(BraketSimulator.AbstractProgramResult, Braket.IR.StateVector("statevector"))) == Braket.IR.StateVector("statevector") +end + @testset "Correctness" begin - Braket.IRType[] = :JAQCD PURE_DEVICE = LocalSimulator("braket_sv_v2") NOISE_DEVICE = LocalSimulator("braket_dm_v2") ALL_DEVICES = [PURE_DEVICE, NOISE_DEVICE] @@ -39,21 +54,21 @@ end shots > 0 ? Dict("atol" => 0.2, "rtol" => 0.25) : Dict("atol" => 0.01, "rtol" => 0) ) - bell_circ() = Circuit([(H, 0), (CNot, 0, 1)]) + bell_circ() = Braket.Circuit([(Braket.H, 0), (Braket.CNot, 0, 1)]) three_qubit_circuit( θ::Float64, ϕ::Float64, φ::Float64, - obs::Observables.Observable, + obs::Braket.Observables.Observable, obs_targets::Vector{Int}, - ) = Circuit([ - (Rx, 0, θ), - (Rx, 1, ϕ), - (Rx, 2, φ), - (CNot, 0, 1), - (CNot, 1, 2), - (Variance, obs, obs_targets), - (Expectation, obs, obs_targets), + ) = Braket.Circuit([ + (Braket.Rx, 0, θ), + (Braket.Rx, 1, ϕ), + (Braket.Rx, 2, φ), + (Braket.CNot, 0, 1), + (Braket.CNot, 1, 2), + (Braket.Variance, obs, obs_targets), + (Braket.Expectation, obs, obs_targets), ]) @inline function variance_expectation_sample_result( @@ -100,7 +115,7 @@ end ("braket_dm_v2", "DensityMatrixSimulator"), ] local_simulator_device = LocalSimulator(backend) - @test name(local_simulator_device) == device_name + @test Braket.name(local_simulator_device) == device_name end @testset "Device $DEVICE, shots $SHOTS" for DEVICE in ALL_DEVICES, SHOTS in SHOT_LIST @@ -108,8 +123,8 @@ end if SHOTS > 0 @testset "qubit ordering" begin device = DEVICE - state_110 = Circuit([(X, 0), (X, 1), (I, 2)]) - state_001 = Circuit([(I, 0), (I, 1), (X, 2)]) + state_110 = Braket.Circuit([(Braket.X, 0), (Braket.X, 1), (Braket.I, 2)]) + state_001 = Braket.Circuit([(Braket.I, 0), (Braket.I, 1), (Braket.X, 2)]) @testset for (state, most_com) in ((state_110, "110"), (state_001, "001")) tasks = (state, ir(state, Val(:JAQCD)), ir(state, Val(:OpenQASM))) @@ -123,25 +138,25 @@ end @testset "Bell pair nonzero shots" begin circuit = bell_circ() - circuit(Expectation, Observables.H() * Observables.X(), [0, 1]) - circuit(Sample, Observables.H() * Observables.X(), [0, 1]) + circuit(Braket.Expectation, Braket.Observables.H() * Braket.Observables.X(), [0, 1]) + circuit(Braket.Sample, Braket.Observables.H() * Braket.Observables.X(), [0, 1]) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) @testset for task in tasks device = DEVICE res = result(device(task; shots = SHOTS)) @test length(res.result_types) == 2 @test 0.6 < - res[Expectation(Observables.H() * Observables.X(), [0, 1])] < + res[Braket.Expectation(Braket.Observables.H() * Braket.Observables.X(), [0, 1])] < 0.8 @test length( - res[Sample(Observables.H() * Observables.X(), [0, 1])], + res[Braket.Sample(Braket.Observables.H() * Braket.Observables.X(), [0, 1])], ) == SHOTS end end end @testset "Bell pair full probability" begin circuit = bell_circ() - circuit(Probability) + circuit(Braket.Probability) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) tol = get_tol(SHOTS) @testset for task in tasks @@ -158,7 +173,7 @@ end end @testset "Bell pair marginal probability" begin circuit = bell_circ() - circuit(Probability, 0) + circuit(Braket.Probability, 0) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) tol = get_tol(SHOTS) @testset for task in tasks @@ -166,7 +181,7 @@ end res = result(device(task, shots = SHOTS)) @test length(res.result_types) == 1 @test isapprox( - res[Probability(0)], + res[Braket.Probability(0)], [0.5, 0.5], rtol = tol["rtol"], atol = tol["atol"], @@ -190,11 +205,11 @@ end device = DEVICE shots = SHOTS @testset "Obs $obs" for obs in ( - Observables.X() * Observables.Y(), - Observables.HermitianObservable(kron([0 1; 1 0], [0 -im; im 0])), + Braket.Observables.X() * Braket.Observables.Y(), + Braket.Observables.HermitianObservable(kron([0 1; 1 0], [0 -im; im 0])), ) circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) - shots > 0 && circuit(Sample, obs, obs_targets) + shots > 0 && circuit(Braket.Sample, obs, obs_targets) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) for task in tasks res = result(device(task, shots = shots)) @@ -212,7 +227,7 @@ end θ = 0.432 ϕ = 0.123 φ = -0.543 - obs = Observables.Z() * Observables.H() * Observables.Y() + obs = Braket.Observables.Z() * Braket.Observables.H() * Braket.Observables.Y() obs_targets = [0, 1, 2] circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) expected_mean = -(cos(φ) * sin(ϕ) + sin(φ) * cos(θ)) / √2 @@ -224,18 +239,22 @@ end expected_eigs = [-1.0, 1.0] device = DEVICE shots = SHOTS - circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) - shots > 0 && circuit(Sample, obs, obs_targets) - tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) - for task in tasks - res = result(device(task, shots = shots)) - variance_expectation_sample_result( - res, - shots, - expected_var, - expected_mean, - expected_eigs, - ) + @testset for obs in ( + Braket.Observables.Z() * Braket.Observables.H() * Braket.Observables.Y(), + ) + circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) + shots > 0 && circuit(Braket.Sample, obs, obs_targets) + tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) + for task in tasks + res = result(device(task, shots = shots)) + variance_expectation_sample_result( + res, + shots, + expected_var, + expected_mean, + expected_eigs, + ) + end end end @testset "Result types z x z" begin @@ -248,14 +267,14 @@ end expected_eigs = [-1.0, 1.0] device = DEVICE shots = SHOTS - for obs in ( - Observables.Z() * Observables.Z(), - Observables.HermitianObservable(kron([1 0; 0 -1], [1 0; 0 -1])), + @testset for obs in ( + Braket.Observables.Z() * Braket.Observables.Z(), + Braket.Observables.HermitianObservable(kron([1 0; 0 -1], [1 0; 0 -1])), ) circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) - shots > 0 && circuit(Sample, obs, obs_targets) + shots > 0 && circuit(Braket.Sample, obs, obs_targets) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) - for task in tasks + @testset for task in tasks res = result(device(task, shots = shots)) variance_expectation_sample_result( res, @@ -278,13 +297,13 @@ end -5-2im -5-4im -4-3im -6 ] @test ishermitian(ho_mat) - ho = Observables.HermitianObservable(ComplexF64.(ho_mat)) + ho = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat)) ho_mat2 = [1 2; 2 4] - ho2 = Observables.HermitianObservable(ComplexF64.(ho_mat2)) + ho2 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat2)) ho_mat3 = [-6 2+im; 2-im 0] - ho3 = Observables.HermitianObservable(ComplexF64.(ho_mat3)) + ho3 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat3)) ho_mat4 = kron([1 0; 0 1], [-6 2+im; 2-im 0]) - ho4 = Observables.HermitianObservable(ComplexF64.(ho_mat4)) + ho4 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat4)) meani = -5.7267957792059345 meany = 1.4499810303182408 meanz = @@ -330,23 +349,23 @@ end obs_targets = [0, 1, 2] @testset "Obs $obs" for (obs, expected_mean, expected_var, expected_eigs) in [ - (Observables.I() * ho, meani, vari, eigsi), - (Observables.Y() * ho, meany, vary, eigsy), - (Observables.Z() * ho, meanz, varz, eigsz), + (Braket.Observables.I() * ho, meani, vari, eigsi), + (Braket.Observables.Y() * ho, meany, vary, eigsy), + (Braket.Observables.Z() * ho, meanz, varz, eigsz), (ho2 * ho, meanh, varh, eigsh), ( - Observables.HermitianObservable(kron(ho_mat2, ho_mat)), + Braket.Observables.HermitianObservable(kron(ho_mat2, ho_mat)), meanh, varh, eigsh, ), - (Observables.I() * Observables.I() * ho3, meanii, varii, eigsii), - (Observables.I() * ho4, meanii, varii, eigsii), + (Braket.Observables.I() * Braket.Observables.I() * ho3, meanii, varii, eigsii), + (Braket.Observables.I() * ho4, meanii, varii, eigsii), ] device = DEVICE shots = SHOTS circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) - shots > 0 && circuit(Sample, obs, obs_targets) + shots > 0 && circuit(Braket.Sample, obs, obs_targets) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) for task in tasks res = result(device(task, shots = shots)) @@ -371,14 +390,14 @@ end -5-2im -5-4im -4-3im -6 ] @test ishermitian(ho_mat) - ho = Observables.HermitianObservable(ComplexF64.(ho_mat)) + ho = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat)) ho_mat2 = [1 2; 2 4] - ho2 = Observables.HermitianObservable(ho_mat2) + ho2 = Braket.Observables.HermitianObservable(ho_mat2) ho_mat3 = [-6 2+im; 2-im 0] - ho3 = Observables.HermitianObservable(ho_mat3) + ho3 = Braket.Observables.HermitianObservable(ho_mat3) ho_mat4 = kron([1 0; 0 1], [-6 2+im; 2-im 0]) - ho4 = Observables.HermitianObservable(ho_mat4) - h = Observables.HermitianObservable(kron(ho_mat2, ho_mat)) + ho4 = Braket.Observables.HermitianObservable(ho_mat4) + h = Braket.Observables.HermitianObservable(kron(ho_mat2, ho_mat)) meani = -5.7267957792059345 meanh = -4.30215023196904 meanii = -5.78059066879935 @@ -407,7 +426,7 @@ end device = DEVICE shots = SHOTS circuit = three_qubit_circuit(θ, ϕ, φ, obs, targets) - shots > 0 && circuit(Sample, obs, targets) + shots > 0 && circuit(Braket.Sample, obs, targets) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) for task in tasks res = result(device(task; shots = shots)) @@ -425,7 +444,7 @@ end @testset "Result types all selected" begin θ = 0.543 ho_mat = [1 2im; -2im 0] - ho = Observables.HermitianObservable(ho_mat) + ho = Braket.Observables.HermitianObservable(ho_mat) expected_mean = 2 * sin(θ) + 0.5 * cos(θ) + 0.5 var_ = 0.25 * (sin(θ) - 4 * cos(θ))^2 expected_var = [var_, var_] @@ -433,9 +452,10 @@ end device = DEVICE shots = SHOTS circuit = - Circuit([(Rx, 0, θ), (Rx, 1, θ), (Variance, ho), (Expectation, ho, 0)]) - shots > 0 && circuit(Sample, ho, 1) - for task in (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) + Braket.Circuit([(Braket.Rx, 0, θ), (Braket.Rx, 1, θ), (Braket.Variance, ho), (Braket.Expectation, ho, 0)]) + shots > 0 && circuit(Braket.Sample, ho, 1) + tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) + for task in tasks res = result(device(task; shots = shots)) tol = get_tol(shots) variance = res.values[1] @@ -486,16 +506,16 @@ end -3 2+im 0 -4+3im -5-2im -5-4im -4-3im -6 ] - obs1 = Observables.X() * Observables.Y() + obs1 = Braket.Observables.X() * Braket.Observables.Y() obs1_targets = [0, 2] - obs2 = Observables.Z() * Observables.Z() + obs2 = Braket.Observables.Z() * Braket.Observables.Z() obs2_targets = [0, 2] - obs3 = Observables.Y() * Observables.HermitianObservable(ho_mat) + obs3 = Braket.Observables.Y() * Braket.Observables.HermitianObservable(ho_mat) obs3_targets = [0, 1, 2] obs3_targets = [0, 1, 2] circuit = three_qubit_circuit(θ, ϕ, φ, obs1, obs1_targets) - circuit(Expectation, obs2, obs2_targets) - circuit(Expectation, obs3, obs3_targets) + circuit(Braket.Expectation, obs2, obs2_targets) + circuit(Braket.Expectation, obs3, obs3_targets) expected_mean1 = sin(θ) * sin(ϕ) * sin(φ) expected_var1 = @@ -520,9 +540,9 @@ end end @testset "Result types noncommuting flipped targets" begin circuit = bell_circ() - tp = Observables.TensorProduct(["h", "x"]) - circuit = Expectation(circuit, tp, [0, 1]) - circuit = Expectation(circuit, tp, [1, 0]) + tp = Braket.Observables.TensorProduct(["h", "x"]) + circuit = Braket.Expectation(circuit, tp, [0, 1]) + circuit = Braket.Expectation(circuit, tp, [1, 0]) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) @testset for task in tasks device = DEVICE @@ -534,8 +554,8 @@ end @testset "Result types all noncommuting" begin circuit = bell_circ() ho = [1 2im; -2im 0] - circuit(Expectation, Observables.HermitianObservable(ho)) - circuit(Expectation, Observables.X()) + circuit(Braket.Expectation, Braket.Observables.HermitianObservable(ho)) + circuit(Braket.Expectation, Braket.Observables.X()) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) @testset for task in tasks device = DEVICE @@ -546,13 +566,13 @@ end end @testset "Result types observable not in instructions" begin bell = bell_circ() - bell(Expectation, Observables.X(), 2) - bell(Variance, Observables.Y(), 3) + bell(Braket.Expectation, Braket.Observables.X(), 2) + bell(Braket.Variance, Braket.Observables.Y(), 3) bell_qasm = ir(bell, Val(:OpenQASM)) @test qubit_count(bell) == 4 shots = SHOTS device = DEVICE - @testset for task in (bell, bell_qasm) + @testset for task in (bell, ir(bell, Val(:JAQCD)), bell_qasm) tol = get_tol(shots) res = result(device(task, shots = shots)) @test isapprox(res.values[1], 0, rtol = tol["rtol"], atol = tol["atol"]) @@ -564,8 +584,8 @@ end @testset "Result types no shots" begin @testset for include_amplitude in [true, false] circuit = bell_circ() - circuit(Expectation, Observables.H() * Observables.X(), 0, 1) - include_amplitude && circuit(Amplitude, ["01", "10", "00", "11"]) + circuit(Braket.Expectation, Braket.Observables.H() * Braket.Observables.X(), 0, 1) + include_amplitude && circuit(Braket.Amplitude, ["01", "10", "00", "11"]) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) @testset for task in tasks device = DEVICE @@ -573,11 +593,11 @@ end res = result(device(task, shots = 0)) @test length(res.result_types) == (include_amplitude ? 2 : 1) @test isapprox( - res[Expectation(Observables.H() * Observables.X(), [0, 1])], + res[Braket.Expectation(Braket.Observables.H() * Braket.Observables.X(), [0, 1])], 1 / √2, ) if include_amplitude - amps = res[Amplitude(["01", "10", "00", "11"])] + amps = res[Braket.Amplitude(["01", "10", "00", "11"])] @test isapprox(amps["01"], 0) @test isapprox(amps["10"], 0) @test isapprox(amps["00"], 1 / √2) @@ -589,13 +609,11 @@ end if SHOTS > 0 @testset "Multithreaded Bell pair" begin tol = get_tol(SHOTS) - tasks = (bell_circ, (()->ir(bell_circ(), Val(:OpenQASM))), (()->ir(bell_circ(), Val(:JAQCD)))) + tasks = (bell_circ, (()->ir(bell_circ(), Val(:JAQCD))), (()->ir(bell_circ(), Val(:OpenQASM)))) device = DEVICE - @testset for task in tasks - run_circuit(circuit) = result(simulate(device, circuit; shots = SHOTS)) - batch_size = 5 - task_array = [task() for ii = 1:batch_size] - batch_results = results(simulate(device, task_array; shots=SHOTS)) + @testset for task in tasks, task_count in (1, 10) + task_array = [task() for ii = 1:task_count] + batch_results = results(device(task_array, shots=SHOTS)) for r in batch_results @test isapprox( r.measurement_probabilities["00"], @@ -619,9 +637,9 @@ end @testset "noisy circuit 1 qubit noise full probability" begin shots = SHOTS tol = get_tol(shots) - circuit = Circuit([(X, 0), (X, 1), (BitFlip, 0, 0.1), (Probability,)]) + circuit = Braket.Circuit([(Braket.X, 0), (Braket.X, 1), (Braket.BitFlip, 0, 0.1), (Braket.Probability,)]) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) - device = DEVICE + device = DEVICE for task in tasks res = result(device(task, shots = shots)) @test length(res.result_types) == 1 @@ -639,14 +657,14 @@ end K0 = √0.9 * diagm(ones(4)) K1 = √0.1 * kron([0.0 1.0; 1.0 0.0], [0.0 1.0; 1.0 0.0]) circuit = - Circuit([(X, 0), (X, 1), (Kraus, [0, 1], [K0, K1]), (Probability,)]) + Braket.Circuit([(Braket.X, 0), (Braket.X, 1), (Braket.Kraus, [0, 1], [K0, K1]), (Braket.Probability,)]) tasks = (circuit, ir(circuit, Val(:JAQCD)), ir(circuit, Val(:OpenQASM))) device = DEVICE for task in tasks res = result(device(task, shots = shots)) @test length(res.result_types) == 1 @test isapprox( - res[Probability()], + res[Braket.Probability()], [0.1, 0.0, 0, 0.9], rtol = tol["rtol"], atol = tol["atol"], diff --git a/test/test_custom_gates.jl b/test/test_custom_gates.jl index 4e47f7e..e82f3e4 100644 --- a/test/test_custom_gates.jl +++ b/test/test_custom_gates.jl @@ -1,17 +1,15 @@ -using Test, Logging, Braket, BraketSimulator, DataStructures - -using Braket: Instruction -using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control +using Test, Logging, BraketSimulator, DataStructures @testset "Custom gates" begin @testset "Double excitation" begin ϕ = 3.56 nq = 4 - instructions = [Instruction(H(), [0]), Instruction(CNot(), [0, 1]), Instruction(DoubleExcitation(ϕ), [0, 1, 2, 3])] + @test BraketSimulator.qubit_count(BraketSimulator.DoubleExcitation(0.1)) == 4 + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), BraketSimulator.Instruction(BraketSimulator.DoubleExcitation(ϕ), [0, 1, 2, 3])] # instructions for the gate decomposition (from PennyLane) - de_instructions = [Instruction(H(), [0]), Instruction(CNot(), [0, 1]), Instruction(CNot(), [2, 3]), Instruction(CNot(), [0, 2]), Instruction(H(), [3]), Instruction(H(), [0]), Instruction(CNot(), [2, 3]), Instruction(CNot(), [0, 1]), Instruction(Ry(ϕ/8), [1]), Instruction(Ry(-ϕ/8), [0]), Instruction(CNot(), [0, 3]), Instruction(H(), [3]), Instruction(CNot(), [3, 1]), Instruction(Ry(ϕ/8), [1]), Instruction(Ry(-ϕ/8), [0]), Instruction(CNot(), [2, 1]), Instruction(CNot(), [2, 0]), Instruction(Ry(-ϕ/8), [1]), Instruction(Ry(ϕ/8), [0]), Instruction(CNot(), [3, 1]), Instruction(H(), [3]), Instruction(CNot(), [0, 3]), Instruction(Ry(-ϕ/8), [1]), Instruction(Ry(ϕ/8), [0]), Instruction(CNot(), [0, 1]), Instruction(CNot(), [2, 0]), Instruction(H(), [0]), Instruction(H(), [3]), Instruction(CNot(), [0, 2]), Instruction(CNot(), [2, 3])] + de_instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 2]), BraketSimulator.Instruction(BraketSimulator.H(), [3]), BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), BraketSimulator.Instruction(BraketSimulator.Ry(ϕ/8), [1]), BraketSimulator.Instruction(BraketSimulator.Ry(-ϕ/8), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 3]), BraketSimulator.Instruction(BraketSimulator.H(), [3]), BraketSimulator.Instruction(BraketSimulator.CNot(), [3, 1]), BraketSimulator.Instruction(BraketSimulator.Ry(ϕ/8), [1]), BraketSimulator.Instruction(BraketSimulator.Ry(-ϕ/8), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 1]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 0]), BraketSimulator.Instruction(BraketSimulator.Ry(-ϕ/8), [1]), BraketSimulator.Instruction(BraketSimulator.Ry(ϕ/8), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [3, 1]), BraketSimulator.Instruction(BraketSimulator.H(), [3]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 3]), BraketSimulator.Instruction(BraketSimulator.Ry(-ϕ/8), [1]), BraketSimulator.Instruction(BraketSimulator.Ry(ϕ/8), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 0]), BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [3]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 2]), BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3])] # instructions for the matrix representation - u_instructions = [Instruction(H(), [0]), Instruction(CNot(), [0, 1]), Instruction(Unitary(Matrix(matrix_rep(DoubleExcitation(ϕ)))), [0, 1, 2, 3])] + u_instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(BraketSimulator.DoubleExcitation(ϕ)))), [0, 1, 2, 3])] # initial state # [ 1/√2, 0, 0, 1/√2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # final state @@ -21,23 +19,25 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control @testset "Simulator $sim, instruction set $ix_label" for sim in (StateVectorSimulator, DensityMatrixSimulator), (ix_label, ixs) in (("raw", instructions), ("decomp", de_instructions), ("unitary", u_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @test probability_amplitudes ≈ collect(BraketSimulator.probabilities(simulation)) end - @test qubit_count(DoubleExcitation(ϕ)) == 4 - @test inv(DoubleExcitation(ϕ)) == DoubleExcitation(-ϕ) + @test BraketSimulator.qubit_count(BraketSimulator.DoubleExcitation(ϕ)) == 4 + @test BraketSimulator.qubit_count(BraketSimulator.DoubleExcitation) == 4 + @test inv(BraketSimulator.DoubleExcitation(ϕ)) == BraketSimulator.DoubleExcitation(ϕ, -1.0) end @testset "Single excitation" begin ϕ = 3.56 nq = 2 - instructions = [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(SingleExcitation(ϕ), [0, 1])] - de_instructions = [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(Ti(), [0]), Instruction(H(), [0]), Instruction(S(), [0]), Instruction(Ti(), [1]), Instruction(Si(), [1]), Instruction(H(), [1]), Instruction(CNot(), [1, 0]), Instruction(Rz(-ϕ/2), [0]), Instruction(Ry(ϕ/2), [1]), Instruction(CNot(), [1, 0]), Instruction(Si(), [0]), Instruction(H(), [0]), Instruction(T(), [0]), Instruction(H(), [1]), Instruction(S(), [1]), Instruction(T(), [1])] + @test BraketSimulator.qubit_count(BraketSimulator.SingleExcitation(0.1)) == 2 + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.SingleExcitation(ϕ), [0, 1])] + de_instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.Ti(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.S(), [0]), BraketSimulator.Instruction(BraketSimulator.Ti(), [1]), BraketSimulator.Instruction(BraketSimulator.Si(), [1]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.CNot(), [1, 0]), BraketSimulator.Instruction(BraketSimulator.Rz(-ϕ/2), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(ϕ/2), [1]), BraketSimulator.Instruction(BraketSimulator.CNot(), [1, 0]), BraketSimulator.Instruction(BraketSimulator.Si(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.T(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.S(), [1]), BraketSimulator.Instruction(BraketSimulator.T(), [1])] # instructions for the matrix representation - u_instructions = [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(Unitary(Matrix(matrix_rep(SingleExcitation(ϕ)))), [1, 0])] + u_instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(BraketSimulator.SingleExcitation(ϕ)))), [0, 1])] # initial state # [ 1/2, 1/2, 1/2, 1/2] # final state @@ -47,23 +47,25 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control @testset "Simulator $sim, instruction set $ix_label" for sim in (StateVectorSimulator, DensityMatrixSimulator), (ix_label, ixs) in (("raw", instructions), ("decomp", de_instructions), ("unitary", u_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @test probability_amplitudes ≈ collect(BraketSimulator.probabilities(simulation)) end - @test qubit_count(SingleExcitation(ϕ)) == 2 - @test inv(SingleExcitation(ϕ)) == SingleExcitation(-ϕ) + @test BraketSimulator.qubit_count(BraketSimulator.SingleExcitation(ϕ)) == 2 + @test BraketSimulator.qubit_count(BraketSimulator.SingleExcitation) == 2 + @test inv(BraketSimulator.SingleExcitation(ϕ)) == BraketSimulator.SingleExcitation(ϕ, -1.0) end @testset "3-angle U" begin θ = 1.34 ϕ = 2.12 λ = 0.43 nq = 2 - instructions = [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(U(θ, ϕ, λ), [0])] - u_instructions = [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(Unitary(Matrix(matrix_rep(U(θ, ϕ, λ)))), [0])] + @test BraketSimulator.qubit_count(BraketSimulator.U(θ, ϕ, λ)) == 1 + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.U(θ, ϕ, λ), [0])] + u_instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(BraketSimulator.U(θ, ϕ, λ)))), [0])] # initial state # [ 1/2, 1/2, 1/2, 1/2] # final state @@ -73,26 +75,28 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control @testset "Simulator $sim, instruction set $ix_label" for sim in (StateVectorSimulator, DensityMatrixSimulator), (ix_label, ixs) in (("raw", instructions), ("unitary", u_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @test probability_amplitudes ≈ collect(BraketSimulator.probabilities(simulation)) end - @test qubit_count(U(θ, ϕ, λ)) == 1 - @test inv(U(θ, ϕ, λ)) == U(-θ, -λ, -ϕ) + @test BraketSimulator.qubit_count(BraketSimulator.U(θ, ϕ, λ)) == 1 + @test BraketSimulator.qubit_count(BraketSimulator.U) == 1 + @test inv(BraketSimulator.U(θ, ϕ, λ)) == BraketSimulator.U(θ, ϕ, λ, -1) end @testset "MultiQubitPhaseShift" begin ϕ = 2.12 @testset "Simulator $sim, n_qubits $nq" for sim in (StateVectorSimulator, DensityMatrixSimulator), nq in 1:4 - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(MultiQubitPhaseShift{nq}(ϕ), collect(0:nq-1))]) - u_instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(Unitary(Matrix(matrix_rep(MultiQubitPhaseShift{nq}(ϕ)))), collect(0:nq-1))]) + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ), collect(0:nq-1))]) + u_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ)))), collect(0:nq-1))]) state_vector = exp(im*ϕ)/√(2^nq) * ones(2^nq) probability_amplitudes = 1/2^nq * ones(2^nq) - @testset "Instruction set $ix_label" for (ix_label, ixs) in (("raw", instructions), ("unitary", u_instructions)) + @test BraketSimulator.qubit_count(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ)) == nq + @testset "BraketSimulator.Instruction set $ix_label" for (ix_label, ixs) in (("raw", instructions), ("unitary", u_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @@ -100,39 +104,42 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control collect(BraketSimulator.probabilities(simulation)) end end - @test qubit_count(MultiQubitPhaseShift{2}(ϕ)) == 2 - @test qubit_count(MultiQubitPhaseShift{3}(ϕ)) == 3 - @test inv(MultiQubitPhaseShift{2}(ϕ)) == MultiQubitPhaseShift{2}(-ϕ) + @test BraketSimulator.qubit_count(BraketSimulator.MultiQubitPhaseShift{2}(ϕ)) == 2 + @test BraketSimulator.qubit_count(BraketSimulator.MultiQubitPhaseShift{3}(ϕ)) == 3 + @test inv(BraketSimulator.MultiQubitPhaseShift{2}(ϕ)) == BraketSimulator.MultiQubitPhaseShift{2}(ϕ, -1.0) end @testset "MultiRz" begin ϕ = 2.12 - @testset "Simulator $sim, n_qubits $nq" for sim in (StateVectorSimulator, DensityMatrixSimulator), nq in 1:4 - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(MultiRZ(ϕ), collect(0:nq-1))]) + @testset "Simulator $sim, n_qubits $nq" for sim in (StateVectorSimulator, DensityMatrixSimulator), nq in 1:6 + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.MultiRZ(ϕ), collect(0:nq-1))]) simulation = sim(nq, 0) - simulation = evolve!(simulation, instructions) - state_vector = √(1/2^nq) * exp.(-im*ϕ/2 .* Braket.PauliEigenvalues(Val(nq))) - probability_amplitudes = 1/2^nq * ones(2^nq) + simulation = BraketSimulator.evolve!(simulation, instructions) + state_vector = √(1/2^nq) * exp.(-im*ϕ/2 .* BraketSimulator.PauliEigenvalues(Val(nq))) + probability_amplitudes = 1/2^nq * ones(2^nq) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @test probability_amplitudes ≈ collect(BraketSimulator.probabilities(simulation)) end - @test qubit_count(MultiRZ(ϕ)) == 1 - @test inv(MultiRZ(ϕ)) == MultiRZ(-ϕ) + @test BraketSimulator.qubit_count(BraketSimulator.MultiRZ(ϕ)) == 1 + @test inv(BraketSimulator.MultiRZ(ϕ)) == BraketSimulator.MultiRZ(ϕ, -1.0) end @testset "Control" begin - x = Control(X(), ()) - @test matrix_rep(x) == matrix_rep(X()) - @test qubit_count(x) == 1 - cx = Control(X(), (1,)) - @test Matrix(matrix_rep(cx)) == [1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0] - @test qubit_count(cx) == 2 - ccx = Control(cx, (1,)) - @test qubit_count(ccx) == 3 - @testset for (nq, g, cg) in ((2, cx, CNot()), (3, ccx, CCNot())) - instructions = vcat([Instruction(H(), [0])], [Instruction(CNot(), [q, q+1]) for q in 0:nq-3], [Instruction(g, collect(0:nq-1))]) - canonical_instructions = vcat([Instruction(H(), [0])], [Instruction(CNot(), [q, q+1]) for q in 0:nq-3], [Instruction(cg, collect(0:nq-1))]) + x = BraketSimulator.Control(BraketSimulator.X(), ()) + @test BraketSimulator.matrix_rep(x) == BraketSimulator.matrix_rep(BraketSimulator.X()) + @test BraketSimulator.qubit_count(x) == 1 + cx = BraketSimulator.Control(BraketSimulator.X(), (1,)) + @test Matrix(BraketSimulator.matrix_rep(cx)) == [1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0] + @test BraketSimulator.qubit_count(cx) == 2 + cx = BraketSimulator.Control(BraketSimulator.Control(BraketSimulator.X(), (1,)), ()) + @test Matrix(BraketSimulator.matrix_rep(cx)) == [1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0] + @test BraketSimulator.qubit_count(cx) == 2 + ccx = BraketSimulator.Control(cx, (1,)) + @test BraketSimulator.qubit_count(ccx) == 3 + @testset for (nq, g, cg) in ((2, cx, BraketSimulator.CNot()), (3, ccx, BraketSimulator.CCNot())) + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [0])], [BraketSimulator.Instruction(BraketSimulator.CNot(), [q, q+1]) for q in 0:nq-3], [BraketSimulator.Instruction(g, collect(0:nq-1))]) + canonical_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [0])], [BraketSimulator.Instruction(BraketSimulator.CNot(), [q, q+1]) for q in 0:nq-3], [BraketSimulator.Instruction(cg, collect(0:nq-1))]) vec = zeros(2^nq) vec[1] = 1 vec[end] = 1 @@ -141,7 +148,7 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control @testset "Simulator $sim, instruction set $ix_label" for sim in (StateVectorSimulator, DensityMatrixSimulator), (ix_label, ixs) in (("control", instructions), ("builtin", canonical_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end @@ -151,16 +158,16 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control end @testset for nq in 1:2 ϕ = 2.12 - @test qubit_count(Control(MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq))) == nq - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(Control(MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq)), collect(0:nq-1))]) - u = Matrix(matrix_rep(Control(MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq)))) - u_instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(Unitary(u), collect(0:nq-1))]) + @test BraketSimulator.qubit_count(BraketSimulator.Control(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq))) == nq + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.Control(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq)), collect(0:nq-1))]) + u = Matrix(BraketSimulator.matrix_rep(BraketSimulator.Control(BraketSimulator.MultiQubitPhaseShift{nq}(ϕ), ntuple(i->0, nq)))) + u_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.Unitary(u), collect(0:nq-1))]) state_vector = 1/√(2^nq) * ones(ComplexF64, 2^nq) state_vector[1] *= exp(im*ϕ) probability_amplitudes = 1/2^nq * ones(2^nq) @testset "Simulator $sim, instruction set $ix_label" for sim in (StateVectorSimulator, DensityMatrixSimulator), (ix_label, ixs) in (("raw", instructions), ("unitary", u_instructions)) simulation = sim(nq, 0) - simulation = evolve!(simulation, ixs) + simulation = BraketSimulator.evolve!(simulation, ixs) if sim == StateVectorSimulator @test state_vector ≈ collect(BraketSimulator.state_vector(simulation)) end diff --git a/test/test_dm_simulator.jl b/test/test_dm_simulator.jl index 710a425..85ced26 100644 --- a/test/test_dm_simulator.jl +++ b/test/test_dm_simulator.jl @@ -1,6 +1,4 @@ -using Test, LinearAlgebra, Braket, BraketSimulator, DataStructures - -import Braket: I, Instruction +using Test, LinearAlgebra, BraketSimulator, DataStructures LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) @@ -8,7 +6,7 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) sx = ComplexF64[0 1; 1 0] si = ComplexF64[1 0; 0 1] matrix_1q = sx - matrix_2q = kron(sx, si) + matrix_2q = kron(si, sx) matrix_3q = kron(sx, kron(si, si)) matrix_4q = kron(kron(sx, si), kron(si, si)) matrix_5q = kron(sx, kron(kron(sx, si), kron(si, si))) @@ -24,11 +22,11 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) XX = kron([0 1; 1 0], [0 1; 1 0]) YZ = kron([0 -im; im 0], [1 0; 0 -1]) - tqcp_kraus = Kraus([√0.7 * diagm(ones(4)), √0.1 * XX, √0.2 * YZ]) + tqcp_kraus = BraketSimulator.Kraus([√0.7 * diagm(ones(4)), √0.1 * XX, √0.2 * YZ]) simulation = DensityMatrixSimulator(2, 0) simulation = evolve!( simulation, - [Instruction(X(), [0]), Instruction(X(), [1]), Instruction(tqcp_kraus, [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.X(), [1]), BraketSimulator.Instruction(tqcp_kraus, [0, 1])], ) tqcp_dm = simulation.density_matrix @@ -39,50 +37,50 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) probability_amplitudes, ) in [ ( - [Instruction(X(), [0]), Instruction(BitFlip(0.1), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.BitFlip(0.1), [0])], 1, [0.1 0.0; 0.0 0.9], [0.1, 0.9], ), ( - [Instruction(H(), [0]), Instruction(PhaseFlip(0.1), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.PhaseFlip(0.1), [0])], 1, [0.5 0.4; 0.4 0.5], [0.5, 0.5], ), ( - [Instruction(X(), [0]), Instruction(Depolarizing(0.3), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Depolarizing(0.3), [0])], 1, [0.2 0.0; 0.0 0.8], [0.2, 0.8], ), ( - [Instruction(X(), [0]), Instruction(AmplitudeDamping(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.AmplitudeDamping(0.15), [0])], 1, [0.15 0.0; 0.0 0.85], [0.15, 0.85], ), ( [ - Instruction(X(), [0]), - Instruction(GeneralizedAmplitudeDamping(0.15, 0.2), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.GeneralizedAmplitudeDamping(0.15, 0.2), [0]), ], 1, [0.03 0.0; 0.0 0.97], [0.03, 0.97], ), ( - [Instruction(X(), [0]), Instruction(PauliChannel(0.15, 0.16, 0.17), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.PauliChannel(0.15, 0.16, 0.17), [0])], 1, [0.31 0.0; 0.0 0.69], [0.31, 0.69], ), ( [ - Instruction(X(), [0]), - Instruction(X(), [1]), - Instruction( - TwoQubitPauliChannel(Dict("XX" => 0.1, "YZ" => 0.2)), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [1]), + BraketSimulator.Instruction( + BraketSimulator.TwoQubitPauliChannel(Dict("XX" => 0.1, "YZ" => 0.2)), [0, 1], ), ], @@ -92,9 +90,9 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ), ( [ - Instruction(H(), [0]), - Instruction(PhaseDamping(0.36), [0]), - Instruction(H(), [0]), + BraketSimulator.Instruction(BraketSimulator.H(), [0]), + BraketSimulator.Instruction(BraketSimulator.PhaseDamping(0.36), [0]), + BraketSimulator.Instruction(BraketSimulator.H(), [0]), ], 1, [0.9 0.0; 0.0 0.1], @@ -102,8 +100,8 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ), ( [ - Instruction(X(), [0]), - Instruction(Kraus([[0.8 0; 0 0.8], [0 0.6; 0.6 0]]), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.Kraus([[0.8 0; 0 0.8], [0 0.6; 0.6 0]]), [0]), ], 1, [0.36 0.0; 0.0 0.64], @@ -111,9 +109,9 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ), ( [ - Instruction(X(), [0]), - Instruction(X(), [1]), - Instruction(TwoQubitDepolarizing(0.1), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [1]), + BraketSimulator.Instruction(BraketSimulator.TwoQubitDepolarizing(0.1), [0, 1]), ], 2, [ @@ -126,11 +124,11 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ), ( [ - Instruction(H(), [0]), - Instruction(H(), [1]), - Instruction(TwoQubitDephasing(0.1), [0, 1]), - Instruction(H(), [0]), - Instruction(H(), [1]), + BraketSimulator.Instruction(BraketSimulator.H(), [0]), + BraketSimulator.Instruction(BraketSimulator.H(), [1]), + BraketSimulator.Instruction(BraketSimulator.TwoQubitDephasing(0.1), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.H(), [0]), + BraketSimulator.Instruction(BraketSimulator.H(), [1]), ], 2, [ @@ -141,33 +139,33 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ], [0.8999999999, 0.03333333333333, 0.03333333333333, 0.033333333333], ), - ([Instruction(X(), [0])], 2, density_matrix_2q, [0.0, 0.0, 1.0, 0.0]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0])], 2, density_matrix_2q, [0.0, 0.0, 1.0, 0.0]), ( - [Instruction(Unitary(matrix_1q), [0])], + [BraketSimulator.Instruction(BraketSimulator.Unitary(matrix_1q), [0])], 2, density_matrix_2q, [0.0, 0.0, 1.0, 0.0], ), ( - [Instruction(Unitary(matrix_2q), (0, 1))], + [BraketSimulator.Instruction(BraketSimulator.Unitary(matrix_2q), (0, 1))], 2, density_matrix_2q, [0.0, 0.0, 1.0, 0.0], ), ( - [Instruction(X(), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0])], 3, density_matrix_3q, [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0], ), ( - [Instruction(Unitary(matrix_3q), (0, 1, 2))], + [BraketSimulator.Instruction(BraketSimulator.Unitary(matrix_3q), (0, 1, 2))], 3, density_matrix_3q, [0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0], ), ( - [Instruction(Unitary(matrix_4q), (0, 1, 2, 3))], + [BraketSimulator.Instruction(BraketSimulator.Unitary(matrix_4q), (0, 1, 2, 3))], 4, density_matrix_4q, [ @@ -189,7 +187,7 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) 0.0, ], ), - ([Instruction(Kraus([matrix_5q]), [0, 1, 2, 3, 4])], 5, density_matrix_5q, [ + ([BraketSimulator.Instruction(BraketSimulator.Kraus([matrix_5q]), [0, 1, 2, 3, 4])], 5, density_matrix_5q, [ 0.0, 0.0, 0.0, @@ -224,7 +222,7 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) 0.0, ], ), - ([Instruction(Kraus([matrix_5q, 0.0 * matrix_5qi]), [0, 1, 2, 3, 4])], 5, density_matrix_5q, [ + ([BraketSimulator.Instruction(BraketSimulator.Kraus([matrix_5q, 0.0 * matrix_5qi]), [0, 1, 2, 3, 4])], 5, density_matrix_5q, [ 0.0, 0.0, 0.0, @@ -267,58 +265,58 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) collect(BraketSimulator.probabilities(simulation)) end @testset "Apply observables $obs" for (obs, equivalent_gates, qubit_count) in [ - ([(Braket.Observables.X(), [0])], [Instruction(H(), [0])], 1), - ([(Braket.Observables.Z(), [0])], Instruction[], 1), - ([(Braket.Observables.I(), [0])], Instruction[], 1), + ([(BraketSimulator.Observables.X(), [0])], [BraketSimulator.Instruction(BraketSimulator.H(), [0])], 1), + ([(BraketSimulator.Observables.Z(), [0])], BraketSimulator.Instruction[], 1), + ([(BraketSimulator.Observables.I(), [0])], BraketSimulator.Instruction[], 1), ( [ - (Braket.Observables.X(), [0]), - (Braket.Observables.Z(), [3]), - (Braket.Observables.H(), [2]), + (BraketSimulator.Observables.X(), [0]), + (BraketSimulator.Observables.Z(), [3]), + (BraketSimulator.Observables.H(), [2]), ], - [Instruction(H(), [0]), Instruction(Ry(-π / 4), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(-π / 4), [2])], 5, ), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.X(), - Braket.Observables.Z(), - Braket.Observables.H(), - Braket.Observables.I(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.X(), + BraketSimulator.Observables.Z(), + BraketSimulator.Observables.H(), + BraketSimulator.Observables.I(), ]), [0, 3, 2, 1], )], - [Instruction(H(), [0]), Instruction(Ry(-π / 4), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(-π / 4), [2])], 5, ), ( - [(Braket.Observables.X(), [0, 1])], - [Instruction(H(), [0]), Instruction(H(), [1])], + [(BraketSimulator.Observables.X(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1])], 2, ), - ([(Braket.Observables.Z(), [0, 1])], Instruction[], 2), - ([(Braket.Observables.I(), [0, 1])], Instruction[], 2), + ([(BraketSimulator.Observables.Z(), [0, 1])], BraketSimulator.Instruction[], 2), + ([(BraketSimulator.Observables.I(), [0, 1])], BraketSimulator.Instruction[], 2), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.I(), - Braket.Observables.Z(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.I(), + BraketSimulator.Observables.Z(), ]), [2, 0], )], - Instruction[], + BraketSimulator.Instruction[], 3, ), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.X(), - Braket.Observables.Z(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.X(), + BraketSimulator.Observables.Z(), ]), [2, 0], )], - [Instruction(H(), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [2])], 3, ), ] @@ -333,11 +331,11 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) simulation = DensityMatrixSimulator(4, 0) simulation = BraketSimulator.apply_observables!( simulation, - [(Braket.Observables.X(), [0])], + [(BraketSimulator.Observables.X(), [0])], ) @test_throws ErrorException BraketSimulator.apply_observables!( simulation, - [(Braket.Observables.X(), [0])], + [(BraketSimulator.Observables.X(), [0])], ) end @testset "state_with_observables fails before any observables are applied" begin @@ -346,14 +344,14 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) end @testset "QFT simulation" begin function qft_circuit_operations(qubit_count::Int) - qft_ops = Instruction[] + qft_ops = BraketSimulator.Instruction[] for target_qubit = 0:qubit_count-1 angle = π / 2 - push!(qft_ops, Instruction(H(), [target_qubit])) + push!(qft_ops, BraketSimulator.Instruction(BraketSimulator.H(), [target_qubit])) for control_qubit = target_qubit+1:qubit_count-1 push!( qft_ops, - Instruction(CPhaseShift(angle), [control_qubit, target_qubit]), + BraketSimulator.Instruction(BraketSimulator.CPhaseShift(angle), [control_qubit, target_qubit]), ) angle /= 2 end @@ -372,10 +370,10 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) @testset "samples" begin simulation = DensityMatrixSimulator(2, 10000) simulation = - evolve!(simulation, [Instruction(H(), [0]), Instruction(CNot(), [0, 1])]) + evolve!(simulation, [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1])]) samples = counter(BraketSimulator.samples(simulation)) - @test qubit_count(simulation) == 2 + @test BraketSimulator.qubit_count(simulation) == 2 @test collect(keys(samples)) == [0, 3] @test 0.4 < samples[0] / (samples[0] + samples[3]) < 0.6 @test 0.4 < samples[3] / (samples[0] + samples[3]) < 0.6 @@ -383,19 +381,18 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) end @testset "batch" begin function make_ghz(num_qubits) - ghz = Circuit() - ghz(H, 0) + ghz = BraketSimulator.Program(BraketSimulator.braketSchemaHeader("braket.ir.jaqcd.program", "1"), BraketSimulator.Instruction[BraketSimulator.Instruction(BraketSimulator.H(), 0)], BraketSimulator.AbstractProgramResult[], BraketSimulator.Instruction[]) for ii in 0:num_qubits-2 - ghz(CNot, ii, ii+1) + push!(ghz.instructions, BraketSimulator.Instruction(BraketSimulator.CNot(), [ii, ii+1])) end - return ir(ghz) + return ghz end num_qubits = 5 n_circuits = 100 shots = 1000 jl_ghz = [make_ghz(num_qubits) for ix in 1:n_circuits] jl_sim = DensityMatrixSimulator(num_qubits, 0); - results = simulate(jl_sim, jl_ghz, shots) + results = BraketSimulator.simulate(jl_sim, jl_ghz, shots) for (r_ix, r) in enumerate(results) @test length(r.measurements) == shots @test 400 < count(m->m == fill(0, num_qubits), r.measurements) < 600 @@ -471,5 +468,6 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) "phase_damping", "kraus", ] + @test BraketSimulator.supported_result_types(sim) == BraketSimulator.supported_result_types(sim, Val(:OpenQASM)) end end diff --git a/test/test_gate_operations.jl b/test/test_gate_operations.jl index 0162258..f9dae3b 100644 --- a/test/test_gate_operations.jl +++ b/test/test_gate_operations.jl @@ -1,7 +1,4 @@ -using Test, LinearAlgebra, Logging, Braket, BraketSimulator, DataStructures - -using Braket: Instruction -using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control +using Test, LinearAlgebra, Logging, BraketSimulator, DataStructures @testset "Gate operations" begin nq = 4 @@ -11,71 +8,161 @@ using BraketSimulator: DoubleExcitation, SingleExcitation, matrix_rep, Control q1_mat = [0 -im; im 0] q2_mat = [1 0 0 0; 0 1 0 0 ; 0 0 0 -im; 0 0 im 0] @testset "Inverted gates" begin - @testset "1q Gate $g" for g in [X(), Y(), Z(), H(), GPi(ϕ), GPi2(ϕ), Rx(ϕ), Ry(ϕ), Rz(ϕ), PRx(θ, ϕ), PhaseShift(ϕ), S(), Si(), T(), Ti(), V(), Vi(), U(θ, ϕ, λ), Unitary(q1_mat)] - @test inv(matrix_rep(g)) ≈ matrix_rep(inv(g)) - @test matrix_rep(inv(g)) * matrix_rep(g) ≈ Diagonal(ones(2)) + @testset "1q Gate $g" for g in [BraketSimulator.X(), + BraketSimulator.Y(), + BraketSimulator.Z(), + BraketSimulator.H(), + BraketSimulator.GPi(ϕ), + BraketSimulator.GPi2(ϕ), + BraketSimulator.Rx(ϕ), + BraketSimulator.Ry(ϕ), + BraketSimulator.Rz(ϕ), + BraketSimulator.PRx(θ, ϕ), + BraketSimulator.PhaseShift(ϕ), + BraketSimulator.S(), + BraketSimulator.Si(), + BraketSimulator.T(), + BraketSimulator.Ti(), + BraketSimulator.V(), + BraketSimulator.Vi(), + BraketSimulator.U(θ, ϕ, λ), + BraketSimulator.Unitary(q1_mat), + BraketSimulator.MultiQubitPhaseShift{1}(ϕ), + ] + @test inv(BraketSimulator.matrix_rep(g)) ≈ BraketSimulator.matrix_rep(inv(g)) + @test BraketSimulator.matrix_rep(inv(g)) * BraketSimulator.matrix_rep(g) ≈ Diagonal(ones(2)) sim = StateVectorSimulator(nq, 0) - instructions = [Instruction(H(), [q]) for q in 0:nq-1] - sim = evolve!(sim, instructions) + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1] + sim = BraketSimulator.evolve!(sim, instructions) new_sim = copy(sim) - new_sim = evolve!(new_sim, [Instruction(g, [0]), Instruction(inv(g), [0])]) + new_sim = BraketSimulator.evolve!(new_sim, [BraketSimulator.Instruction(g, [0]), BraketSimulator.Instruction(inv(g), [0])]) @test new_sim.state_vector ≈ sim.state_vector end - @testset "2q Gate $g" for g in [XX(ϕ), YY(ϕ), ZZ(ϕ), XY(ϕ), ECR(), Swap(), ISwap(), PSwap(ϕ), MS(θ, ϕ, λ), CPhaseShift(ϕ), CPhaseShift00(ϕ), CPhaseShift01(ϕ), CPhaseShift10(ϕ), Unitary(q2_mat), CNot(), CY(), CZ(), CV()] - @test inv(matrix_rep(g)) ≈ matrix_rep(inv(g)) - @test matrix_rep(inv(g)) * matrix_rep(g) ≈ Diagonal(ones(4)) + @testset "2q Gate $g" for g in [BraketSimulator.XX(ϕ), + BraketSimulator.YY(ϕ), + BraketSimulator.ZZ(ϕ), + BraketSimulator.XY(ϕ), + BraketSimulator.ECR(), + BraketSimulator.Swap(), + BraketSimulator.ISwap(), + BraketSimulator.PSwap(ϕ), + BraketSimulator.MS(θ, ϕ, λ), + BraketSimulator.CPhaseShift(ϕ), + BraketSimulator.CPhaseShift00(ϕ), + BraketSimulator.CPhaseShift01(ϕ), + BraketSimulator.CPhaseShift10(ϕ), + BraketSimulator.Unitary(q2_mat), + BraketSimulator.CNot(), + BraketSimulator.CY(), + BraketSimulator.CZ(), + BraketSimulator.CV(), + BraketSimulator.MultiQubitPhaseShift{2}(ϕ), + BraketSimulator.Control(BraketSimulator.MultiQubitPhaseShift{2}(ϕ), (0,0)), + BraketSimulator.Control(BraketSimulator.X(), (1,)), + BraketSimulator.Control(BraketSimulator.U(θ, ϕ, λ), (1,))] + @test inv(BraketSimulator.matrix_rep(g)) ≈ BraketSimulator.matrix_rep(inv(g)) + @test BraketSimulator.matrix_rep(inv(g)) * BraketSimulator.matrix_rep(g) ≈ Diagonal(ones(4)) sim = StateVectorSimulator(nq, 0) - instructions = [Instruction(H(), [q]) for q in 0:nq-1] - sim = evolve!(sim, instructions) + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1] + sim = BraketSimulator.evolve!(sim, instructions) new_sim = copy(sim) - new_sim = evolve!(new_sim, [Instruction(g, [0, 1]), Instruction(inv(g), [0, 1])]) + new_sim = BraketSimulator.evolve!(new_sim, [BraketSimulator.Instruction(g, [0, 1]), BraketSimulator.Instruction(inv(g), [0, 1])]) @test new_sim.state_vector ≈ sim.state_vector atol=1e-5 end - @testset "3q Gate $g" for g in [CCNot(), CSwap()] - @test inv(matrix_rep(g)) ≈ matrix_rep(inv(g)) - @test matrix_rep(inv(g)) * matrix_rep(g) ≈ Diagonal(ones(8)) + @testset "3q Gate $g" for g in [BraketSimulator.CCNot(), BraketSimulator.CSwap()] + @test inv(BraketSimulator.matrix_rep(g)) ≈ BraketSimulator.matrix_rep(inv(g)) + @test BraketSimulator.matrix_rep(inv(g)) * BraketSimulator.matrix_rep(g) ≈ Diagonal(ones(8)) sim = StateVectorSimulator(nq, 0) - instructions = [Instruction(H(), [q]) for q in 0:nq-1] - sim = evolve!(sim, instructions) + instructions = [BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1] + sim = BraketSimulator.evolve!(sim, instructions) new_sim = copy(sim) - new_sim = evolve!(new_sim, [Instruction(g, [0, 1, 3]), Instruction(inv(g), [0, 1, 3])]) + new_sim = BraketSimulator.evolve!(new_sim, [BraketSimulator.Instruction(g, [0, 1, 3]), BraketSimulator.Instruction(inv(g), [0, 1, 3])]) @test new_sim.state_vector ≈ sim.state_vector end end - @testset "Exponentiated gates" begin - @testset "1q Gate $g, pow $pow" for g in [X(), Y(), Z(), H(), GPi(ϕ), GPi2(ϕ), Rx(ϕ), Ry(ϕ), Rz(ϕ), PRx(θ, ϕ), PhaseShift(ϕ), S(), Si(), T(), Ti(), V(), Vi(), U(θ, ϕ, λ), Unitary(q1_mat), MultiQubitPhaseShift{1}(ϕ)], pow in (0, 1, 2, 3, 4) + @testset "Exponentiated gates - pow $pow" for pow in (-0.5, 0, 0.5, 1, 2, 2.5, 3, 4, -2) + @testset "1q Gate $g" for g in [BraketSimulator.X(), + BraketSimulator.Y(), + BraketSimulator.Z(), + BraketSimulator.H(), + BraketSimulator.GPi(ϕ), + BraketSimulator.GPi2(ϕ), + BraketSimulator.Rx(ϕ), + BraketSimulator.Ry(ϕ), + BraketSimulator.Rz(ϕ), + BraketSimulator.PRx(θ, ϕ), + BraketSimulator.PhaseShift(ϕ), + BraketSimulator.S(), + BraketSimulator.Si(), + BraketSimulator.T(), + BraketSimulator.Ti(), + BraketSimulator.V(), + BraketSimulator.Vi(), + BraketSimulator.U(θ, ϕ, λ), + BraketSimulator.Unitary(q1_mat), + BraketSimulator.MultiQubitPhaseShift{1}(ϕ) + ] sim = StateVectorSimulator(nq, 0) new_sim = StateVectorSimulator(nq, 0) - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(g^pow, [0])]) - new_instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(Unitary(Matrix(matrix_rep(g)^pow)), [0])]) - @test matrix_rep(g)^pow ≈ matrix_rep(g^pow) - sim = evolve!(sim, instructions) - new_sim = evolve!(new_sim, new_instructions) + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(g^pow, [0])]) + new_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(g)^pow)), [0])]) + @test BraketSimulator.matrix_rep(g)^pow ≈ BraketSimulator.matrix_rep(g^pow) + sim = BraketSimulator.evolve!(sim, instructions) + new_sim = BraketSimulator.evolve!(new_sim, new_instructions) @test new_sim.state_vector ≈ sim.state_vector end - @testset "2q Gate $g, pow $pow" for g in [XX(ϕ), YY(ϕ), ZZ(ϕ), XY(ϕ), CNot(), CY(), CZ(), CV(), ECR(), Swap(), ISwap(), PSwap(ϕ), MS(θ, ϕ, λ), CPhaseShift(ϕ), CPhaseShift00(ϕ), CPhaseShift01(ϕ), CPhaseShift10(ϕ), Unitary(q2_mat), MultiQubitPhaseShift{2}(ϕ), Control(MultiQubitPhaseShift{2}(ϕ), (0,0)), Control(X(), (1,))], pow in (0, 1, 2, 3, 4) + @testset "2q Gate $g" for g in [BraketSimulator.XX(ϕ), + BraketSimulator.YY(ϕ), + BraketSimulator.ZZ(ϕ), + BraketSimulator.XY(ϕ), + BraketSimulator.ECR(), + BraketSimulator.Swap(), + BraketSimulator.ISwap(), + BraketSimulator.PSwap(ϕ), + BraketSimulator.MS(θ, ϕ, λ), + BraketSimulator.CPhaseShift(ϕ), + BraketSimulator.CPhaseShift00(ϕ), + BraketSimulator.CPhaseShift01(ϕ), + BraketSimulator.CPhaseShift10(ϕ), + BraketSimulator.Unitary(q2_mat), + BraketSimulator.Control(BraketSimulator.MultiQubitPhaseShift{2}(ϕ), (0,0)), + BraketSimulator.MultiQubitPhaseShift{2}(ϕ),] sim = StateVectorSimulator(nq, 0) new_sim = StateVectorSimulator(nq, 0) - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(g^pow, [0, 1])]) - new_ixs = [Instruction(g, [0, 1]) for p in 1:pow] - new_instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], new_ixs) - if !isa(g^pow, Braket.I) - @test Matrix(matrix_rep(g))^pow ≈ Matrix(matrix_rep(g^pow)) - end - sim = evolve!(sim, instructions) - new_sim = evolve!(new_sim, new_instructions) + new_ixs = [BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(g)^pow)), [0, 1])] + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), q) for q in 0:nq-1], [BraketSimulator.Instruction(g^pow, [0, 1])]) + new_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), q) for q in 0:nq-1], new_ixs) + @test Matrix(BraketSimulator.matrix_rep(g))^pow ≈ Matrix(BraketSimulator.matrix_rep(g^pow)) + sim = BraketSimulator.evolve!(sim, instructions) + new_sim = BraketSimulator.evolve!(new_sim, new_instructions) + @test new_sim.state_vector ≈ sim.state_vector + end + @testset "2q Gate $g" for (g,tg) in [(BraketSimulator.CNot(), BraketSimulator.X()), + (BraketSimulator.CY(), BraketSimulator.Y()), + (BraketSimulator.CZ(), BraketSimulator.Z()), + (BraketSimulator.CV(), BraketSimulator.V()), + (BraketSimulator.Control(BraketSimulator.X(), (1,)), BraketSimulator.X()), + (BraketSimulator.Control(BraketSimulator.U(θ, ϕ, λ), (1,)), BraketSimulator.U(θ, ϕ, λ))] + sim = StateVectorSimulator(nq, 0) + new_sim = StateVectorSimulator(nq, 0) + new_ixs = [BraketSimulator.Instruction(BraketSimulator.Control(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(tg)^pow)), (1,)), [0, 1])] + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), q) for q in 0:nq-1], [BraketSimulator.Instruction(g^pow, [0, 1])]) + new_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), q) for q in 0:nq-1], new_ixs) + sim = BraketSimulator.evolve!(sim, instructions) + new_sim = BraketSimulator.evolve!(new_sim, new_instructions) @test new_sim.state_vector ≈ sim.state_vector end - @testset "3q Gate $g, pow $pow" for g in [CCNot(), CSwap()], pow in (0, 1, 2, 3, 4) + @testset "3q Gate $g" for g in [BraketSimulator.CCNot(), BraketSimulator.CSwap()] + nq = 5 sim = StateVectorSimulator(nq, 0) new_sim = StateVectorSimulator(nq, 0) - instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(g^pow, [0, 1, 3])]) - new_instructions = vcat([Instruction(H(), [q]) for q in 0:nq-1], [Instruction(Unitary(Matrix(matrix_rep(g)^pow)), [0, 1, 3])]) - if !isa(g^pow, Braket.I) - @test matrix_rep(g)^pow ≈ matrix_rep(g^pow) + instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(g^pow, [0, 1, 3])]) + new_instructions = vcat([BraketSimulator.Instruction(BraketSimulator.H(), [q]) for q in 0:nq-1], [BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(BraketSimulator.matrix_rep(g)^pow)), [0, 1, 3])]) + if !isa(g^pow, BraketSimulator.I) + @test BraketSimulator.matrix_rep(g)^pow ≈ BraketSimulator.matrix_rep(g^pow) end - sim = evolve!(sim, instructions) - new_sim = evolve!(new_sim, new_instructions) + sim = BraketSimulator.evolve!(sim, instructions) + new_sim = BraketSimulator.evolve!(new_sim, new_instructions) @test new_sim.state_vector ≈ sim.state_vector end end diff --git a/test/test_gates.jl b/test/test_gates.jl new file mode 100644 index 0000000..ddedd65 --- /dev/null +++ b/test/test_gates.jl @@ -0,0 +1,257 @@ +using Test, BraketSimulator, LinearAlgebra + +CCNot_mat = round.(reduce(hcat, [[1.0, 0, 0, 0, 0, 0, 0, 0], + [0, 1.0, 0, 0, 0, 0, 0, 0], + [0, 0, 1.0, 0, 0, 0, 0, 0], + [0, 0, 0, 1.0, 0, 0, 0, 0], + [0, 0, 0, 0, 1.0, 0, 0, 0], + [0, 0, 0, 0, 0, 1.0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1.0], + [0, 0, 0, 0, 0, 0, 1.0, 0]]), digits=8) +ECR_mat = round.(reduce(hcat, [[0, 0, 0.70710678, 0.70710678im], + [0, 0, 0.70710678im, 0.70710678], + [0.70710678, -0.70710678im, 0, 0], + [-0.70710678im, 0.70710678, 0, 0]]), digits=8) +T_mat = round.(reduce(hcat, [[1.0, 0], [0, 0.70710678 + 0.70710678im]]), digits=8) + +@testset "Gates" begin + @testset for g in (BraketSimulator.H(), + BraketSimulator.I(), + BraketSimulator.X(), + BraketSimulator.Y(), + BraketSimulator.Z(), + BraketSimulator.S(), + BraketSimulator.Si(), + BraketSimulator.T(), + BraketSimulator.Ti(), + BraketSimulator.V(), + BraketSimulator.Vi()) + @test qubit_count(g) == 1 + @test qubit_count(typeof(g)) == 1 + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, BraketSimulator.Instruction(g, 0)) + @test c.instructions == [BraketSimulator.Instruction(g, 0)] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.NonParametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 0 + @test BraketSimulator.qubit_count(g) == 1 + end + @testset for g in (BraketSimulator.CNot(), + BraketSimulator.Swap(), + BraketSimulator.ISwap(), + BraketSimulator.CV(), + BraketSimulator.CY(), + BraketSimulator.CZ(), + BraketSimulator.ECR()) + @test qubit_count(g) == 2 + @test qubit_count(typeof(g)) == 2 + ix = BraketSimulator.Instruction(g, [0, 1]) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + ix = BraketSimulator.Instruction(g, [10, 1]) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.NonParametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 0 + @test BraketSimulator.qubit_count(g) == 2 + end + @testset for g in (BraketSimulator.CCNot(), BraketSimulator.CSwap()) + @test qubit_count(g) == 3 + @test qubit_count(typeof(g)) == 3 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, [0, 1, 2]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.NonParametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 0 + @test BraketSimulator.qubit_count(g) == 3 + end + α = BraketSimulator.FreeParameter(:α) + β = BraketSimulator.FreeParameter(:β) + γ = BraketSimulator.FreeParameter(:γ) + @testset for (angle1, angle2, angle3) in ((rand(), rand(), rand()), (π, rand(), rand())) + @testset for g in (BraketSimulator.Rx(angle1), BraketSimulator.Ry(angle1), BraketSimulator.Rz(angle1), BraketSimulator.PhaseShift(angle1)) + @test qubit_count(g) == 1 + @test qubit_count(typeof(g)) == 1 + ix = BraketSimulator.Instruction(g, 0) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 1 + @test BraketSimulator.qubit_count(g) == 1 + end + @testset for g in (BraketSimulator.Rx, BraketSimulator.Ry, BraketSimulator.Rz, BraketSimulator.PhaseShift) + @test qubit_count(g) == 1 + ix = BraketSimulator.Instruction(g(α), 0) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g(α)) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g(α)) == BraketSimulator.FreeParameter[α] + bound_g = BraketSimulator.bind_value!(BraketSimulator.Parametrized(), g(α), Dict(:α=>angle1)) + @test bound_g == g(angle1) + end + @testset for g in (BraketSimulator.PSwap(angle1), + BraketSimulator.XY(angle1), + BraketSimulator.CPhaseShift(angle1), + BraketSimulator.CPhaseShift00(angle1), + BraketSimulator.CPhaseShift01(angle1), + BraketSimulator.CPhaseShift10(angle1), + BraketSimulator.XX(angle1), + BraketSimulator.YY(angle1), + BraketSimulator.ZZ(angle1)) + @test qubit_count(g) == 2 + @test qubit_count(typeof(g)) == 2 + ix = BraketSimulator.Instruction(g, [0, 1]) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 1 + @test BraketSimulator.qubit_count(g) == 2 + end + @testset for g in (BraketSimulator.PSwap, BraketSimulator.XY, BraketSimulator.CPhaseShift, BraketSimulator.CPhaseShift00, BraketSimulator.CPhaseShift01, BraketSimulator.CPhaseShift10, BraketSimulator.XX, BraketSimulator.YY, BraketSimulator.ZZ) + @test qubit_count(g) == 2 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α), [0, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α), [10, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g(α)) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g(α)) == BraketSimulator.FreeParameter[α] + bound_g = BraketSimulator.bind_value!(BraketSimulator.Parametrized(), g(α), Dict(:α=>angle1)) + @test bound_g == g(angle1) + end + @testset for g in (BraketSimulator.MS(angle1, angle2, angle3),) + @test qubit_count(g) == 2 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, [0, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, [10, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 3 + @test BraketSimulator.qubit_count(g) == 2 + end + @testset for g in (BraketSimulator.MS,) + @test qubit_count(g) == 2 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α, β, γ), [0, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α, β, γ), [10, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g(α, β, γ)) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g(α, β, γ)) == BraketSimulator.FreeParameter[α, β, γ] + bound_g = BraketSimulator.bind_value!(BraketSimulator.Parametrized(), g(α, β, γ), Dict(:α=>angle1, :β=>angle2, :γ=>angle3)) + @test bound_g == g(angle1, angle2, angle3) + end + @testset for g in (BraketSimulator.U(angle1, angle2, angle3),) + @test qubit_count(g) == 1 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, 0) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 3 + @test BraketSimulator.qubit_count(g) == 1 + end + @testset for g in (BraketSimulator.U,) + @test qubit_count(g) == 1 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α, β, γ), 0) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g(α, β, γ)) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g(α, β, γ)) == BraketSimulator.FreeParameter[α, β, γ] + bound_g = BraketSimulator.bind_value!(BraketSimulator.Parametrized(), g(α, β, γ), Dict(:α=>angle1, :β=>angle2, :γ=>angle3)) + @test bound_g == g(angle1, angle2, angle3) + end + @testset for g in (BraketSimulator.PRx(angle1, angle2),) + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, 0) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g) == BraketSimulator.FreeParameter[] + @test BraketSimulator.n_angles(g) == 2 + @test BraketSimulator.qubit_count(g) == 1 + end + @testset for g in (BraketSimulator.PRx,) + @test qubit_count(g) == 1 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g(α, β), 0) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + @test BraketSimulator.Parametrizable(g(α, β)) == BraketSimulator.Parametrized() + @test BraketSimulator.parameters(g(α, β)) == BraketSimulator.FreeParameter[α, β] + bound_g = BraketSimulator.bind_value!(BraketSimulator.Parametrized(), g(α, β), Dict(:α=>angle1, :β=>angle2)) + @test bound_g == g(angle1, angle2) + end + end + @testset "g = Unitary" begin + X = complex([0. 1.; 1. 0.]) + Y = [0. -im; im 0.] + g = BraketSimulator.Unitary(X) + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, 0) + @test BraketSimulator.qubit_count(g) == 1 + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + g = BraketSimulator.Unitary(kron(X, X)) + @test BraketSimulator.qubit_count(g) == 2 + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, [0, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(g, [0, 1]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + g = BraketSimulator.Unitary(kron(Y, Y)) + @test BraketSimulator.qubit_count(g) == 2 + ix = BraketSimulator.Instruction(g, [0, 1]) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + end + @testset "Angled 3 qubit gates" begin + # build some "fake" (for now) 3 qubit gates to test gate applicators + mutable struct CCPhaseShift <: BraketSimulator.AngledGate{1} + angle::NTuple{1, Union{Real, BraketSimulator.FreeParameter}} + pow_exponent::Float64 + CCPhaseShift(angle::T, pow_exponent::Float64=1.0) where {T<:NTuple{1, Union{Real, FreeParameter}}} = new(angle, pow_exponent) + end + mutable struct CXX <: BraketSimulator.AngledGate{1} + angle::NTuple{1, Union{Float64, BraketSimulator.FreeParameter}} + pow_exponent::Float64 + CXX(angle::T, pow_exponent::Float64=1.0) where {T<:NTuple{1, Union{Real, FreeParameter}}} = new(angle, pow_exponent) + end + angle = rand() + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(CCPhaseShift(angle), [0, 1, 2]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + c = BraketSimulator.Circuit() + ix = BraketSimulator.Instruction(CXX(angle), [0, 1, 2]) + BraketSimulator.add_instruction!(c, ix) + @test c.instructions == [ix] + end +end diff --git a/test/test_noises.jl b/test/test_noises.jl new file mode 100644 index 0000000..6f2da32 --- /dev/null +++ b/test/test_noises.jl @@ -0,0 +1,60 @@ +using Test, BraketSimulator, LinearAlgebra + +struct CustomNoise <: BraketSimulator.Noise end + +@testset "Noises" begin + @testset for noise in (BraketSimulator.BitFlip, BraketSimulator.PhaseFlip, BraketSimulator.AmplitudeDamping, BraketSimulator.PhaseDamping, BraketSimulator.Depolarizing) + n = noise(0.1) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset "noise = PauliChannel" begin + n = BraketSimulator.PauliChannel(0.1, 0.2, 0.1) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset "noise = MultiQubitPauliChannel{1}" begin + n = BraketSimulator.MultiQubitPauliChannel{1}(Dict("X"=>0.1, "Y"=>0.2)) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + n = BraketSimulator.MultiQubitPauliChannel(Dict("X"=>0.1, "Y"=>0.2)) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset "noise = BraketSimulator.TwoQubitPauliChannel" begin + n = BraketSimulator.TwoQubitPauliChannel(Dict("XX"=>0.1, "YY"=>0.2)) + @test BraketSimulator.qubit_count(n) == 2 + ix = BraketSimulator.Instruction(n, [0, 1]) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset for noise in (BraketSimulator.TwoQubitDephasing, BraketSimulator.TwoQubitDepolarizing) + n = noise(0.4) + @test BraketSimulator.qubit_count(n) == 2 + ix = BraketSimulator.Instruction(n, [0, 1]) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset "noise = GeneralizedAmplitudeDamping" begin + n = BraketSimulator.GeneralizedAmplitudeDamping(0.1, 0.2) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.Parametrized() + end + @testset "noise = Kraus" begin + mat = complex([0 1; 1 0]) + n = BraketSimulator.Kraus([mat]) + @test BraketSimulator.qubit_count(n) == 1 + ix = BraketSimulator.Instruction(n, 0) + @test BraketSimulator.Parametrizable(n) == BraketSimulator.NonParametrized() + end + @testset "fallback" begin + n = CustomNoise() + @test BraketSimulator.bind_value!(n, Dict(:theta=>0.1)) === n + @test BraketSimulator.parameters(n) == BraketSimulator.FreeParameter[] + @test BraketSimulator.Parametrizable(n) == BraketSimulator.NonParametrized() + end + @test BraketSimulator.StructTypes.StructType(Noise) == BraketSimulator.StructTypes.AbstractType() +end diff --git a/test/test_observables.jl b/test/test_observables.jl index 7db4a50..8bd33df 100644 --- a/test/test_observables.jl +++ b/test/test_observables.jl @@ -1,40 +1,44 @@ -using Test, LinearAlgebra, Braket, Braket.Observables, BraketSimulator -import Braket: Instruction, PauliEigenvalues +using Test, LinearAlgebra, BraketSimulator.Observables, BraketSimulator herm_mat = [-0.32505758-0.32505758im 0.88807383; 0.62796303+0.62796303im 0.45970084] single_qubit_tests = [ - (Observables.H(), (Ry(-π / 4),), PauliEigenvalues(Val(1))), - (Observables.X(), (H(),), PauliEigenvalues(Val(1))), - (Observables.Y(), (Z(), S(), H()), PauliEigenvalues(Val(1))), - (Observables.Z(), (), PauliEigenvalues(Val(1))), + (Observables.H(), (BraketSimulator.Ry(-π / 4),), BraketSimulator.PauliEigenvalues(Val(1))), + (Observables.X(), (BraketSimulator.H(),), BraketSimulator.PauliEigenvalues(Val(1))), + (Observables.Y(), (BraketSimulator.Z(), BraketSimulator.S(), BraketSimulator.H()), BraketSimulator.PauliEigenvalues(Val(1))), + (Observables.Z(), (), BraketSimulator.PauliEigenvalues(Val(1))), (Observables.I(), (), [1, 1]), - (Observables.HermitianObservable([1 1-im; 1+im -1]), (Unitary(herm_mat),), [-√3, √3]), + (Observables.HermitianObservable([1 1-im; 1+im -1]), (BraketSimulator.Unitary(herm_mat),), [-√3, √3]), ] @testset "Observables" begin @testset "Single qubit $obs" for (obs, expected_gates, eigenvalues) in single_qubit_tests - actual_gates = Braket.basis_rotation_gates(obs) + actual_gates = BraketSimulator.basis_rotation_gates(obs) for (actual_gate, expected_gate) in zip(actual_gates, expected_gates) @test BraketSimulator.matrix_rep(actual_gate) ≈ BraketSimulator.matrix_rep(expected_gate) end @test collect(eigvals(obs)) ≈ collect(eigenvalues) + @test BraketSimulator.qubit_count(obs) == 1 + @test ishermitian(obs) + @test copy(obs) == obs + if !(obs isa Observables.HermitianObservable) + @test BraketSimulator.Observables.unscaled(2.0 * obs) == obs + end end - @testset "Tensor product of Pauli-like (with eigenvalues ±1) observables" begin - tensor = Observables.TensorProduct([ - Observables.H(), - Observables.X(), - Observables.Z(), - Observables.Y(), - ]) - @test eigvals(tensor) == PauliEigenvalues(Val(4)) + @testset "Tensor product of BraketSimulator.Pauli-like (with eigenvalues ±1) observables" begin + tensor = Observables.TensorProduct(["h", "x", "z", "y"]) + @test eigvals(tensor) == BraketSimulator.PauliEigenvalues(Val(4)) - actual_gates = Braket.basis_rotation_gates(tensor) + actual_gates = BraketSimulator.basis_rotation_gates(tensor) @test length(actual_gates) == 4 - @test actual_gates[1] == Braket.basis_rotation_gates(Observables.H()) - @test actual_gates[2] == Braket.basis_rotation_gates(Observables.X()) - @test actual_gates[4] == Braket.basis_rotation_gates(Observables.Y()) + @test actual_gates[1] == BraketSimulator.basis_rotation_gates(Observables.H()) + @test actual_gates[2] == BraketSimulator.basis_rotation_gates(Observables.X()) + @test actual_gates[4] == BraketSimulator.basis_rotation_gates(Observables.Y()) + @test BraketSimulator.qubit_count(tensor) == 4 + @test ishermitian(tensor) + @test copy(tensor) == tensor + @test BraketSimulator.Observables.unscaled(2.0 * tensor) == tensor end @testset "Tensor product of arbitrary observables" begin tensor = Observables.TensorProduct([ @@ -45,10 +49,13 @@ single_qubit_tests = [ Observables.Y(), ]) @test eigvals(tensor) == mapreduce(eigvals, kron, tensor.factors) - actual_gates = Braket.basis_rotation_gates(tensor) + actual_gates = BraketSimulator.basis_rotation_gates(tensor) @test length(actual_gates) == 5 - @test actual_gates[1] == Braket.basis_rotation_gates(Observables.H()) - @test actual_gates[3] == Braket.basis_rotation_gates(Observables.X()) - @test actual_gates[5] == Braket.basis_rotation_gates(Observables.Y()) + @test actual_gates[1] == BraketSimulator.basis_rotation_gates(Observables.H()) + @test actual_gates[3] == BraketSimulator.basis_rotation_gates(Observables.X()) + @test actual_gates[5] == BraketSimulator.basis_rotation_gates(Observables.Y()) + @test ishermitian(tensor) + @test copy(tensor) == tensor + @test BraketSimulator.Observables.unscaled(2.0 * tensor) == tensor end end diff --git a/test/test_openqasm3.jl b/test/test_openqasm3.jl index 3601154..01278d9 100644 --- a/test/test_openqasm3.jl +++ b/test/test_openqasm3.jl @@ -1,6 +1,4 @@ -using BraketSimulator.Quasar, Braket, Statistics, LinearAlgebra, BraketSimulator, Braket.Observables - -using Braket: Instruction +using BraketSimulator.Quasar, Statistics, LinearAlgebra, BraketSimulator, BraketSimulator.Observables get_tol(shots::Int) = return ( shots > 0 ? Dict("atol" => 0.1, "rtol" => 0.15) : Dict("atol" => 0.01, "rtol" => 0) @@ -10,6 +8,19 @@ get_tol(shots::Int) = return ( @testset "Printing" begin expr = Quasar.QasmExpression(:head, Quasar.QasmExpression(:integer_literal, 2)) @test sprint(show, expr) == "QasmExpression :head\n└─ QasmExpression :integer_literal\n └─ 2\n" + bad_expression = Quasar.QasmExpression(:invalid_expression, Quasar.QasmExpression(:error)) + err = Quasar.QasmVisitorError("unable to evaluate expression $bad_expression") + @test sprint(showerror, err) == "QasmVisitorError: unable to evaluate expression $bad_expression" + end + @testset "Expression basics" begin + expr = Quasar.QasmExpression(:head, Quasar.QasmExpression(:integer_literal, 2)) + @test length(expr) == 1 + push!(expr, Quasar.QasmExpression(:integer_literal, 3)) + @test length(expr.args) == 2 + append!(expr, Quasar.QasmExpression(:integer_literal, 4)) + @test length(expr.args) == 3 + append!(expr, [Quasar.QasmExpression(:integer_literal, 5), Quasar.QasmExpression(:integer_literal, 6)]) + @test length(expr.args) == 5 end @testset "Equality" begin expr_a = Quasar.QasmExpression(:head, Quasar.QasmExpression(:integer_literal, 2)) @@ -44,20 +55,20 @@ get_tol(shots::Int) = return ( for_visitor = Quasar.QasmForLoopVisitor(visitor) @test Quasar.function_defs(for_visitor) == Quasar.function_defs(visitor) @test Quasar.qubit_defs(for_visitor) == Quasar.qubit_defs(visitor) - @test Braket.qubit_count(for_visitor) == Quasar.qubit_count(visitor) - push!(for_visitor, Amplitude("00")) - @test visitor.results[1] == Amplitude("00") - push!(for_visitor, [Braket.StateVector(), Probability()]) - @test visitor.results[2] == Braket.StateVector() - @test visitor.results[3] == Probability() - push!(for_visitor, [Instruction(X(), 0), Instruction(Y(), 1)]) - @test visitor.instructions == [Instruction(X(), 0), Instruction(X(), 0), Instruction(Y(), 1)] - gate_visitor = Quasar.QasmGateDefVisitor(visitor, Dict{String, FreeParameter}(), Dict{String, Quasar.Qubit}(), Dict{String, Vector{Int}}(), 0, Instruction[]) - push!(gate_visitor, [Instruction(X(), 0), Instruction(Y(), 1)]) - @test gate_visitor.instructions == [Instruction(X(), 0), Instruction(Y(), 1)] + @test BraketSimulator.qubit_count(for_visitor) == Quasar.qubit_count(visitor) + push!(for_visitor, BraketSimulator.Amplitude("00")) + @test visitor.results[1] == BraketSimulator.Amplitude("00") + push!(for_visitor, [BraketSimulator.StateVector(), BraketSimulator.Probability()]) + @test visitor.results[2] == BraketSimulator.StateVector() + @test visitor.results[3] == BraketSimulator.Probability() + push!(for_visitor, [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)]) + @test visitor.instructions == [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)] + gate_visitor = Quasar.QasmGateDefVisitor(visitor, Dict{String, FreeParameter}(), Dict{String, Quasar.Qubit}(), Dict{String, Vector{Int}}(), 0, BraketSimulator.Instruction[]) + push!(gate_visitor, [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)]) + @test gate_visitor.instructions == [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)] function_visitor = Quasar.QasmFunctionVisitor(visitor, Quasar.QasmExpression[], Quasar.QasmExpression[]) - push!(function_visitor, [Instruction(X(), 0), Instruction(Y(), 1)]) - @test function_visitor.instructions == [Instruction(X(), 0), Instruction(Y(), 1)] + push!(function_visitor, [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)]) + @test function_visitor.instructions == [BraketSimulator.Instruction(BraketSimulator.X(), 0), BraketSimulator.Instruction(BraketSimulator.Y(), 1)] end @testset "Sized types" begin for (t_string, T) in (("SizedBitVector", Quasar.SizedBitVector), @@ -72,6 +83,8 @@ get_tol(shots::Int) = return ( @test sprint(show, array_object) == "SizedArray{" * t_string * "{4}, 1}" @test_throws BoundsError size(array_object, 1) @test size(array_object, 0) == 10 + new_object = T(object) + @test sprint(show, new_object) == t_string * "{4}" end bitvector = Quasar.SizedBitVector(Quasar.QasmExpression(:integer_literal, 10)) @test length(bitvector) == Quasar.QasmExpression(:integer_literal, 10) @@ -124,41 +137,43 @@ get_tol(shots::Int) = return ( visitor(parsed) @test visitor.qubit_count == 10 correct_instructions = [ - Instruction{X}(X(), QubitSet(6)) - Instruction{X}(X(), QubitSet(3)) - Instruction{X}(X(), QubitSet(7)) - Instruction{X}(X(), QubitSet(4)) - Instruction{X}(X(), QubitSet(8)) - Instruction{CNot}(CNot(), QubitSet(4, 8)) - Instruction{CNot}(CNot(), QubitSet(4, 0)) - Instruction{CCNot}(CCNot(), QubitSet(0, 8, 4)) - Instruction{CNot}(CNot(), QubitSet(3, 7)) - Instruction{CNot}(CNot(), QubitSet(3, 4)) - Instruction{CCNot}(CCNot(), QubitSet(4, 7, 3)) - Instruction{CNot}(CNot(), QubitSet(2, 6)) - Instruction{CNot}(CNot(), QubitSet(2, 3)) - Instruction{CCNot}(CCNot(), QubitSet(3, 6, 2)) - Instruction{CNot}(CNot(), QubitSet(1, 5)) - Instruction{CNot}(CNot(), QubitSet(1, 2)) - Instruction{CCNot}(CCNot(), QubitSet(2, 5, 1)) - Instruction{CNot}(CNot(), QubitSet(1, 9)) - Instruction{CCNot}(CCNot(), QubitSet(2, 5, 1)) - Instruction{CNot}(CNot(), QubitSet(1, 2)) - Instruction{CNot}(CNot(), QubitSet(2, 5)) - Instruction{CCNot}(CCNot(), QubitSet(3, 6, 2)) - Instruction{CNot}(CNot(), QubitSet(2, 3)) - Instruction{CNot}(CNot(), QubitSet(3, 6)) - Instruction{CCNot}(CCNot(), QubitSet(4, 7, 3)) - Instruction{CNot}(CNot(), QubitSet(3, 4)) - Instruction{CNot}(CNot(), QubitSet(4, 7)) - Instruction{CCNot}(CCNot(), QubitSet(0, 8, 4)) - Instruction{CNot}(CNot(), QubitSet(4, 0)) - Instruction{CNot}(CNot(), QubitSet(0, 8)) + BraketSimulator.Instruction(BraketSimulator.X(), BraketSimulator.QubitSet(6)) + BraketSimulator.Instruction(BraketSimulator.X(), BraketSimulator.QubitSet(3)) + BraketSimulator.Instruction(BraketSimulator.X(), BraketSimulator.QubitSet(7)) + BraketSimulator.Instruction(BraketSimulator.X(), BraketSimulator.QubitSet(4)) + BraketSimulator.Instruction(BraketSimulator.X(), BraketSimulator.QubitSet(8)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(4, 8)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(4, 0)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(0, 8, 4)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(3, 7)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(3, 4)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(4, 7, 3)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(2, 6)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(2, 3)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(3, 6, 2)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(1, 5)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(1, 2)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(2, 5, 1)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(1, 9)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(2, 5, 1)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(1, 2)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(2, 5)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(3, 6, 2)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(2, 3)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(3, 6)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(4, 7, 3)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(3, 4)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(4, 7)) + BraketSimulator.Instruction(BraketSimulator.CCNot(), BraketSimulator.QubitSet(0, 8, 4)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(4, 0)) + BraketSimulator.Instruction(BraketSimulator.CNot(), BraketSimulator.QubitSet(0, 8)) ] for (ix, c_ix) in zip(visitor.instructions, correct_instructions) @test ix == c_ix end - @test visitor.results == Result[Probability(QubitSet(9, 5, 6, 7, 8)), Probability(QubitSet(9)), Probability(QubitSet(5, 6, 7, 8))] + @test visitor.results == BraketSimulator.Result[BraketSimulator.Probability(BraketSimulator.QubitSet(9, 5, 6, 7, 8)), + BraketSimulator.Probability(BraketSimulator.QubitSet(9)), + BraketSimulator.Probability(BraketSimulator.QubitSet(5, 6, 7, 8))] end @testset "Randomized Benchmarking" begin qasm = """ @@ -174,8 +189,16 @@ get_tol(shots::Int) = return ( h q[0]; measure q -> c; """ - circuit = Circuit(qasm) - @test circuit.instructions == [Instruction(H(), 0), Instruction(CZ(), [0, 1]), Instruction(S(), 0), Instruction(CZ(), [0, 1]), Instruction(S(), 0), Instruction(Z(), 0), Instruction(H(), 0), Instruction(Measure(), 0), Instruction(Measure(), 1)] + circuit = BraketSimulator.Circuit(qasm) + @test circuit.instructions == [BraketSimulator.Instruction(BraketSimulator.H(), 0), + BraketSimulator.Instruction(BraketSimulator.CZ(), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.S(), 0), + BraketSimulator.Instruction(BraketSimulator.CZ(), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.S(), 0), + BraketSimulator.Instruction(BraketSimulator.Z(), 0), + BraketSimulator.Instruction(BraketSimulator.H(), 0), + BraketSimulator.Instruction(BraketSimulator.Measure(), 0), + BraketSimulator.Instruction(BraketSimulator.Measure(), 1)] end @testset "GPhase" begin qasm = """ @@ -201,12 +224,12 @@ get_tol(shots::Int) = return ( negctrl @ ctrl @ gphase(2 * π) qs[0], qs[1]; #pragma braket result amplitude '00', '01', '10', '11' """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(2, 0) BraketSimulator.evolve!(simulation, circuit.instructions) sv = 1/√2 * [-1; 0; 0; 1] @test simulation.state_vector ≈ sv - @test circuit.result_types == [Amplitude(["00", "01", "10", "11"])] + @test circuit.result_types == [BraketSimulator.Amplitude(["00", "01", "10", "11"])] end @testset "Numbers" begin qasm = """ @@ -234,7 +257,7 @@ get_tol(shots::Int) = return ( h \$0; cnot \$0, \$1; """ - @test Circuit(qasm) == Circuit([(H, 0), (CNot, 0, 1)]) + @test BraketSimulator.Circuit(qasm).instructions == [BraketSimulator.Instruction(BraketSimulator.H(), 0), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1])] end @testset "For loop and subroutines" begin qasm_str = """ @@ -258,11 +281,22 @@ get_tol(shots::Int) = return ( __bit_0__[2] = measure __qubits__[2]; __bit_0__[3] = measure __qubits__[3]; """ - braket_circ = Circuit([(H, 0), (CNot, 0, 1), (H, 2), (CNot, 2, 3), (H, 2), (CNot, 2, 3), (H, 2), (CNot, 2, 3), (H, 2), (CNot, 2, 3), (H, 2), (CNot, 2, 3)]) inputs = Dict("theta"=>0.2) - parsed_circ = Circuit(qasm_str, inputs) + parsed_circ = BraketSimulator.Circuit(qasm_str, inputs) deleteat!(parsed_circ.instructions, length(parsed_circ.instructions)-3:length(parsed_circ.instructions)) - @test ir(parsed_circ, Val(:JAQCD)) == Braket.Program(braket_circ) + @test parsed_circ.instructions == [BraketSimulator.Instruction(BraketSimulator.H(), 0), + BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.CNot(), [2, 3]) + ] end @testset "For Loop" begin qasm = """ @@ -459,25 +493,25 @@ get_tol(shots::Int) = return ( x = 1.0 y = 2.0 inputs = Dict("x"=>x, "y"=>y) - parsed_circ = Circuit(qasm, inputs) - ixs = [Braket.Instruction(Rx(x), 0), - Braket.Instruction(Rx(acos(x)), 0), - Braket.Instruction(Rx(asin(x)), 0), - Braket.Instruction(Rx(atan(x)), 0), - Braket.Instruction(Rx(ceil(x)), 0), - Braket.Instruction(Rx(cos(x)), 0), - Braket.Instruction(Rx(exp(x)), 0), - Braket.Instruction(Rx(floor(x)), 0), - Braket.Instruction(Rx(log(x)), 0), - Braket.Instruction(Rx(mod(x, y)), 0), - Braket.Instruction(Rx(sin(x)), 0), - Braket.Instruction(Rx(sqrt(x)), 0), - Braket.Instruction(Rx(tan(x)), 0)] - c = Circuit() + parsed_circ = BraketSimulator.Circuit(qasm, inputs) + ixs = [BraketSimulator.Instruction(BraketSimulator.Rx(x), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(acos(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(asin(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(atan(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(ceil(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(cos(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(exp(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(floor(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(log(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(mod(x, y)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(sin(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(sqrt(x)), 0), + BraketSimulator.Instruction(BraketSimulator.Rx(tan(x)), 0)] + c = BraketSimulator.Circuit() for ix in ixs - Braket.add_instruction!(c, ix) + BraketSimulator.add_instruction!(c, ix) end - @test parsed_circ == c + @test parsed_circ.instructions == c.instructions end end @testset "Bad pragma" begin @@ -493,7 +527,7 @@ get_tol(shots::Int) = return ( x q[0]; reset q[0]; """ - @test_throws Quasar.QasmParseError parse_qasm(qasm) + @test_warn "reset expression encountered -- currently `reset` is a no-op" parse_qasm(qasm) end @testset "Gate call missing/extra args" begin qasm = """ @@ -518,9 +552,9 @@ get_tol(shots::Int) = return ( rx(theta) q[0]; #pragma braket result adjoint_gradient expectation(-6 * y(q[0]) @ i(q[1]) + 0.75 * y(q[2]) @ z(q[3])) theta """ - circuit = Circuit(qasm, Dict("theta"=>0.1)) + circuit = BraketSimulator.Circuit(qasm, Dict("theta"=>0.1)) θ = FreeParameter("theta") - obs = -2 * Braket.Observables.Y() * (3 * Braket.Observables.I()) + 0.75 * Braket.Observables.Y() * Braket.Observables.Z() + obs = -2 * BraketSimulator.Observables.Y() * (3 * BraketSimulator.Observables.I()) + 0.75 * BraketSimulator.Observables.Y() * BraketSimulator.Observables.Z() @test circuit.result_types[1].observable == obs @test circuit.result_types[1].targets == [QubitSet([0, 1]), QubitSet([2, 3])] @test circuit.result_types[1].parameters == ["theta"] @@ -611,8 +645,11 @@ get_tol(shots::Int) = return ( y \$2; h \$3; """ - circ = Circuit(qasm) - @test circ.instructions == [Instruction(Z(), 0), Instruction(X(), 1), Instruction(H(), 2), Instruction(Y(), 3)] + circ = BraketSimulator.Circuit(qasm) + @test circ.instructions == [BraketSimulator.Instruction(BraketSimulator.Z(), 0), + BraketSimulator.Instruction(BraketSimulator.X(), 1), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.Y(), 3)] end @testset "Switch/case" begin qasm = """ @@ -622,35 +659,35 @@ get_tol(shots::Int) = return ( default { z \$0; } } """ - circ = Circuit(qasm, Dict("x"=> -1)) + circ = BraketSimulator.Circuit(qasm, Dict("x"=> -1)) @test isempty(circ.instructions) - circ = Circuit(qasm, Dict("x"=> 0)) - @test circ.instructions == [Instruction(Z(), 0)] + circ = BraketSimulator.Circuit(qasm, Dict("x"=> 0)) + @test circ.instructions == [BraketSimulator.Instruction(BraketSimulator.Z(), 0)] qasm = """ input int[8] x; switch (x) { case 0 {} case 1, 2 { z \$0; } } """ - circ = Circuit(qasm, Dict("x"=> 0)) + circ = BraketSimulator.Circuit(qasm, Dict("x"=> 0)) @test isempty(circ.instructions) - circ = Circuit(qasm, Dict("x"=> 1)) - @test circ.instructions == [Instruction(Z(), 0)] - circ = Circuit(qasm, Dict("x"=> 2)) - @test circ.instructions == [Instruction(Z(), 0)] + circ = BraketSimulator.Circuit(qasm, Dict("x"=> 1)) + @test circ.instructions == [BraketSimulator.Instruction(BraketSimulator.Z(), 0)] + circ = BraketSimulator.Circuit(qasm, Dict("x"=> 2)) + @test circ.instructions == [BraketSimulator.Instruction(BraketSimulator.Z(), 0)] qasm = """ input int[8] x; switch (x) { case 0 {} default { z \$0; } default { x \$0; } } """ - @test_throws Quasar.QasmParseError Circuit(qasm, Dict("x"=>0)) + @test_throws Quasar.QasmParseError BraketSimulator.Circuit(qasm, Dict("x"=>0)) qasm = """ input int[8] x; switch (x) { default { z \$0; } case 0 {} } """ - @test_throws Quasar.QasmParseError Circuit(qasm, Dict("x"=>0)) + @test_throws Quasar.QasmParseError BraketSimulator.Circuit(qasm, Dict("x"=>0)) qasm = """ input int[8] x; switch (x) { case 0 { z \$0; } true {} } """ - @test_throws Quasar.QasmParseError Circuit(qasm, Dict("x"=>0)) + @test_throws Quasar.QasmParseError BraketSimulator.Circuit(qasm, Dict("x"=>0)) end @testset "If/Else" begin qasm = """ @@ -701,9 +738,9 @@ get_tol(shots::Int) = return ( y q; } """ - for (flag, which_gate) in ((true, X()), (false, Y())) - circuit = Circuit(qasm, Dict("which_gate"=>flag)) - @test circuit.instructions == [Instruction(which_gate, 0)] + for (flag, which_gate) in ((true, BraketSimulator.X()), (false, BraketSimulator.Y())) + circuit = BraketSimulator.Circuit(qasm, Dict("which_gate"=>flag)) + @test circuit.instructions == [BraketSimulator.Instruction(which_gate, 0)] end end @testset "Global gate control" begin @@ -715,7 +752,7 @@ get_tol(shots::Int) = return ( h q2; ctrl @ s q1, q2; """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(2, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ [0.5, 0.5, 0.5, 0.5im] @@ -737,11 +774,11 @@ get_tol(shots::Int) = return ( s q1; // s """ - canonical_ixs = [Instruction(H(), 0), Instruction(H(), 1), Instruction(S(), 0)] + canonical_ixs = [BraketSimulator.Instruction(BraketSimulator.H(), 0), BraketSimulator.Instruction(BraketSimulator.H(), 1), BraketSimulator.Instruction(BraketSimulator.S(), 0)] canonical_simulation = BraketSimulator.StateVectorSimulator(2, 0) BraketSimulator.evolve!(canonical_simulation, canonical_ixs) @testset "$title" for (title, qasm) in (("standard", standard_qasm), ("custom", custom_qasm)) - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(2, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ canonical_simulation.state_vector @@ -817,7 +854,7 @@ get_tol(shots::Int) = return ( @testset "$title" for (title, qasm) in (("standard", standard_qasm), ("custom", custom_qasm) ) - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(5, 0) BraketSimulator.evolve!(simulation, circuit.instructions) sv = zeros(32) @@ -863,14 +900,24 @@ get_tol(shots::Int) = return ( ccx_2 q1, q2, q4; ccx_2 q1, q2, q5; """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(5, 0) sv = zeros(ComplexF64, 32) sv[end] = 1.0 - canonical_circuit = Circuit([(CNot, 0, 1), (X, 0), (CNot, 0, 1), (CCNot, 0, 3, 2), (CCNot, 0, 2, 3), (CCNot, 0, 2, 4), (CCNot, 0, 1, 2), (CCNot, 0, 1, 3), (CCNot, 0, 1, 4)]) - canonical_simulation = BraketSimulator.StateVectorSimulator(5, 0) + canonical_ixs = [ + BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.X(), 0), + BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 3, 2]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 2, 3]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 2, 4]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 1, 2]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 1, 3]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 1, 4]) + ] + canonical_simulation = BraketSimulator.StateVectorSimulator(5, 0) ii = 1 - @testset for (ix, c_ix) in zip(circuit.instructions, canonical_circuit.instructions) + @testset for (ix, c_ix) in zip(circuit.instructions, canonical_ixs) BraketSimulator.evolve!(simulation, [ix]) BraketSimulator.evolve!(canonical_simulation, [c_ix]) for jj in 1:32 @@ -903,14 +950,14 @@ get_tol(shots::Int) = return ( cccx q1, q2, q5, q3; ncccx q4, q2, q5, q3; """ - circuit = Circuit(qasm) - @test circuit.instructions == [Instruction(H(), 0), - Instruction(H(), 1), - Instruction(H(), 2), - Instruction(H(), 3), - Instruction(H(), 4), - Instruction(Control(X(), (1, 1, 1)), [0, 1, 4, 2]), - Instruction(Control(X(), (0, 0, 0)), [3, 1, 4, 2]), + circuit = BraketSimulator.Circuit(qasm) + @test circuit.instructions == [BraketSimulator.Instruction(BraketSimulator.H(), 0), + BraketSimulator.Instruction(BraketSimulator.H(), 1), + BraketSimulator.Instruction(BraketSimulator.H(), 2), + BraketSimulator.Instruction(BraketSimulator.H(), 3), + BraketSimulator.Instruction(BraketSimulator.H(), 4), + BraketSimulator.Instruction(BraketSimulator.Control(BraketSimulator.X(), (1, 1, 1)), [0, 1, 4, 2]), + BraketSimulator.Instruction(BraketSimulator.Control(BraketSimulator.X(), (0, 0, 0)), [3, 1, 4, 2]), ] end @testset "Gate inverses" begin @@ -963,9 +1010,9 @@ get_tol(shots::Int) = return ( t q; inv @ t q; """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) collapsed = prod(BraketSimulator.matrix_rep(ix.operator) for ix in circuit.instructions) - @test collapsed ≈ diagm(ones(ComplexF64, 2^qubit_count(circuit))) + @test collapsed ≈ diagm(ones(ComplexF64, 2^BraketSimulator.qubit_count(circuit))) end @testset "Noise" begin qasm = """ @@ -984,19 +1031,19 @@ get_tol(shots::Int) = return ( #pragma braket noise kraus([[0.9486833im, 0], [0, 0.9486833im]], [[0, 0.31622777], [0.31622777, 0]]) qs[0] #pragma braket noise kraus([[0.9486832980505138, 0, 0, 0], [0, 0.9486832980505138, 0, 0], [0, 0, 0.9486832980505138, 0], [0, 0, 0, 0.9486832980505138]], [[0, 0.31622776601683794, 0, 0], [0.31622776601683794, 0, 0, 0], [0, 0, 0, 0.31622776601683794], [0, 0, 0.31622776601683794, 0]]) qs[{1, 0}] """ - circuit = Circuit(qasm) - inst_list = [Instruction(BitFlip(0.5), [1]), - Instruction(PhaseFlip(0.5), [0]), - Instruction(PauliChannel(0.1, 0.2, 0.3), [0]), - Instruction(Depolarizing(0.5), [0]), - Instruction(TwoQubitDepolarizing(0.9), [0, 1]), - Instruction(TwoQubitDepolarizing(0.7), [1, 0]), - Instruction(TwoQubitDephasing(0.6), [0, 1]), - Instruction(AmplitudeDamping(0.2), [0]), - Instruction(GeneralizedAmplitudeDamping(0.2, 0.3), [1]), - Instruction(PhaseDamping(0.4), [0]), - Instruction(Kraus([[0.9486833im 0; 0 0.9486833im], [0 0.31622777; 0.31622777 0]]), [0]), - Instruction(Kraus([diagm(fill(√0.9, 4)), √0.1*kron([1.0 0.0; 0.0 1.0], [0.0 1.0; 1.0 0.0])]), [1, 0]), + circuit = BraketSimulator.Circuit(qasm) + inst_list = [BraketSimulator.Instruction(BraketSimulator.BitFlip(0.5), [1]), + BraketSimulator.Instruction(BraketSimulator.PhaseFlip(0.5), [0]), + BraketSimulator.Instruction(BraketSimulator.PauliChannel(0.1, 0.2, 0.3), [0]), + BraketSimulator.Instruction(BraketSimulator.Depolarizing(0.5), [0]), + BraketSimulator.Instruction(BraketSimulator.TwoQubitDepolarizing(0.9), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.TwoQubitDepolarizing(0.7), [1, 0]), + BraketSimulator.Instruction(BraketSimulator.TwoQubitDephasing(0.6), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.AmplitudeDamping(0.2), [0]), + BraketSimulator.Instruction(BraketSimulator.GeneralizedAmplitudeDamping(0.2, 0.3), [1]), + BraketSimulator.Instruction(BraketSimulator.PhaseDamping(0.4), [0]), + BraketSimulator.Instruction(BraketSimulator.Kraus([[0.9486833im 0; 0 0.9486833im], [0 0.31622777; 0.31622777 0]]), [0]), + BraketSimulator.Instruction(BraketSimulator.Kraus([diagm(fill(√0.9, 4)), √0.1*kron([1.0 0.0; 0.0 1.0], [0.0 1.0; 1.0 0.0])]), [1, 0]), ] @testset "Operator $(typeof(ix.operator)), target $(ix.target)" for (cix, ix) in zip(circuit.instructions, inst_list) @test cix.operator == ix.operator @@ -1013,10 +1060,10 @@ get_tol(shots::Int) = return ( #pragma braket result variance x(q[0]) @ y(q[1]) #pragma braket result sample x(q[0]) """ - circuit = Circuit(qasm) - Braket.basis_rotation_instructions!(circuit) - c_bris = [circuit.basis_rotation_instructions[1], Instruction(Unitary(Matrix(mapreduce(ix->BraketSimulator.matrix_rep(ix.operator), *, circuit.basis_rotation_instructions[2:end]))), [1])] - bris = vcat(Instruction(H(), [0]), BraketSimulator.diagonalizing_gates(Braket.Observables.Y(), [1])) + circuit = BraketSimulator.Circuit(qasm) + BraketSimulator.basis_rotation_instructions!(circuit) + c_bris = [circuit.basis_rotation_instructions[1], BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(mapreduce(ix->BraketSimulator.matrix_rep(ix.operator), *, circuit.basis_rotation_instructions[2:end]))), [1])] + bris = vcat(BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.diagonalizing_gates(BraketSimulator.Observables.Y(), [1])) for (ix, bix) in zip(c_bris, bris) @test BraketSimulator.matrix_rep(ix.operator) ≈ transpose(BraketSimulator.matrix_rep(bix.operator)) @test ix.target == bix.target @@ -1031,10 +1078,10 @@ get_tol(shots::Int) = return ( #pragma braket result variance x(q[0]) @ y(q[1]) #pragma braket result sample i(q[0]) """ - circuit = Circuit(qasm) - Braket.basis_rotation_instructions!(circuit) - c_bris = [circuit.basis_rotation_instructions[1], Instruction(Unitary(Matrix(mapreduce(ix->BraketSimulator.matrix_rep(ix.operator), *, circuit.basis_rotation_instructions[2:end]))), [1])] - bris = vcat(Instruction(H(), [0]), BraketSimulator.diagonalizing_gates(Braket.Observables.Y(), [1])) + circuit = BraketSimulator.Circuit(qasm) + BraketSimulator.basis_rotation_instructions!(circuit) + c_bris = [circuit.basis_rotation_instructions[1], BraketSimulator.Instruction(BraketSimulator.Unitary(Matrix(mapreduce(ix->BraketSimulator.matrix_rep(ix.operator), *, circuit.basis_rotation_instructions[2:end]))), [1])] + bris = vcat(BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.diagonalizing_gates(BraketSimulator.Observables.Y(), [1])) for (ix, bix) in zip(c_bris, bris) @test BraketSimulator.matrix_rep(ix.operator) ≈ transpose(BraketSimulator.matrix_rep(bix.operator)) @test ix.target == bix.target @@ -1050,16 +1097,16 @@ get_tol(shots::Int) = return ( // # noqa: E501 #pragma braket result expectation x(q[2]) @ hermitian([[-6+0im, 2+1im, -3+0im, -5+2im], [2-1im, 0im, 2-1im, -5+4im], [-3+0im, 2+1im, 0im, -4+3im], [-5-2im, -5-4im, -4-3im, -6+0im]]) q[0:1] """ - circuit = Circuit(qasm) - Braket.basis_rotation_instructions!(circuit) + circuit = BraketSimulator.Circuit(qasm) + BraketSimulator.basis_rotation_instructions!(circuit) arr = [-6 2+1im -3 -5+2im; 2-1im 0 2-1im -5+4im; -3 2+1im 0 -4+3im; -5-2im -5-4im -4-3im -6] - h = Braket.Observables.HermitianObservable(arr) - bris = vcat(BraketSimulator.diagonalizing_gates(h, [0, 1]), Instruction(H(), [2])) + h = BraketSimulator.Observables.HermitianObservable(arr) + bris = vcat(BraketSimulator.diagonalizing_gates(h, [0, 1]), BraketSimulator.Instruction(BraketSimulator.H(), [2])) for (ix, bix) in zip(circuit.basis_rotation_instructions, bris) - @test BraketSimulator.matrix_rep(ix.operator) ≈ adjoint(BraketSimulator.matrix_rep(bix.operator)) + @test Matrix(BraketSimulator.matrix_rep(ix.operator)) ≈ adjoint(BraketSimulator.fix_endianness(Matrix(BraketSimulator.matrix_rep(bix.operator)))) @test ix.target == bix.target end end @@ -1083,7 +1130,7 @@ get_tol(shots::Int) = return ( // unitary pragma for ccnot gate #pragma braket unitary([[1.0, 0, 0, 0, 0, 0, 0, 0], [0, 1.0, 0, 0, 0, 0, 0, 0], [0, 0, 1.0, 0, 0, 0, 0, 0], [0, 0, 0, 1.0, 0, 0, 0, 0], [0, 0, 0, 0, 1.0, 0, 0, 0], [0, 0, 0, 0, 0, 1.0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1.0], [0, 0, 0, 0, 0, 0, 1.0, 0]]) q """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(3, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ [0, 0, 0, 0, 0.70710678, 0, 0, 0.70710678] @@ -1124,7 +1171,7 @@ get_tol(shots::Int) = return ( cphaseshift(1) qs, q; phaseshift(-2) q; """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(4, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ (1/√2)*[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0] @@ -1143,7 +1190,7 @@ get_tol(shots::Int) = return ( b[0] = measure q[0]; b[1] = measure q[1]; """ - circuit = Circuit(with_verbatim) + circuit = BraketSimulator.Circuit(with_verbatim) sim_w_verbatim = BraketSimulator.StateVectorSimulator(2, 0) pop!(circuit.instructions) pop!(circuit.instructions) @@ -1161,7 +1208,7 @@ get_tol(shots::Int) = return ( b[0] = measure q[0]; b[1] = measure q[1]; """ - circuit = Circuit(without_verbatim) + circuit = BraketSimulator.Circuit(without_verbatim) sim_wo_verbatim = BraketSimulator.StateVectorSimulator(2, 0) pop!(circuit.instructions) pop!(circuit.instructions) @@ -1196,7 +1243,7 @@ get_tol(shots::Int) = return ( qubit[2] qs; flip(qs[0]); """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(2, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ [0, 0, 1, 0] @@ -1307,7 +1354,7 @@ get_tol(shots::Int) = return ( $operation #pragma braket result state_vector """ - circuit = Circuit(qasm) + circuit = BraketSimulator.Circuit(qasm) simulation = BraketSimulator.StateVectorSimulator(1, 0) BraketSimulator.evolve!(simulation, circuit.instructions) @test simulation.state_vector ≈ state_vector @@ -1320,149 +1367,10 @@ get_tol(shots::Int) = return ( h q[0]; ctrl @ x q[0], q[1]; """ - circuit = Circuit(qasm) - program = Braket.Program(circuit) + circuit = BraketSimulator.Circuit(qasm) + program = BraketSimulator.Program(circuit) simulation = BraketSimulator.StateVectorSimulator(2, 0) - @test_throws BraketSimulator.ValidationError simulate(simulation, program, 2, 0) - end - @testset "Parsing Hermitian observables" begin - three_qubit_circuit( - θ::Float64, - ϕ::Float64, - φ::Float64, - obs::Braket.Observables.Observable, - obs_targets::Vector{Int}, - ) = Circuit([ - (Rx, 0, θ), - (Rx, 1, ϕ), - (Rx, 2, φ), - (CNot, 0, 1), - (CNot, 1, 2), - (Variance, obs, obs_targets), - (Expectation, obs, obs_targets), - (Sample, obs, obs_targets), - ]) - θ = 0.432 - ϕ = 0.123 - φ = -0.543 - obs_targets = [0, 1, 2] - ho_mat = [ - -6 2+im -3 -5+2im - 2-im 0 2-im -5+4im - -3 2+im 0 -4+3im - -5-2im -5-4im -4-3im -6 - ] - ho_mat2 = [1 2; 2 4] - ho_mat3 = [-6 2+im; 2-im 0] - ho_mat4 = kron([1 0; 0 1], [-6 2+im; 2-im 0]) - ho = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat)) - ho2 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat2)) - ho3 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat3)) - ho4 = Braket.Observables.HermitianObservable(ComplexF64.(ho_mat4)) - meani = -5.7267957792059345 - meany = 1.4499810303182408 - meanz = - 0.5 * ( - -6 * cos(θ) * (cos(φ) + 1) - - 2 * sin(φ) * (cos(θ) + sin(ϕ) - 2 * cos(ϕ)) + - 3 * cos(φ) * sin(ϕ) + - sin(ϕ) - ) - meanh = -4.30215023196904 - meanii = -5.78059066879935 - - vari = 43.33800156673375 - vary = 74.03174647518193 - varz = - ( - 1057 - cos(2ϕ) + 12 * (27 + cos(2ϕ)) * cos(φ) - - 2 * cos(2φ) * sin(ϕ) * (16 * cos(ϕ) + 21 * sin(ϕ)) + 16 * sin(2ϕ) - - 8 * (-17 + cos(2ϕ) + 2 * sin(2ϕ)) * sin(φ) - - 8 * cos(2θ) * (3 + 3 * cos(φ) + sin(φ))^2 - - 24 * cos(ϕ) * (cos(ϕ) + 2 * sin(ϕ)) * sin(2φ) - - 8 * - cos(θ) * - ( - 4 * - cos(ϕ) * - (4 + 8 * cos(φ) + cos(2φ) - (1 + 6 * cos(φ)) * sin(φ)) + - sin(ϕ) * - (15 + 8 * cos(φ) - 11 * cos(2φ) + 42 * sin(φ) + 3 * sin(2φ)) - ) - ) / 16 - varh = 370.71292282796804 - varii = 6.268315532585994 - - i_array = [1 0; 0 1] - y_array = [0 -im; im 0] - z_array = diagm([1, -1]) - eigsi = eigvals(kron(i_array, ho_mat)) - eigsy = eigvals(kron(y_array, ho_mat)) - eigsz = eigvals(kron(z_array, ho_mat)) - eigsh = [-70.90875406, -31.04969387, 0, 3.26468993, 38.693758] - eigsii = eigvals(kron(i_array, kron(i_array, ho_mat3))) - d = LocalSimulator("braket_sv_v2") - @testset "Obs $obs" for (obs, expected_mean, expected_var, expected_eigs) in - [ - (Observables.I() * ho, meani, vari, eigsi), - (Observables.Y() * ho, meany, vary, eigsy), - (Observables.Z() * ho, meanz, varz, eigsz), - (ho2 * ho, meanh, varh, eigsh), - ( - Observables.HermitianObservable(kron(ho_mat2, ho_mat)), - meanh, - varh, - eigsh, - ), - (Observables.I() * Observables.I() * ho3, meanii, varii, eigsii), - (Observables.I() * ho4, meanii, varii, eigsii), - ] - circuit = three_qubit_circuit(θ, ϕ, φ, obs, obs_targets) - Braket.basis_rotation_instructions!(circuit) - raw_oq3_circ = ir(circuit, Val(:OpenQASM)) - oq3_circ = Braket.OpenQasmProgram(raw_oq3_circ.braketSchemaHeader, raw_oq3_circ.source * "\n", raw_oq3_circ.inputs) - jaqcd_circ = ir(circuit, Val(:JAQCD)) - @testset "Simulator $sim" for sim in (StateVectorSimulator,) - shots = 8000 - tol = get_tol(shots) - j_simulation = sim(qubit_count(circuit), shots) - p_simulation = sim(qubit_count(circuit), shots) - parsed_circ = Braket.Program(Circuit(oq3_circ.source)) - @test length(parsed_circ.instructions) == length(jaqcd_circ.instructions) - for (p_ix, j_ix) in zip(parsed_circ.instructions, jaqcd_circ.instructions) - @test p_ix == j_ix - end - @test length(parsed_circ.basis_rotation_instructions) == length(jaqcd_circ.basis_rotation_instructions) - for (p_ix, j_ix) in zip(parsed_circ.basis_rotation_instructions, jaqcd_circ.basis_rotation_instructions) - @test p_ix == j_ix - end - @test length(parsed_circ.results) == length(jaqcd_circ.results) - for (p_rt, j_rt) in zip(parsed_circ.results, jaqcd_circ.results) - @test p_rt == j_rt - end - for (p_ix, j_ix) in zip(parsed_circ.instructions, jaqcd_circ.instructions) - j_simulation = evolve!(j_simulation, [j_ix]) - p_simulation = evolve!(p_simulation, [p_ix]) - @test j_simulation.state_vector ≈ p_simulation.state_vector - end - formatted_measurements = [rand(0:1, 3) for s in 1:shots] - measured_qubits = [0, 1, 2] - j_bundled = BraketSimulator._bundle_results(Braket.ResultTypeValue[], jaqcd_circ, j_simulation) - p_rtv = [Braket.ResultTypeValue(rt, 0.0) for rt in jaqcd_circ.results] - p_bundled = BraketSimulator._bundle_results(p_rtv, oq3_circ, p_simulation) - @test j_bundled.measuredQubits == measured_qubits - @test p_bundled.measuredQubits == measured_qubits - # test with pre-computed measurements - new_j_bundled = Braket.GateModelTaskResult(j_bundled.braketSchemaHeader, formatted_measurements, nothing, j_bundled.resultTypes, j_bundled.measuredQubits, j_bundled.taskMetadata, j_bundled.additionalMetadata) - new_p_bundled = Braket.GateModelTaskResult(p_bundled.braketSchemaHeader, formatted_measurements, nothing, p_bundled.resultTypes, p_bundled.measuredQubits, p_bundled.taskMetadata, p_bundled.additionalMetadata) - - j_formatted = Braket.computational_basis_sampling(Braket.GateModelQuantumTaskResult, new_j_bundled) - p_formatted = Braket.computational_basis_sampling(Braket.GateModelQuantumTaskResult, new_p_bundled) - for (j_v, p_v) in zip(j_formatted.values, p_formatted.values) - @test j_v == p_v - end - end - end + @test_throws BraketSimulator.ValidationError BraketSimulator.simulate(simulation, program, 2, 0) end @testset "Referencing invalid qubit(s)" begin source = """ @@ -1539,11 +1447,11 @@ get_tol(shots::Int) = return ( i q; } """ - circ = Circuit(qasm_string, Dict("x"=>"1011")) + circ = BraketSimulator.Circuit(qasm_string, Dict("x"=>"1011")) end @testset "GRCS 16" begin simulator = BraketSimulator.StateVectorSimulator(16, 0) - circuit = Circuit(joinpath(@__DIR__, "grcs_16.qasm")) + circuit = BraketSimulator.Circuit(joinpath(@__DIR__, "grcs_16.qasm")) BraketSimulator.evolve!(simulator, circuit.instructions) probs = BraketSimulator.probabilities(simulator) @test first(probs) ≈ 0.0000062 atol=1e-7 diff --git a/test/test_python_ext.jl b/test/test_python_ext.jl index 37c1ae0..13b5ff6 100644 --- a/test/test_python_ext.jl +++ b/test/test_python_ext.jl @@ -1,102 +1,6 @@ -using Test, PythonCall, BraketSimulator, Braket -using PythonCall: pyconvert +using Test, JSON3, PythonCall, BraketSimulator @testset "Python integration" begin - braket_rts = pyimport("braket.ir.jaqcd.results") - np = pyimport("numpy") - jl_mat = ComplexF64[0.0 1.0; 1.0 0.0] - py_mat = pylist([pylist([pylist([0.0; 0.0]); pylist([1.0; 0.0])]); pylist([pylist([1.0; 0.0]); pylist([0.0; 0.0])])]) - py_sim_mat = np.array(pylist([pylist([0.0, 1.0]); pylist([1.0, 0.0])])) - @testset "Result types" begin - jl_tp_1 = ["h", "x"] - py_tp_1 = pylist([pystr("h"), pystr("x")]) - jl_herm = Braket.complex_matrix_to_ir(jl_mat) - py_herm = py_mat - jl_tp_2 = Union{String, Vector{Vector{Vector{Float64}}}}["h", jl_herm] - py_tp_2 = pylist([pystr("h"), py_herm]) - @testset for (jl_rt, py_rt, jl_braket_rt) in zip( - [ - Braket.IR.StateVector("statevector"), - Braket.IR.Amplitude(["00", "11"], "amplitude"), - Braket.IR.Probability(nothing, "probability"), - Braket.IR.Probability([0], "probability"), - Braket.IR.DensityMatrix(nothing, "densitymatrix"), - Braket.IR.DensityMatrix([0], "densitymatrix"), - Braket.IR.Sample("x", nothing, "sample"), - Braket.IR.Sample("x", [0], "sample"), - Braket.IR.Sample([jl_herm], nothing, "sample"), - Braket.IR.Sample([jl_herm], [0], "sample"), - Braket.IR.Sample(jl_tp_1, [0, 1], "sample"), - Braket.IR.Sample(jl_tp_2, [0, 1], "sample"), - Braket.IR.Expectation("x", nothing, "expectation"), - Braket.IR.Expectation("x", [0], "expectation"), - Braket.IR.Expectation([jl_herm], nothing, "expectation"), - Braket.IR.Expectation([jl_herm], [0], "expectation"), - Braket.IR.Expectation(jl_tp_1, [0, 1], "expectation"), - Braket.IR.Expectation(jl_tp_2, [0, 1], "expectation"), - Braket.IR.Variance("x", nothing, "variance"), - Braket.IR.Variance("x", [0], "variance"), - Braket.IR.Variance([jl_herm], nothing, "variance"), - Braket.IR.Variance([jl_herm], [0], "variance"), - Braket.IR.Variance(jl_tp_1, [0, 1], "variance"), - Braket.IR.Variance(jl_tp_2, [0, 1], "variance"), - ], - [ - braket_rts.StateVector(), - braket_rts.Amplitude(states=pylist([pystr("00"), pystr("11")])), - braket_rts.Probability(), - braket_rts.Probability(targets=pylist([0])), - braket_rts.DensityMatrix(), - braket_rts.DensityMatrix(targets=pylist([0])), - braket_rts.Sample(observable=pylist([pystr("x")])), - braket_rts.Sample(observable=pylist([pystr("x")]), targets=pylist([0])), - braket_rts.Sample(observable=pylist([py_herm])), - braket_rts.Sample(observable=pylist([py_herm]), targets=pylist([0])), - braket_rts.Sample(observable=py_tp_1, targets=pylist([0, 1])), - braket_rts.Sample(observable=py_tp_2, targets=pylist([0, 1])), - braket_rts.Expectation(observable=pylist([pystr("x")])), - braket_rts.Expectation(observable=pylist([pystr("x")]), targets=pylist([0])), - braket_rts.Expectation(observable=pylist([py_herm])), - braket_rts.Expectation(observable=pylist([py_herm]), targets=pylist([0])), - braket_rts.Expectation(observable=py_tp_1, targets=pylist([0, 1])), - braket_rts.Expectation(observable=py_tp_2, targets=pylist([0, 1])), - braket_rts.Variance(observable=pylist([pystr("x")])), - braket_rts.Variance(observable=pylist([pystr("x")]), targets=pylist([0])), - braket_rts.Variance(observable=pylist([py_herm])), - braket_rts.Variance(observable=pylist([py_herm]), targets=pylist([0])), - braket_rts.Variance(observable=py_tp_1, targets=pylist([0, 1])), - braket_rts.Variance(observable=py_tp_2, targets=pylist([0, 1])), - ], - [ - Braket.StateVector(), - Braket.Amplitude(["00", "11"]), - Braket.Probability(), - Braket.Probability(0), - Braket.DensityMatrix(), - Braket.DensityMatrix(0), - Braket.Sample(Braket.Observables.X(), Int[]), - Braket.Sample(Braket.Observables.X(), [0]), - Braket.Sample(Braket.Observables.HermitianObservable(jl_mat), Int[]), - Braket.Sample(Braket.Observables.HermitianObservable(jl_mat), [0]), - Braket.Sample(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.X()]), [0, 1]), - Braket.Sample(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.HermitianObservable(jl_mat)]), [0, 1]), - Braket.Expectation(Braket.Observables.X(), Int[]), - Braket.Expectation(Braket.Observables.X(), [0]), - Braket.Expectation(Braket.Observables.HermitianObservable(jl_mat), Int[]), - Braket.Expectation(Braket.Observables.HermitianObservable(jl_mat), [0]), - Braket.Expectation(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.X()]), [0, 1]), - Braket.Expectation(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.HermitianObservable(jl_mat)]), [0, 1]), - Braket.Variance(Braket.Observables.X(), Int[]), - Braket.Variance(Braket.Observables.X(), [0]), - Braket.Variance(Braket.Observables.HermitianObservable(jl_mat), Int[]), - Braket.Variance(Braket.Observables.HermitianObservable(jl_mat), [0]), - Braket.Variance(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.X()]), [0, 1]), - Braket.Variance(Braket.Observables.TensorProduct([Braket.Observables.H(), Braket.Observables.HermitianObservable(jl_mat)]), [0, 1]), - ], - ) - @test PythonCall.pyconvert(Bool, Py(jl_rt) == py_rt) - end - end @testset "Programs" begin sv_adder = """ OPENQASM 3; @@ -139,39 +43,32 @@ using PythonCall: pyconvert #pragma braket result probability cout #pragma braket result probability b """ - oq3_program = Braket.OpenQasmProgram(Braket.braketSchemaHeader("braket.ir.openqasm.program", "1"), sv_adder, Dict("a_in"=>3, "b_in"=>7)) - n_qubits = 5 - function qft_circuit(qubit_count::Int) - qft_circ = Circuit() - for target_qubit = 0:qubit_count-1 - angle = π/2 - qft_circ(H(), target_qubit) - for control_qubit = target_qubit+1:qubit_count-1 - qft_circ(CPhaseShift(angle), control_qubit, target_qubit) - angle /= 2 - end - end - qft_circ(Amplitude([repeat("0", qubit_count), repeat("1", qubit_count)])) - qft_circ(Expectation(Braket.Observables.X(), 0)) - qft_circ(DensityMatrix()) - return qft_circ - end - @test pyconvert(Braket.OpenQasmProgram, Py(oq3_program)) == oq3_program @testset "Full Python circuit execution" begin @testset "OpenQASM3" begin + n_qubits = 5 # test a "batch" sv_simulator = StateVectorSimulator(n_qubits, 0) - py_inputs = PyList{Any}([pydict(Dict("a_in"=>2, "b_in"=>5)), pydict(Dict("a_in"=>3, "b_in"=>2))]) - oq3_results = simulate(sv_simulator, PyList{Any}([oq3_program, oq3_program]); inputs=py_inputs, shots=0) + py_inputs = [Dict{String, Any}("a_in"=>2, "b_in"=>5), Dict{String, Any}("a_in"=>3, "b_in"=>2)] + oq3_results = BraketSimulator.simulate(sv_simulator, [sv_adder, sv_adder], py_inputs, 0) for oq3_result in oq3_results - @test pyconvert(Vector{Float64}, oq3_result.resultTypes[0].value) ≠ pyconvert(Vector{Float64}, oq3_result.resultTypes[1].value) + @test oq3_result isa String end # test a "batch" of length 1 sv_simulator = StateVectorSimulator(n_qubits, 0) - py_inputs = PyList{Any}([pydict(Dict("a_in"=>2, "b_in"=>5))]) - oq3_results = simulate(sv_simulator, PyList{Any}([oq3_program]); inputs=py_inputs, shots=0) + py_inputs = [Dict{String, Any}("a_in"=>2, "b_in"=>5)] + oq3_results = BraketSimulator.simulate(sv_simulator, [sv_adder], py_inputs, 0) + for oq3_result in oq3_results + @test oq3_result isa String + end + simple_bell_qasm = """ + h \$0; + cnot \$0, \$1; + #pragma braket result state_vector + """ + sv_simulator = StateVectorSimulator(2, 0) + oq3_results = BraketSimulator.simulate(sv_simulator, [simple_bell_qasm], [Dict{String, Any}()], 0) for oq3_result in oq3_results - @test pyconvert(Vector{Float64}, oq3_result.resultTypes[0].value) ≠ pyconvert(Vector{Float64}, oq3_result.resultTypes[1].value) + @test oq3_result isa String end end end diff --git a/test/test_qubit_set.jl b/test/test_qubit_set.jl new file mode 100644 index 0000000..c29bdf3 --- /dev/null +++ b/test/test_qubit_set.jl @@ -0,0 +1,40 @@ +using BraketSimulator, Test + +@testset "QubitSet and Qubit" begin + @testset "ctors" begin + @test BraketSimulator.Qubit(1) == BraketSimulator.Qubit(1.0) + @test BraketSimulator.Qubit(BigFloat(1.0)) == BraketSimulator.Qubit(1.0) + @test BraketSimulator.Qubit(BraketSimulator.Qubit(1)) == BraketSimulator.Qubit(1.0) + @test BraketSimulator.QubitSet(nothing) == BraketSimulator.QubitSet() + end + @testset "equality" begin + @test BraketSimulator.Qubit(1) == Int8(1) + @test BigInt(10) == BraketSimulator.Qubit(10) + @test 10 == BraketSimulator.Qubit(10) + @test BraketSimulator.Qubit(10) == BigInt(10) + end + @testset "Convert to Int" begin + @test Int(BraketSimulator.Qubit(1)) == 1 + @test convert(Int, BraketSimulator.Qubit(1)) == 1 + end + @testset "show" begin + s = sprint(show, BraketSimulator.Qubit(1)) + @test s == "Qubit(1)" + end + @testset "QubitSet indexing" begin + qs = BraketSimulator.QubitSet(0, 1, 2) + @test copy(qs) == qs + @test length(qs) == 3 + @test lastindex(qs) == 3 + @test 3 ∉ qs + @test !isempty(qs) + o = popfirst!(qs) + @test o == 0 + @test length(qs) == 2 + q1 = BraketSimulator.QubitSet(0, 1, 2) + q2 = BraketSimulator.QubitSet(2, 4, 3) + @test q1[1:2] == BraketSimulator.QubitSet(0, 1) + @test intersect(q1, q2) == BraketSimulator.QubitSet(2) + @test sort(q2) == BraketSimulator.QubitSet(2, 3, 4) + end +end diff --git a/test/test_result_types.jl b/test/test_result_types.jl index 342d2cb..1dde577 100644 --- a/test/test_result_types.jl +++ b/test/test_result_types.jl @@ -1,27 +1,26 @@ -using Test, Braket, BraketSimulator, LinearAlgebra -import Braket: Instruction +using Test, BraketSimulator, LinearAlgebra const NUM_SAMPLES = 1000 observables_testdata = [ ( - Braket.Observables.TensorProduct([Braket.Observables.X(), Braket.Observables.H()]), + BraketSimulator.Observables.TensorProduct([BraketSimulator.Observables.X(), BraketSimulator.Observables.H()]), (1, 2), ), ( - Braket.Observables.TensorProduct([Braket.Observables.I(), Braket.Observables.Y()]), + BraketSimulator.Observables.TensorProduct([BraketSimulator.Observables.I(), BraketSimulator.Observables.Y()]), (0, 2), ), - (Braket.Observables.Y(), (2,)), + (BraketSimulator.Observables.Y(), (2,)), ] all_qubit_observables_testdata = [ - Braket.Observables.X(), - Braket.Observables.Y(), - Braket.Observables.Z(), - Braket.Observables.H(), - Braket.Observables.I(), - Braket.Observables.HermitianObservable([0.0 1.0; 1.0 0.0]), + BraketSimulator.Observables.X(), + BraketSimulator.Observables.Y(), + BraketSimulator.Observables.Z(), + BraketSimulator.Observables.H(), + BraketSimulator.Observables.I(), + BraketSimulator.Observables.HermitianObservable([0.0 1.0; 1.0 0.0]), ] @testset "Result types" begin @@ -37,7 +36,7 @@ all_qubit_observables_testdata = [ end density_matrix(sv) = kron(adjoint(sv), sv) observable() = ( - Braket.Observables.TensorProduct([Braket.Observables.X(), Braket.Observables.H()]), + BraketSimulator.Observables.TensorProduct([BraketSimulator.Observables.X(), BraketSimulator.Observables.H()]), (1, 2), ) dm_dict = Dict( @@ -101,7 +100,7 @@ all_qubit_observables_testdata = [ @testset "Simulation type $sim_type" for sim_type in (Val(:sv), Val(:dm)) if sim_type isa Val{:sv} @testset "Amplitude" begin - result_type = Braket.Amplitude(["0010", "0101", "1110"]) + result_type = BraketSimulator.Amplitude(["0010", "0101", "1110"]) amplitudes = BraketSimulator.calculate( result_type, simulation(observable, sim_type), @@ -114,7 +113,7 @@ all_qubit_observables_testdata = [ end @testset "Probability" begin probability_12 = BraketSimulator.calculate( - Braket.Probability([1, 2]), + BraketSimulator.Probability([1, 2]), simulation(nothing, sim_type), ) @test collect(probability_12) ≈ marginal_12() @@ -122,16 +121,16 @@ all_qubit_observables_testdata = [ state_vector_probabilities = collect(abs2.(state_vector())) probability_all_qubits = collect( BraketSimulator.calculate( - Braket.Probability([0, 1, 2, 3]), + BraketSimulator.Probability([0, 1, 2, 3]), simulation(nothing, sim_type), ), ) @test probability_all_qubits ≈ state_vector_probabilities end @testset "Expectation obs $obs" for obs in observables_testdata - result_type = Expectation(obs...) + result_type = BraketSimulator.Expectation(obs...) @test result_type.observable == obs[1] - @test result_type.targets == QubitSet(obs[2]) + @test result_type.targets == BraketSimulator.QubitSet(obs[2]) sim = simulation(() -> obs, sim_type) calculated = BraketSimulator.calculate(result_type, sim) @@ -145,7 +144,7 @@ all_qubit_observables_testdata = [ @test calculated ≈ from_diagonalization end @testset "Expectation no targets $obs" for obs in all_qubit_observables_testdata - result_types = [Expectation(obs, t) for t in targs] + result_types = [BraketSimulator.Expectation(obs, t) for t in targs] @test all(result_type.observable == obs for result_type in result_types) calculated = [ @@ -167,9 +166,9 @@ all_qubit_observables_testdata = [ end @testset "Variance obs $obs" for obs in observables_testdata sim = simulation(() -> obs, sim_type) - result_type = Variance(obs...) + result_type = BraketSimulator.Variance(obs...) @test result_type.observable == obs[1] - @test result_type.targets == QubitSet(obs[2]) + @test result_type.targets == BraketSimulator.QubitSet(obs[2]) calculated = BraketSimulator.calculate(result_type, sim) from_diagonalization = _variance_from_diagonalization( BraketSimulator.state_with_observables( @@ -181,7 +180,7 @@ all_qubit_observables_testdata = [ @test calculated ≈ from_diagonalization atol = 1e-12 end @testset "Variance no targets $obs" for obs in all_qubit_observables_testdata - result_types = [Variance(obs, t) for t in targs] + result_types = [BraketSimulator.Variance(obs, t) for t in targs] @test all(result_type.observable == obs for result_type in result_types) calculated = [ @@ -202,7 +201,7 @@ all_qubit_observables_testdata = [ @test calculated ≈ from_diagonalization atol = 1e-12 end @testset "Density matrix $qubit" for (qubit, mat) in dm_dict - dm = DensityMatrix(qubit) + dm = BraketSimulator.DensityMatrix(qubit) sim = simulation(nothing, sim_type) calculated = BraketSimulator.calculate(dm, sim) @test collect(calculated) ≈ mat rtol = 1e-6 @@ -211,9 +210,9 @@ all_qubit_observables_testdata = [ @testset "Permutation of probability/density matrix" begin sim = BraketSimulator.StateVectorSimulator(4, 0) sim.state_vector = state_vector() - sv = BraketSimulator.calculate(Braket.Probability(reverse(0:3)), sim) + sv = BraketSimulator.calculate(BraketSimulator.Probability(reverse(0:3)), sim) @test sv ≈ conj(state_vector()) .* state_vector() - dm = BraketSimulator.calculate(Braket.DensityMatrix(reverse(0:3)), sim) + dm = BraketSimulator.calculate(BraketSimulator.DensityMatrix(reverse(0:3)), sim) @test dm ≈ kron(adjoint(state_vector()), state_vector()) end end diff --git a/test/test_sv_simulator.jl b/test/test_sv_simulator.jl index 2cbe80d..1047f6b 100644 --- a/test/test_sv_simulator.jl +++ b/test/test_sv_simulator.jl @@ -1,6 +1,4 @@ -using Test, Braket, BraketSimulator, DataStructures - -import Braket: I, Instruction +using Test, BraketSimulator, DataStructures LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) @@ -11,138 +9,138 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) state_vector, probability_amplitudes, ) in [ - ([Instruction(H(), [0])], 1, [0.70710678, 0.70710678], [0.5, 0.5]), - ([Instruction(X(), [0])], 1, [0, 1], [0, 1]), - ([Instruction(X(), [0])], 2, [0, 0, 1, 0], [0, 0, 1, 0]), - ([Instruction(Y(), [0])], 1, [0, im], [0, 1]), - ([Instruction(X(), [0]), Instruction(X(), [1])], 2, [0, 0, 0, 1], [0, 0, 0, 1]), - ([Instruction(X(), [0]), Instruction(Z(), [0])], 1, [0, -1], [0, 1]), - ( - [Instruction(X(), [0]), Instruction(CNot(), [0, 1])], + ([BraketSimulator.Instruction(BraketSimulator.H(), [0])], 1, [0.70710678, 0.70710678], [0.5, 0.5]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0])], 1, [0, 1], [0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0])], 2, [0, 0, 1, 0], [0, 0, 1, 0]), + ([BraketSimulator.Instruction(BraketSimulator.Y(), [0])], 1, [0, im], [0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.X(), [1])], 2, [0, 0, 0, 1], [0, 0, 0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Z(), [0])], 1, [0, -1], [0, 1]), + ( + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1])], 2, [0, 0, 0, 1], [0, 0, 0, 1], ), ( - [Instruction(X(), [0]), Instruction(CY(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.CY(), [0, 1])], 2, [0, 0, 0, im], [0, 0, 0, 1], ), ( - [Instruction(X(), [0]), Instruction(CZ(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.CZ(), [0, 1])], 2, [0, 0, 1, 0], [0, 0, 1, 0], ), ( - [Instruction(X(), [0]), Instruction(Swap(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Swap(), [0, 1])], 2, [0, 1, 0, 0], [0, 1, 0, 0], ), ( - [Instruction(X(), [0]), Instruction(ISwap(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.ISwap(), [0, 1])], 2, [0, im, 0, 0], [0, 1, 0, 0], ), ( - [Instruction(X(), [0]), Instruction(Swap(), [0, 2])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Swap(), [0, 2])], 3, [0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], ), - ([Instruction(X(), [0]), Instruction(S(), [0])], 1, [0, im], [0, 1]), - ([Instruction(X(), [0]), Instruction(Si(), [0])], 1, [0, -im], [0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.S(), [0])], 1, [0, im], [0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Si(), [0])], 1, [0, -im], [0, 1]), ( - [Instruction(X(), [0]), Instruction(T(), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.T(), [0])], 1, [0, 0.70710678 + 0.70710678 * im], [0, 1], ), ( - [Instruction(X(), [0]), Instruction(Ti(), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Ti(), [0])], 1, [0, 0.70710678 - 0.70710678 * im], [0, 1], ), - ([Instruction(V(), [0])], 1, [0.5 + 0.5 * im, 0.5 - 0.5 * im], [0.5, 0.5]), - ([Instruction(Vi(), [0])], 1, [0.5 - 0.5 * im, 0.5 + 0.5 * im], [0.5, 0.5]), - ([Instruction(I(), [0])], 1, [1, 0], [1, 0]), - ([Instruction(Unitary([0 1; 1 0]), [0])], 1, [0, 1], [0, 1]), + ([BraketSimulator.Instruction(BraketSimulator.V(), [0])], 1, [0.5 + 0.5 * im, 0.5 - 0.5 * im], [0.5, 0.5]), + ([BraketSimulator.Instruction(BraketSimulator.Vi(), [0])], 1, [0.5 - 0.5 * im, 0.5 + 0.5 * im], [0.5, 0.5]), + ([BraketSimulator.Instruction(BraketSimulator.I(), [0])], 1, [1, 0], [1, 0]), + ([BraketSimulator.Instruction(BraketSimulator.Unitary([0 1; 1 0]), [0])], 1, [0, 1], [0, 1]), ( - [Instruction(X(), [0]), Instruction(PhaseShift(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.PhaseShift(0.15), [0])], 1, [0, 0.98877108 + 0.14943813 * im], [0, 1], ), ( [ - Instruction(X(), [0]), - Instruction(X(), [1]), - Instruction(CPhaseShift(0.15), [0, 1]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [1]), + BraketSimulator.Instruction(BraketSimulator.CPhaseShift(0.15), [0, 1]), ], 2, [0, 0, 0, 0.98877108 + 0.14943813 * im], [0, 0, 0, 1], ), ( - [Instruction(CPhaseShift00(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.CPhaseShift00(0.15), [0, 1])], 2, [0.98877108 + 0.14943813 * im, 0, 0, 0], [1, 0, 0, 0], ), ( - [Instruction(X(), [1]), Instruction(CPhaseShift01(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [1]), BraketSimulator.Instruction(BraketSimulator.CPhaseShift01(0.15), [0, 1])], 2, [0, 0.98877108 + 0.14943813 * im, 0, 0], [0, 1, 0, 0], ), ( - [Instruction(X(), [0]), Instruction(CPhaseShift10(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.CPhaseShift10(0.15), [0, 1])], 2, [0, 0, 0.98877108 + 0.14943813 * im, 0], [0, 0, 1, 0], ), ( - [Instruction(Rx(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.Rx(0.15), [0])], 1, [0.99718882, -0.07492971 * im], [0.99438554, 0.00561446], ), ( - [Instruction(X(), [0]), Instruction(Ry(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(0.15), [0])], 1, [-0.07492971, 0.99718882], [0.00561446, 0.99438554], ), ( - [Instruction(H(), [0]), Instruction(Rz(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.Rz(0.15), [0])], 1, [0.70511898 - 0.0529833 * im, 0.70511898 + 0.0529833 * im], [0.5, 0.5], ), ( - [Instruction(H(), [0]), Instruction(GPi(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.GPi(0.15), [0])], 1, [0.69916673 - 0.10566872im, 0.69916673 + 0.10566872im], [0.5, 0.5], ), ( - [Instruction(H(), [0]), Instruction(GPi2(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.GPi2(0.15), [0])], 1, [0.42528093 - 0.49438554im, 0.57471907 - 0.49438554im], [0.42528093, 0.57471907], ), ( - [Instruction(MS(π/2, -π/4, 0.3), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.MS(π/2, -π/4, 0.3), [0, 1])], 2, [0.98877108, 0, 0, 0.10566872 - 0.10566872im], [0.97766824, 0, 0, 0.02233176], ), ( - [Instruction(H(), [0]), Instruction(H(), [1]), Instruction(ECR(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1]), BraketSimulator.Instruction(BraketSimulator.ECR(), [0, 1])], 2, [ 0.35355339 + 0.35355339im, @@ -153,58 +151,58 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) [0.25, 0.25, 0.25, 0.25], ), ( - [Instruction(H(), [0]), Instruction(U(0.15, 0.4, 0.7), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.U(0.15, 0.4, 0.7), [0])], 1, [0.66459511 - 0.03413278im, 0.36864009 + 0.64903989im], [0.44285171, 0.55714829], ), ( - [Instruction(H(), [0]), Instruction(MultiQubitPhaseShift{1}(0.15), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.MultiQubitPhaseShift{1}(0.15), [0])], 1, [0.69916673 + 0.10566872im, 0.69916673 + 0.10566872im], [0.5, 0.5], ), ( - [Instruction(H(), [0]), Instruction(PRx(0.15, 0.4), [0])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.PRx(0.15, 0.4), [0])], 1, [0.6844863 - 0.04880085im, 0.72575165 - 0.04880085im], [0.47090303, 0.52909697], ), ( - [Instruction(X(), [0]), Instruction(PSwap(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.PSwap(0.15), [0, 1])], 2, [0, 0.98877108 + 0.14943813 * im, 0, 0], [0, 1, 0, 0], ), ( - [Instruction(X(), [0]), Instruction(XY(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.X(), [0]), BraketSimulator.Instruction(BraketSimulator.XY(0.15), [0, 1])], 2, [0, 0.07492971 * im, 0.99718882, 0], [0, 0.00561446, 0.99438554, 0], ), ( - [Instruction(XX(0.3), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.XX(0.3), [0, 1])], 2, [0.98877108, 0, 0, -0.14943813 * im], [0.97766824, 0, 0, 0.02233176], ), ( - [Instruction(YY(0.3), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.YY(0.3), [0, 1])], 2, [0.98877108, 0, 0, 0.14943813 * im], [0.97766824, 0, 0, 0.02233176], ), ( - [Instruction(ZZ(0.15), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.ZZ(0.15), [0, 1])], 2, [0.99718882 - 0.07492971 * im, 0, 0, 0], [1, 0, 0, 0], ), ( [ - Instruction(X(), [0]), - Instruction(X(), [1]), - Instruction(CCNot(), [0, 1, 2]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [1]), + BraketSimulator.Instruction(BraketSimulator.CCNot(), [0, 1, 2]), ], 3, [0, 0, 0, 0, 0, 0, 0, 1], @@ -212,9 +210,9 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) ), ( [ - Instruction(X(), [0]), - Instruction(X(), [1]), - Instruction(CSwap(), [0, 1, 2]), + BraketSimulator.Instruction(BraketSimulator.X(), [0]), + BraketSimulator.Instruction(BraketSimulator.X(), [1]), + BraketSimulator.Instruction(BraketSimulator.CSwap(), [0, 1, 2]), ], 3, [0, 0, 0, 0, 0, 1, 0, 0], @@ -232,58 +230,58 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) end end @testset "Apply observables $obs" for (obs, equivalent_gates, qubit_count) in [ - ([(Braket.Observables.X(), [0])], [Instruction(H(), [0])], 1), - ([(Braket.Observables.Z(), [0])], Instruction[], 1), - ([(Braket.Observables.I(), [0])], Instruction[], 1), + ([(BraketSimulator.Observables.X(), [0])], [BraketSimulator.Instruction(BraketSimulator.H(), [0])], 1), + ([(BraketSimulator.Observables.Z(), [0])], BraketSimulator.Instruction[], 1), + ([(BraketSimulator.Observables.I(), [0])], BraketSimulator.Instruction[], 1), ( [ - (Braket.Observables.X(), [0]), - (Braket.Observables.Z(), [3]), - (Braket.Observables.H(), [2]), + (BraketSimulator.Observables.X(), [0]), + (BraketSimulator.Observables.Z(), [3]), + (BraketSimulator.Observables.H(), [2]), ], - [Instruction(H(), [0]), Instruction(Ry(-π / 4), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(-π / 4), [2])], 5, ), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.X(), - Braket.Observables.Z(), - Braket.Observables.H(), - Braket.Observables.I(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.X(), + BraketSimulator.Observables.Z(), + BraketSimulator.Observables.H(), + BraketSimulator.Observables.I(), ]), (0, 3, 2, 1), )], - [Instruction(H(), [0]), Instruction(Ry(-π / 4), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.Ry(-π / 4), [2])], 5, ), ( - [(Braket.Observables.X(), [0, 1])], - [Instruction(H(), [0]), Instruction(H(), [1])], + [(BraketSimulator.Observables.X(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.H(), [1])], 2, ), - ([(Braket.Observables.Z(), [0, 1])], Instruction[], 2), - ([(Braket.Observables.I(), [0, 1])], Instruction[], 2), + ([(BraketSimulator.Observables.Z(), [0, 1])], BraketSimulator.Instruction[], 2), + ([(BraketSimulator.Observables.I(), [0, 1])], BraketSimulator.Instruction[], 2), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.I(), - Braket.Observables.Z(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.I(), + BraketSimulator.Observables.Z(), ]), (2, 0), )], - Instruction[], + BraketSimulator.Instruction[], 3, ), ( [( - Braket.Observables.TensorProduct([ - Braket.Observables.X(), - Braket.Observables.Z(), + BraketSimulator.Observables.TensorProduct([ + BraketSimulator.Observables.X(), + BraketSimulator.Observables.Z(), ]), (2, 0), )], - [Instruction(H(), [2])], + [BraketSimulator.Instruction(BraketSimulator.H(), [2])], 3, ), ] @@ -298,11 +296,11 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) simulation = StateVectorSimulator(4, 0) simulation = BraketSimulator.apply_observables!( simulation, - [(Braket.Observables.X(), [0])], + [(BraketSimulator.Observables.X(), [0])], ) @test_throws ErrorException BraketSimulator.apply_observables!( simulation, - [(Braket.Observables.X(), [0])], + [(BraketSimulator.Observables.X(), [0])], ) end @testset "state_with_observables fails before any observables are applied" begin @@ -311,14 +309,14 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) end @testset "QFT simulation" begin function qft_circuit_operations(qubit_count::Int) - qft_ops = Instruction[] + qft_ops = BraketSimulator.Instruction[] for target_qubit = 0:qubit_count-1 angle = π / 2 - push!(qft_ops, Instruction(H(), [target_qubit])) + push!(qft_ops, BraketSimulator.Instruction(BraketSimulator.H(), [target_qubit])) for control_qubit = target_qubit+1:qubit_count-1 push!( qft_ops, - Instruction(CPhaseShift(angle), [control_qubit, target_qubit]), + BraketSimulator.Instruction(BraketSimulator.CPhaseShift(angle), [control_qubit, target_qubit]), ) angle /= 2 end @@ -338,11 +336,11 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) simulation = StateVectorSimulator(2, 10000) simulation = BraketSimulator.evolve!( simulation, - [Instruction(H(), [0]), Instruction(CNot(), [0, 1])], + [BraketSimulator.Instruction(BraketSimulator.H(), [0]), BraketSimulator.Instruction(BraketSimulator.CNot(), [0, 1])], ) samples = counter(BraketSimulator.samples(simulation)) - @test qubit_count(simulation) == 2 + @test BraketSimulator.qubit_count(simulation) == 2 @test collect(keys(samples)) == [0, 3] @test 0.4 < samples[0] / (samples[0] + samples[3]) < 0.6 @test 0.4 < samples[3] / (samples[0] + samples[3]) < 0.6 @@ -350,19 +348,18 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) end @testset "batch" begin function make_ghz(num_qubits) - ghz = Circuit() - ghz(H, 0) - for ii in 0:num_qubits-2 - ghz(CNot, ii, ii+1) + ghz = BraketSimulator.Program(BraketSimulator.braketSchemaHeader("braket.ir.jaqcd.program", "1"), BraketSimulator.Instruction[BraketSimulator.Instruction(BraketSimulator.H(), 0)], BraketSimulator.AbstractProgramResult[], BraketSimulator.Instruction[]) + for ii in 1:num_qubits-1 + push!(ghz.instructions, BraketSimulator.Instruction(BraketSimulator.CNot(), [0, ii])) end - return ir(ghz) + return ghz end num_qubits = 5 @testset for n_circuits in (1, 100) shots = 1000 jl_ghz = [make_ghz(num_qubits) for ix in 1:n_circuits] jl_sim = StateVectorSimulator(num_qubits, 0); - results = simulate(jl_sim, jl_ghz, shots) + results = BraketSimulator.simulate(jl_sim, jl_ghz, shots) for (r_ix, r) in enumerate(results) @test length(r.measurements) == shots @test 400 < count(m->m == fill(0, num_qubits), r.measurements) < 600 @@ -394,7 +391,8 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) b[3] = measure q[3]; """ simulator = StateVectorSimulator(0, 0) - res = simulate(simulator, ir(Circuit(qasm), Val(:OpenQASM)), 1000) + oq3_program = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), qasm, nothing) + res = BraketSimulator.simulate(simulator, oq3_program, 1000) @test all(m -> m == zeros(Int, 4), res.measurements) @test length(res.measurements) == 1000 @test res.measuredQubits == collect(0:3) @@ -408,7 +406,8 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) b = measure q; """ simulator = StateVectorSimulator(0, 0) - res = simulate(simulator, ir(Circuit(qasm), Val(:OpenQASM)), 1000) + oq3_program = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), qasm, nothing) + res = BraketSimulator.simulate(simulator, oq3_program, 1000) @test res.measuredQubits == collect(0:3) @test 400 < sum(m[1] for m in res.measurements) < 600 @test 400 < sum(m[2] for m in res.measurements) < 600 @@ -461,6 +460,203 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) "z", "zz", ] + new_sv_qubit_count = 18 + new_sv_max_shots = 1_000_000 + new_sv_observables = ["x", "y", "z", "h", "i", "hermitian"] + new_sv_props_dict = Dict( + :braketSchemaHeader => Dict( + :name => "braket.device_schema.simulators.gate_model_simulator_device_capabilities", + :version => "1", + ), + :service => Dict( + :executionWindows => [ + Dict( + :executionDay => "Everyday", + :windowStartHour => "00:00", + :windowEndHour => "23:59:59", + ), + ], + :shotsRange => [0, new_sv_max_shots], + ), + :action => Dict( + "braket.ir.jaqcd.program" => Dict( + :actionType => "braket.ir.jaqcd.program", + :version => ["1"], + :supportedOperations => [ + "ccnot", + "cnot", + "cphaseshift", + "cphaseshift00", + "cphaseshift01", + "cphaseshift10", + "cswap", + "cv", + "cy", + "cz", + "ecr", + "h", + "i", + "iswap", + "pswap", + "phaseshift", + "prx", + "rx", + "ry", + "rz", + "s", + "si", + "swap", + "t", + "ti", + "unitary", + "v", + "vi", + "x", + "xx", + "xy", + "y", + "yy", + "z", + "zz", + ], + :supportedResultTypes => [ + Dict( + :name => "Sample", + :observables => new_sv_observables, + :minShots => 1, + :maxShots => new_sv_max_shots, + ), + Dict( + :name => "Expectation", + :observables => new_sv_observables, + :minShots => 0, + :maxShots => new_sv_max_shots, + ), + Dict( + :name => "Variance", + :observables => new_sv_observables, + :minShots => 0, + :maxShots => new_sv_max_shots, + ), + Dict(:name => "Probability", :minShots => 0, :maxShots => new_sv_max_shots), + Dict(:name => "StateVector", :minShots => 0, :maxShots => 0), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), + Dict(:name => "Amplitude", :minShots => 0, :maxShots => 0), + ], + ), + "braket.ir.openqasm.program" => Dict( + :actionType => "braket.ir.openqasm.program", + :version => ["1"], + :supportedOperations => [ + "U", + "GPhase", + "ccnot", + "cnot", + "cphaseshift", + "cphaseshift00", + "cphaseshift01", + "cphaseshift10", + "cswap", + "cv", + "cy", + "cz", + "ecr", + "gpi", + "gpi2", + "h", + "i", + "iswap", + "ms", + "pswap", + "phaseshift", + "prx", + "rx", + "ry", + "rz", + "s", + "si", + "swap", + "t", + "ti", + "unitary", + "v", + "vi", + "x", + "xx", + "xy", + "y", + "yy", + "z", + "zz", + ], + :supportedModifiers => [ + Dict(:name => "ctrl"), + Dict(:name => "negctrl"), + Dict(:name => "pow", :exponent_types => ["int", "float"]), + Dict(:name => "inv"), + ], + :supportedPragmas => [ + "braket_unitary_matrix", + "braket_result_type_state_vector", + "braket_result_type_density_matrix", + "braket_result_type_sample", + "braket_result_type_expectation", + "braket_result_type_variance", + "braket_result_type_probability", + "braket_result_type_amplitude", + ], + :forbiddenPragmas => [ + "braket_noise_amplitude_damping", + "braket_noise_bit_flip", + "braket_noise_depolarizing", + "braket_noise_kraus", + "braket_noise_pauli_channel", + "braket_noise_generalized_amplitude_damping", + "braket_noise_phase_flip", + "braket_noise_phase_damping", + "braket_noise_two_qubit_dephasing", + "braket_noise_two_qubit_depolarizing", + ], + :supportedResultTypes => [ + Dict( + :name => "Sample", + :observables => new_sv_observables, + :minShots => 1, + :maxShots => new_sv_max_shots, + ), + Dict( + :name => "Expectation", + :observables => new_sv_observables, + :minShots => 0, + :maxShots => new_sv_max_shots, + ), + Dict( + :name => "Variance", + :observables => new_sv_observables, + :minShots => 0, + :maxShots => new_sv_max_shots, + ), + Dict(:name => "Probability", :minShots => 0, :maxShots => new_sv_max_shots), + Dict(:name => "StateVector", :minShots => 0, :maxShots => 0), + Dict(:name => "DensityMatrix", :minShots => 0, :maxShots => 0), + Dict(:name => "Amplitude", :minShots => 0, :maxShots => 0), + ], + :supportPhysicalQubits => false, + :supportsPartialVerbatimBox => false, + :requiresContiguousQubitIndices => true, + :requiresAllQubitsMeasurement => true, + :supportsUnassignedMeasurements => true, + :disabledQubitRewiringSupported => false, + ), + ), + :paradigm => Dict(:qubitCount => new_sv_qubit_count), + :deviceParameters => + Dict(:paradigmParameters => Dict(:qubitCount => new_sv_qubit_count)), + ) + + new_sv_props = BraketSimulator.StructTypes.constructfrom(BraketSimulator.GateModelSimulatorDeviceCapabilities, new_sv_props_dict) + @test new_sv_props.paradigm.qubitCount == new_sv_qubit_count + @test BraketSimulator.supported_result_types(sim) == BraketSimulator.supported_result_types(sim, Val(:OpenQASM)) end @testset "inputs handling" begin sv_adder_qasm = """ @@ -505,8 +701,8 @@ LARGE_TESTS = get(ENV, "BRAKET_SV_LARGE_TESTS", false) #pragma braket result probability b """ simulator = StateVectorSimulator(6, 0) - oq3_program = Braket.OpenQasmProgram(Braket.header_dict[Braket.OpenQasmProgram], sv_adder_qasm, Dict("a_in"=>3, "b_in"=>7)) + oq3_program = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), sv_adder_qasm, Dict("a_in"=>3, "b_in"=>7)) # should NOT throw a missing input error - simulate(simulator, oq3_program, 0; inputs=Dict{String, Float64}()) + BraketSimulator.simulate(simulator, oq3_program, 0; inputs=Dict{String, Float64}()) end end diff --git a/test/test_validation.jl b/test/test_validation.jl index aaae770..64ee61e 100644 --- a/test/test_validation.jl +++ b/test/test_validation.jl @@ -1,21 +1,23 @@ -using Test, Braket, BraketSimulator +using Test, BraketSimulator @testset "IR validation" begin sim = DensityMatrixSimulator(2, 0) results = [(type="NotARealResult",)] @test_throws ErrorException BraketSimulator._validate_ir_results_compatibility(sim, results, Val(:OpenQASM)) @test_throws ErrorException BraketSimulator._validate_ir_results_compatibility(sim, results, Val(:JAQCD)) - - @test_throws ErrorException BraketSimulator._validate_input_provided(Circuit([(Rx(FreeParameter(:α)), 0)])) - @test isnothing(BraketSimulator._validate_input_provided(Circuit([(Rx(0.1), 0)]))) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, BraketSimulator.Instruction(BraketSimulator.Rx(BraketSimulator.FreeParameter(:α)), 0)) + @test_throws ErrorException BraketSimulator._validate_input_provided(c) + c = BraketSimulator.Circuit() + BraketSimulator.add_instruction!(c, BraketSimulator.Instruction(BraketSimulator.Rx(0.1), 0)) + @test isnothing(BraketSimulator._validate_input_provided(c)) sim = DensityMatrixSimulator(2, 0) - c = Circuit([(Rx(0.1), 0)]) @test_logs (:warn, "You are running a noise-free circuit on the density matrix simulator. Consider running this circuit on the state vector simulator: LocalSimulator(\"braket_sv_v2\") for a better user experience.") BraketSimulator._validate_ir_instructions_compatibility(sim, c, Val(:OpenQASM)) @test_logs (:warn, "You are running a noise-free circuit on the density matrix simulator. Consider running this circuit on the state vector simulator: LocalSimulator(\"braket_sv_v2\") for a better user experience.") BraketSimulator._validate_ir_instructions_compatibility(sim, c, Val(:JAQCD)) sim = StateVectorSimulator(2, 0) - c = Circuit([(BitFlip(0.1), 0)]) + BraketSimulator.add_instruction!(c, BraketSimulator.Instruction(BraketSimulator.BitFlip(0.1), 0)) @test_throws ValidationError BraketSimulator._validate_ir_instructions_compatibility(sim, c, Val(:OpenQASM)) @test_throws ValidationError BraketSimulator._validate_ir_instructions_compatibility(sim, c, Val(:JAQCD)) end