Executing Circuits on Qiskit Providers

True-Qᵀᴹ supports direct execution of circuit collections on hardware and simulators that use a Qiskit backend. This includes the IBMQ superconducting qubit chips . Transpiling to the given backend is done automatically for any backend whose gates are a subset of [‘u1’, ‘u2’, ‘u3’, ‘cx’].

Circuits to be run by a backend through Qiskit are submitted as jobs, which can contain one or more circuits. Like many modern quantum hardware platforms, Qiskit backends have restrictions on how many circuits a user can submit per job, as well as how many jobs can be in the global job queue at once. Thus, large circuits collections (e.g. as generated by True-Qᵀᴹ protocols) must be batched into multiple jobs, while restricting the job count in the queue.

The True-Qᵀᴹ Executor class automates the batching and job submission process according to the above restrictions. An asynchronous thread monitors the status of each submitted job, and submits new jobs as spots open in the queue.

Example (Loading IBM Config File and Transpiling to it)

import qiskit as qk
import trueq as tq

# Load user credentials
qk.IBMQ.load_account()

# Load the backend for IBM's machine "ibmqx2"
provider = qk.IBMQ.get_provider()
backend = provider.get_backend("ibmqx2")

# Create a configuration file from the backend of "ibmqx2"
config = tq.interface.qiskit.config_from_backend(backend)

# Make a transpiler based on the device configuration.
transpiler = tq.compilation.get_transpiler(config)

# Define a circuit.
circuit = tq.Circuit([{(0, 1): tq.Gate.cz}])

# Transpile the circuit based on the device.
transpiled_circuit = transpiler.compile(circuit)

Example (Running a circuit on an IBM Device)

The executor automatically populates the results of circuits run on a hardware platform.

import trueq as tq
import qiskit as qk

qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend('ibmq_ourense')

# Define the circuit we want to run
circs = tq.Circuit([{0: tq.Gate.x, (1,2): tq.Gate.cz},
                    {0: tq.Meas()}])

# Executes the circuit on ibmq_ourense
ex = tq.interface.qiskit.Executor(circs, backend)

# This is a blocking operation, and will block until all data has been acquired
ex.results().results

Example (Running a circuit collection on an IBM Device)

In this example, we use batches of 75 circuits because that is the maximum that ibmqx2 will accept.

import trueq as tq
import qiskit as qk

qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend('ibmqx2')

# Define the cycle we wish to do noise reconstruction on.
cycle = {(0,): tq.Gate.x,(1,2): tq.Gate.cz}

# Generate a circuit collection to measure noise.
circs = tq.make_knr(cycle, [4, 32, 64], 30)

# Batch the circuits into groups of 75
batches = circs.batch(75)

# Run the batches on ibmqx2
tq.interface.qiskit.Executor(batches, backend, filename='example_srb.tq')

While code is running, the status of the jobs looks like the following:

../_images/queued_jobs.png

Note

When running in Jupyter, the executor has an automatically updating output which relies on IPywidgets. If these are not installed then no display will show up when running the executor in Jupyter.