Custom Backends

Two extension points let you plug execution targets into the SDK without touching the core:

  1. Subclass Backend for a new local / native execution engine — implement run_circuit (raw gate matrices) or run (a bound QuantumCircuit), and optionally override capabilities / validate / supports / execute.

  2. Subclass BackendAdapter for an external or vendor system. Implement the two abstract methods; vendor types never leak through the SDK surface.

Adapter example

from microquantum import BackendAdapter, BackendResult, QuantumCircuit

class _FakeVendor:
    """Stand-in for a vendor SDK (never leaks through the SDK surface)."""

    def submit(self, wire, *, shots):
        return {"wire": wire, "shots": shots}          # opaque handle

    def collect(self, handle):
        return {"counts": {"00": handle["shots"]}, "shots": handle["shots"]}

vendor = _FakeVendor()

def to_wire(circuit):
    return circuit.qasm()

class MyVendorBackend(BackendAdapter):
    @property
    def name(self) -> str:
        return "my-vendor"

    def submit_to_vendor(self, circuit, *, shots, seed):
        # serialize the bound circuit to the vendor's wire format
        return vendor.submit(to_wire(circuit), shots=shots)   # opaque handle

    def collect_from_vendor(self, handle, circuit) -> BackendResult:
        # map every vendor result/error back into a BackendResult
        data = vendor.collect(handle)
        return BackendResult(
            num_qubits=circuit.num_qubits,
            backend_name=self.name,
            counts=data["counts"],
            shots=int(data["shots"]),
            metadata={"vendor": "my-vendor"},
        )

backend = MyVendorBackend()
bound_circuit = QuantumCircuit(2).h(0).cx(0, 1)
result = backend.run(bound_circuit, shots=1000, seed=0)
print(result.counts)

Usage notes

  • Register the backend for name-based selection (BackendRegistry) or pass the instance straight into a plan’s backend field — the runtime resolves either.

  • Adapters take responsibility for mapping every vendor error into the SDK’s validation/execution error style (ValueError naming the backend and the failing capability).

  • run_circuit on an adapter raises ValueError by design — external targets can only execute bound circuits through run / execute.

Design boundary

Vendor SDKs stay inside the subclass: callers only ever see plans, BackendResult and capabilities. This keeps MicroQuantum dependency-free (NumPy-only runtime) and hardware-provider-free for the SDK.