# OQpy: Generating OpenQASM 3 + OpenPulse in Python
The goal of `oqpy` ("ock-pie") is to make it easy to generate OpenQASM 3 + OpenPulse in Python. The
`oqpy` library builds off of the [`openqasm3`][openqasm3] and [`openpulse`][openpulse] packages,
which serve as Python reference implementations of the _abstract syntax tree_ (AST) for the
OpenQASM 3 and OpenPulse grammars.
[openqasm3]: https://pypi.org/project/openqasm3/
[openpulse]: https://pypi.org/project/openpulse/
## What are OpenQASM 3 and OpenPulse?
OpenQASM is an imperative programming language designed for near-term quantum computing algorithms
and applications. [OpenQASM 3][openqasm3-docs] extends the original specification by adding support
for classical logic, explicit timing, and pulse-level definitions. The latter is enabled via the use
of [_calibration grammars_][pulses-docs] which allow quantum hardware builders to extend the language
to support hardware-specific directives via `cal` and `defcal` blocks. One such grammar is
[OpenPulse][openpulse-docs], which provides the instructions required for pulse-based control of
many common quantum computing architectures (e.g. superconducting qubits).
[openqasm3-docs]: https://openqasm.com/
[pulses-docs]: https://openqasm.com/language/pulses.html
[openpulse-docs]: https://openqasm.com/language/openpulse.html
## Installation and Getting Started
OQpy can be installed from [PyPI][pypi] or from source in an environment with Python 3.7 or greater.
To install it from PyPI (via `pip`), do the following:
```
pip install oqpy
```
To instead install OQpy from source, do the following from within the repository after cloning it:
```
poetry install
```
Next, check out the following example to get a sense of the kinds of programs we can write with
OQpy.
[pypi]: https://pypi.org/project/oqpy/
## Example: Ramsey Interferometry
A common and useful experiment for qubit characterization is [Ramsey interferometry][ramsey],
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.
[ramsey]: https://en.wikipedia.org/wiki/Ramsey_interferometry
```python
import oqpy
prog = oqpy.Program() # create a new oqpy program
# Declare frames: transmon driving frame and readout receive/transmit frames
xy_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 with
constant_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 defcals
qubit = oqpy.PhysicalQubits[1] # get physical qubit 1
with oqpy.defcal(prog, qubit, "reset"):
prog.delay(1e-3) # reset to ground state by waiting 1 ms
with oqpy.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))
with oqpy.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 duration
with oqpy.ForIn(prog, range(100), "shot_index"):
prog.set(delay_time, 0) # reset delay time to zero
# Loop over delays
with oqpy.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 ns
```
Running `print(prog.to_qasm(encal_declarations=True))` generates the following OpenQASM:
```qasm3
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;
}
}
```
## Contributing
We welcome contributions to OQpy including bug fixes, feature requests, etc. To get started, check
out our [contributing guidelines](CONTRIBUTING.md). Those who make a nontrivial contribution to the
source code will be added as an author to the [`CITATION.cff`][citation-file] file (see below).
## Citation
If you use OQpy in your work or research, please cite it using the metadata in the
[`CITATION.cff`][citation-file] file in the repository (which includes a
[Zenodo DOI][zenodo-doi]). You can copy the citation in BibTeX format using the
["Cite this repository" widget][citation-widget] in the About section of the
[repository page on GitHub][github].
[zenodo-doi]: https://doi.org/10.5281/zenodo.7349265
[citation-file]: https://github.com/openqasm/oqpy/blob/main/CITATION.cff
[citation-widget]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files
[github]: https://github.com/openqasm/oqpy
Raw data
{
"_id": null,
"home_page": "https://github.com/openqasm/oqpy",
"name": "oqpy",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "openqasm,quantum",
"author": "OQpy Contributors",
"author_email": "oqpy-contributors@amazon.com",
"download_url": "https://files.pythonhosted.org/packages/80/1e/1d0cf4d3cd4dd00bee3a7c9d3de6dac94c78bc1bf92ef6f77287ce39707f/oqpy-0.3.4.tar.gz",
"platform": null,
"description": "# OQpy: Generating OpenQASM 3 + OpenPulse in Python\n\nThe goal of `oqpy` (\"ock-pie\") is to make it easy to generate OpenQASM 3 + OpenPulse in Python. The\n`oqpy` library builds off of the [`openqasm3`][openqasm3] and [`openpulse`][openpulse] packages,\nwhich serve as Python reference implementations of the _abstract syntax tree_ (AST) for the\nOpenQASM 3 and OpenPulse grammars.\n\n[openqasm3]: https://pypi.org/project/openqasm3/\n[openpulse]: https://pypi.org/project/openpulse/\n\n## What are OpenQASM 3 and OpenPulse?\n\nOpenQASM is an imperative programming language designed for near-term quantum computing algorithms\nand applications. [OpenQASM 3][openqasm3-docs] extends the original specification by adding support\nfor classical logic, explicit timing, and pulse-level definitions. The latter is enabled via the use\nof [_calibration grammars_][pulses-docs] which allow quantum hardware builders to extend the language\nto support hardware-specific directives via `cal` and `defcal` blocks. One such grammar is\n[OpenPulse][openpulse-docs], which provides the instructions required for pulse-based control of\nmany common quantum computing architectures (e.g. superconducting qubits).\n\n[openqasm3-docs]: https://openqasm.com/\n[pulses-docs]: https://openqasm.com/language/pulses.html\n[openpulse-docs]: https://openqasm.com/language/openpulse.html\n\n## Installation and Getting Started\n\nOQpy can be installed from [PyPI][pypi] or from source in an environment with Python 3.7 or greater.\n\nTo install it from PyPI (via `pip`), do the following:\n\n```\npip install oqpy\n```\n\nTo instead install OQpy from source, do the following from within the repository after cloning it:\n\n```\npoetry install\n```\n\nNext, check out the following example to get a sense of the kinds of programs we can write with\nOQpy.\n\n[pypi]: https://pypi.org/project/oqpy/\n\n## Example: Ramsey Interferometry\n\nA common and useful experiment for qubit characterization is [Ramsey interferometry][ramsey],\nwhich can be used for two purposes: performing a careful measurement of a qubit\u2019s resonant\nfrequency, and for investigating how long a qubit retains its coherence. In a typical Ramsey\nexperiment, one varies the length of a delay between the two \u03c0/2 pulses, and then measures the state\nof the qubit. Below, we'll create a Ramsey interferometry experiment in OpenQASM 3 using OQpy.\nAs part of this, we\u2019ll use the OpenPulse grammar to allow this experiment to specify its operation\nimplementations at the calibrated pulse level.\n\n[ramsey]: https://en.wikipedia.org/wiki/Ramsey_interferometry\n\n```python\nimport oqpy\nprog = oqpy.Program() # create a new oqpy program\n\n# Declare frames: transmon driving frame and readout receive/transmit frames\nxy_frame = oqpy.FrameVar(oqpy.PortVar(\"dac0\"), 6.431e9, name=\"xy_frame\")\nrx_frame = oqpy.FrameVar(oqpy.PortVar(\"adc0\"), 5.752e9, name=\"rx_frame\")\ntx_frame = oqpy.FrameVar(oqpy.PortVar(\"dac1\"), 5.752e9, name=\"tx_frame\")\n\n# Declare the type of waveform we are working with\nconstant_waveform = oqpy.declare_waveform_generator(\n \"constant\",\n [(\"length\", oqpy.duration),\n (\"amplitude\", oqpy.float64)],\n)\ngaussian_waveform = oqpy.declare_waveform_generator(\n \"gaussian\",\n [(\"length\", oqpy.duration),\n (\"sigma\", oqpy.duration),\n (\"amplitude\", oqpy.float64)],\n)\n\n# Provide gate / operation definitions as defcals\nqubit = oqpy.PhysicalQubits[1] # get physical qubit 1\n\nwith oqpy.defcal(prog, qubit, \"reset\"):\n prog.delay(1e-3) # reset to ground state by waiting 1 ms\n\nwith oqpy.defcal(prog, qubit, \"measure\"):\n prog.play(tx_frame, constant_waveform(2.4e-6, 0.2))\n prog.capture(rx_frame, constant_waveform(2.4e-6, 1))\n\nwith oqpy.defcal(prog, qubit, \"x90\"):\n prog.play(xy_frame, gaussian_waveform(32e-9, 8e-9, 0.2063))\n\n# Loop over shots (i.e. repetitions)\ndelay_time = oqpy.DurationVar(0, \"delay_time\") # initialize a duration\nwith oqpy.ForIn(prog, range(100), \"shot_index\"):\n prog.set(delay_time, 0) # reset delay time to zero\n # Loop over delays\n with oqpy.ForIn(prog, range(101), \"delay_index\"):\n (prog.reset(qubit) # prepare in ground state\n .gate(qubit, \"x90\") # pi/2 pulse (90\u00b0 rotation about the x-axis)\n .delay(delay_time, qubit) # variable delay\n .gate(qubit, \"x90\") # pi/2 pulse (90\u00b0 rotation about the x-axis)\n .measure(qubit) # final measurement\n .increment(delay_time, 100e-9)) # increase delay by 100 ns\n```\n\nRunning `print(prog.to_qasm(encal_declarations=True))` generates the following OpenQASM:\n\n```qasm3\nOPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n extern constant(duration, float[64]) -> waveform;\n extern gaussian(duration, duration, float[64]) -> waveform;\n port dac1;\n port adc0;\n port dac0;\n frame tx_frame = newframe(dac1, 5752000000.0, 0);\n frame rx_frame = newframe(adc0, 5752000000.0, 0);\n frame xy_frame = newframe(dac0, 6431000000.0, 0);\n}\nduration delay_time = 0.0ns;\ndefcal reset $1 {\n delay[1000000.0ns];\n}\ndefcal measure $1 {\n play(tx_frame, constant(2400.0ns, 0.2));\n capture(rx_frame, constant(2400.0ns, 1));\n}\ndefcal x90 $1 {\n play(xy_frame, gaussian(32.0ns, 8.0ns, 0.2063));\n}\nfor int shot_index in [0:99] {\n delay_time = 0.0ns;\n for int delay_index in [0:100] {\n reset $1;\n x90 $1;\n delay[delay_time] $1;\n x90 $1;\n measure $1;\n delay_time += 100.0ns;\n }\n}\n```\n\n## Contributing\n\nWe welcome contributions to OQpy including bug fixes, feature requests, etc. To get started, check\nout our [contributing guidelines](CONTRIBUTING.md). Those who make a nontrivial contribution to the\nsource code will be added as an author to the [`CITATION.cff`][citation-file] file (see below).\n\n## Citation\n\nIf you use OQpy in your work or research, please cite it using the metadata in the\n[`CITATION.cff`][citation-file] file in the repository (which includes a\n[Zenodo DOI][zenodo-doi]). You can copy the citation in BibTeX format using the\n[\"Cite this repository\" widget][citation-widget] in the About section of the\n[repository page on GitHub][github].\n\n[zenodo-doi]: https://doi.org/10.5281/zenodo.7349265\n[citation-file]: https://github.com/openqasm/oqpy/blob/main/CITATION.cff\n[citation-widget]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files\n[github]: https://github.com/openqasm/oqpy\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Generating OpenQASM 3 + OpenPulse in Python",
"version": "0.3.4",
"project_urls": {
"Homepage": "https://github.com/openqasm/oqpy",
"Repository": "https://github.com/openqasm/oqpy"
},
"split_keywords": [
"openqasm",
"quantum"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "801e1d0cf4d3cd4dd00bee3a7c9d3de6dac94c78bc1bf92ef6f77287ce39707f",
"md5": "7bbc871a31b583d14006422de9cdc94d",
"sha256": "4bf40aa201e7c0f894ad7f1699ae67588896cd90ce6f10c85dbbdb4917f41d65"
},
"downloads": -1,
"filename": "oqpy-0.3.4.tar.gz",
"has_sig": false,
"md5_digest": "7bbc871a31b583d14006422de9cdc94d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 31235,
"upload_time": "2023-10-30T13:46:16",
"upload_time_iso_8601": "2023-10-30T13:46:16.164082Z",
"url": "https://files.pythonhosted.org/packages/80/1e/1d0cf4d3cd4dd00bee3a7c9d3de6dac94c78bc1bf92ef6f77287ce39707f/oqpy-0.3.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-10-30 13:46:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "openqasm",
"github_project": "oqpy",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "oqpy"
}