Skip to content

🤝 Design discussion: client interface, interoperability, and “stack-as-device” composition #215

Description

@burgholzer

This is a kick-off discussion to settle several architectural decisions around QDMI, interoperability, and how we expose an entire software stack to other stacks.

Context recap

  • QDMI today is two C interfaces:
    • Device interface (C header/ABI): implemented by providers and third parties; each implementation is nameshifted via a unique prefix to avoid symbol collisions in-process. This interface contains device/property queries and job submission/management (plus authentication via sessions).
    • Client interface (C header/ABI): a neutral, non-nameshifted mirror of the device interface that adds a device handle as first argument to most methods. A QDMI “driver” loads one or more provider device libraries (nameshifted), exposes enumeration and returns opaque handles to use devices via the client interface.
  • Above QDMI we’re building:
    • A compiler infrastructure (MLIR-based) that uses QDMI queries to tailor compilation and QDMI job APIs to submit programs and retrieve results; sessions handle auth.
    • A scheduler and other orchestration components.
    • Frontend adapters (e.g., Qiskit, PennyLane) that drive the stack.

Big question 1 — Do we need the client interface? Should we standardize the compiler↔QDMI boundary?

  • Observation: While working on a QDMI driver implementation for the MQT (see ✨ MQT QDMI Driver munich-quantum-toolkit/core#1010) we noticed that our C++ driver already has an object-oriented abstraction. Writing a FoMaC C++ wrapper over the C client interface risks duplicating many of the same concepts, feeling redundant.
  • Tension:
    • If we let the driver expose a FoMaC API directly (skipping the client interface), the compiler stack becomes tightly coupled to the specific driver. That improves ergonomics short-term but loses plug-and-play interoperability with other drivers/stacks.
    • If we keep the client interface as the canonical boundary, we preserve the ability to mix-and-match compilers, drivers, and devices across organizations (e.g., MQV collaborations), at the cost of boilerplate and a stricter ABI.
  • Options (not mutually exclusive):
    1. Keep and evolve the client interface (recommended for interoperability):
      • Formalize versioning and capability negotiation (feature bits/extensions, error codes, profiles).
      • Reference FoMaC bindings (C++/Rust/Python) that wrap the client interface in ergonomic types while remaining driver-agnostic.
      • Provide conformance tests for drivers and bindings.
    2. Driver-native high-level API (ergonomics first):
      • A driver may additionally expose a C++ API tailored to a specific stack.
      • The compiler can talk to this API directly where interop isn’t required.
      • We keep the client interface for interop scenarios and upstream collaborations.
  • Proposed stance:
    • Prioritize interoperability as a core goal. Keep the client interface and invest in it (versioning, capability discovery, conformance tests). Build reference C++ FoMaC libraries layered over the client interface to remove boilerplate for users.
    • Document this decision and avoid re-litigating unless we plan a v2 with a different approach.

Big question 2 — How do we expose an entire software stack to other stacks (stack-as-device), without bypassing schedulers?

  • Constraints we established in prior discussions:
    • We do not share individual provider device libraries with external stacks. That would create contention outside our scheduler’s control.
    • Sharing direct access to a driver’s client interface also bypasses scheduling and policies.
  • Desire: Wrap the whole software stack (scheduler + compiler + drivers + devices) behind a QDMI-compatible façade, so another stack can consume it via the same primitives. This enables A to consume B’s stack and vice versa.
  • Challenges:
    • A stack may manage multiple devices. A naĂŻve “stack looks like one device” wrapper either hides multiplicity or requires duplicating N exposed devices.
    • We lack a notion of composite/hierarchical devices and device graphs in QDMI v1.
    • Properties and capabilities across multiple child devices: how to surface them (union/intersection/selection)? How to identify and select a child at job submission time?
    • For stack-as-device composition, should device selection be explicit (client chooses) or delegated (provider/driver schedules), or both?

Proposed next steps:

  • Reaffirm the client interface as the portability boundary for compilers and drivers, with FoMaC bindings layered on top. Or decide that this should be handled differently
  • Outline a concept for interoperability between two stacks relying on QDMI and start the development of a small proof-of-concept.

Explicitly tagging some people here because I think this is a pretty fundamental discussion: @ystade @echavarria-lrz @mnfarooqi
Your input on this would be highly appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions