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.
Metadata
Release files for limbo-quantum 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| limbo_quantum-0.1.0.tar.gz | 17.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| limbo_quantum-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.6 kB
Release files / limbo_quantum-0.1.0.tar.gz
| Download URL | limbo_quantum-0.1.0.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
28aa6550ecf85d63f690c425f9d1ecf730ecb08db639ae3ce0edb941d6ed38ca
|
|
BLAKE2b-256 checksum How to use checksums |
326980d196d44a702771176eacf097f0c4c9b6d0e28746c636acc98916e6f1c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|
Release files / limbo_quantum-0.1.0-py3-none-any.whl
| Download URL | limbo_quantum-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6cd3eeefdd78580cdd162f5a02d8a3c6fae2a172ae78079555c2d5a3b8b53eb5
|
|
BLAKE2b-256 checksum How to use checksums |
d1e0163125f5d07e34f68fb8c24f3628b71601d0d5e185ccba73ba76358a44c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|
Security for limbo-quantum 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.