Skip to main content

The developer SDK for multi-chip quantum computing.

Project description

limbo-quantum

The developer SDK for multi-chip quantum computing.

limbo-quantum is the client-side companion to the Limbo compiler — a quantum compilation stack designed around the assumption that the next-generation device isn't one giant chip but a network of chips stitched together by photonic interconnects. The SDK gives you a single Python entry point that ingests circuits from Qiskit, Cirq, or OpenQASM 3, runs a preflight capacity audit + hotspot scan, transpiles for your target device, and submits to whichever backend you've configured.

The local simulator path runs fully in-process. There's also an optional hosted backend at limbosys.dev that runs the multi-chip-aware partitioner + cross-chip scheduler described in the paper — bring your own API key, the SDK doesn't require it.


Install

pip install limbo-quantum

The SDK itself is pure-Python with minimal hard dependencies. Install whichever circuit framework matches the format you'll feed in:

pip install qiskit qiskit-aer    # for QuantumCircuit + local simulation
pip install cirq-core            # for Cirq Circuit ingestion
pip install openqasm3            # for OpenQASM 3 source ingestion

Quickstart

from qiskit import QuantumCircuit
from limbo_quantum import DistributedCompilerSDK, LocalSimulationProvider

# 1. A familiar Qiskit circuit.
qc = QuantumCircuit(4)
qc.h(0)
for i in range(3):
    qc.cx(0, i + 1)
qc.measure_all()

# 2. Configure the SDK with a local simulator backend. Everything from
#    here on runs on your laptop — no cloud account required.
sdk = DistributedCompilerSDK(
    provider=LocalSimulationProvider(),
    num_qpus=2,
    max_capacity_per_qpu=4,
)

# 3. One call → ingest → lint → compile → simulate → counts.
result = sdk.compile(qc, shots=1024)
print(result.counts)
print(f"compiled to {len(result.compiled_qasm)} sub-circuit(s)")

That's the whole workflow. To run on real hardware, swap LocalSimulationProvider() for a CloudProductionProvider (see Cloud backend) or a custom QuantumProvider subclass that targets your own infrastructure.


What's in the box

Component What it does
DistributedCompilerSDK One-call entry point. Ingest → lint → optional pre-optimize → compile → execute.
CircuitParser Multi-framework ingestion: Qiskit / Cirq / OpenQASM 3 → standardized JSON IR.
LocalStaticLinter Offline capacity audit + interaction-hotspot detection. Catches broken layouts before any network round-trip.
ParametricRuntime + TopologicalTemplate Compile-once-bind-many runtime for variational workloads (VQE / QAOA). Parameters bind locally; the compile step only re-runs when the circuit's structural signature changes.
LocalSimulationProvider In-process Aer simulator. Zero credentials, zero network.
CloudProductionProvider HTTP client for the hosted Limbo backend at limbosys.dev. Optional.
QuantumProvider Abstract base. Subclass it to point the SDK at your own infrastructure.
TelemetryLogger Auto-detects Jupyter vs. terminal, prints per-step timings + payload sizes. Drop-in optional.

Features in depth

Multi-framework ingestion

from limbo_quantum import CircuitParser

# All three return the same IR shape.
ir = CircuitParser.from_qiskit(my_qiskit_circuit)
ir = CircuitParser.from_cirq(my_cirq_circuit)
ir = CircuitParser.from_openqasm3(my_qasm3_source_string)

The IR is plain JSON (no Python-specific types) so it round-trips cleanly through caches, message queues, and HTTP payloads. The schema descriptor is exported as limbo_quantum.IRSchema.

Multi-chip capacity audit

The capacity linter is the SDK's most distinctive feature for multi-chip targets. Qiskit's transpiler checks coupling maps during compilation; Limbo's linter checks layout feasibility up front, with a structured exception you can catch.

from limbo_quantum import (
    CircuitParser, LocalStaticLinter, TopologyCapacityError,
)

ir = CircuitParser.from_qiskit(big_circuit)
linter = LocalStaticLinter(ir, num_qpus=4, max_capacity_per_qpu=20)
try:
    linter.capacity_audit()
except TopologyCapacityError as exc:
    print(f"layout infeasible: requested {exc.num_qubits}q, "
          f"available {exc.target_capacity}, "
          f"need per-QPU >= {exc.min_qubits_per_qpu}")

Hotspot dashboard

Identifies "hub" qubits whose interaction degree dominates the circuit — the ones that will burn cross-chip traffic when partitioned. By default any qubit holding more than 30% of total degree is flagged.

linter = LocalStaticLinter(ir)
report = linter.hotspot_detection(threshold_ratio=0.30)
# When verbose=True (the default), prints a formatted ASCII table to
# stdout. The structured report is also returned for CI integration.

Parametric template caching (variational amortization)

For VQE / QAOA workflows, ParametricRuntime compiles the template once and binds parameters locally on each subsequent call:

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from limbo_quantum import ParametricRuntime, InProcessCompilerClient

theta = Parameter("theta")
qc = QuantumCircuit(2)
qc.ry(theta, 0)
qc.cx(0, 1)
qc.measure_all()

runtime = ParametricRuntime(qc, client=InProcessCompilerClient())

for theta_val in [0.0, 0.1, 0.2, 0.3]:
    result = runtime.run({theta: theta_val}, shots=512)
    print(theta_val, result.counts)

The first .run() does the heavy compile. Every subsequent call binds into the cached template and skips re-compilation. The cache key is a SHA-256 of the circuit's structural signature, so different parameter values share a cache entry but a different gate sequence forces a re-compile.

Cost-preview mode

Compile without executing — useful when you want to see the metrics (number of partitions, cross-chip operations, output gate count) before spending shots:

result = sdk.compile(qc, execute=False)
print(result.compiled_qasm)
print(result.lint_report)

Custom backends

The QuantumProvider abstract base has three methods to implement:

from limbo_quantum import QuantumProvider, Job, JobResult

class MyBackend(QuantumProvider):
    name = "mine"

    def submit(self, payload, *, shots=1024, **options) -> Job:
        ...

    def _fetch_status(self, job_id: str) -> JobResult:
        ...

    def list_devices(self, credentials=None):
        ...

sdk = DistributedCompilerSDK(provider=MyBackend(), num_qpus=1, max_capacity_per_qpu=32)

That's enough to swap in your own infrastructure — AWS Braket, IBM Runtime directly, a self-hosted Aer cluster, anything.

Telemetry

from limbo_quantum import (
    DistributedCompilerSDK, LocalSimulationProvider, TelemetryLogger,
)

sdk = DistributedCompilerSDK(
    provider=LocalSimulationProvider(),
    num_qpus=2,
    max_capacity_per_qpu=4,
    telemetry=TelemetryLogger(),         # auto-detects terminal vs. Jupyter
)

Per-step timings, payload sizes, and lint outcomes print to the host as a clean timeline.

Auto-provider

from limbo_quantum import auto_provider, DistributedCompilerSDK

# CloudProductionProvider if LIMBO_API_KEY is set in the env, else local.
sdk = DistributedCompilerSDK(
    provider=auto_provider(),
    num_qpus=2,
    max_capacity_per_qpu=8,
)

Execution backends

limbo-quantum does not lock you into any single execution path. The SDK is structured around a narrow QuantumProvider interface (provider.py) with three implementations shipped in the box and a documented extension point for everything else. Pick the one that matches your workflow:

Path A — Local simulator (no account, no network)

The default. Runs Qiskit Aer in-process.

from limbo_quantum import DistributedCompilerSDK, LocalSimulationProvider

sdk = DistributedCompilerSDK(
    provider=LocalSimulationProvider(),
    num_qpus=2, max_capacity_per_qpu=4,
)

Path B — Hosted Limbo backend (one account, multiple vendors)

CloudProductionProvider is an HTTP client for the hosted Limbo service at limbosys.dev. The hosted service holds your IBM / AWS Braket / Azure Quantum credentials encrypted server-side and runs the multi-chip-aware partitioner + cross-chip scheduler. You manage one API key; the service brokers the rest.

from limbo_quantum import DistributedCompilerSDK, CloudProductionProvider

sdk = DistributedCompilerSDK(
    provider=CloudProductionProvider(
        api_key="lmb_live_...",                  # from your dashboard
        server_url="https://api.limbosys.dev",
    ),
    num_qpus=4, max_capacity_per_qpu=20,
)

Path C — Direct to a vendor (IBM / AWS / Azure)

If you already have vendor quotas and want to keep them, the SDK ships first-class wrappers for the three major clouds. Install the right extra and pass an instance to the SDK — no subclassing required.

IBM Quantum (pip install 'limbo-quantum[ibm]'):

from limbo_quantum import DistributedCompilerSDK, IBMProvider

sdk = DistributedCompilerSDK(
    provider=IBMProvider(
        token="...",                             # from quantum.ibm.com
        backend_name="ibm_brisbane",
    ),
    num_qpus=1, max_capacity_per_qpu=127,        # single-chip target
)
result = sdk.compile(qc, shots=1024)

AWS Braket (pip install 'limbo-quantum[aws]'):

from limbo_quantum import DistributedCompilerSDK, AWSProvider

sdk = DistributedCompilerSDK(
    provider=AWSProvider(
        device_arn="arn:aws:braket:::device/quantum-simulator/amazon/sv1",
        # s3_folder=("my-results-bucket", "limbo/"),  # optional
    ),
    num_qpus=1, max_capacity_per_qpu=34,
)

AWS credentials are picked up from the standard boto3 chain (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env vars, ~/.aws/credentials, or an attached IAM role).

Azure Quantum (pip install 'limbo-quantum[azure]'):

from limbo_quantum import DistributedCompilerSDK, AzureProvider

sdk = DistributedCompilerSDK(
    provider=AzureProvider(
        subscription_id="...",
        resource_group="quantum-rg",
        workspace_name="my-workspace",
        location="eastus",
        target_name="ionq.qpu",
    ),
    num_qpus=1, max_capacity_per_qpu=23,
)

Azure authentication uses DefaultAzureCredential from azure-identity — i.e. az login on a laptop, a managed identity in production, or service-principal env vars.

All three vendor providers handle the QASM → vendor-circuit translation, job submission, status polling, and result decoding for you. They lazy-import their vendor SDK so import limbo_quantum stays fast even if you've only installed one of the three extras.

Path D — Bring your own backend

If you're targeting something else (Quantinuum, IonQ direct, Rigetti, a self-hosted Aer cluster, a private FPGA, anything), subclass QuantumProvider with three methods:

from limbo_quantum import QuantumProvider, Job, JobResult

class MyBackend(QuantumProvider):
    name = "mine"

    def submit(self, payload, *, shots=1024, **options) -> Job:
        """Send the compiled QASM. Return a Job wrapping the backend's
        native job ID."""
        ...

    def _fetch_status(self, job_id: str) -> JobResult:
        """Poll. Return a JobResult with status in
        {queued, running, completed, failed}; on completion include
        the measurement counts."""
        ...

    def list_devices(self) -> list[dict]:
        """Optional device catalog for auto-routing. Can be []."""
        ...

The shipped IBM / AWS / Azure providers in vendors.py are full reference implementations of this pattern — copy one as a starting point.

Which path to choose

Scenario Use
Prototyping, CI, anything Aer can run Path A (LocalSimulationProvider)
One bill, one credential, multi-chip-aware compile server-side Path B (CloudProductionProvider)
You already have IBM / AWS / Azure quotas Path C (IBMProvider / AWSProvider / AzureProvider)
Anything else Path D (subclass QuantumProvider)

All four paths get you the same client API — only the provider= argument changes.


Correctness scope

Limbo is a faithful transport for circuits that fit on your chosen target device. If your circuit fits on the device (i.e. circuit_qubits <= device_qubits), the SDK ingests, optionally pre-optimizes (Qiskit passes only), transpiles against the device's coupling map, and submits via the provider's official SDK. The result is semantically identical to what direct Qiskit + the vendor's SDK would produce.

The multi-chip routing path (when your circuit doesn't fit on a single physical device and the SDK partitions across multiple QPUs) is research-grade. There is no commercial cloud QPU today that exposes a multi-chip interconnect, so the cross-chip operations the SDK produces can only be validated on a simulator. Don't ship a num_qpus > 1 configuration to a single-chip cloud backend and expect correct results — the cross-chip entanglement won't be implemented.


Error model

Exception When
ImportError Framework SDK isn't installed (from_qiskit with no qiskit, etc.)
TypeError Wrong object type passed in (e.g. a Cirq circuit to from_qiskit)
ValueError Malformed IR, bad QASM source, invalid configuration
TopologyCapacityError Capacity audit rejected the layout
TimeoutError Cloud job didn't finish within the configured polling window

All errors are raised locally before any network call, except TimeoutError (raised after polling).


Citing

If you use Limbo's multi-chip compilation in published work, please cite the paper (forthcoming, IEEE).


License

Apache 2.0. See LICENSE.


Status

Public release planned for Fall 2026. Pre-1.0 versions on PyPI should be considered beta — APIs may change in minor versions until then.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

limbo_quantum-0.1.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

limbo_quantum-0.1.0-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file limbo_quantum-0.1.0.tar.gz.

File metadata

  • Download URL: limbo_quantum-0.1.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for limbo_quantum-0.1.0.tar.gz
Algorithm Hash digest
SHA256 28aa6550ecf85d63f690c425f9d1ecf730ecb08db639ae3ce0edb941d6ed38ca
MD5 a818d7b1f5a280da671ddf74beb70705
BLAKE2b-256 326980d196d44a702771176eacf097f0c4c9b6d0e28746c636acc98916e6f1c5

See more details on using hashes here.

File details

Details for the file limbo_quantum-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: limbo_quantum-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for limbo_quantum-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6cd3eeefdd78580cdd162f5a02d8a3c6fae2a172ae78079555c2d5a3b8b53eb5
MD5 4ca721b0fdfcfe2f0a3af9c87c03a97b
BLAKE2b-256 d1e0163125f5d07e34f68fb8c24f3628b71601d0d5e185ccba73ba76358a44c6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page