In the qBraid-SDK, a “transpile” action refers to converting a quantum program from one type to another, such as from Qiskit to Amazon Braket. In contrast, a “transform” action involves modifying a quantum program to meet specific requirements dictated by the target device or API through which the program will be executed.

Let’s delve into the various “transforms” employed to prepare a quantum program for execution on an IonQ backend.

We begin by constructing a simple Qiskit circuit that executes a controlled Y rotation:

import numpy as np
from qiskit import QuantumCircuit

circuit = QuantumCircuit(2, 2)

circuit.cry(np.pi/4, 0, 1)

circuit.measure_all()

We then connect to the IonQProvider and retrieve the specifications for the IonQ Harmony device:

from qbraid.runtime import IonQProvider

provider = IonQProvider()

device = provider.get_device("qpu.harmony")

device.profile.get("program_spec")
# <ProgramSpec('openqasm3', openqasm3.ast.Program)>

device.profile.get("basis_gates")
# { "x","y","z","rx","ry","rz","h","cx","s","sdg","t","tdg","sx","sxdg","swap" }

By reviewing the device’s TargetProfile, we understand that in order to run a program on IonQ Harmony, qBraid runtime requires that it be expressed as an openqasm3.ast.Program and utilize only the gates from its defined basis gate set. Consequently, our first step is to transpile our qiskit program to the openqasm3 program type:

from qbraid import transpile

qasm3_program = transpile(circuit, 'openqasm3')

type(qasm3_program)
# openqasm3.ast.Program

Next, we load the program into a qBraid QuantumProgram object and examine its string representation:

from qbraid import load_program

qprogram = load_program(qasm3_program)

print(qprogram.program)
# OPENQASM 3.0;
# include "stdgates.inc";
# bit[2] c;
# bit[2] meas;
# qubit[2] q;
# cry(pi / 4) q[0], q[1];
# barrier q[0], q[1];
# meas[0] = measure q[0];
# meas[1] = measure q[1];

We can now apply a “transform” to this program, using our device object as argument, ensuring it is represented exclusively in terms of gates supported by IonQ Harmony:

program.transform(device)

print(program.program)
# OPENQASM 3.0;
# bit[2] b;
# qubit[2] q;
# ry(0.39269908169872414) q[1];
# cx q[0], q[1];
# ry(-0.39269908169872414) q[1];
# cx q[0], q[1];
# b[0] = measure q[0];
# b[1] = measure q[1];

Device-specific transforms are a crucial component of the qBraid runtime framework, applied as the final step before a program is executed on a quantum backend.

We’ve just demonstrated how one can utilize these transforms independently, outside of a runtime protocol, which may be beneficial for testing or local simulations. However, for qBraid runtime end-users, these steps are automatically performed behind the scenes whenever the QuantumDevice.run method is invoked.