Qdislib — 09 · Distributed execution & real QPUs

The whole point of cutting is to run the pieces in parallel — across a cluster with PyCOMPSs, and/or on real quantum hardware. The cells below are illustrative: they need a PyCOMPSs runtime, IBM credentials, or the BSC QPU environment, so they aren’t executed in the docs build.

1. Distributed with PyCOMPSs

The API is identical — under PyCOMPSs each expectation_value runs as a COMPSs task and *_subcircuits returns serializable Subcircuit wrappers automatically. In a notebook you start the runtime interactively:

[ ]:
import pycompss.interactive as ipycompss
ipycompss.start(graph=True, monitor=1000)

import Qdislib as qd
from qibo import models, gates

circuit = models.Circuit(5)
circuit.add(gates.RY(0, 0.8)); circuit.add(gates.CZ(0, 1)); circuit.add(gates.RY(1, 0.5))
circuit.add(gates.CZ(1, 2)); circuit.add(gates.RY(2, 0.6)); circuit.add(gates.CZ(2, 3))
circuit.add(gates.RY(3, 0.4)); circuit.add(gates.CZ(3, 4)); circuit.add(gates.RX(4, 0.3))

cut = qd.find_cut(circuit, gate_cut=True, wire_cut=False)
subcircuits = qd.gate_cutting_subcircuits(circuit, cut, software="qibo")
values = [qd.expectation_value(s) for s in subcircuits]   # scheduled as tasks
print(subcircuits.reconstruct(values))

ipycompss.stop(sync=True)

For batch jobs, run a plain script under runcompss instead — see `examples/compss_app.py <https://gitlab.bsc.es/wdc/quantum/qdislib>`__ and examples/README.md. Nothing in your Qdislib code changes.

2. IBM Quantum

With Qdislib[qiskit] and an IBM Quantum account (get a token at quantum.ibm.com), set your credentials as environment variables and run the cut subcircuits on real IBM hardware with qpu=True.

[ ]:
import os

# Required:
os.environ["IBM_QUANTUM_TOKEN"] = "<your_token>"
# Optional:
os.environ["IBM_QUANTUM_INSTANCE"] = "<your_instance>"
os.environ["IBM_QUANTUM_CHANNEL"] = "ibm_cloud"        # or "ibm_quantum"
os.environ["IBM_QUANTUM_MAX_TIME"] = "60"              # batch session, seconds
os.environ["IBM_QUANTUM_QPU_NAME"] = "ibm_marrakesh"   # omit -> least-busy backend

If IBM_QUANTUM_QPU_NAME is unset, Qdislib runs on the least-busy real backend (service.least_busy(operational=True, simulator=False)).

[ ]:
import Qdislib as qd
from qiskit import QuantumCircuit

circuit = QuantumCircuit(10)
for i in range(9):
    circuit.cz(i, i + 1)

# find_cut's IBM path uses Qiskit's hardware-aware cut finder:
cut = qd.find_cut(circuit, max_qubits=5, implementation="ibm-ckt")

# qpu_dict maps a QPU to its qubit count (the chip's maximum).
value = qd.gate_cutting(circuit, cut, software="qiskit",
                        qpu=True, qpu_dict={"IBM_Quantum": 127})
print(value)

3. BSC QPUs (cross-cluster bridge)

At BSC the classical (PyCOMPSs) job and the quantum-control job run on separate clusters. They communicate through a shared filesystem directory: a listener on the quantum cluster executes submitted subcircuits on a QPU (Blue or Red), while the cut job submits them from the classical side. Both agree on $QDISLIB_SUBCIRCUITS_DIR.

On the quantum cluster (see examples/qpu_listener.py):

[ ]:
import Qdislib as qd

# $QDISLIB_SUBCIRCUITS_DIR and $RUNCARD_RED must be set.
qd.run_qpu_listener(qpu="red", nshots=1000)   # runs until a STOP file / Ctrl-C

On the classical cluster, point a cut at the QPU (same shared directory):

[ ]:
import Qdislib as qd
from qibo import models, gates

circuit = models.Circuit(5)
circuit.add(gates.RY(0, 0.8)); circuit.add(gates.CZ(0, 1)); circuit.add(gates.RY(1, 0.5))
circuit.add(gates.CZ(1, 2)); circuit.add(gates.RY(2, 0.6)); circuit.add(gates.CZ(2, 3))
circuit.add(gates.RY(3, 0.4)); circuit.add(gates.CZ(3, 4)); circuit.add(gates.RX(4, 0.3))

cut = qd.find_cut(circuit, gate_cut=True, wire_cut=False)
value = qd.gate_cutting(circuit, cut, software="qibo",
                        qpu=True, qpu_dict={"MN_Ona": 5})
print(value)

You’ve finished the learning path 🎉

You can now cut a circuit, run it (serially, distributed, or on a QPU), choose a backend, measure arbitrary observables, and cache results. See the API reference for the full surface.