Skip to content

Make the Python/provider layer pluggable like the PHP driver layer #13

Description

@corgab

Context

The package's core goal is backend modularity: pick AWS, or another provider, and swapping should "just work". On the PHP side this is already true — QuantumManager extends Laravel's Manager, there is a QuantumDevice contract, and Quantum::extend('my-driver', ...) lets a user register a custom backend without touching the core.

On the Python side, which is the layer that actually talks to the hardware, modularity breaks down:

  • bin/python/common.py::resolve_device() is a hardcoded if driver == "local" / elif "aws" switch.
  • bin/python/circuit.py and entropy.py contain cabled if driver == "aws": branches (e.g. the S3 bucket / s3_destination_folder logic).

The consequence is that extensibility is built only halfway — open at the top, closed at the bottom. A user can register a PHP driver via extend(), but that driver cannot reach a new backend (IBM/Qiskit, Azure Quantum, IonQ direct, a self-hosted simulator) without editing the shared Python scripts. extend() is the front door and it is already open, but there is no room behind it on the Python side — just a wall.

Target architecture

Mirror Laravel's Manager/contract/driver pattern on both sides of the PHP↔Python bridge, with a stable intermediate representation as the contract at the boundary:

  • IR as the boundary contract. The provider-neutral circuit description (the gate-list already produced by CircuitBuilder::toArray()) is the single interchange format. It must stay stable and backend-agnostic; everything else translates to/from it.
  • Thin PHP drivers. A driver declares only its name, requiredConfig(), and safety hooks (e.g. synchronous_safe), then serializes the IR and hands it to the bridge. Shared logic stays in AbstractQuantumDriver. No backend-specific logic in the driver.
  • A Python provider registry that mirrors Manager::extend(). resolve_device() becomes a registry lookup instead of an if/elif. Each provider is a self-contained module exposing a uniform interface (build_circuit(ir), run(circuit, shots, config), and — see Provide an async/queued execution flow for QPU tasks #6submit(...) / result(arn)). Adding IBM means dropping in providers/qiskit.py that registers itself, touching no core file.
  • End-to-end extensibility. Quantum::extend('ibm', ...) registers the PHP driver; the driver names its Python handler; the registry resolves it. A third party adds a backend by providing a PHP driver + a Python handler, with no core edits. The translation strategy is native-per-provider (each handler speaks its SDK directly, like Laravel's Queue connectors).

Sequencing (important — do not build this prematurely)

Today both shipped drivers (local, aws) are Braket, so they are nearly the same backend. That means the gate-list IR is currently shaped by Braket's assumptions (gate names like cnot/ccnot, measure structure, classical-register handling) without it being obvious. The IR's neutrality cannot be validated against a single backend family.

Best practice — and the way Laravel's own components evolved (concrete first, abstract later) — is to earn the abstraction from 2+ genuinely different implementations:

  1. Add one real non-Braket provider (e.g. Qiskit/IBM, where CNOT is cx, classical registers differ, etc.) the most direct way possible.
  2. Let it expose where Braket assumptions leak out of the IR.
  3. Then extract the registry and the neutral IR from two working examples, not from one-and-a-half.

Worth evaluating before reinventing: Laravel prefers delegating to an existing unifying library (Flysystem for storage, Symfony Mailer for mail) over building its own abstraction. The quantum equivalent would be checking whether an existing cross-backend Python library already covers the target providers, which would make the registry a thin delegation layer rather than one translator per provider.

This issue is the most load-bearing gap for the package's stated direction (modular, multi-provider, production-oriented), but it is a target to converge on after a second real backend proves the IR — not a plugin framework to build up front while only Braket exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions