Skip to content

Commit

Permalink
feature: Add Reset, Barrier, Delay, and bump deps (#104)
Browse files Browse the repository at this point in the history
* feature: Add Reset, Barrier, Delay, and bump deps

* fix: Doc ref

* fix: doctests

* fix: More coverage

* fix: even more tests for coverage
  • Loading branch information
kshyatt-aws authored Oct 7, 2024
1 parent 81486d8 commit 2efe7c3
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,5 @@ jobs:
run: |
using Documenter: DocMeta, doctest
using Braket
DocMeta.setdocmeta!(Braket, :DocTestSetup, :(using Braket); recursive=true)
DocMeta.setdocmeta!(Braket, :DocTestSetup, :(using Braket, Braket.Dates); recursive=true)
doctest(Braket)
10 changes: 5 additions & 5 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Braket"
uuid = "19504a0f-b47d-4348-9127-acc6cc69ef67"
authors = ["Katharine Hyatt <hyatkath@amazon.com>"]
version = "0.9.4"
version = "0.9.5"

[deps]
AWS = "fbe9abb3-538b-5e4e-ba9e-bc94f4f92ebc"
Expand Down Expand Up @@ -33,7 +33,7 @@ Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[compat]
AWS = "=1.91.0"
AWS = "=1.92.0"
AWSS3 = "=0.11.2"
Aqua = "=0.8"
AxisArrays = "=0.4.7"
Expand All @@ -50,20 +50,20 @@ Downloads = "1"
Graphs = "=1.11.2"
HTTP = "=1.10.8"
InteractiveUtils = "1.6"
JLD2 = "=0.4.51"
JLD2 = "=0.5.4"
JSON3 = "=1.14.0"
LinearAlgebra = "1.6"
Logging = "1.6"
Markdown = "=0.7.5"
Mocking = "=0.7.9"
Mocking = "=0.8.1"
NamedTupleTools = "=0.14.3"
OrderedCollections = "=1.6.3"
Pkg = "1.6"
Random = "1.6"
SparseArrays = "1.6"
StaticArrays = "=1.9.7"
Statistics = "1.6"
StructTypes = "=1.10.0"
StructTypes = "=1.11.0"
Tar = "1.9.3"
Test = "1.6"
UUIDs = "1.6"
Expand Down
6 changes: 3 additions & 3 deletions PyBraket/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PyBraket"
uuid = "e85266a6-1825-490b-a80e-9b9469c53660"
authors = ["Katharine Hyatt <hyatkath@amazon.com>"]
version = "0.9.4"
version = "0.9.5"

[deps]
Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67"
Expand All @@ -14,13 +14,13 @@ StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"

[compat]
Aqua = "=0.8"
Braket = "=0.9.4"
Braket = "=0.9.5"
CondaPkg = "=0.2.23"
DataStructures = "=0.18.20"
LinearAlgebra = "1.6"
PythonCall = "=0.9.22"
Statistics = "1"
StructTypes = "=1.10.0"
StructTypes = "=1.11.0"
Test = "1.6"
julia = "1.6"

Expand Down
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
push!(LOAD_PATH,"../src/")

using Documenter, Braket
using Documenter, Braket, Braket.Dates

makedocs(sitename="Braket.jl")

Expand Down
6 changes: 6 additions & 0 deletions docs/src/circuits.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ qubits
qubit_count
measure
Measure
barrier
Barrier
reset(::Circuit, ::Any)
Reset
delay
Delay
```

## Output to IR
Expand Down
2 changes: 1 addition & 1 deletion src/Braket.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export provider_name, properties, type
export apply_gate_noise!, apply
export logs, log_metric, metrics, @hybrid_job
export depth, qubit_count, qubits, ir, IRType, OpenQASMSerializationProperties
export OpenQasmProgram, Measure, measure
export OpenQasmProgram, Measure, Reset, Barrier, Delay, measure, reset, barrier, delay
export simulate
export QueueDepthInfo, QueueType, Normal, Priority, queue_depth, queue_position

Expand Down
65 changes: 65 additions & 0 deletions src/circuit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,71 @@ function measure(c::Circuit, target_qubits)
return _add_measure!(c, target_qubits)
end

"""
reset(c::Circuit, target_qubits) -> Circuit
Add a [`Reset`](@ref) operator to `c`, performing an active reset to the `|0>` state on the targeted qubits.
A `Reset` operation can be applied after a [`Measure`](@ref) to re-initialize the qubit and allow it to be reused
after mid-circuit measurement.
# Examples
```jldoctest
julia> circ = Circuit([(H, 0), (CNot, 0, 1)]);
julia> circ = reset(circ, 0);
julia> circ.instructions
3-element Vector{Braket.Instruction}:
Braket.Instruction{H}(H(), QubitSet(0))
Braket.Instruction{CNot}(CNot(), QubitSet(0, 1))
Braket.Instruction{Reset}(Reset(), QubitSet(0))
```
"""
Base.reset(c::Circuit, target_qubits) = (foreach(t->add_instruction!(c, Instruction(Reset(), t)), target_qubits); return c)

"""
delay(c::Circuit, duration::Dates.Period, target_qubits) -> Circuit
Add a [`Delay`](@ref) operator to `c`, which forces all targeted qubits to wait for `duration`
before any new operations may be applied to any of them.
# Examples
```jldoctest
julia> circ = Circuit([(H, 0), (CNot, 0, 1)]);
julia> circ = delay(circ, Nanosecond(10), [0, 1]);
julia> circ.instructions
3-element Vector{Braket.Instruction}:
Braket.Instruction{H}(H(), QubitSet(0))
Braket.Instruction{CNot}(CNot(), QubitSet(0, 1))
Braket.Instruction{Delay}(Delay(Nanosecond(10)), QubitSet(0, 1))
```
"""
delay(c::Circuit, duration::Dates.Period, target_qubits) = (add_instruction!(c, Instruction(Delay(duration), target_qubits)); return c)
# TODO enforce this in `Moments` as well

"""
barrier(c::Circuit, target_qubits) -> Circuit
Add a [`Barrier`](@ref) operator to `c`, which forces all targeted qubits to reach the barrier before any new
operations may be applied to any of them.
# Examples
```jldoctest
julia> circ = Circuit([(H, 0), (CNot, 0, 1)]);
julia> circ = barrier(circ, [0, 1]);
julia> circ.instructions
3-element Vector{Braket.Instruction}:
Braket.Instruction{H}(H(), QubitSet(0))
Braket.Instruction{CNot}(CNot(), QubitSet(0, 1))
Braket.Instruction{Barrier}(Barrier(), QubitSet(0, 1))
```
"""
barrier(c::Circuit, target_qubits) = (add_instruction!(c, Instruction(Barrier(), target_qubits)); return c)

function openqasm_header(c::Circuit, sps::SerializationProperties=OpenQASMSerializationProperties())
ir_instructions = ["OPENQASM 3.0;"]
for p in sort(string.(c.parameters))
Expand Down
56 changes: 52 additions & 4 deletions src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ struct PauliEigenvalues{N}
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.iterate(p::PauliEigenvalues{N}, ix::Int=1) where {N} = ix <= length(p) ? (p[ix], ix+1) : nothing

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
Expand Down Expand Up @@ -71,8 +69,9 @@ end
Measure() = Measure(-1)
Parametrizable(m::Measure) = NonParametrized()
chars(::Type{Measure}) = ("M",)
chars(m::Measure) = ("M",)
chars(::Measure) = chars(Measure)
qubit_count(::Type{Measure}) = 1
qubit_count(::Measure) = qubit_count(Measure)
ir(m::Measure, target::QubitSet, ::Val{:JAQCD}; kwargs...) = error("measure instructions are not supported with JAQCD.")
function ir(m::Measure, target::QubitSet, ::Val{:OpenQASM}; serialization_properties=OpenQASMSerializationProperties())
instructions = Vector{String}(undef, length(target))
Expand All @@ -83,3 +82,52 @@ function ir(m::Measure, target::QubitSet, ::Val{:OpenQASM}; serialization_proper
end
return join(instructions, "\n")
end

"""
Reset() <: QuantumOperator
Represents an active reset operation on targeted qubit.
"""
struct Reset <: QuantumOperator end
Parametrizable(m::Reset) = NonParametrized()
chars(::Type{Reset}) = ("Reset",)
chars(::Reset) = chars(Reset)
label(::Reset) = "reset"
qubit_count(::Type{Reset}) = 1
qubit_count(r::Reset) = qubit_count(Reset)

"""
Barrier() <: QuantumOperator
Represents a barrier operation on targeted qubit.
"""
struct Barrier <: QuantumOperator end
Parametrizable(b::Barrier) = NonParametrized()
chars(::Type{Barrier}) = ("Barrier",)
chars(r::Barrier) = chars(Barrier)
label(::Barrier) = "barrier"
qubit_count(::Type{Barrier}) = 1
qubit_count(b::Barrier) = qubit_count(Barrier)

"""
Delay(duration::Period) <: QuantumOperator
Represents a delay operation for `duration` on targeted qubit.
"""
struct Delay <: QuantumOperator
duration::Dates.Period
end
Parametrizable(m::Delay) = NonParametrized()
chars(d::Delay) = ("Delay($(label(d.duration)))",)
label(d::Delay) = "delay[$(label(d.duration))]"
qubit_count(::Type{Delay}) = 1
qubit_count(d::Delay) = qubit_count(Delay)
Base.:(==)(d1::Delay, d2::Delay) = d1.duration == d2.duration
label(d::Microsecond) = "$(d.value)ms"
label(d::Nanosecond) = "$(d.value)ns"
label(d::Second) = "$(d.value)s"

ir(ix::Union{Reset, Barrier, Delay}, target::QubitSet, ::Val{:JAQCD}; kwargs...) = error("$(label(ix)) instructions are not supported with JAQCD.")
function ir(ix::Union{Reset, Barrier, Delay}, target::QubitSet, v::Val{:OpenQASM}; serialization_properties=OpenQASMSerializationProperties())
return join(("$(label(ix)) $(format_qubits(qubit, serialization_properties));" for qubit in target), "\n")
end
53 changes: 53 additions & 0 deletions test/circuit_timing.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Braket, Braket.Dates, Test
using Braket: Instruction, VIRTUAL, PHYSICAL, OpenQASMSerializationProperties

@testset "Barrier, reset, and delay operators" begin
@test Barrier() isa Braket.QuantumOperator
@test Reset() isa Braket.QuantumOperator
@test Braket.Parametrizable(Reset()) == Braket.NonParametrized()
@test Braket.Parametrizable(Barrier()) == Braket.NonParametrized()
@test Braket.Parametrizable(Delay(Microsecond(200))) == Braket.NonParametrized()
@test qubit_count(Reset()) == 1
@test qubit_count(Barrier()) == 1
circ = Circuit([(H, 0), (CNot, 0, 1)])
circ = barrier(circ, 0)
@test circ.instructions == [Instruction{H}(H(), QubitSet(0)), Instruction{CNot}(CNot(), QubitSet(0, 1)), Instruction{Barrier}(Barrier(), QubitSet(0))]
circ = Circuit([(H, 0), (CNot, 0, 1)])
circ = reset(circ, 0)
@test circ.instructions == [Instruction{H}(H(), QubitSet(0)), Instruction{CNot}(CNot(), QubitSet(0, 1)), Instruction{Reset}(Reset(), QubitSet(0))]
circ = Circuit([(H, 0), (CNot, 0, 1)])
circ = delay(circ, Nanosecond(10), 0)
@test circ.instructions == [Instruction{H}(H(), QubitSet(0)), Instruction{CNot}(CNot(), QubitSet(0, 1)), Instruction{Delay}(Delay(Nanosecond(10)), QubitSet(0))]
@test qubit_count(Delay(Microsecond(200))) == 1
@test Delay(Microsecond(200)) isa Braket.QuantumOperator
@testset "Equality" for t in (Barrier, Reset)
t1 = t()
t2 = t()
non_t = Measure()
@test t1 == t2
@test t1 != non_t
end
@test Delay(Nanosecond(10)) != Delay(Microsecond(10))
@test Delay(Nanosecond(10_000)) == Delay(Microsecond(10))
@test Braket.chars(Barrier()) == ("Barrier",)
@test Braket.chars(Reset()) == ("Reset",)
@test Braket.chars(Delay(Nanosecond(4))) == ("Delay(4ns)",)
@test Braket.chars(Delay(Microsecond(4))) == ("Delay(4ms)",)
@testset "To IR" for (t, str) in ((Barrier(), "barrier"),
(Reset(), "reset"),
(Delay(Second(1)), "delay[1s]"),
)
@testset "Invalid ir_type $ir_type" for (ir_type, message) in ((:JAQCD, "$str instructions are not supported with JAQCD."),
)
@test_throws ErrorException(message) ir(t, QubitSet([0]), Val(ir_type))
end
@testset "OpenQASM, target $target, serialization properties $sps" for (target, sps, expected_ir) in (
([0], OpenQASMSerializationProperties(qubit_reference_type=VIRTUAL), "$str q[0];"),
([4], OpenQASMSerializationProperties(qubit_reference_type=PHYSICAL), "$str \$4;"),
)


@test ir(Instruction(t, target), Val(:OpenQASM); serialization_properties=sps) == expected_ir
end
end
end
5 changes: 5 additions & 0 deletions test/measure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ using Braket: Instruction, VIRTUAL, PHYSICAL, OpenQASMSerializationProperties

@testset "Measure operator" begin
@test Measure() isa Braket.QuantumOperator
@test Braket.Parametrizable(Measure()) == Braket.NonParametrized()
@test qubit_count(Measure()) == 1
@testset "Equality" begin
measure1 = Measure()
measure2 = Measure()
Expand All @@ -11,6 +13,9 @@ using Braket: Instruction, VIRTUAL, PHYSICAL, OpenQASMSerializationProperties
@test measure1 != non_measure
end
@test Braket.chars(Measure()) == ("M",)
circ = Circuit([(H, 0), (CNot, 0, 1)])
circ = measure(circ, 0)
@test circ.instructions == [Instruction{H}(H(), QubitSet(0)), Instruction{CNot}(CNot(), QubitSet(0, 1)), Instruction{Measure}(Measure(0), QubitSet(0))]

@testset "To IR" begin
@testset "Invalid ir_type $ir_type" for (ir_type, message) in ((:JAQCD, "measure instructions are not supported with JAQCD."),
Expand Down
4 changes: 4 additions & 0 deletions test/observables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ using LinearAlgebra: eigvals
Braket.IRType[] = :JAQCD
@testset "pauli eigenvalues" begin
z = [1.0 0.0; 0.0 -1.0]
@test PauliEigenvalues(Val(1))[1] == 1.0
@test PauliEigenvalues(Val(1))[2] == -1.0
@test collect(PauliEigenvalues(Val(1))) == [1.0, -1.0]
for n in 2:6
pe = PauliEigenvalues(Val(n))
@test length(pe) == 2^n
mat = kron(ntuple(i->diag(z), n)...)
for ix in 1:2^n
@test pe[ix] == mat[ix]
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ for group in groups
include("device.jl")
include("circuits.jl")
include("measure.jl")
include("circuit_timing.jl")
include("free_parameter.jl")
include("gates.jl")
include("observables.jl")
Expand Down

4 comments on commit 2efe7c3

@kshyatt-aws
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/116776

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.9.5 -m "<description of version>" 2efe7c3082da22da2e993a8ad92768151098d244
git push origin v0.9.5

@kshyatt-aws
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register subdir=PyBraket

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/116777

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a PyBraket-v0.9.5 -m "<description of version>" 2efe7c3082da22da2e993a8ad92768151098d244
git push origin PyBraket-v0.9.5

Also, note the warning: Version 0.9.5 skips over 0.9.3
This can be safely ignored. However, if you want to fix this you can do so. Call register() again after making the fix. This will update the Pull request.

Please sign in to comment.