Interacting with Neutral Atom Hardware

Bloqade contains its own schema used to represent Hamiltonians in an IR (Intermediate Representation) that can then be executed via simulator/hardware as well as converted to and from other formats. Furthermore, tools such as hardware_transform and validate are available to check that user-defined Hamiltonians are capable of being executed on hardware and if not, transform them to be able to do so.

3-Level Support

The schema and conversion capabilities are currently not available for 3-level Hamiltonians

Transforming Hamiltonians to Hardware Compatible Form

We start with creating a hamiltonian:

julia> using Bloqade, BloqadeSchema
julia> Δ = constant(;duration=1.1, value=1.2*2π);
julia> Ω = linear_ramp(duration=1.1, start_value=0.0, stop_value=2π*1.0);
julia> ϕ = Waveform(t->2.2*2π*sin(t)^2, duration=1.1);
julia> atoms = generate_sites(ChainLattice(), 4, scale=1.0);
julia> h = rydberg_h(atoms; Δ = Δ, Ω = Ω, ϕ = ϕ)nqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i

To transform the Hamiltonian into something the hardware is capable of supporting, we can pass it through hardware_transform.

Limitations on Transformations

While hardware_transform may attempt to adjust atom positions so that they conform to hardware position resolution capabilities, the function will NOT move atoms such that they satisfy minimum spacing constraints. The validate function presented later will explicitly indicate which atoms are in violation of the position constraints but will require the user to make the necessary changes.

Furthermore, hardware_transform requires that all waveforms the Hamiltonian could use (Rabi frequency, detuning, and phase) are explicitly specified even if they are not used. To indicate non-use of a waveform, BloqadeWaveforms.constant should be used with the value set to zero.

hardware_transform accepts information from get_device_capabilities (already called as a default argument) which provides information on the machine's capabilities and returns the transformed hamiltonian along with additional information regarding the difference (error) between the originally defined lattice geometry and waveforms versus their transformed versions through a HardwareTransformInfo instance.

julia> transformed_h, transform_info = hardware_transform(h);
julia> transformed_hnqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i
julia> transform_infoHardwareTransformInfo(0.19634919330815342, 0.13983001873346415, 3.452294642629581e-8, (Δ = Waveform(_, 1.1), δ = nothing, Δi = 1.0), 0.0)
julia> dump(transform_info)HardwareTransformInfo ϕ_error: Float64 0.19634919330815342 Ω_error: Float64 0.13983001873346415 Δ_error: Float64 3.452294642629581e-8 Δ_mask: NamedTuple{(:Δ, :δ, :Δi), Tuple{Waveform{BloqadeWaveforms.var"#39#40"{Float64}, Float64}, Nothing, Float64}} Δ: Waveform{BloqadeWaveforms.var"#39#40"{Float64}, Float64} f: #39 (function of type BloqadeWaveforms.var"#39#40"{Float64}) value: Float64 7.5398223686155035 duration: Float64 1.1 δ: Nothing nothing Δi: Float64 1.0 mse_atoms: Float64 0.0

Validating Hamiltonians

We can see if this hamiltonian or any other hamiltonian we create will run on hardware with the help of validate.

julia> validate(transformed_h)The following validation violations occured:

1. positions 3 => (2.0, 0.0) and 4 => (3.0, 0.0) are a distance of 1.0 μm apart which is below minimum value of 4.0 μm
2. positions 2 => (1.0, 0.0) and 3 => (2.0, 0.0) are a distance of 1.0 μm apart which is below minimum value of 4.0 μm
3. positions 2 => (1.0, 0.0) and 4 => (3.0, 0.0) are a distance of 2.0 μm apart which is below minimum value of 4.0 μm
4. positions 1 => (0.0, 0.0) and 4 => (3.0, 0.0) are a distance of 3.0 μm apart which is below minimum value of 4.0 μm
5. positions 1 => (0.0, 0.0) and 2 => (1.0, 0.0) are a distance of 1.0 μm apart which is below minimum value of 4.0 μm
6. positions 1 => (0.0, 0.0) and 3 => (2.0, 0.0) are a distance of 2.0 μm apart which is below minimum value of 4.0 μm

In this case, the waveforms have been successfully transformed but there are still some issues with the atom positions. We can rescale their positions, regenerate the Hamiltonian and validate again to make sure the changes are correct.

julia> atoms = generate_sites(ChainLattice(), 4, scale=4.0);
julia> fixed_h = rydberg_h(atoms; Δ = Δ, Ω = Ω, ϕ = ϕ) # Keep older waveforms with new atom geometrynqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i
julia> transformed_h, _ = hardware_transform(fixed_h)(nqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i , HardwareTransformInfo(0.19634919330815342, 0.13983001873346415, 3.452294642629581e-8, (Δ = Waveform(_, 1.1), δ = nothing, Δi = 1.0), 0.0))
julia> validate(transformed_h)The following validation violations occured:

No violations are present meaning the new Hamiltonian has passed validation and can now be executed on hardware.

Converting Between Formats

You can convert the Hamiltonian to and from:

  • JSON Object format
  • Julia Dictionary representation
  • Schema representation
  • Amazon Braket representation

to store the Hamiltonian for other applications or execute it in Bloqade/Neutral Atom hardware.

Internal Validation

By default, all conversion functions invoke validate internally to ensure the Hamiltonian is capable of being run on hardware. If a violation is detected, the Hamiltonian is not converted. For JSON and Schema representations, this can be bypassed by invoking the "no validation" variants to_schema_no_validation and to_json_no_validation respectively. This bypass ability is not available for dictionary representation and Amazon Braket representation (which requires the Hamiltonian is already in TaskSpecification format).

Schema

to_schema allows you to convert a Hamiltonian to Bloqade's native schema format (TaskSpecification) along with an optional SchemaTranslationParams argument to specify the number of shots and device capabilities for validation.

julia> h_schema = to_schema(transformed_h)QuEraTaskSpecification(
  nshots = 1,
  lattice = BloqadeSchema.Lattice(
    sites = [(
        0.0,
        0.0,
      ), (
        4.0e-6,
        0.0,
      ), (
        8.0e-6,
        0.0,
      ), (
        1.2e-5,
        0.0,
      )],
    filling = Int32[1, 1, 1, 1],
  ),
  effective_hamiltonian = BloqadeSchema.EffectiveHamiltonian(
    rydberg = BloqadeSchema.RydbergHamiltonian(
      rabi_frequency_amplitude = BloqadeSchema.RabiFrequencyAmplitude(
        global_value = BloqadeSchema.GlobalField(
          times = [0.0, 5.5e-7, 8.25e-7, 9.63e-7, 1.031e-6, 1.1e-6],
          values = [0.0, 3.1416e6, 4.7124e6, 5.4976e6, 5.8904e6, 0.0],
        ),
      ),
      rabi_frequency_phase = BloqadeSchema.RabiFrequencyPhase(
        global_value = BloqadeSchema.GlobalField(
          times = [
            0.0,
            1.38e-7,
            2.06e-7,
            2.75e-7,
            3.44e-7,
            4.12e-7,
            4.81e-7,
            5.5e-7,
            6.19e-7,
            6.88e-7,
            7.56e-7,
            8.25e-7,
            8.94e-7,
            9.63e-7,
            1.031e-6,
            1.1e-6,
          ],
          values = [
            0.0,
            0.4094655,
            0.7898545,
            1.2857985,
            1.887936,
            2.584901,
            3.363537,
            4.2091465,
            5.1057665,
            6.0364725,
            6.983696,
            7.929557,
            8.8562005,
            9.7461355,
            10.582562,
            10.582562,
          ],
        ),
      ),
      detuning = BloqadeSchema.Detuning(
        global_value = BloqadeSchema.GlobalField(
          times = [0.0, 1.1e-6],
          values = [7.5398224e6, 7.5398224e6],
        ),
      ),
    ),
  ),
)
julia> from_schema(h_schema) # to convert back to Hamiltoniannqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i

JSON

to_json allows you to convert a Hamiltonian to a JSON Object along with an optional SchemaTranslationParams argument to specify the number of shots and device capabilities for validation.

julia> h_json = to_json(transformed_h)"{\"nshots\":1,\"lattice\":{\"sites\":[[0.0,0.0],[4.0e-6,0.0],[8.0e-6,0.0],[1.2e-5,0.0]],\"filling\":[1,1,1,1]},\"effective_hamiltonian\":{\"rydberg\":{\"rabi_frequency_amplitude\":{\"global\":{\"times\":[0.0,5.5e-7,8.25e-7,9.63e-7,1.031e-6,1.1e-6],\"values\":[0.0,3.1416e6,4.7124e6,5.4976e6," ⋯ 157 bytes ⋯ ",9.63e-7,1.031e-6,1.1e-6],\"values\":[0.0,0.4094655,0.7898545,1.2857985,1.887936,2.584901,3.363537,4.2091465,5.1057665,6.0364725,6.983696,7.929557,8.8562005,9.7461355,10.582562,10.582562]}},\"detuning\":{\"global\":{\"times\":[0.0,1.1e-6],\"values\":[7.5398224e6,7.5398224e6]}}}}}"
julia> from_json(h_json) # to convert back to Hamiltoniannqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i

Dictionary

to_dict allows you to convert a Hamiltonian to a Julia dictionary along with an optional SchemaTranslationParams argument to specify the number of shots and device capabilities for validation.

julia> h_dict = to_dict(transformed_h)OrderedCollections.OrderedDict{String, Any} with 3 entries:
  "nshots"                => 1
  "lattice"               => OrderedDict{String, Vector}("sites"=>[[0.0, 0.0], …
  "effective_hamiltonian" => OrderedDict{String, Any}("rydberg"=>OrderedDict{St…
julia> from_dict(h_dict) # to convert back to Hamiltoniannqubits: 4 + ├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j ├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0| └─ [-] Δ(t) ⋅ ∑ n_i

Amazon Braket

to_braket_ahs_ir allows you to convert a TaskSpecification instance into an Braket.IR.AHSProgram that can be submitted for execution on Neutral Atom hardware such as QuEra's 256-qubit Aquila machine via Amazon Braket.

julia> h_schema = to_schema(transformed_h)QuEraTaskSpecification(
  nshots = 1,
  lattice = BloqadeSchema.Lattice(
    sites = [(
        0.0,
        0.0,
      ), (
        4.0e-6,
        0.0,
      ), (
        8.0e-6,
        0.0,
      ), (
        1.2e-5,
        0.0,
      )],
    filling = Int32[1, 1, 1, 1],
  ),
  effective_hamiltonian = BloqadeSchema.EffectiveHamiltonian(
    rydberg = BloqadeSchema.RydbergHamiltonian(
      rabi_frequency_amplitude = BloqadeSchema.RabiFrequencyAmplitude(
        global_value = BloqadeSchema.GlobalField(
          times = [0.0, 5.5e-7, 8.25e-7, 9.63e-7, 1.031e-6, 1.1e-6],
          values = [0.0, 3.1416e6, 4.7124e6, 5.4976e6, 5.8904e6, 0.0],
        ),
      ),
      rabi_frequency_phase = BloqadeSchema.RabiFrequencyPhase(
        global_value = BloqadeSchema.GlobalField(
          times = [
            0.0,
            1.38e-7,
            2.06e-7,
            2.75e-7,
            3.44e-7,
            4.12e-7,
            4.81e-7,
            5.5e-7,
            6.19e-7,
            6.88e-7,
            7.56e-7,
            8.25e-7,
            8.94e-7,
            9.63e-7,
            1.031e-6,
            1.1e-6,
          ],
          values = [
            0.0,
            0.4094655,
            0.7898545,
            1.2857985,
            1.887936,
            2.584901,
            3.363537,
            4.2091465,
            5.1057665,
            6.0364725,
            6.983696,
            7.929557,
            8.8562005,
            9.7461355,
            10.582562,
            10.582562,
          ],
        ),
      ),
      detuning = BloqadeSchema.Detuning(
        global_value = BloqadeSchema.GlobalField(
          times = [0.0, 1.1e-6],
          values = [7.5398224e6, 7.5398224e6],
        ),
      ),
    ),
  ),
)
julia> h_braket = to_braket_ahs_ir(h_schema)Braket.IR.AHSProgram(Braket.braketSchemaHeader("braket.ir.ahs.program", "1"), Braket.IR.Setup(Braket.IR.AtomArrangement(Vector{DecFP.Dec128}[[0.0, 0.0], [4.0e-6, 0.0], [8.0e-6, 0.0], [1.2e-5, 0.0]], [1, 1, 1, 1])), Braket.IR.Hamiltonian(Braket.IR.DrivingField[Braket.IR.DrivingField(Braket.IR.PhysicalField(Braket.IR.TimeSeries(DecFP.Dec128[0.0, 3.1416e6, 4.7124e6, 5.4976e6, 5.8904e6, 0.0], DecFP.Dec128[0.0, 5.5e-7, 8.25e-7, 9.63e-7, 1.031e-6, 1.1e-6]), "uniform"), Braket.IR.PhysicalField(Braket.IR.TimeSeries(DecFP.Dec128[0.0, 0.4094655, 0.7898545, 1.2857985, 1.887936, 2.584901, 3.363537, 4.2091465, 5.1057665, 6.0364725, 6.983696, 7.929557, 8.8562005, 9.7461355, 10.582562, 10.582562], DecFP.Dec128[0.0, 1.38e-7, 2.06e-7, 2.75e-7, 3.44e-7, 4.12e-7, 4.81e-7, 5.5e-7, 6.19e-7, 6.88e-7, 7.56e-7, 8.25e-7, 8.94e-7, 9.63e-7, 1.031e-6, 1.1e-6]), "uniform"), Braket.IR.PhysicalField(Braket.IR.TimeSeries(DecFP.Dec128[7.5398224e6, 7.5398224e6], DecFP.Dec128[0.0, 1.1e-6]), "uniform"))], Braket.IR.ShiftingField[]))
One-Way Conversion

Unlike the previous conversion functions, from_braket_ahs_ir does not exist meaning it is not possible to obtain a TaskSpecification from a Braket.IR.AHSProgram.

No Validation

to_braket_ahs_ir does no validation on its input. It is assumed that the TaskSpecification given to it is already validated. Therefore, it is possible to produce a Braket.IR.AHSProgram that is incapable of being run on Neutral Atom hardware and may cause the Braket API to reject it.

Submitting to Amazon Braket

To submit to Neutral Atom hardware on Amazon Braket, Bloqade provides submit_to_braket which can submit BOTH the native Bloqade representation of Hamiltonians (BloqadeExpr.RydbergHamiltonian) as well as the TaskSpecification representation.

Implicit Transformation and No Validation for TaskSpecification

For any BloqadeExpr.RydbergHamiltonian passed in, hardware_transform is invoked to ensure it is compatible with hardware. On the other hand, TaskSpecification types are assumed to already be valid.

submit_to_braket requires that AWS credentials are given either explicitly through an AWS.AWSCredentials type or by setting the environment variables in the shell running Bloqade with the credentials. The credentials (and instructions for setting environment variables!) can be found through your AWS account's "Command line or programmatic access" option.

Let us try to submit the Hamiltonian we made earlier. We remind ourselves that our Hamiltonian is currently the following:

julia> fixed_hnqubits: 4
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j
├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0|
└─ [-] Δ(t) ⋅ ∑ n_i

(Recall we had to modify the atom positions in order to pass validation!)

Now we define the number of shots (how many times the Hamiltonian will be executed on hardware) as well as the credentials, allowing submit_to_braket to automatically handle transforming the Hamiltonian to fit within hardware capabilities. By default, submit_to_braket will submit to QuEra's Aquila Neutral Atom hardware and take into account its capabilities for Hamiltonian transformation.

using AWS
access_key_id = "your_access_key_id"
secret_key = "your_secret_key"
token = "your_token"
credentials = AWS.AWSCredentials(access_key_id, secret_key, token)
task = submit_to_braket(fixed_h, 100; credentials=credentials)

If submission was successful you will see something like

AwsQuantumTask(...)

in the REPL with the Task ARN (Amazon Resource Name) as a string in the parentheses.

Inspecting Results from Braket

To see the status of our task we can use state from the Braket.jl package.

using Braket
Braket.state(task)

state can return a String that is either: "CANCELLED", "FAILED", "COMPLETED", "QUEUED", or "RUNNING".

To obtain results, the result function from Braket.jl can be used

res = Braket.result(task)
Braket.result is Blocking

Per the docstring for result, the function is BLOCKING "until a result is available, in which case the result is returned, or the task enters a terminal state without a result ("FAILED" or "CANCELLED")...".

To obtain the raw measurements (pre- and post-Hamiltonian application) of the atoms, the measurements field can be accessed:

res.measurements

Reference

BloqadeSchema.get_device_capabilitiesFunction
get_device_capabilities(capabilities_file=nothing)

Generates a DeviceCapabilities struct from either an explicitly provided path to a capabilities JSON file or using the default JSON provided in "lib/BloqadeSchema/config/capabilities-qpu1-mock.json".

By default, the units for capabilities JSON file are specified by the "lib/BloqadeSchema/config/capabilities-qpu1-mock-units.json" file this function gives a DeviceCapabilities struct with non-SI base (e.g. μm, μs) units.

See also get_device_capabilities_SI

julia> get_device_capabilities()
BloqadeSchema.DeviceCapabilities(BloqadeSchema.TaskCapabilities(1, 1000), BloqadeSchema.LatticeCapabilities(BloqadeSchema.LatticeAreaCapabilities(75.0, 76.0), BloqadeSchema.LatticeGeometryCapabilities(4.0, 4.0, 0.1, 256), 256), BloqadeSchema.RydbergCapabilities(5.42e6, BloqadeSchema.RydbergGlobalCapabilities(0.0, 15.8, 0.0004, 250.0, -125.0, 125.0, 2.0e-7, 2500.0, -99.0, 99.0, 5.0e-7, 0.0, 4.0, 0.001, 0.05), nothing))
source
BloqadeSchema.get_device_capabilities_SIFunction
get_device_capabilities_SI(capabilities_file=nothing)

Generates a DeviceCapabilities struct from either an explicitly provided path to a capabilities JSON file or using the default JSON provided in "lib/BloqadeSchema/config/capabilities-qpu1-mock.json".

The values returned are in Base SI units: m, s, rad/s, etc.

julia> get_device_capabilities_SI()
BloqadeSchema.DeviceCapabilities(BloqadeSchema.TaskCapabilities(1, 1000), BloqadeSchema.LatticeCapabilities(BloqadeSchema.LatticeAreaCapabilities(7.5e-5, 7.6e-5), BloqadeSchema.LatticeGeometryCapabilities(4.0e-6, 4.0e-6, 1.0e-7, 256), 256), BloqadeSchema.RydbergCapabilities(5.42e-24, BloqadeSchema.RydbergGlobalCapabilities(0.0, 1.58e7, 400.0, 2.5e14, -1.25e8, 1.25e8, 0.2, 2.5e15, -99.0, 99.0, 5.0e-7, 0.0, 4.0e-6, 1.0e-9, 5.0e-8), nothing))
source
BloqadeSchema.hardware_transform_ΩFunction
hardware_transform_Ω(Ω,device_capabilities::DeviceCapabilities=get_device_capabilities())

Given the device_capabilities of the machine and a Rabi frequency (Ω) Waveform, return a transformed Ω capable of being implemented by the machine along with the error between the original ($A$) and transformed ($B$) waveforms calculated as $\Vert A - B\Vert_1$. If the waveform durations are different, the shorter waveform is padded with zeros for values to make the durations equal in error calculation.

Logs/Warnings/Exceptions

Exceptions are thrown if Ω is:

  • Not of type BloqadWaveforms.Waveform
  • Not present (nothing was passed in)
  • Not a global drive (e.g.: Vector of Waveforms, localized Ω is not supported)
  • the maximum slope allowed for the waveform from device_capabilities is set to infinity
  • the minimum time step allowed for the waveform from device_capabilities is set to zero

Debug logs are issued if the following are encountered in Ω:

  • duration may be rounded due to time resolution from device_capabilities
  • the initial waveform does not start/end in zero for its value
  • the values in the waveform exceed device_capabilities supported values, and must be clipped

Examples

julia> wf = sinusoidal(duration=2, amplitude=1.3*π);

julia> hardware_transform_Ω(wf)
(Waveform(_, 2.0), 2.632451578170084)
source
BloqadeSchema.hardware_transform_ϕFunction
hardware_transform_ϕ(ϕ,device_capabilities::DeviceCapabilities=get_device_capabilities())

Given the device_capabilities of the machine and a phase Waveform, return a transformed ϕ capable of being implemented by the machine along with the error between the original ($A$) and transformed ($B$) waveforms calculated as $\Vert A - B\Vert_1$. If the waveform durations are different, the shorter waveform is padded with zeros for values to make the durations equal in error calculation.

Logs/Warnings/Exceptions

Exceptions are thrown if ϕ is:

  • Not of type BloqadWaveforms.Waveform
  • Not present (nothing was passed in)
  • Not a global drive (e.g.: Vector of Waveforms, localized ϕ is not supported)
  • the maximum slope allowed for the waveform from device_capabilities is set to infinity
  • the minimum time step allowed for the waveform from device_capabilities is set to zero

Debug logs are issued if the following are encountered in ϕ:

  • duration may be rounded due to time resolution from device_capabilities
  • the initial waveform does not start/end in zero for its value
  • the values in the waveform exceed device_capabilities supported values, and must be clipped

Examples

julia> wf = sinusoidal(duration=2, amplitude=1.3*π);

julia> hardware_transform_ϕ(wf)
(Waveform(_, 2.0), 0.5386117854062276)
source
BloqadeSchema.hardware_transform_ΔFunction
hardware_transform_Δ(Δ,device_capabilities::DeviceCapabilities=get_device_capabilities())

Given the device_capabilities of the machine and a detuning waveform Δ, return a transformed Δ capable of being implemented by the machine along with the error between the original ($A$) and transformed ($B$) waveforms calculated as $\Vert A - B\Vert_1$. If the waveform durations are different, the shorter waveform is padded with zeros for values to make the durations equal in error calculation.

Logs/Warnings/Exceptions

Exceptions are thrown if Δ is:

  • Not of type BloqadWaveforms.Waveform
  • Not present (nothing was passed in)
  • Not a global drive (e.g. Vector of Waveforms, localized Δ is not supported)
  • the maximum slope allowed for the waveform from device_capabilities is set to infinity
  • the minimum time step allowed for the waveform from device_capabilities is set to zero

Debug logs are issued if the following are encountered in Δ:

  • duration may be rounded due to time resolution from device_capabilities
  • the initial waveform does not start/end in zero for its value
  • the values in the waveform exceed device_capabilities supported values, and must be clipped

Examples

julia> wf = sinusoidal(duration=2, amplitude=1.3*π);

julia> hardware_transform_Δ(wf)
(Waveform(_, 2.0), 0.06492452289703464)
source
BloqadeSchema.hardware_transform_atomsFunction
hardware_transform_atoms(atoms,device_capabilities::DeviceCapabilities=get_device_capabilities())

Given the constraints of the hardware from device_capabilities (specifically the position resolution) and an iterable containing the atom positions atoms, returns a Tuple containing the adjusted atom positions the machine is capable of resolving and the mean squared error between the desired atom positions and newly generated ones.

Note that other constraints such as the maximum width, height, and minimum supported spacings are not taken into account in adjusting the atoms. This may result in the validation function failing and requiring user intervention to modify the atom positions such that they satisfy the other constraints.

Examples

julia> atom_positions = ((1.12,), (2.01,), (3.01,));

julia> hardware_transform_atoms(atom_positions) # by default, calls get_device_capabilities()
([(1.1,), (2.0,), (3.0,)], 0.013333333333333197)
source
BloqadeSchema.hardware_transformFunction
hardware_transform(h::BloqadeExpr.RydbergHamiltonian;device_capabilities::DeviceCapabilities=get_device_capabilities())

Given the constraints of the hardware via device_capabilities, transforms h into one the machine is capable of executing as well as:

  • The mean squared error between original positions of the atoms and the transformed ones
  • The 1-norm of the difference between the original and transformed waveforms

which are all stored in a HardwareTransformInfo struct.

hardware_transform expects that ALL waveforms h can have specified (Ω, Δ, ϕ) are explicitly defined. If there is a waveform that is not being used, a BloqadeWaveforms.constant waveform should be created with value zero to indicate non-use.

Note that not all atom position constraints are accounted for, such as the maximum lattice width, lattice height, and minimum supported spacings. Only position resolution is automatically accounted for. This may result in the validation function failing and requiring user intervention to modify the atom positions such that they satisfy the other constraints.

Logs/Warnings/Exceptions

Debug logs are always emitted containing the error (defined as the 1-norm of the difference between the original waveform and the transformed waveform) across all waveforms (Ω, Δ, ϕ) as well as the Mean Squared Error between the original atom positions and the adjusted atom positions.

The debug logs/warnings from constituent functions hardware_transform_Ω, hardware_transform_Δ, hardware_transform_ϕ are also emitted should the waveforms in h cause them to.

See also hardware_transform_atoms, hardware_transform_Ω, hardware_transform_Δ, hardware_transform_ϕ.

Examples

julia> atom_positions = AtomList([(1.12,), (2.01,), (3.01,)]);

julia> Δ = Ω = ϕ = sinusoidal(duration=2, amplitude=1.3*π);

julia> h = rydberg_h(atom_positions; Ω=Ω,Δ=Δ,ϕ=ϕ)
nqubits: 3
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j
├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0|
└─ [-] Δ(t) ⋅ ∑ n_i


julia> hardware_transform(h)
(nqubits: 3
+
├─ [+] ∑ 2π ⋅ 8.627e5.0/|x_i-x_j|^6 n_i n_j
├─ [+] Ω(t) ⋅∑ e^{ϕ(t) ⋅ im} |0⟩⟨1| + e^{-ϕ(t) ⋅ im} |1⟩⟨0|
└─ [-] Δ(t) ⋅ ∑ n_i
, BloqadeSchema.HardwareTransformInfo(0.5386117854062276, 2.632451578170084, 0.06492452289703464, (Δ = Waveform(_, 2), δ = nothing, Δi = 1.0), 0.013333333333333197))
source
BloqadeSchema.HardwareTransformInfoType
struct HardwareTransformInfo <: QuEraSchema

Contains the calculated differences (error) betwen the original and transformed waveforms and atoms from invoking hardware_transform on a BloqadeExpr.RydbergHamiltonian.

Fields

  • ϕ_error: Error between the original laser phase waveform ($A$) and transformed one ($B$) waveforms calculated as $\Vert A - B\Vert_1$.
  • Ω_error: Error between the original Rabi frequency waveform ($A$) and transformed one ($B$) waveforms calculated as $\Vert A - B\Vert_1$.
  • Δ_error: Error between the global detuning waveform ($A$) and transformed one ($B$) waveforms calculated as $\Vert A - B\Vert_1$.
  • Δ_mask: Decoupling of local detuning field inferred from the detuning value specified in Δ.
Local Detuning Support

Local Detunings are currently not supported by Bloqade but will be in future releases.

  • mse_atoms: Mean Squared Error between original atom positions and transformed ones.
source
BloqadeSchema.validateFunction
validate(H::BloqadeExpr.RydbergHamiltonian;device_capabilities::DeviceCapabilities=get_device_capabilities())

Checks if H is capable of being represented as part of the internal schema as well as if it falls in the capabilities of what the machine can do via device_capabilities.

Returns ValidationViolations with each field containing a set of strings indicating which constraints were violated for which part of H.

Violations include:

Waveform Type

  • ϕ is not of type PiecewiseConstantWaveform
  • Ω and Δ are not of type PiecewiseLinearWaveform

Atom Position

  • Number of qubits requested exceeds what is supported by the device
  • Atom positions exceed position resolution supported by the device
  • The total width/height of the atom arrangement exceeds what is supported by the device
  • The radial spacing between atoms is smaller than what is supported by the device
  • The vertical row spacing between atoms is smaller than what is supported by the device

General Waveform Constraints (apply to Ω, Δ, ϕ)

  • duration exceeds device supported duration
  • duration is smaller than device supported minimum time step
  • smallest time step is smaller than supported smallest time step
  • value is smaller than smallest supported value
  • value is larger than largest supported value

Ω Waveform specific constraints

  • Slope exceeds largest supported slope
  • Start and end values are not equal to 0.0 rad/μs

Δ Waveform specific constraints

  • Slope exceeds largest supported slope

ϕ Waveform specific constraints

  • start value is not equal to 0.0 rad/μs

Logs/Warnings/Exceptions

The following exceptions can be thrown:

  • ϕ is not of type PiecewiseConstantWaveform
  • Ω and Δ are not of type PiecewiseLinearWaveform

Examples

julia> Δ = Ω = ϕ = sinusoidal(duration=2, amplitude=1.3*π);

julia> h = rydberg_h(atom_positions; Ω=Ω,Δ=Δ,ϕ=ϕ)

julia> transformed_h, _ = transform(h); # transform returns error info

julia> validate(transformed_h) # constrained by default value of `device_capabilities` argument
The following validation violations occurred:

1. positions 2 => (2.0, 0.0) and 3 => (3.0, 0.0) are a distance of 1.0 μm apart which is below minimum value of 4.0 μm
2. positions 1 => (1.1, 0.0) and 2 => (2.0, 0.0) are a distance of 0.8999999999999999 μm apart which is below minimum value of 4.0 μm
3. positions 1 => (1.1, 0.0) and 3 => (3.0, 0.0) are a distance of 1.9 μm apart which is below minimum value of 4.0 μm
source
BloqadeSchema.to_jsonFunction
to_json(h::AbstractBlock; kw...)
to_json(h::BloqadeExpr.RydbergHamiltonian,params::SchemaTranslationParams)

Converts h and associated params into a JSON object. If params is not explicitly provided as a SchemaTranslationParams instance, it is automatically built from nshots and device_capabilities.

Validation is performed to ensure h is capable of being run on the machine. This can cause an exception to be thrown should any violations be caught. Refer to Logs/Warnings/Exceptions below.

Logs/Warnings/Exceptions

A ValidationException can be thrown which wraps a ValidationViolations instance.

ValidationViolations contains any constraint violations detected from to_schema

Violations include:

Waveform Type

  • ϕ is not of type PiecewiseConstantWaveform
  • Ω and Δ are not of type PiecewiseLinearWaveform

Atom Position

  • Number of qubits requested exceeds what is supported by the device
  • Atom positions exceed position resolution supported by the device
  • The total width/height of the atom arrangement exceeds what is supported by the device
  • The radial spacing between atoms is smaller than what is supported by the device
  • The vertical row spacing between atoms is smaller than what is supported by the device

General Waveform Constraints (apply to Ω, Δ, ϕ)

  • duration exceeds device supported duration
  • duration is smaller than device supported minimum time step
  • smallest time step is smaller than supported smallest time step
  • value is smaller than smallest supported value
  • value is larger than largest supported value

Ω Waveform specific constraints

  • Slope exceeds largest supported slope
  • Start and end values are not equal to 0.0 rad/μs

Δ Waveform specific constraints

  • Slope exceeds largest supported slope

ϕ Waveform specific constraints

  • start value is not equal to 0.0 rad/μs

Miscellaneous Violations

  • Number of shots is below minimum supported
  • Number of shots exceeds maximum supported

Examples

julia> Ω = BloqadeWaveforms.piecewise_constant(; clocks=[0, 2, 4, 6, 7], values=[5, 3, 4, 6]);

julia> Δ = BloqadeWaveforms.piecewise_linear(; clocks=[0.0, 0.6, 2.1, 2.2], values=[-10.1, -10.1, 10.1, 10.1]);

julia> ϕ = BloqadeWaveforms.piecewise_linear(; clocks=[0, 5], values=[33, 0]);

julia> atoms = [(0, 0), (1, 3), (4, 2), (6, 3), (0, 5), (2, 5)];

julia> block = BloqadeExpr.rydberg_h(atoms; Δ=Δ, Ω=Ω, ϕ=ϕ);

julia> BloqadeSchema.to_json(block; n_shots=10)
"{"nshots":10,"lattice":{"sites":[[0.0,0.0],[1.0,3.0],[4.0,2.0],[6.0,3.0],[0.0,5.0],[2.0,5.0]],"filling":[1,1,1,1,1,1]},"effective_hamiltonian":{"rydberg":{"rabi_frequency_amplitude":{"global":{"times":[0.0,-18.0,2.0,-6.0,4.0,-14.0,7.0],"values":[5.0,5.0,3.0,3.0,4.0,4.0,6.0]}},"rabi_frequency_phase":{"global":{"times":[0.0,5.0],"values":[33.0,0.0]}},"detuning":{"global":{"times":[0.0,0.6,2.1,2.2],"values":[-10.1,-10.1,10.1,10.1]}}}}}"
source
BloqadeSchema.to_json_no_validationFunction
to_json_no_validation(lattice::Union{Vector,Lattice};
    ϕ::Maybe{PiecewiseConstantWaveform}=nothing,
    Ω::Maybe{PiecewiseLinearWaveform}=nothing,
    Δ::Maybe{PiecewiseLinearWaveform}=nothing,
    δ::Maybe{PiecewiseLinearWaveform}=nothing,
    Δi::Maybe{Vector{Number}}=nothing,kw...)

Converts lattice, ϕ, Δ, δ, and Δi to a JSON representation of a QuEraTaskSpecification instance WITHOUT ensuring the provided values are capable of being executed on the machine (fit within the constraints of the device's capabilities)

See also to_json

source
BloqadeSchema.to_dictFunction
to_dict(h::BloqadeExpr.RydbergHamiltonian; nshots::Int, device_capabilities::DeviceCapabilities=get_device_capabilities())
to_dict(h::BloqadeExpr.RydbergHamiltonian,params::SchemaTranslationParams)

Converts h and associated params into the dictionary representation of a QuEraTaskSpecification. If params is not explicitly provided as a SchemaTranslationParams instance, it is automatically built from nshots and device_capabilities.

Validation is performed to ensure h is capable of being run on the machine. This can cause an exception to be thrown should any violations be caught. Refer to Logs/Warnings/Exceptions below.

Logs/Warnings/Exceptions

A ValidationException can be thrown which wraps a ValidationViolations instance.

ValidationViolations contains any constraint violations detected from to_schema

Violations include:

Waveform Type

  • ϕ is not of type PiecewiseConstantWaveform
  • Ω and Δ are not of type PiecewiseLinearWaveform

Atom Position

  • Number of qubits requested exceeds what is supported by the device
  • Atom positions exceed position resolution supported by the device
  • The total width/height of the atom arrangement exceeds what is supported by the device
  • The radial spacing between atoms is smaller than what is supported by the device
  • The vertical row spacing between atoms is smaller than what is supported by the device

General Waveform Constraints (apply to Ω, Δ, ϕ)

  • duration exceeds device supported duration
  • duration is smaller than device supported minimum time step
  • smallest time step is smaller than supported smallest time step
  • value is smaller than smallest supported value
  • value is larger than largest supported value

Ω Waveform specific constraints

  • Slope exceeds largest supported slope
  • Start and end values are not equal to 0.0 rad/μs

Δ Waveform specific constraints

  • Slope exceeds largest supported slope

ϕ Waveform specific constraints

  • start value is not equal to 0.0 rad/μs

Miscellaneous Violations

  • Number of shots is below minimum supported
  • Number of shots exceeds maximum supported
source
BloqadeSchema.to_schemaFunction
to_schema(h::BloqadeExpr.RydbergHamiltonian; nshots::Int, device_capabilities::DeviceCapabilities=get_device_capabilities())
to_schema(h::BloqadeExpr.RydbergHamiltonian, params::SchemaTranslationParams)

Converts h to a QuEraTaskSpecification instance with params. If params is not explicitly constructed, it will be built automatically from nshots and device_capabilities.

Validation is performed to ensure h is capable of being run on the machine. This can cause an exception to be thrown should any violations be caught. Refer to Logs/Warnings/Exceptions below.

Logs/Warnings/Exceptions

If any violations of device_capabilities are detected, a ValidationException is thrown which wraps a ValidationViolations instance.

Violations include:

Waveform Type

  • ϕ is not of type PiecewiseConstantWaveform
  • Ω and Δ are not of type PiecewiseLinearWaveform

Atom Position

  • Number of qubits requested exceeds what is supported by the device
  • Atom positions exceed position resolution supported by the device
  • The total width/height of the atom arrangement exceeds what is supported by the device
  • The vertical row spacing between atoms is smaller than what is supported by the device
  • The radial spacing between atoms is smaller than what is supported by the device

General Waveform Constraints (apply to Ω, Δ, ϕ)

  • duration exceeds device supported duration
  • duration is smaller than device supported minimum time step
  • smallest time step is smaller than supported smallest time step
  • value is smaller than smallest supported value
  • value is larger than largest supported value

Ω Waveform specific constraints

  • Slope exceeds largest supported slope
  • Start and end values are not equal to 0.0 rad/μs

Δ Waveform specific constraints

  • Slope exceeds largest supported slope

ϕ Waveform specific constraints

  • start value is not equal to 0.0 rad/μs

Miscellaneous Violations

  • Number of shots is below minimum supported
  • Number of shots exceeds maximum supported
source
BloqadeSchema.to_schema_no_validationFunction
to_schema_no_validation(lattice::Union{Vector,Lattice};
    ϕ::Maybe{PiecewiseConstantWaveform}=nothing,
    Ω::Maybe{PiecewiseLinearWaveform}=nothing,
    Δ::Maybe{PiecewiseLinearWaveform}=nothing,
    δ::Maybe{PiecewiseLinearWaveform}=nothing,
    Δi::Maybe{Vector{Number}}=nothing, 
    nshots::Int,
    device_capabilities::DeviceCapabilities=get_device_capabilities())
to_schema_no_validation(lattice::Union{Vector,Lattice},
    ϕ::Maybe{PiecewiseConstantWaveform},
    Ω::Maybe{PiecewiseLinearWaveform},
    Δ::Maybe{PiecewiseLinearWaveform},
    δ::Maybe{PiecewiseLinearWaveform},
    Δi::Maybe{Vector{Number}}, 
    params::SchemaTranslationParams)

Converts lattice, ϕ, Δ, δ, and Δi to a QuEraTaskSpecification instance WITHOUT ensuring the provided values are capable of being executed on the machine (fit within the constraints of the device's capabilities).

If params is not already provided, it is constructed automatically from nshots::Int and device_capabilities.

See also to_schema

source
BloqadeSchema.to_braket_ahs_irFunction
function to_braket_ahs_ir(local_value::BloqadeSchema.LocalField)

Converts local_value to Braket.IR.PhysicalField

source
function to_braket_ahs_ir(global_values::BloqadeSchema.GlobalField)

Converts global_values to Braket.IR.PhysicalField

source
function to_braket_ahs_ir(amplitude_or_phase::Union{BloqadeSchema.RabiFrequencyAmplitude,
BloqadeSchema.RabiFrequencyPhase})

Unwraps amplitude_or_phase to extract their global_value fields which are immediately evaluated by function to_braket_ahs_ir(global_values::BloqadeSchema.GlobalField)

source
function to_braket_ahs_ir(detuning::BloqadeSchema.Detuning)

Converts detuning to Braket.IR.PhysicalField's for the global_value and local_value fields of detuning. Returns the converted global_value first followed by the local_value. ``

source
function to_braket_ahs_ir(rydberg_hamiltonian::BloqadeSchema.RydbergHamiltonian)

Converts rydberg_hamiltonian to Braket.IR.Hamiltonian

source
function to_braket_ahs_ir(lattice::BloqadeSchema.Lattice)

Converts lattice to a Braket.IR.Setup instance.

source
function to_braket_ahs_ir(hamiltonian::BloqadeSchema.EffectiveHamiltonian)

Unwraps the BloqadeSchema.RydbergHamiltonian contained inside hamiltonian and immediately evaluates it using to_braket_ahs_ir(rydberg_hamiltonian::BloqadeSchema.RydbergHamiltonian)

source

function tobraketahsir(bloqadetask::BloqadeSchema.QuEraTaskSpecification)

Converts a bloqade_task into a Braket.IR.AHSProgram capable of being submitted to AWS Braket for execution on a QPU.

NOTE: BloqadeSchema.QuEraTaskSpecification contains a field nshots which does not have a corresponding field in Braket.IR.AHSProgram. This value must be fed as a keyword argument to a Braket.AwsDevice instance separately.

source
BloqadeSchema.submit_to_braketFunction
submit_to_braket(h::BloqadeExpr.Hamiltonian, n_shots::Int; <keyword arguments>)

Submits a BloqadeExpr.RydbergHamiltonian instance to Braket with n_shots defining the number of times the Hamiltonian should be executed.

Credentials can be passed in explicitly through an AWS.AWSCredentials struct or by passing in nothing, in which case credentials will be sought in the standard AWS locations.

Keyword Arguments

  • arn="arn:aws:braket:us-east-1::device/qpu/quera/Aquila": ARN for the machine
  • region="us-east-1": AWS Region machine is located in
  • credentials::Union{AWSCredentials, Nothing}=nothing: AWS.AWSCredentials instance you can create to login.

Logs/Warnings/Exceptions

An AWS.NoCredentials exception is thrown containing a message string "Can't find AWS credentials!" if the credentials given are invalid.

BloqadeSchema.hardware_transform is always invoked, meaning its debug logs are also always emitted containing the difference (error) between the original waveforms in h and the newly generated ones compatible with hardware as well as the same transformation for atom positions.

source
submit_to_braket(h::BloqadeExpr.RydbergHamiltonian, translation_params::BloqadeSchema.SchemaTranslationParams; <keyword arguments>)

Submits a BloqadeExpr.RydbergHamiltonian instance to Braket with BloqadeSchema.SchemaTranslationParams containing the number of shots and device capabilities. Returns an AWS.AwsQuantumTask upon converting the Hamiltonian to one the hardware can execute and submitting it.

Credentials can be passed in explicitly through an AWS.AWSCredentials struct or by passing in nothing, in which case credentials will be sought in the standard AWS locations.

Keyword Arguments

  • arn="arn:aws:braket:us-east-1::device/qpu/quera/Aquila": ARN for the machine
  • region="us-east-1": AWS Region machine is located in
  • credentials::Union{AWSCredentials, Nothing}=nothing: AWS.AWSCredentials instance you can create to login.

Logs/Warnings/Exceptions

An AWS.NoCredentials exception is thrown containing a message string "Can't find AWS credentials!" if the credentials given are invalid.

hardware_transform is always invoked internally, meaning its debug logs are also always emitted containing the difference (error) between the original waveforms in h and the newly generated ones compatible with hardware as well as the same transformation for atom positions.

source
sumbit_to_braket(ts:BloqadeSchema.QuEraTaskSpecification; <keyword arguments>)

Submits a BloqadeSchema.QuEraTaskSpecification instance to Braket, returning an AWS.AwsQuantumTask.

Credentials can be passed in explicitly through an AWS.AWSCredentials struct or by passing in nothing, in which case credentials will be sought in the standard AWS locations.

Keyword Arguments

  • arn="arn:aws:braket:us-east-1::device/qpu/quera/Aquila": ARN for the machine
  • region="us-east-1": AWS Region machine is located in
  • credentials::Union{AWSCredentials, Nothing}=nothing: AWS.AWSCredentials instance you can create to login.

Logs/Warnings/Exceptions

An AWS.NoCredentials exception is thrown containing a message string "Can't find AWS credentials!" if the credentials given are invalid.

source
BloqadeSchema.executeFunction
execute(j::Dict)

Executes a task given as a Dict in the task specification API format, and returns a JSON string of the result

source
execute(j::QuEraTaskSpecification)

Executes a task given as a QuEraTaskSpecification object in the task specification API format, and returns a JSON string of the result

source
Missing docstring.

Missing docstring for TaskSpecification. Check Documenter's build log for details.

BloqadeSchema.TaskOutputType
struct TaskOutput <: QuEraSchema

The result of executing a QuEraTaskSpecification on the machine.

Output of execute function.

Fields

  • task_status_code::Int: Task Status
  • shot_outputs::Vector{ShotOutput}: Contains pre- and post- shot

sequence in binary of if atoms are in Rydberg/Ground state.

source
BloqadeSchema.ValidationViolationsType
struct ValidationViolations <: QuEraSchema

Stores violations of hardware constraints from the user-supplied BloqadeExpr.RydbergHamiltonian as strings in sets. This is returned by validate and to_schema.

Fields

  • lattice_violations::Set: violations of hardware-supported lattice geometry
  • misc_violations::Set: violations that do not fall into other categories (e.g. number of shots)
  • Δ_violations::Set: violations of detuning waveform
  • Ω_violations::Set: violations of Rabi frequency waveform
  • ϕ_violations::Set: violations of Phase waveform
  • δ_violations::Set: violations of local detuning waveforms
source