Repository navigation
QFw: build the Qiskit backend's target from the QPM's device telemetry - #163
Merged
Merged
Conversation
QFwBackend.target was build_qfw_target(400): a generic 400-qubit all-to-all target with a fixed gate list, whatever QPM the backend was bound to. A workflow that needed the device for target-aware transpilation (layout search, RZZ handling) had no public API and called the shim driver's private _build_backend_target in-process. The client now binds the QPM's telemetry API next to the execution API, on the same managed binding (qfw_lookup_service.get_qpm_telemetry), and exposes it as backend.telemetry: a QFwTelemetry with get_backend_info, get_device_info, get_coupling_graph, get_calibration_snapshot and get_dynamic_backend_info, each carrying the backend's shim library and reservation token. backend.target is built from it once per backend: - an IBM record, the raw BackendConfiguration under static_architecture and, new in the shim's get_backend_info, the raw BackendProperties under backend_properties, goes through qiskit_ibm_runtime's convert_to_target, the conversion _build_backend_target does; without the package the configuration alone gives the qubits, basis gates and coupling map; - qhw records (IQM through the shim, any QDMI device) give the qubits, the native operations on their loci (prx -> r, reset_wait -> reset, both orders of a symmetric two-qubit locus) and the calibration snapshot's error and duration per locus and T1/T2 per qubit, read from the iqm.v1 and qdmi.fomac.v1 extensions; - a plain description (the fake IQM's qubit count and couplings list) gives the qubits and edges with QFw's generic gates on them; - metadata_supported false (NWQSim), a failing telemetry call, or a connection without a managed binding keeps the generic target, with the reason logged and recorded in backend.target_source. The legacy configuration() dict follows the target. The mock suite's qiskit stubs gain InstructionProperties, Gate, Parameter and a Target that records what was added on which qargs; tests/qiskit runs the real conversion on a FakeManilaV2 configuration and transpiles a GHZ against a qhw-built IQM target. Verified on the cluster inside qfw-slurm jobs: provider fake-iqm gets a 20-qubit target with the device's linear coupling, provider nwqsim keeps the generic target, and a run against the real q20 through the shim reached the device under the reservation while the telemetry fell back, with its reason recorded, for want of the service user's credential record. Signed-off-by: Doug Oucharek <dougso@me.com>
DougSO
force-pushed
the
qiskit-device-target
branch
from
October 21, 2026 04:02
566dfad to
931f9a4
Compare
The Qiskit client leads with get_backend_info when it builds its device target and keeps the generic target when the call fails. The QDMI driver had no get_backend_info, and the default capability table routed the call to QRMI alone, so every resource wired for QDMI only (the Braket entries) answered "library 'qdmi' does not implement 'get_backend_info'" and the client stayed generic, although the driver's device, coupling and calibration records are exactly what the builder reads. QdmiDriver.get_backend_info now returns the composite the QRMI driver returns for a device that is not IBM: the provider, metadata_supported, the active qubits (the site labels), the provider's calibration set id from its custom slot (fomac_normalize.calibration_set_id, the public name for the lookup the snapshot already does) and the qhw device record from the topology, with the profile's technology. QDMI has no raw provider architecture, so static_architecture is empty, as it is for a QRMI too old to report one. The IQM profile names its technology (superconducting), so the QDMI record matches qhw_iqm's. DEFAULT_CAPS offers get_backend_info on both libraries, in the order the other introspection calls use. get_dynamic_backend_info stays with QRMI. Tests cover the composite, the real device record, the Frontend routing with and without a preference and for a QDMI-only resource, and the client building its target through QDMI records with lib qdmi. Verified on the real q20 through QDMI: in-process with the branch's driver, and end to end with a job-owned shim QPM from an install of the branch, where the client built the device target through the QDMI library and ran a GHZ through it. The docs say both libraries serve the call. Signed-off-by: Doug Oucharek <dougso@me.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
QFwBackend.targetwasbuild_qfw_target(400): a generic 400-qubit all-to-all target with a fixed 39-gate list, whatever QPM the backend was bound to. A workflow that wanted the device for target-aware transpilation (layout search, RZZ handling) found no public API and called the shim driver's private_build_backend_targetin-process.The client now binds the QPM's telemetry API binding next to the execution one, on the same managed binding (
qfw_lookup_service.get_qpm_telemetry), and exposes it asbackend.telemetry(QFwTelemetry:get_backend_info,get_device_info,get_coupling_graph,get_calibration_snapshot,get_dynamic_backend_info, each carrying the backend's shim library and reservation token).backend.targetis built from it once per backend instance:backend.targetholdsBackendConfigurationunderstatic_architectureand, new in the shim'sget_backend_info, the rawBackendPropertiesunderbackend_propertiesqiskit_ibm_runtime.convert_to_target(BackendConfiguration.from_dict(...), BackendProperties.from_dict(...)), the conversion_build_backend_targetdoes; without the package the configuration alone gives the qubits, basis gates and coupling mapprx->r,reset_wait->reset, both orders of a symmetric two-qubit locus), error and duration per locus and T1/T2 per qubit from the calibration snapshot'siqm.v1/qdmi.fomac.v1extensionscouplingslist)metadata_supported: false(NWQSim), a failing telemetry call, no managed bindingbackend.target_sourceThe legacy
configuration()dict follows the target. Docs: a Device Target section inusage.md, a note in the shim provider guide (step 5) and inqpmd-supported-apis.md.Tests
tests/mock/test_qfw_backend_target.py: the binding, the shim-library/token context, the fake-IQM shape, the qhw-record shape with IQM calibration observations, the QDMI extension, opaque device operations, the IBM path through a converter seam and without the converter, the three fallbacks with their logged reasons, caching, an explicit target, optional secondary records,configuration().tests/mock/test_qfw_lookup_service.py: the telemetry API is selected from the service record the execution client's lifecycle binding already holds (no second directory query).tests/mock/test_qrmi_ibm_dispatch.py:backend_propertiesin the IBM composite record.tests/qiskit/test_qfw_target.py(real qiskit): a qhw-built IQM target transpiles a GHZ tor/cz/measure; aFakeManilaV2configuration + properties through the realconvert_to_target.InstructionProperties,Gate,Parameterand aTargetthat records what was added on which qargs.Local run in c1 against this branch: ci-syntax clean, mock 669 passed / 1 skipped, unit 130 passed,
tests/qiskit53 passed. The builder was also run on a saved live QRMItarget()dump of the ORNL q20 through the qhw_iqm normalizers: 20 qubits,czon 60 directed qargs (30 edges),r/measure/reseton 20, errors and durations filled (e.g.cz(0,1): duration 6e-08 s, error 0.0044), T1/T2 per qubit, and a GHZ transpiles tor/cz/measure.Live validation on the cluster
Inside qfw-slurm jobs as user-a (
sbatch --qpu=... --workload-kind=quantum --circ-count=1 --max-qubits=5 --max-depth=16 --max-shots=100, thenqfw-setup/qfw-srun probe.py/qfw-teardown), with this branch'sbackends/ahead of the image's installed copy onPYTHONPATH. The probe prints the telemetry records, the target, transpiles a 3-qubit GHZ against it and samples it through the reservation.--qpu=fake-iqm-20q, providerfake-iqm(Slurm job 13, COMPLETED, 13 s on c1):(The fake IQM QPM names no gate set, so the target carries QFw's generic gates on the device's 20 qubits and linear coupling; three-qubit gates are left out, the transpiler decomposes them. Its canned result is all zeros.)
--qpu=nwqsim, providernwqsim(Slurm job 14, COMPLETED, 13 s on c1):--qpu=ornl-shim-20q, providershim(Slurm job 16, COMPLETED, 31 s on c1), q20 tunnel up, shim-head's device-access URL on the tunnel port, a user-a record in shim-head's credential DB:This exercised the failure path for real. The reservation was granted on user-a's record and the GHZ ran on the real q20 through the shim (hardware counts), while the four telemetry calls resolved the credential of the user the QPM process runs as (
root, fromUSERin the service's environment;credential-mode: required), which has no record on shim-head, so the backend kept the generic target with the reason intarget_source. The device target from the q20 therefore needs a record for the service user, as the 2026-10-12 site-route runs had.usage.mdand the shim guide now say so.With that root record added on shim-head,
--qpu=ornl-shim-20qas user-a, library unset (Slurm job 17, COMPLETED, 24 s on c1): the device target from the real q20, through the site shim as deployed (QRMI servesget_backend_info, the shim's QDMI preference serves the three records):Second commit:
get_backend_infofrom the QDMI driverThe client leads with
get_backend_info; the QDMI driver had no such method andDEFAULT_CAPSrouted the call to QRMI alone, so a resource wired for QDMI only (the Braket entries) answeredlibrary 'qdmi' does not implement 'get_backend_info'and the client stayed generic, although the driver's device, coupling and calibration records are exactly what the builder reads. Now:QdmiDriver.get_backend_inforeturns the composite the QRMI driver returns for a device that is not IBM:backend,metadata_supported,active_qubits(the site labels),calibration_set_idfrom the provider's custom slot (fomac_normalize.calibration_set_id, the public name for the lookup the snapshot already does) andqhw_devicefromto_device_record(extract_topology(device))with the profile's technology;static_architectureis{}(QDMI has no raw provider architecture; a QRMI older than 0.22.0 reports it empty too). The IQM profile now names its technology (superconducting), so the QDMI record matches qhw_iqm's.DEFAULT_CAPS["get_backend_info"] = ["qdmi", "qrmi"], the order the other introspection calls use;get_dynamic_backend_infostays with QRMI.tests/mock/test_qdmi_backend_info.py(the composite with a stubbed and a real device record, the Frontend routing with and without a preference, a QDMI-only resource served,lib="qrmi"still refused there), the client building its target through QDMI records withlib="qdmi"intest_qfw_backend_target.py, the profile-defaults test updated. Docs:qpmd-supported-apis.md, the shim guide,qpu-frontend-contract.md.Offline, from a saved QDMI extraction of the q20 (the four records read in-process on shim-head with this branch's
QdmiDriver, device access resolved by the driver from the site's file; saved asshared-dir/tmp/p31/q20-qdmi-records.json, device data only):The IQM QDMI adapter reports per-operation fidelities and per-qubit T1/T2 but no per-operation durations, so a QDMI-built IQM target carries errors and coherence times only; the QRMI-built one (the
target()dump above) carries durations as well.On the q20 through QDMI, before and after, both as the client sees it:
QFW_SHIM_LIB=qdmi, telemetry only (Slurm job 18, user-a, COMPLETED):get_backend_info: FAILED ... library 'qdmi' does not implement 'get_backend_info' for resource 'ornl-iqm-20q'; the three record calls succeeded through QDMI;target source: generic: the QPM's device telemetry failed: ..., 400 qubits, no coupling map.shared-dir/qfw-target-install), the shim smoke's flow with a required-credential manifest and a site config naming shim-head's device-access file, placed on shim-head under a rootsallocand reached through the stand-in reservation driver as owner root,QFW_SHIM_LIB=qdmifor the telemetry and the run (Slurm job 19, COMPLETED, 46 s):Cluster configuration, not in this PR:
descriptor._copy_capstakes a device's owncapsblock as the whole table (caps or DEFAULT_CAPS, no merge). The cluster repo'sconfig/device-access.yamllists execution caps only (run_circuit,get_task_timing,get_task_metadata) foribm-156-nh,aws,aws-ionq-aria-1andaws-rigetti-ankaa, so those services serve no introspection call at all and the client gets the generic target for them. Those entries needget_backend_info,get_device_info,get_coupling_graphandget_calibration_snapshotadded ([qdmi]for the Braket entries,[qrmi]for IBM), or theircapsblocks dropped to inherit the defaults.Notes
iqm.v1(IQM's observation sets) andqdmi.fomac.v1, and ignores any other namespace. A neutral per-locus metric list published by the shim would let the client drop that knowledge; a follow-up.credential-mode: requiredshim the telemetry calls resolve the service user's record, not the reservation owner's, becauseget_backend_infoand the record calls carry no reservation context (job 16 above; job 17 once the root record existed). Letting the QPM use the reservation's bound credential for introspection (the telemetry methods already taketoken) would make the device target work for any entitled user without a record for the service user; a follow-up.