Skip to content

Index

analyze_channels

analyze_channels(circuit: AnalogCircuit) -> Dict
  1. Scan channels

This pass checks to make sure that: * There is no hyperfine coupling in the sequence * There are no non-uniform spatial modulation for rabi phase and amplitude * there is no more than one non-uniform spatial modulation for detuning

Parameters:

Name Type Description Default
circuit AnalogCircuit

AnalogCircuit to analyze

required

Returns:

Name Type Description
level_couplings Dict

Dictionary containing the required channels for the sequence. Note that this will insert a uniform field for any missing channels.

Raises:

Type Description
ValueError

If there is hyperfine coupling in the sequence.

ValueError

If there is more than one non-uniform spatial modulation for detuning.

ValueError

If there are non-uniform spatial modulations for rabi phase and amplitude.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def analyze_channels(circuit: analog_circuit.AnalogCircuit) -> Dict:
    """1. Scan channels

    This pass checks to make sure that:
    * There is no hyperfine coupling in the sequence
    * There are no non-uniform spatial modulation for rabi phase and amplitude
    * there is no more than one non-uniform spatial modulation for detuning

    Args:
        circuit: AnalogCircuit to analyze

    Returns:
        level_couplings: Dictionary containing the required channels for the
            sequence. Note that this will insert a uniform field for any missing
            channels.

    Raises:
        ValueError: If there is hyperfine coupling in the sequence.
        ValueError: If there is more than one non-uniform spatial modulation for
            detuning.
        ValueError: If there are non-uniform spatial modulations for rabi phase
            and amplitude.

    """
    from bloqade.analog.compiler.analysis.common import ScanChannels
    from bloqade.analog.compiler.analysis.hardware import ValidateChannels

    ValidateChannels().scan(circuit)
    level_couplings = ScanChannels().scan(circuit)

    # add missing channels
    fields = level_couplings[sequence.rydberg]
    # detuning, phase and amplitude are required
    # to have at least a uniform field
    updated_fields = {
        field_name: fields.get(field_name, {field.Uniform}).union({field.Uniform})
        for field_name in [pulse.detuning, pulse.rabi.amplitude, pulse.rabi.phase]
    }

    return {sequence.rydberg: updated_fields}

assign_circuit

assign_circuit(
    circuit: AnalogCircuit,
    assignments: Dict[str, ParamType],
) -> Tuple[analog_circuit.AnalogCircuit, Dict]
  1. Assign variables and validate assignment

This pass assigns variables to the circuit and validates that all variables have been assigned.

Parameters:

Name Type Description Default
circuit AnalogCircuit

AnalogCircuit to assign variables to

required
assignments Dict[str, ParamType]

Dictionary containing the assignments for the variables in the circuit.

required

Returns:

Name Type Description
assigned_circuit Tuple[AnalogCircuit, Dict]

AnalogCircuit with variables assigned.

Raises:

Type Description
ValueError

If there are any variables that have not been assigned.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def assign_circuit(
    circuit: analog_circuit.AnalogCircuit, assignments: Dict[str, ParamType]
) -> Tuple[analog_circuit.AnalogCircuit, Dict]:
    """3. Assign variables and validate assignment

    This pass assigns variables to the circuit and validates that all variables
    have been assigned.

    Args:
        circuit: AnalogCircuit to assign variables to
        assignments: Dictionary containing the assignments for the variables in
            the circuit.

    Returns:
        assigned_circuit: AnalogCircuit with variables assigned.

    Raises:
        ValueError: If there are any variables that have not been assigned.

    """
    from bloqade.analog.compiler.rewrite.common import AssignBloqadeIR
    from bloqade.analog.compiler.analysis.common import ScanVariables, AssignmentScan

    final_assignments = AssignmentScan(assignments).scan(circuit)

    assigned_circuit = AssignBloqadeIR(final_assignments).visit(circuit)

    assignment_analysis = ScanVariables().scan(assigned_circuit)

    if not assignment_analysis.is_assigned:
        missing_vars = assignment_analysis.scalar_vars.union(
            assignment_analysis.vector_vars
        )
        raise ValueError(
            "Missing assignments for variables:\n"
            + ("\n".join(f"{var}" for var in missing_vars))
            + "\n"
        )

    return assigned_circuit, final_assignments

canonicalize_circuit

canonicalize_circuit(
    circuit: AnalogCircuit, level_couplings: Dict
) -> analog_circuit.AnalogCircuit
  1. Insert zero waveform in the explicit time intervals missing a waveform

This pass inserts a zero waveform in the explicit time intervals missing a waveform. This is required for later analysis passes to check that the waveforms are compatible with the hardware.

Parameters:

Name Type Description Default
circuit AnalogCircuit

AnalogCircuit to add padding to

required
level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Return circuit: AnalogCircuit with zero waveforms inserted in the explicit time intervals missing a waveform.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def canonicalize_circuit(
    circuit: analog_circuit.AnalogCircuit, level_couplings: Dict
) -> analog_circuit.AnalogCircuit:
    """2. Insert zero waveform in the explicit time intervals missing a waveform

    This pass inserts a zero waveform in the explicit time intervals missing a
    waveform. This is required for later analysis passes to check that the
    waveforms are compatible with the hardware.

    Args:
        circuit: AnalogCircuit to add padding to
        level_couplings: Dictionary containing the given channels for the
            sequence.

    Return
        circuit: AnalogCircuit with zero waveforms inserted in the explicit time
            intervals missing a waveform.

    """
    from bloqade.analog.compiler.rewrite.common import (
        AddPadding,
        Canonicalizer,
        AssignToLiteral,
    )

    circuit = AddPadding(level_couplings).visit(circuit)
    # these two passes are equivalent to a constant propagation pass
    circuit = AssignToLiteral().visit(circuit)
    circuit = Canonicalizer().visit(circuit)

    return circuit

generate_ahs_code

generate_ahs_code(
    capabilities: Optional[QuEraCapabilities],
    level_couplings: Dict,
    circuit: AnalogCircuit,
) -> AHSComponents
  1. generate ahs code

Generates the AHS code for the given circuit. This includes generating the lattice data, global detuning, global amplitude, global phase, local detuning and lattice site coefficients (if applicable).

Parameters:

Name Type Description Default
capabilities QuEraCapabilities | None

Capabilities of the hardware.

required
level_couplings Dict

Dictionary containing the given channels for the sequence.

required
circuit AnalogCircuit

AnalogCircuit to generate AHS code for.

required

Returns:

Name Type Description
ahs_components AHSComponents

A collection of the AHS components generated for the given circuit. Can be used to generate the QuEra and Braket IR.

Raises:

Type Description
ValueError

If the capabilities are not provided but the circuit has a ParallelRegister. This is because the ParallelRegister requires the capabilities to generate the lattice data.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def generate_ahs_code(
    capabilities: Optional[QuEraCapabilities],
    level_couplings: Dict,
    circuit: analog_circuit.AnalogCircuit,
) -> AHSComponents:
    """5. generate ahs code

    Generates the AHS code for the given circuit. This includes generating the
    lattice data, global detuning, global amplitude, global phase, local
    detuning and lattice site coefficients (if applicable).

    Args:
        capabilities (QuEraCapabilities | None): Capabilities of the hardware.
        level_couplings (Dict): Dictionary containing the given channels for the
            sequence.
        circuit (AnalogCircuit): AnalogCircuit to generate AHS code for.

    Returns:
        ahs_components (AHSComponents): A collection of the AHS components
            generated for the given circuit. Can be used to generate the QuEra
            and Braket IR.

    Raises:
        ValueError: If the capabilities are not provided but the circuit has
            a ParallelRegister. This is because the ParallelRegister requires
            the capabilities to generate the lattice data.

    """
    from bloqade.analog.compiler.codegen.hardware import (
        GenerateLattice,
        GeneratePiecewiseLinearChannel,
        GenerateLatticeSiteCoefficients,
        GeneratePiecewiseConstantChannel,
    )
    from bloqade.analog.compiler.analysis.hardware import BasicLatticeValidation

    if capabilities is not None:
        # only validate the lattice if capabilities are provided
        BasicLatticeValidation(capabilities).visit(circuit)

    ahs_lattice_data = GenerateLattice(capabilities).emit(circuit)

    global_detuning = GeneratePiecewiseLinearChannel(
        sequence.rydberg, pulse.detuning, field.Uniform
    ).visit(circuit)

    global_amplitude = GeneratePiecewiseLinearChannel(
        sequence.rydberg, pulse.rabi.amplitude, field.Uniform
    ).visit(circuit)

    global_phase = GeneratePiecewiseConstantChannel(
        sequence.rydberg, pulse.rabi.phase, field.Uniform
    ).visit(circuit)

    local_detuning = None
    lattice_site_coefficients = None

    extra_sm = set(level_couplings[sequence.rydberg][pulse.detuning]) - {field.Uniform}

    if extra_sm:
        if capabilities is not None and capabilities.capabilities.rydberg.local is None:
            raise ValueError(
                "Device does not support local detuning, but the program has a "
                "non-uniform spatial modulation for detuning."
            )

        sm = extra_sm.pop()

        lattice_site_coefficients = GenerateLatticeSiteCoefficients(
            parallel_decoder=ahs_lattice_data.parallel_decoder
        ).emit(circuit)

        local_detuning = GeneratePiecewiseLinearChannel(
            sequence.rydberg, pulse.detuning, sm
        ).visit(circuit)

    return AHSComponents(
        lattice_data=ahs_lattice_data,
        global_detuning=global_detuning,
        global_amplitude=global_amplitude,
        global_phase=global_phase,
        local_detuning=local_detuning,
        lattice_site_coefficients=lattice_site_coefficients,
    )

generate_braket_ir

generate_braket_ir(
    ahs_components: AHSComponents, shots: int
) -> BraketTaskSpecification
  1. generate braket ir

This pass takes the AHS components and generates the Braket IR.

Parameters:

Name Type Description Default
ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required
shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description
task_specification BraketTaskSpecification

Braket IR for the given circuit.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
def generate_braket_ir(
    ahs_components: AHSComponents, shots: int
) -> BraketTaskSpecification:
    """7. generate braket ir

    This pass takes the AHS components and generates the Braket IR.

    Args:
        ahs_components (AHSComponents): A collection of the AHS components
            generated for the given circuit.
        shots (int): Number of shots to run the circuit for.

    Returns:
        task_specification (BraketTaskSpecification): Braket IR for the given
            circuit.

    """
    import braket.ir.ahs as ahs

    from bloqade.analog.compiler.passes.hardware.units import (
        convert_time_units,
        convert_energy_units,
        convert_coordinate_units,
    )

    ahs_register = ahs.AtomArrangement(
        sites=list(map(convert_coordinate_units, ahs_components.lattice_data.sites)),
        filling=ahs_components.lattice_data.filling,
    )

    global_detuning_time_series = ahs.TimeSeries(
        times=list(map(convert_time_units, ahs_components.global_detuning.times)),
        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),
    )

    local_detuning_time_series = None
    if ahs_components.lattice_site_coefficients is not None:
        local_detuning_time_series = ahs.TimeSeries(
            times=list(map(convert_time_units, ahs_components.local_detuning.times)),
            values=list(
                map(convert_energy_units, ahs_components.local_detuning.values)
            ),
        )

    amplitude_time_series = ahs.TimeSeries(
        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),
        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),
    )

    phase_time_series = ahs.TimeSeries(
        times=list(map(convert_time_units, ahs_components.global_phase.times)),
        values=ahs_components.global_phase.values,
    )

    detuning = ahs.PhysicalField(
        time_series=global_detuning_time_series,
        pattern="uniform",
    )

    amplitude = ahs.PhysicalField(
        time_series=amplitude_time_series,
        pattern="uniform",
    )

    phase = ahs.PhysicalField(
        time_series=phase_time_series,
        pattern="uniform",
    )

    local_detuning = None
    if ahs_components.lattice_site_coefficients is not None:
        local_detuning = ahs.PhysicalField(
            time_series=local_detuning_time_series,
            pattern=ahs_components.lattice_site_coefficients,
        )

    driving_field = ahs.DrivingField(
        detuning=detuning,
        amplitude=amplitude,
        phase=phase,
    )

    shiftingFields = []
    if ahs_components.lattice_site_coefficients is not None:
        shiftingFields = [ahs.ShiftingField(magnitude=local_detuning)]

    program = ahs.Program(
        setup=ahs.Setup(ahs_register=ahs_register),
        hamiltonian=ahs.Hamiltonian(
            drivingFields=[driving_field],
            shiftingFields=shiftingFields,
        ),
    )

    return BraketTaskSpecification(nshots=shots, program=program)

generate_quera_ir

generate_quera_ir(
    ahs_components: AHSComponents, shots: int
) -> QuEraTaskSpecification
  1. generate quera ir

This pass takes the AHS components and generates the QuEra IR.

Parameters:

Name Type Description Default
ahs_components AHSComponents

A collection of the AHS components generated for the given circuit.

required
shots int

Number of shots to run the circuit for.

required

Returns:

Name Type Description
task_specification QuEraTaskSpecification

QuEra IR for the given circuit.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
def generate_quera_ir(
    ahs_components: AHSComponents, shots: int
) -> QuEraTaskSpecification:
    """7. generate quera ir

    This pass takes the AHS components and generates the QuEra IR.

    Args:
        ahs_components (AHSComponents): A collection of the AHS components
            generated for the given circuit.
        shots (int): Number of shots to run the circuit for.

    Returns:
        task_specification (QuEraTaskSpecification): QuEra IR for the given
            circuit.

    """
    import bloqade.analog.submission.ir.task_specification as task_spec
    from bloqade.analog.compiler.passes.hardware.units import (
        convert_time_units,
        convert_energy_units,
        convert_coordinate_units,
    )

    lattice = task_spec.Lattice(
        sites=list(
            map(
                convert_coordinate_units,
                ahs_components.lattice_data.sites,
            )
        ),
        filling=ahs_components.lattice_data.filling,
    )

    global_detuning = task_spec.GlobalField(
        times=list(map(convert_time_units, ahs_components.global_detuning.times)),
        values=list(map(convert_energy_units, ahs_components.global_detuning.values)),
    )

    local_detuning = None

    if ahs_components.lattice_site_coefficients is not None:
        local_detuning = task_spec.LocalField(
            times=list(map(convert_time_units, ahs_components.local_detuning.times)),
            values=list(
                map(convert_energy_units, ahs_components.local_detuning.values)
            ),
            lattice_site_coefficients=ahs_components.lattice_site_coefficients,
        )

    rabi_frequency_amplitude_field = task_spec.GlobalField(
        times=list(map(convert_time_units, ahs_components.global_amplitude.times)),
        values=list(map(convert_energy_units, ahs_components.global_amplitude.values)),
    )

    rabi_frequency_phase_field = task_spec.GlobalField(
        times=list(map(convert_time_units, ahs_components.global_phase.times)),
        values=ahs_components.global_phase.values,
    )

    detuning = task_spec.Detuning(
        global_=global_detuning,
        local=local_detuning,
    )

    rabi_frequency_amplitude = task_spec.RabiFrequencyAmplitude(
        global_=rabi_frequency_amplitude_field,
    )

    rabi_frequency_phase = task_spec.RabiFrequencyPhase(
        global_=rabi_frequency_phase_field,
    )

    rydberg = task_spec.RydbergHamiltonian(
        rabi_frequency_amplitude=rabi_frequency_amplitude,
        rabi_frequency_phase=rabi_frequency_phase,
        detuning=detuning,
    )

    effective_hamiltonian = task_spec.EffectiveHamiltonian(
        rydberg=rydberg,
    )

    return task_spec.QuEraTaskSpecification(
        nshots=shots,
        lattice=lattice,
        effective_hamiltonian=effective_hamiltonian,
    )

validate_waveforms

validate_waveforms(
    level_couplings: Dict, circuit: AnalogCircuit
) -> None
  1. validate piecewise linear and piecewise constant pieces of pulses

This pass check to make sure that the waveforms are compatible with the hardware. This includes checking that the waveforms are piecewise linear or piecewise constant. It also checks that the waveforms are compatible with the given channels.

Parameters:

Name Type Description Default
circuit AnalogCircuit

AnalogCircuit to validate waveforms for

required
level_couplings Dict

Dictionary containing the given channels for the sequence.

required

Raises:

Type Description
ValueError

If the waveforms are not piecewise linear or piecewise constant, e.g. the waveform is not continuous.

ValueError

If a waveform segment is not compatible with the given channels.

Source code in .venv/lib/python3.12/site-packages/bloqade/analog/compiler/passes/hardware/define.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
def validate_waveforms(
    level_couplings: Dict, circuit: analog_circuit.AnalogCircuit
) -> None:
    """4. validate piecewise linear and piecewise constant pieces of pulses

    This pass check to make sure that the waveforms are compatible with the
    hardware. This includes checking that the waveforms are piecewise linear or
    piecewise constant. It also checks that the waveforms are compatible with
    the given channels.

    Args:
        circuit: AnalogCircuit to validate waveforms for
        level_couplings: Dictionary containing the given channels for the
            sequence.

    Raises:
        ValueError: If the waveforms are not piecewise linear or piecewise
            constant, e.g. the waveform is not continuous.
        ValueError: If a waveform segment is not compatible with the given
            channels.

    """
    from bloqade.analog.compiler.analysis.common import CheckSlices
    from bloqade.analog.compiler.analysis.hardware import (
        ValidatePiecewiseLinearChannel,
        ValidatePiecewiseConstantChannel,
    )

    channel_iter = (
        (level_coupling, field_name, sm)
        for level_coupling, fields in level_couplings.items()
        for field_name, spatial_modulations in fields.items()
        for sm in spatial_modulations
    )
    for channel in channel_iter:
        if channel[1] in [pulse.detuning, pulse.rabi.amplitude]:
            ValidatePiecewiseLinearChannel(*channel).visit(circuit)
        else:
            ValidatePiecewiseConstantChannel(*channel).visit(circuit)

    CheckSlices().visit(circuit)

    if circuit.sequence.duration() == 0:
        raise ValueError("Circuit Duration must be be non-zero")