Getting Up and Running with Quil-T

Language Documentation

See https://github.com/rigetti/quil/tree/master/rfcs/analog (in particular, proposal.md and spec_changes.md) for documentation on the Quil-T language.

Construct a QuantumComputer object linked to the Quil-T compiler

[1]:
from pyquil import Program, get_qc
qc = get_qc("Aspen-8")

As a sanity check, the following call should work.

[2]:
qc.compiler.get_version_info()
[2]:
{'quilc': {'quilc': '1.22.0', 'githash': '3b3160c'}, 'qpu_compiler': {}}

Get Quil-T Calibrations

A production QPU has a set of calibrations associated with it. These include frame definitions, gate and measurement calibrations, and custom waveforms. Below we show how to get the default calibrations.

[3]:
cals = qc.compiler.calibration_program

The calibration_program property of QPUCompiler provides cached access to the QPU calibration information. Upon first using this property a request will be made for the calibration information and may take some time to complete. Subsequent usage of this property will use the cached calibrations and thus will be instantaneous. It should be noted therefore that calibrations will vary with time and should be regularly refreshed though the specifics of when to refresh the calibrations is left as an exercise for the user. See QPUCompiler#refresh_calibration_program.

Frame Definitions

Frame definitions correspond to specific hardware channels. These have a name (e.g. 0 "ro_rx" for the hardware readout receive channel on Qubit 0), and some metadata (DAC sample rate, initial frame frequency, and a direction).

Note: These are fixed and should not be edited. If you wish to set a frame’s frequency to one different from its initial frequency, your Quil-T program should use SET-FREQUENCY (for an absolute value) or SHIFT-FREQUENCY (for a relative shift).

[4]:
from pyquil.quilatom import Frame

# Look for CZ frames.
cz_frames = filter(lambda f: f[0].name == "cz", cals.frames.items())
# The first elt is the frame (of type Frame) and the second elt is
# the frame definition (of type DefFrame).
print(next(cz_frames)[1])
DEFFRAME 0 7 "cz":
    DIRECTION: "tx"
    INITIAL-FREQUENCY: 298517072.1886101
    CENTER-FREQUENCY: 375000000.0
    HARDWARE-OBJECT: "q0_ff"
    SAMPLE-RATE: 1000000000.0

Gate Calibrations

Gate and Measurement calibrations present the current Quil-T specification of Rigetti’s native gates.

[5]:
print(len(cals.calibrations), "total calibrations, peeking at first two:\n")
for defn in cals.calibrations[:2]:
    print(defn)
396 total calibrations, peeking at first two:

DEFCAL RX(pi/2) 0:
    FENCE 0
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 1.2e-07, fwhm: 3e-08, t0: 6e-08, anh: -190000000.0, alpha: -0.5128791143256078, scale: 0.31430257697073, phase: 0.0, detuning: 0.0)
    FENCE 0

DEFCAL RX(-pi/2) 0:
    FENCE 0
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 1.2e-07, fwhm: 3e-08, t0: 6e-08, anh: -190000000.0, alpha: -0.5128791143256078, scale: -0.31430257697073, phase: 0.0, detuning: 0.0)
    FENCE 0

Waveform Definitions

Certain gates (e.g. RX gates above) use template waveforms. Others, notably CZ gates, use custom waveforms. The waveforms member maps waveform names to their definitions.

[6]:
cals.waveforms
[6]:
{'q0_q7_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341350>,
 'q0_q7_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341590>,
 'q0_q7_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341610>,
 'q1_q16_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d603415d0>,
 'q1_q16_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341690>,
 'q1_q16_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341650>,
 'q1_q2_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341710>,
 'q1_q2_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603417d0>,
 'q1_q2_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341790>,
 'q10_q11_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341850>,
 'q10_q11_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341890>,
 'q10_q11_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341810>,
 'q10_q17_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d603418d0>,
 'q10_q17_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341990>,
 'q10_q17_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341a10>,
 'q11_q12_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d603419d0>,
 'q11_q12_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341a90>,
 'q11_q12_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341b10>,
 'q11_q26_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341ad0>,
 'q11_q26_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341b90>,
 'q11_q26_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341c10>,
 'q12_q13_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341c50>,
 'q12_q13_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341c90>,
 'q12_q13_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341bd0>,
 'q12_q25_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341cd0>,
 'q12_q25_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341d90>,
 'q12_q25_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341e10>,
 'q15_q16_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341dd0>,
 'q15_q16_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341e90>,
 'q15_q16_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341e50>,
 'q16_q17_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341ed0>,
 'q16_q17_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60341f90>,
 'q16_q17_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60341f50>,
 'q2_q15_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60341f10>,
 'q2_q15_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603720d0>,
 'q2_q15_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372150>,
 'q2_q3_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372110>,
 'q2_q3_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603721d0>,
 'q2_q3_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372190>,
 'q20_q21_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372210>,
 'q20_q21_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603722d0>,
 'q20_q21_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372350>,
 'q20_q27_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372310>,
 'q20_q27_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603723d0>,
 'q20_q27_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372450>,
 'q21_q22_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372410>,
 'q21_q22_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603724d0>,
 'q21_q22_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372490>,
 'q21_q36_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372510>,
 'q21_q36_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603725d0>,
 'q21_q36_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372590>,
 'q22_q23_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372610>,
 'q22_q23_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603726d0>,
 'q22_q23_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372750>,
 'q22_q35_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372710>,
 'q22_q35_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603727d0>,
 'q22_q35_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372850>,
 'q23_q24_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372810>,
 'q23_q24_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603728d0>,
 'q23_q24_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372950>,
 'q24_q25_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372910>,
 'q24_q25_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d603729d0>,
 'q24_q25_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372990>,
 'q25_q26_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372a10>,
 'q25_q26_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372ad0>,
 'q25_q26_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372a90>,
 'q26_q27_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372b10>,
 'q26_q27_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372bd0>,
 'q26_q27_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372b90>,
 'q3_q4_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372c10>,
 'q3_q4_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372cd0>,
 'q3_q4_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372d50>,
 'q30_q31_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372d10>,
 'q30_q31_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372dd0>,
 'q30_q31_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372e50>,
 'q30_q37_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372e10>,
 'q30_q37_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372ed0>,
 'q30_q37_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372e90>,
 'q31_q32_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d60372f10>,
 'q31_q32_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d60372fd0>,
 'q31_q32_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d60372f90>,
 'q32_q33_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b050>,
 'q32_q33_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b110>,
 'q32_q33_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b190>,
 'q33_q34_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b150>,
 'q33_q34_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b210>,
 'q33_q34_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b1d0>,
 'q34_q35_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b250>,
 'q34_q35_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b310>,
 'q34_q35_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b2d0>,
 'q35_q36_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b350>,
 'q35_q36_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b410>,
 'q35_q36_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b490>,
 'q36_q37_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b450>,
 'q36_q37_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b510>,
 'q36_q37_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b4d0>,
 'q4_q5_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b550>,
 'q4_q5_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b610>,
 'q4_q5_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b5d0>,
 'q5_q6_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b650>,
 'q5_q6_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b710>,
 'q5_q6_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b6d0>,
 'q6_q7_cz/CZ': <pyquil.quilbase.DefWaveform at 0x7f1d6032b750>,
 'q6_q7_cphase/sqrtCPHASE': <pyquil.quilbase.DefWaveform at 0x7f1d6032b810>,
 'q6_q7_xy/sqrtiSWAP': <pyquil.quilbase.DefWaveform at 0x7f1d6032b7d0>}

Here is what one of these definitions looks like.

[7]:
print(next(iter(cals.waveforms.values()), None))
DEFWAVEFORM q0_q7_cz/CZ:
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.00012178364559662996, 0.0017544499272112704, 0.013457291321491907, 0.0568509693447061, 0.1403395097840485, 0.22382805022339092, 0.26722172824660506, 0.27892456964088574, 0.28055723592250037, 0.2806746072122791, 0.2806789371383469, 0.28067901878029905, 0.28067901956426555, 0.28067901956808755, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.280679019568097, 0.28067901956808755, 0.28067901956426555, 0.28067901878029905, 0.2806789371383469, 0.2806746072122791, 0.28055723592250037, 0.27892456964088574, 0.26722172824660495, 0.2238280502233906, 0.14033950978404605, 0.05685096934470464, 0.013457291321491488, 0.0017544499272112081, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

Compiling and running a Quil-T Program

There are three ways to access the compiler from PyQuil:

  • qc.compile is the usual pipeline, and only works for Quil code

  • qc.compiler.quil_to_native_quil is the entry point for compiling Quil to native Quil

  • qc.compiler.native_quil_to_executable is the entry point for compiling Quil-T programs

In particular, the usual workflow of just delegating to qc.compile does not currently work with Quil-T. If you wish to use Quil-T right now, your workflow should involve 1. calling qc.compiler.quil_to_native_quil on code blocks which do not involve Quil-T or Quil-T calibrations 2. subsequently calling qc.compiler.native_quil_to_executable on blocks involving Quil-T

Compiling Quil Programs

qc.compiler.native_quil_to_executable requires native Quil + Quil-T operations. In particular, it is assumed that the only gates used are those Rigetti native gates, or ones for which you have provided explicit calibrations. For example, the program below expresses

DECLARE ro BIT
H 0
CNOT 0 1
MEASURE 0 ro

using Rigetti native gates by first using qc.compiler.quil_to_native_quil.

[8]:
prog = Program(
    'DECLARE ro BIT',
    'H 0',
    'CNOT 0 1',
    'MEASURE 0 ro'
)
compiled = qc.compiler.quil_to_native_quil(prog)
[9]:
exe = qc.compiler.native_quil_to_executable(compiled)

Note: The above compilation may be done even when not on an active QPU reservation. However,

  • as always, the executable cannot be run until on an active QPU reservation

  • the QPU settings used for compilation may go stale

Therefore, we suggest that although you may rely on qc.compiler.native_quil_to_executable for development purposes (for example, to verify correct Quil-T syntax), when executing on a QPU all Quil-T programs should be compiled afresh.

Running the executable proceeds as before:

[10]:
qc.run(exe)
[10]:
array([[0]])

Another example: a simple T1 experiment

As an example of mixing Quil with the new Quil-T instructions, we consider a simple T1 experiment. In short, we

  1. excite the qubit state

  2. wait some amount of time

  3. measure out

In this example, we do not do any further data analysis. The purpose here is simply to demonstrate how to compile and run a Quil-T program.

[11]:
def t1_program(time, qubit, num_shots=1000):
    prog = Program( "DECLARE ro BIT\n"
                   f"RX(pi) {qubit}\n"
                   f"FENCE 0\n"
                   f"DELAY {qubit} {time}\n"
                   f"MEASURE {qubit} ro")
    prog.wrap_in_numshots_loop(num_shots)
    return prog
[12]:
import numpy as np

probs = []

times = np.geomspace(20e-9, 60e-4, 20)
for time in times:
    prog = t1_program(time, 0)
    exe = qc.compiler.native_quil_to_executable(prog)
    results = qc.run(exe)
    prob = np.sum(results) / results.size
    probs.append(prob)
    print(f"time: {time:.2e} \tprob: {prob:.2}")
time: 2.00e-08  prob: 0.97
time: 3.88e-08  prob: 0.97
time: 7.54e-08  prob: 0.97
time: 1.47e-07  prob: 0.95
time: 2.85e-07  prob: 0.92
time: 5.53e-07  prob: 0.94
time: 1.07e-06  prob: 0.9
time: 2.08e-06  prob: 0.86
time: 4.05e-06  prob: 0.77
time: 7.86e-06  prob: 0.64
time: 1.53e-05  prob: 0.45
time: 2.96e-05  prob: 0.25
time: 5.76e-05  prob: 0.17
time: 1.12e-04  prob: 0.16
time: 2.17e-04  prob: 0.17
time: 4.22e-04  prob: 0.16
time: 8.19e-04  prob: 0.17
time: 1.59e-03  prob: 0.14
time: 3.09e-03  prob: 0.16
time: 6.00e-03  prob: 0.14
[13]:
%matplotlib inline
import matplotlib.pyplot as plt

plt.semilogx(times, probs, '-')
plt.xlabel('time (s)')
plt.ylabel('p')
plt.show()
_images/quilt_getting_started_25_0.png

Using a Custom Calibration

All gate and measure applications in a Quil-T program are translated according to either user-supplied or Rigetti calibrations. To easily check which calibration applies to a specific gate, use the Program.match_calibrations method.

[14]:
from math import pi
from pyquil.gates import RX

print(cals.get_calibration(RX(pi, 0)))
DEFCAL RX(pi) 0:
    FENCE 0
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 1.2e-07, fwhm: 3e-08, t0: 6e-08, anh: -190000000.0, alpha: -0.5128791143256078, scale: 0.63376686965814, phase: 0.0, detuning: 0.0)
    FENCE 0

None of the above programs needed us to specify calibrations. By default, the Rigetti native calibrations are used. However, if you specify a calibration in a program, it will take precedence over the native calibrations.

[15]:
prog = t1_program(1e-6, 0)

# Note: we did NOT specify a calibration for RX(pi) 0 in our previous program
assert prog.match_calibrations(RX(pi, 0)) is None
# The Quil-T translator provided the default: namely, the same calibration we obtained for ourselves
# with `qc.compiler.get_calibration_program()`.

In the example below, we use a custom calibration, we conjugate the usual pulse with a frequency shift. There’s no motivation for the particular value used, beyond simply showing what is possible.

[16]:
prog = Program("""DEFCAL RX(pi/2) 0:
    FENCE 0
    SET-SCALE 0 "rf" 0.353088482172993
    SHIFT-FREQUENCY 0 "rf" 1e6
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)
    SHIFT-FREQUENCY 0 "rf" -1e6
    FENCE 0

DECLARE ro BIT
RX(pi/2) 0
MEASURE 0 ro""")
print(prog)
DEFCAL RX(pi/2) 0:
    FENCE 0
    SET-SCALE 0 "rf" 0.353088482172993
    SHIFT-FREQUENCY 0 "rf" 1000000.0
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)
    SHIFT-FREQUENCY 0 "rf" -1000000.0
    FENCE 0

DECLARE ro BIT[1]
RX(pi/2) 0
MEASURE 0 ro[0]

[17]:
print(prog.get_calibration(RX(pi/2, 0)))
DEFCAL RX(pi/2) 0:
    FENCE 0
    SET-SCALE 0 "rf" 0.353088482172993
    SHIFT-FREQUENCY 0 "rf" 1000000.0
    NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)
    SHIFT-FREQUENCY 0 "rf" -1000000.0
    FENCE 0

[18]:
exe = qc.compiler.native_quil_to_executable(prog)
[19]:
qc.run(exe)
[19]:
array([[1]])

Of course, it is not required to use calibrations. One can construct an equivalent program by replacing the RX gate with the body of the calibration:

[20]:
prog = Program("""
DECLARE ro BIT
FENCE 0
SET-SCALE 0 "rf" 0.353088482172993
SHIFT-FREQUENCY 0 "rf" 1e6
NONBLOCKING PULSE 0 "rf" drag_gaussian(duration: 6.000000000000001e-08, fwhm: 1.5000000000000002e-08, t0: 3.0000000000000004e-08, anh: -210000000.0, alpha: 6.389096630631076)
SHIFT-FREQUENCY 0 "rf" -1e6
FENCE 0
MEASURE 0 ro
""".strip())
[21]:
exe = qc.compiler.native_quil_to_executable(prog)
[22]:
qc.run(exe)
[22]:
array([[0]])

Parametric Calibrations

Some calibrations (e.g. for RX) are defined for specific parameter values. Others may depend on general symbolic values, as with RZ.

[23]:
from pyquil.gates import RZ

print(cals.get_calibration(RZ(pi,0)))
DEFCAL RZ(%theta) 0:
    FENCE 0
    SHIFT-PHASE 0 "rf" -1.0*%theta
    SHIFT-PHASE 0 7 "xy" -0.5*%theta
    FENCE 0

To get more information about how the matching calibration applies to a specific gate, use Program.match_calibrations. The result is a CalibrationMatch object which indicates not just the calibration, but the value for parameters.

[24]:
match = cals.match_calibrations(RZ(pi,0))
print(match.cal)
print(match.settings)
DEFCAL RZ(%theta) 0:
    FENCE 0
    SHIFT-PHASE 0 "rf" -1.0*%theta
    SHIFT-PHASE 0 7 "xy" -0.5*%theta
    FENCE 0

{Parameter('theta'): 3.141592653589793}

You may conveniently recover the body of the calibration, with the matched parameters substituted, using Program.calibrate.

[25]:
instrs = cals.calibrate(RZ(pi,0))
for instr in instrs:
    print(instr)
FENCE 0
SHIFT-PHASE 0 "rf" -3.141592653589793
SHIFT-PHASE 0 7 "xy" -1.5707963267948966
FENCE 0

Non-Native Gates

As mentioned above, the qc.compiler.native_quil_to_executable call will provide calibrations for Rigetti native gates, if they are not provided by a user. However, a program with non-native gates and no corresponding user-provided calibrations will result in a compilation failure.

[26]:
prog = Program("DECLARE ro BIT\n"
               "H 0\n"
               "CNOT 0 1\n"
               "MEASURE 0 ro")

try:
    qc.compiler.native_quil_to_executable(prog)
except Exception as e:
    print("Fails on non-native operations {H, CNOT} as expected.")
Fails on non-native operations {H, CNOT} as expected.