Note
Click here to download the full example code
Running Jobs on Qiskit Backends
import trueq as tq
import qiskit as qk
Running jobs on a Qiskit backend requires credentials for the provider of the backend. See the provider’s documentation for instructions for how to set this up. For example, the following snippet demonstrates how one instantiates a remote backend object from the IBM Quantum Experience. This example file does not have any credentials, so we make do with the local Qiskit simulator which uses the same backend abstraction.
have_credentials = False
if have_credentials:
qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend("ibmq_manila")
else:
from qiskit.providers.aer import AerSimulator
from qiskit.test.mock import FakeMelbourne
backend = AerSimulator.from_backend(FakeMelbourne())
Submitting a Circuit Collection
# Define a 3-qubit cycle to work with.
cycle = {0: tq.Gate.x, 1: tq.Gate.y, 2: tq.Gate.h}
# Generate a circuit collection to measure noise.
circuits = tq.make_knr(cycle, [4, 32, 64], 24)
The executor (defined below) will automatically attempt to batch the circuit collection into the maximum number of circuits per job that the backend supports. Here, however, we manually batch beforehand. Supposing the backend accepts at most 75 circuits and has a memory cutoff for the number of gates allowed per job, we choose to riffle circuits in the batch by circuit depth. In our protocol above, we selected 3 sequence lengths, 4, 32, and 64, with 24 random circuits per sequence length per configuration. Thus we use fit \(24\times 3+2=72\) circuits per batch, where the extra \(2\) are readout calibration (RCAL) circuits.
ro_circuits = tq.make_rcal(circuits.labels)
batches = circuits.batch(74, extra_circuits=ro_circuits, sequencer=tq.sequencer.RIFFLER)
Run the batches on our backend. If a filename is provided, it will periodically save to the given file so that we can resume the experiment if, for example, our Python kernel crashes.
ex = tq.interface.Executor(batches, backend, n_shots=128)
# the executor is asynchronous, call a blocking function to wait for it to finish
ex.block()
circuits.plot.timestamps()

{'text/html': '\n\n\n<script>\n if (trueq !== "2.12.2") {\n var css = document.createElement("style");\n css.type = "text/css";\n css.innerHTML = "div.input,div.output_wrapper { z-index: auto;}.jp-OutputArea-output .tq-tooltip.tq-tooltip dl { width: unset;}.jp-OutputArea-output .tq-tooltip.tq-tooltip dt { display: flex; float: none;}.jp-RenderedHTMLCommon .tq-tooltip.tq-tooltip svg { max-width: unset; height: unset;}.tq-tooltip { background-color: #fff; border: 1px solid #333; border-radius: 2px; color: #000; display: none; font-size: 1em; font-weight: normal; line-height: normal; margin: 0px; overflow-wrap: normal; padding: 8px; position: fixed; text-align: left; z-index: 100;}.tq-tooltip.tq-tooltip > dl > dd > ul { list-style-type: none; margin: 0px; padding: 0px;}.tq-tooltip.tq-tooltip > dl > dd > ul > li { list-style-type: none; margin: 0px 0px 0px 1em; padding: 0px;}.tq-tooltip.tq-tooltip dt { background: none !important; border-left: none !important; color: #134f6d !important; font-size: 1.1em; font-weight: bold; margin: 0px !important; padding: 0px;}.tq-tooltip.tq-tooltip dl { display: inline-block; margin: 0px; vertical-align: top;}.tq-tooltip.tq-tooltip dd { margin: 0px 10px 0px 0px;}.tq-tooltip canvas { outline: black 1px solid;}.tq-table tr,.tq-table.tq-table tr:nth-child(odd) { background: transparent; text-align: right;}.tq-table td { padding: 0px 3px 3px 3px; white-space: nowrap;}.tq-table td:hover { background-color: #ebf8ff;}.tq-table.tq-table tr:hover { background-color: #f5f5f5;}.tq-table td { min-width: 2em;}.tq-highlight { background-color: #f2f6ff !important;}.tq-highlight p { margin: 0px;}.tq-right-border td { border-right: 1px solid black;}.tq-trusted { display: none;}.tq-executor { line-height: 1; display: flex;}.tq-executor .indicator { background-color: #000000; height: 1em; width: 1em;}.tq-executor .indicator.cancelled { background-color: #800000;}.tq-executor .indicator.done { background-color: #90ee90;}.tq-executor .indicator.error { background-color: #ff0000;}.tq-executor .indicator.initializing { background-color: #a9a9a9;}.tq-executor .indicator.queued { background-color: #add8e6;}.tq-executor .indicator.running { background-color: #008000;}.tq-executor .indicator.validating { background-color: #ffa500;}.tq-executor .index { padding-left: 1em; text-align: right;}.tq-executor .status { min-width: 6em; padding-left: 1em;}.tq-executor .message { padding-left: 1em;}";\n document.head.appendChild(css);\n var polyfill = document.createElement("script");\n polyfill.src = "https://polyfill.io/v3/polyfill.min.js?features=es6";\n document.body.appendChild(polyfill);\n var mathjax = document.createElement("script");\n mathjax.id = "MathJax-script";\n mathjax.async = true;\n mathjax.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js";\n mathjax.innerHTML = "MathJax = {tex2jax: {inlineMath: [[\'$\', \'$\'], [\'\\\\(\', \'\\\\)\']]}};";\n document.body.appendChild(mathjax);\n var trueq = "2.12.2";\n }\n</script>\n<div class="tq-trusted">True-Q formatting will not be loaded without trusting this\nnotebook or rerunning the affected cells. Notebooks can be marked as trusted by clicking\n"File -> Trust Notebook".</div>\n'}
HTML(value='')
HTML(value='')
HTML(value='')
HTML(value='')
HBox(children=(Button(button_style='danger', description='Cancel', disabled=True, layout=Layout(width='9em'), style=ButtonStyle(), tooltip='Cancel all submitted jobs'), Checkbox(value=False, description='Enable Cancel', indent=False, layout=Layout(width='8em'))), layout=Layout(align_items='flex-end', display='flex', flex_flow='column'))
Note
When running in Jupyter, the executor has an automatically updating output which relies on IPywidgets being installed and enabled. If these are not installed then no display will show up when running the executor in Jupyter.
Transpiling for a Specific Backend
Sometimes it is useful to see what the circuit conversion is doing for a particular circuit. To do this, we first instantiate a True-Q configuration object from our desired backend. This will contain the device topology and native gates of the backend. We create a compiler object based on this configuration.
Note
This process is done during submission automatically by the
Executor
, and the steps below should only be used as
a reference. The output of this should not be put into the Executor
or it will
apply the same compiler operations a second time, which may alter the circuit
further.
config = tq.interface.qiskit.config_from_backend(backend)
transpiler = tq.Compiler.from_config(config)
Define a circuit.
circuit = tq.Circuit([{4: tq.Gate.random(2), 5: tq.Gate.x}])
circuit
Transpile the circuit based on the device.
transpiled_circuit = transpiler.compile(circuit)
transpiled_circuit
Total running time of the script: ( 0 minutes 35.533 seconds)