Skip to content

Add Quantinuum Nexus backend - #81

Closed
jf-kong wants to merge 17 commits into
mainfrom
nexus-client
Closed

Add Quantinuum Nexus backend#81
jf-kong wants to merge 17 commits into
mainfrom
nexus-client

Conversation

@jf-kong

@jf-kong jf-kong commented Apr 26, 2026

Copy link
Copy Markdown

Summary

  • New NexusClientBackend (nexus-client) that submits Qibo circuits through Quantinuum Nexus using the latest qnexus APIs.
  • Two execution paths in one backend, selected by the platform argument:
    • H-Series (hseries:H2-1LE, hseries:H2-1, …): qibo → OpenQASM → pytket → Nexus compile+execute, with H2 syntax-checker HQC estimation.
    • Helios (helios:Helios-1, helios:Helios-1E): qibo → pytket → guppylang HUGR package → qnx.start_execute_job, with qnx.hugr.cost_confidence for HQC estimation.
  • Batch execution (execute_circuits / estimate_circuits) on both paths.
  • Helios cost estimation always targets Helios-1SC, since qnx.hugr.cost_confidence builds its costing job from QuantinuumConfig(device_name=f"{system_name}SC") and only Helios-1SC exists as a syntax checker.
  • Optional install: pip install qibo-cloud-backends[nexus] (pulls qnexus, pytket, guppylang).
  • Lazy imports throughout: importing qibo_cloud_backends does not require the nexus extras; auth and project resolution are deferred until the first execute / estimate call.

What changed

  • src/qibo_cloud_backends/nexus_client.pyNexusClientBackend (Qibo NumpyBackend subclass) implementing execute_circuit, execute_circuits, estimate_circuit, estimate_circuits.
  • src/qibo_cloud_backends/nexus_config.pyNexusBackendConfig dataclass, parse_platform, build_nexus_backend_config (handles hseries, helios, aer; splits options between HeliosConfig and HeliosEmulatorConfig).
  • src/qibo_cloud_backends/nexus_helios.py — Helios HUGR package builder (pytket → AutoRebase to {CX, H, Rz} → guppy load_pytket → generated entrypoint with result(...) / discard(...)) and map_helios_result_to_qibo for converting Helios shot results into a Qibo MeasurementOutcomes.
  • src/qibo_cloud_backends/nexus_translation.py — qibo → pytket via OpenQASM 2.0, with normalization for measurement-register names, multi-control decomposition, and Y-basis rotation rebuild
  • src/qibo_cloud_backends/nexus_results.py — generic count → Qibo bitstring / MeasurementOutcomes mapping (shared by H-Series and Helios result paths).
  • src/qibo_cloud_backends/nexus_auth.py, nexus_errors.py — auth / project plumbing and the typed exception hierarchy (NexusBackendError, NexusAuthError, NexusResultMappingError, UnsupportedExecutionError).
  • src/qibo_cloud_backends/__init__.py — register nexus-client in MetaBackend.load / CLIENTS / _client_available; lazy class export via __getattr__.
  • pyproject.toml — adds qnexus, pytket, guppylang.
  • README.md, doc/source/index.rst, doc/source/backends.rst — install instructions and quickstart for the Nexus backend.

Test plan

50 nexus-specific tests, all passing locally:

  • tests/test_translator.py (8) — qibo → pytket round-trip, multicontrol decomposition, Helios measurement stripping.
  • tests/test_config.py (13) — platform parsing, HeliosConfig / HeliosEmulatorConfig resolution, options split (n_qubits sizing on emulator).
  • tests/test_results.py (7) — count normalization, endianness, MeasurementOutcomes mapping.
  • tests/test_helios.py (3) — HUGR entrypoint generation (measurement order, discard for unmeasured qubits), pytket pre-Guppy rebase.
  • tests/test_backend_contract.py (16) — backend contract: H-Series and Helios paths for execute_circuit / estimate_circuit / execute_circuits, including the regression test that locks in (a) per-program max_cost flowing through qnx.start_execute_job, (b) emulator state sized to the widest circuit's nqubits, (c) no attempt_batching injection, (d) cost estimation targeting Helios-1SC even when the user platform is Helios-1E.
  • tests/test_nexus_meta_backend.py (3) — MetaBackend.load(client="nexus-client", ...), default-platform fallthrough, set_backend("qibo-cloud-backends", client="nexus-client", ...). Split out from tests/test_backends.py so they collect without the optional braket / qiskit extras installed.

Notes

  • All Nexus authentication is lazy (_ensure_connected); just importing the package never triggers a Nexus login or network call.
  • The qnexus 0.x API surface is moving; the version pin is intentionally >=0.39,<1.

jf-kong and others added 16 commits March 2, 2026 00:42
…checker

Batch-aware Helios execution: pass per-program max_cost as a list directly
to qnx.start_execute_job rather than threading it through HeliosConfig.
This removes the attempt_batching/max_batch_cost injection (unsupported
on Helios emulators) and lets the emulator state size with the widest
circuit's nqubits. Cost estimation now always targets Helios-1SC, since
qnx.hugr.cost_confidence builds its costing job from
QuantinuumConfig(device_name=f"{system_name}SC") and only Helios-1SC
exists as a syntax checker — emulator targets must still use this name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… platform

Previously passed platform=None when caller omitted it, which broke
parse_platform. Now only forwards platform when set, letting
NexusClientBackend's own default ("hseries:H2-1LE") take effect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NumpyBackend.__init__ assigns self.name = "numpy", which silently shadowed
the class-level name attribute. Set it explicitly after super().__init__()
to match the pattern used by the other client backends. Also drop the
unused parse_platform import (now that all call sites moved into config)
and drop the dead self.platform/self.project state — both are read from
self.config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both modules used print() for diagnostic messages, bypassing log-level
configuration. Use module-level loggers instead, matching the LOGGER
pattern already established in nexus_client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The three nexus meta-backend tests in tests/test_backends.py could not
be collected unless the optional braket extra was installed (the file
eagerly imports BraketClientBackend at module scope). Move them into
tests/test_nexus_meta_backend.py so they run in any env that has the
nexus extra.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous ^0.39 / ^0.21 caret constraints pinned qnexus < 0.40 and
guppylang < 0.22, which blocked installation against current upstream
releases (qnexus is now on 0.43.x). Loosen to >=lower,<1 so users can
pick up the latest 0.x APIs. Also add the same nexus extras to the
tests dependency group and regenerate poetry.lock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jf-kong
jf-kong requested review from a team April 26, 2026 17:22
@scarrazza

Copy link
Copy Markdown
Member

Closing this in favour of qiboteam/nexus-backend#1 (review)

@scarrazza scarrazza closed this Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants