Package: oqpy
OQpy: Generating OpenQASM 3 + OpenPulse in PythonThe goal ofoqpy("ock-pie") is to make it easy to generate OpenQASM 3 + OpenPulse in Python. Theoqpylibrary builds off of theopenqasm3andopenpulsepackages,
which serve as Python reference implementations of theabstract syntax tree(AST) for the
OpenQASM 3 and OpenPulse grammars.What are OpenQASM 3 and OpenPulse?OpenQASM is an imperative programming language designed for near-term quantum computing algorithms
and applications.OpenQASM 3extends the original specification by adding support
for classical logic, explicit timing, and pulse-level definitions. The latter is enabled via the use
ofcalibration grammarswhich allow quantum hardware builders to extend the language
to support hardware-specific directives viacalanddefcalblocks. One such grammar isOpenPulse, which provides the instructions required for pulse-based control of
many common quantum computing architectures (e.g. superconducting qubits).Installation and Getting StartedOQpy can be installed fromPyPIor from source in an environment with Python 3.7 or greater.To install it from PyPI (viapip), do the following:pip install oqpyTo instead install OQpy from source, do the following from within the repository after cloning it:poetry installNext, check out the following example to get a sense of the kinds of programs we can write with
OQpy.Example: Ramsey InterferometryA common and useful experiment for qubit characterization isRamsey interferometry,
which can be used for two purposes: performing a careful measurement of a qubit’s resonant
frequency, and for investigating how long a qubit retains its coherence. In a typical Ramsey
experiment, one varies the length of a delay between the two π/2 pulses, and then measures the state
of the qubit. Below, we'll create a Ramsey interferometry experiment in OpenQASM 3 using OQpy.
As part of this, we’ll use the OpenPulse grammar to allow this experiment to specify its operation
implementations at the calibrated pulse level.importoqpyprog=oqpy.Program()# create a new oqpy program# Declare frames: transmon driving frame and readout receive/transmit framesxy_frame=oqpy.FrameVar(oqpy.PortVar("dac0"),6.431e9,name="xy_frame")rx_frame=oqpy.FrameVar(oqpy.PortVar("adc0"),5.752e9,name="rx_frame")tx_frame=oqpy.FrameVar(oqpy.PortVar("dac1"),5.752e9,name="tx_frame")# Declare the type of waveform we are working withconstant_waveform=oqpy.declare_waveform_generator("constant",[("length",oqpy.duration),("amplitude",oqpy.float64)],)gaussian_waveform=oqpy.declare_waveform_generator("gaussian",[("length",oqpy.duration),("sigma",oqpy.duration),("amplitude",oqpy.float64)],)# Provide gate / operation definitions as defcalsqubit=oqpy.PhysicalQubits[1]# get physical qubit 1withoqpy.defcal(prog,qubit,"reset"):prog.delay(1e-3)# reset to ground state by waiting 1 mswithoqpy.defcal(prog,qubit,"measure"):prog.play(tx_frame,constant_waveform(2.4e-6,0.2))prog.capture(rx_frame,constant_waveform(2.4e-6,1))withoqpy.defcal(prog,qubit,"x90"):prog.play(xy_frame,gaussian_waveform(32e-9,8e-9,0.2063))# Loop over shots (i.e. repetitions)delay_time=oqpy.DurationVar(0,"delay_time")# initialize a durationwithoqpy.ForIn(prog,range(100),"shot_index"):prog.set(delay_time,0)# reset delay time to zero# Loop over delayswithoqpy.ForIn(prog,range(101),"delay_index"):(prog.reset(qubit)# prepare in ground state.gate(qubit,"x90")# pi/2 pulse (90° rotation about the x-axis).delay(delay_time,qubit)# variable delay.gate(qubit,"x90")# pi/2 pulse (90° rotation about the x-axis).measure(qubit)# final measurement.increment(delay_time,100e-9))# increase delay by 100 nsRunningprint(prog.to_qasm(encal_declarations=True))generates the following OpenQASM:OPENQASM 3.0;
defcalgrammar "openpulse";
cal {
    extern constant(duration, float[64]) -> waveform;
    extern gaussian(duration, duration, float[64]) -> waveform;
    port dac1;
    port adc0;
    port dac0;
    frame tx_frame = newframe(dac1, 5752000000.0, 0);
    frame rx_frame = newframe(adc0, 5752000000.0, 0);
    frame xy_frame = newframe(dac0, 6431000000.0, 0);
}
duration delay_time = 0.0ns;
defcal reset $1 {
    delay[1000000.0ns];
}
defcal measure $1 {
    play(tx_frame, constant(2400.0ns, 0.2));
    capture(rx_frame, constant(2400.0ns, 1));
}
defcal x90 $1 {
    play(xy_frame, gaussian(32.0ns, 8.0ns, 0.2063));
}
for int shot_index in [0:99] {
    delay_time = 0.0ns;
    for int delay_index in [0:100] {
        reset $1;
        x90 $1;
        delay[delay_time] $1;
        x90 $1;
        measure $1;
        delay_time += 100.0ns;
    }
}ContributingWe welcome contributions to OQpy including bug fixes, feature requests, etc. To get started, check
out ourcontributing guidelines. Those who make a nontrivial contribution to the
source code will be added as an author to theCITATION.cfffile (see below).CitationIf you use OQpy in your work or research, please cite it using the metadata in theCITATION.cfffile in the repository (which includes aZenodo DOI). You can copy the citation in BibTeX format using the"Cite this repository" widgetin the About section of therepository page on GitHub.