AWS Quantum Technologies Blog

Qiskit-Braket provider v0.11: New Primitives and Flexible Circuit Compilation

We recently released v0.11 of the Qiskit-Braket provider, which brings more Qiskit features to Amazon Braket users, improves access to Braket backends through Qiskit, and also enables compilation on the Braket SDK or with OpenQASM Programs. With v0.11, the Qiskit-Braket provider now:

  • Supports flexible compilation features for Braket using common Qiskit transpile functionality through the to_braket function
  • Contains new BraketEstimator and BraketSampler primitives, which mirror routines found in similar Qiskit primitives, and includes several features aimed at running with Amazon Braket program sets.
  • Supports Qiskit 2.0, and is fully back compatible to v0.34.2.

With the latest upgrades to the Qiskit-Braket provider, you can use a richer set of tools for executing quantum programs on Amazon Braket.

Updated support for Qiskit 2.0

The Qiskit-Braket-provider now supports Qiskit 2.0, which introduced new functionality and deprecated several old classes, compared to Qiskit 1.x. Additionally, performance increases seen in the refactoring of Qiskit 2.0 can now be leveraged using the Qiskit-Braket provider. The Qiskit-Braket provider is also back compatible to v0.34.2.

For a full list of 2.0 changes, see Qiskit’s release summary, as well as recent releases (0.7.0 and beyond) in the Qiskit-Braket provider.

Unlocking compilation for Braket circuits

The Qiskit-Braket provider can now be used to easily unlock compilation on Braket circuits. You can now compile or transpile to Braket Circuit objects through the to_braket function, which can then be directly submitted to Braket devices:

from qiskit_braket_provider import to_braket 
from braket.circuits import Circuit
from braket.aws import AwsDevice 
from braket.devices import Devices

device = AwsDevice(Devices.IQM.Garnet) 
ghz_4 = Circuit().h(0).cnot(0,1).cnot(1,2).cnot(2,3)
ghz_4_native = to_braket(ghz_4, braket_device = device)
# result = device.run(ghz_4_native, shots=100).result()

Importantly to_braket supports some powerful functionality, converting inputs from Qiskit, Braket, and OpenQASM3. It also supports Qiskit Targets and common transpilation inputs. See the example notebook for more examples.

from qiskit_braket_provider import BraketAwsBackend
backend = BraketAwsBackend(device=device) 
qasm_string = """
    qubit[3] q;
    gate majority a, b, c {
        // set c to the majority of {a, b, c}
        ctrl @ x c, b;
        ctrl @ x c, a;
        ctrl(2) @ x a, b, c;
    }
    pow(0.5) @ x q[0:1];     // sqrt x
    inv @ v q[1];          // inv of (sqrt x)
    // this should flip q[2] to 1
    majority q[0], q[1], q[2];
    """
to_braket(
    qasm_string, 
    target=backend.target, 
    qubit_labels=backend.qubit_labels, 
    optimization_level=1
)

Braket primitives for enhanced and simplified execution

For your applications using Qiskit circuits,  Braket primitives help to improve performance and utilize Braket and Qiskit features. Previously, Braket backends were supplied to the generic BackendEstimator and BackendSampler classes, which could be used in applications using Qiskit, and provided only a simple wrapper around the Braket executables. Now, you can directly utilize updated Primitives for improved performance.

import numpy as np
from qiskit_braket_provider import BraketEstimator, BraketLocalBackend
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit import Parameter
import matplotlib.pyplot as plt 

backend = BraketLocalBackend()
estimator = BraketEstimator(backend=backend)
circuit = QuantumCircuit(2) 
circuit.h(0) 
circuit.cx(0, 1) 
circuit.ry(Parameter("θ"), 0) 
parameters = [[ph] for ph in np.linspace(0, 2 * np.pi, 25)] 
observables = [
    [SparsePauliOp("ZZ")], 
    [SparsePauliOp("ZX")], 
    [SparsePauliOp("XZ")], 
    [SparsePauliOp("XX", -1)]]
estimator_pub = circuit, observables, parameters
task = estimator.run([estimator_pub], precision=0.015625)
evs = task.result()[0].data.evs 
fig = plt.figure()
for ev, obs, color, in zip(evs, observables,["b","o","g","r"]):
    plt.plot(parameters, ev, color, label=obs[0].to_list()[0][0]) 
plt.xlabel(r"Angle")
plt.ylabel(r"Expectation")
fig.legend(loc="upper left", bbox_to_anchor=(0.9, 0.6))
plt.show()

The preceding plot shows the results of a single program set run on the BraketEstimator. This includes sum Hamiltonian observables specified by SparsePauliOps, or even numpy-like array inputs. You can inspect the aggregate ProgramSet object using task.program_set. 

You can utilize the BraketEstimator and BraketSampler primitives with Braket backends within the Qiskit framework. These provide native features that simplify execution, allow for advanced parsing of observables, parameters, or generic PUBs, and importantly harness features like Braket program sets.

Whether you are a seasoned Braket user looking to enhance device-native compilation with Qiskit, or you would like to test out applications on Braket devices using the new primitives, the updated Qiskit-Braket provider can help your quantum-enabled explorations on Amazon Braket.