diff --git a/.agent/plans/1687-iqm-01-models.md b/.agent/plans/1687-iqm-01-models.md new file mode 100644 index 0000000000..5add73df6b --- /dev/null +++ b/.agent/plans/1687-iqm-01-models.md @@ -0,0 +1,324 @@ +# Add reusable IQM Garnet and Emerald superconducting models + +This ExecPlan is a living document. The sections `Progress`, +`Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` must +be kept up to date as work proceeds. + +This plan must be maintained in accordance with `.agent/PLANS.md` from the +repository root. + +## Purpose / Big Picture + +After this change, users can select stable, offline models of IQM Garnet and +Emerald through the built-in superconducting QDMI provider. The registry IDs +`mqt.sc.iqm.garnet` and `mqt.sc.iqm.emerald` open the same provider library with +different installed JSON configurations. The models preserve their topology, +portable operation set, reported qubit names, and the available calibration +snapshot without carrying credentials, calibration identifiers, raw service +responses, or invented operation durations. + +This is the first independently reviewable part of the larger pull request +[#1687](https://github.com/munich-quantum-toolkit/core/pull/1687). It is +deliberately limited to device configuration, provider packaging, documentation, +and tests. Compiler targets, mapping, native synthesis, Python compiler APIs, +and command-line integration belong to later changes. + +## Progress + +- [x] (2026-08-03) Verified the task starts from commit + `fe1935473e940f44ac312376934aabcbfb4a0e8c` in a clean isolated worktree. +- [x] (2026-08-03) Audited the current superconducting schema, provider, + generated registry manifests, runtime-asset installation, and related + tests. +- [x] (2026-08-03) Audited the exact Garnet and Emerald JSON captured at pull + request #1687 commit `dd9619bd27a34ced8ed68a4ee4533cb85771f144`. +- [x] (2026-08-03) Reviewed QDMI-on-IQM revision + `5bef1d49245ae17877203618ad65865405fab361`, specifically + `src/iqm_device.cpp` and `src/internal/iqm_api_config.cpp`, to establish + the meaning and source of site names, topology, T1/T2, and operation + fidelities. +- [x] (2026-08-03) Extended the schema and runtime provider with optional site + names. +- [x] (2026-08-03) Added the two sanitized configurations and registered them as + additional configurations of the existing SC provider. +- [x] (2026-08-03) Added focused schema, provider, registry, driver, and + packaging coverage. +- [x] (2026-08-03) Hardened the reusable CMake helper against empty + configuration IDs/files and duplicate IDs, including collisions with the + provider's primary ID, and added configure-time rejection tests. +- [x] (2026-08-03) Updated the SC provider documentation and changelog with + concise provenance and snapshot limitations. +- [x] (2026-08-03) Configured with LLVM/MLIR 22.1.3, built the three affected + test executables, and ran 42 SC tests, 15 registry tests, and 114 driver + tests. One pre-existing optional SC job-ID test remained skipped. +- [x] (2026-08-03) Passed the eight runtime-file packaging and invalid-helper + configure tests, verified an SC runtime-component install contains both + assets and the generated manifest, and confirmed the two JSON files match + the exact #1687 snapshot after removing only the added site-name lines. +- [x] (2026-08-03) Passed the complete repository lint session, secret and + duration scans, `git diff --check`, and final diff inspection. +- [x] (2026-08-03) Prepared the completed implementation for one signed commit + with the repository-required assistance trailer. + +## Surprises & Discoveries + +- Observation: the SC schema already represents optional per-qubit T1/T2 and + optional per-locus duration/fidelity. It only lacks the optional site name + that QDMI already exposes through `QDMI_SITE_PROPERTY_NAME`. +- Observation: the IQM provider obtains site names from the ordered `qubits` + array of the static architecture response and assigns the array position as + the QDMI site index. IQM qubits in these captures use `QB1` through `QB20` for + Garnet and `QB1` through `QB54` for Emerald. +- Observation: the captured Garnet model contains 20 qubits, 30 topology edges, + complete T1/T2 coverage, and 20 `r`, 30 `cz`, and 20 `measure` fidelities. The + Emerald model contains 54 qubits, 90 topology edges, T2 for all 54 qubits, T1 + for 53 qubits, and 54 `r`, 81 `cz`, and 54 `measure` fidelities. +- Observation: the authenticated interface did not report operation durations. + An absent duration is meaningful and must continue to produce + `QDMI_ERROR_NOTSUPPORTED`. +- Observation: one shared provider library can already own multiple runtime JSON + files, but its generated manifest currently registers only one device + definition. The packaging helper needs a small extension to emit additional + definitions that select a runtime file through `session.device-config.file`. +- Observation: the exact calibration capture is from 2 August 2026. A later live + refresh could drift independently of the larger PR, so this change keeps the + exact reviewed snapshot rather than silently mixing capture dates. +- Observation: QDMI-on-IQM revision `5bef1d49245ae17877203618ad65865405fab361` + maps the service through these endpoint templates: `api/v1/quantum-computers`, + `api/v1/quantum-computers/%s/artifacts/static-quantum-architectures`, + `api/v1/calibration-sets/%s/%s/dynamic-quantum-architecture`, and + `api/v1/calibration-sets/%s/%s/metrics`. The first two select the computer and + return names/topology, the third returns default-calibration operation loci, + and the fourth returns T1/T2 and fidelity metrics. +- Observation: CTest registers the individual GoogleTest cases, not targets + named after the three executables. A target-name regular expression therefore + selected no tests; running each built executable directly exercised 171 tests. + +## Decision Log + +- Decision: keep schema version 1 and add an optional `name` member to each + `qubitProperties.overrides` entry. Rationale: this is a backward-compatible + optional property and follows the existing per-site override structure; a + version bump would make all current configuration files unnecessarily + incompatible. Date/Author: 2026-08-03, Codex. +- Decision: allow a qubit override that supplies only `name`, while continuing + to require at least one of `name`, `t1`, or `t2`. Reject empty names. + Rationale: names are independent of calibration availability, and an empty + configured string is not useful metadata. Date/Author: 2026-08-03, Codex. +- Decision: preserve the reported IQM names and the provider's index order as + `QB1` through `QBN`. Rationale: QDMI index and name are distinct properties; + retaining both permits stable compiler indices while allowing callers to + recover provider-facing hardware names. Date/Author: 2026-08-03, Codex. +- Decision: reuse the exact sanitized topology and calibration files from pull + request #1687 and add only site names. Rationale: the files were already + reviewed, contain no credentials or calibration identifiers, and preserve + nanosecond-level coherence precision through unit `us` with scale factor + `0.001`. Date/Author: 2026-08-03, Codex. +- Decision: do not add any duration field. Rationale: neither the captured + provider data nor the IQM QDMI interface supplied operation durations. + Date/Author: 2026-08-03, Codex. +- Decision: extend `mqt_configure_qdmi_device` with a `CONFIGURATIONS` list + whose entries pair a stable registry ID with the basename of an existing + runtime file. Reject malformed or empty pairs, unknown runtime files, and + duplicate IDs including the provider's primary ID. Rationale: the generated + manifest remains relocatable and unambiguous, and all variants reuse one + library and prefix without duplicating provider targets. Date/Author: + 2026-08-03, Codex. +- Decision: retain the source revision, endpoint interpretation, retrieval date, + and sanitization record solely as technical provenance. No attribution notice + is required for the IQM data, as confirmed by the maintainer during review. + Rationale: this is enough to reproduce and refresh the snapshots without + adding legal/process prose to user documentation or the assets. Date/Author: + 2026-08-03, Codex. + +## Repository Orientation + +`include/mqt-core/qdmi/devices/sc/Configuration.hpp` and +`src/qdmi/devices/sc/Configuration.cpp` define and parse the strict JSON model. +`include/mqt-core/qdmi/devices/sc/Device.hpp` and +`src/qdmi/devices/sc/Device.cpp` materialize one model per QDMI session and +answer QDMI property queries. + +The JSON assets live in `json/sc/`. The SC provider is assembled in +`src/qdmi/devices/sc/CMakeLists.txt`. `cmake/AddMQTQDMIDevice.cmake` generates +relocatable registry fragments, copies runtime files next to provider libraries, +and installs those files. + +Schema and provider behavior are tested in `test/qdmi/devices/sc/`. Generated +registry discovery is tested in `test/qdmi/registry/test_device_registry.cpp`, +and opening every configured device is tested in +`test/qdmi/driver/test_driver.cpp`. + +## Plan of Work + +First, add `std::optional name` to `sc::Device::QubitOverride`. +Teach the strict parser to accept `name`, reject an empty name, and accept an +override when at least one of name, T1, or T2 is present. Preserve the existing +checks for valid unique qubit indices and positive coherence values. + +Add an optional name to `MQT_SC_QDMI_Site_impl_d`. During session +initialization, apply configured names alongside T1/T2. Handle +`QDMI_SITE_PROPERTY_NAME` in `queryProperty`: return the configured +NUL-terminated string when present and `QDMI_ERROR_NOTSUPPORTED` when absent. +This keeps every existing unnamed configuration valid. + +Add `json/sc/iqm-garnet.json` and `json/sc/iqm-emerald.json` from exact pull +request #1687 commit `dd9619bd27a34ced8ed68a4ee4533cb85771f144`. Add the +reported name corresponding to each index. Preserve all topology, T1/T2, and +fidelity values byte-for-byte apart from the added names. Verify +programmatically that no object contains a `duration` key. + +Extend `mqt_configure_qdmi_device` so a provider manifest can contain the +existing default entry plus named configuration entries. Validate that every +entry has exactly an ID and filename and that the filename is among +`RUNTIME_FILES`. Add the two assets and IDs in +`src/qdmi/devices/sc/CMakeLists.txt`. The existing runtime copy and install +loops then package all three SC JSON files. + +Expand configuration tests to assert the model names, qubit and edge counts, +exact operation names, calibration coverage, locus-fidelity counts, site-name +endpoints, and complete absence of operation durations. Add schema coverage for +name-only overrides and empty-name rejection. Expand provider tests to prove +configured names are queryable and absent names remain unsupported. Expand +registry and driver tests to prove that five built-in definitions exist, both +stable IDs use packaged configuration files, and both models can be opened. + +Update `docs/qdmi/sc_device.md` to describe optional names and the two shared +models. Record that topology and site names came from the static architecture, +operation loci from the default dynamic architecture, and T1/T2/fidelities from +default calibration-set quality metrics retrieved on 2 August 2026. State that +the files contain no credentials or calibration identifiers and intentionally +omit unavailable durations. In this ExecPlan, pin the interpretation to +QDMI-on-IQM revision `5bef1d49245ae17877203618ad65865405fab361` and record its +source paths and the fact that no provider source, documentation text, or raw +service response is redistributed. Add one narrowly scoped `Unreleased` +changelog entry without inventing a pull request reference; add the reference in +a post-publication follow-up. + +## Milestones + +### Milestone 1: Schema and provider support optional site names + +At the end of this milestone, a JSON qubit override may contain a non-empty +`name`, and a caller can query it through QDMI. Existing unnamed models still +parse and return `QDMI_ERROR_NOTSUPPORTED` for name queries. + +From the repository root, build and run the SC provider tests: + + ./.agent/run.sh cmake --preset debug + ./.agent/run.sh cmake --build --preset debug --target \ + mqt-core-qdmi-sc-device-test + ./.agent/run.sh ./build/debug/test/qdmi/devices/sc/\ + mqt-core-qdmi-sc-device-test + +The new name parsing and querying tests must pass together with all existing SC +tests. + +### Milestone 2: Reusable IQM models are registered and packaged + +At the end of this milestone, building the provider places both new JSON files +beside its library and the generated manifest contains `mqt.sc.iqm.garnet` and +`mqt.sc.iqm.emerald`. Registry and driver tests open the configured variants and +report the correct device names. + +From the repository root, build and run: + + ./.agent/run.sh cmake --build --preset debug --target \ + mqt-core-qdmi-registry-test mqt-core-qdmi-driver-test + ./.agent/run.sh ./build/debug/test/qdmi/registry/\ + mqt-core-qdmi-registry-test + ./.agent/run.sh ./build/debug/test/qdmi/driver/\ + mqt-core-qdmi-driver-test + +The registry test must find five built-in definitions and regular files for both +configuration paths. The driver test must open five devices and include +`IQM Garnet` and `IQM Emerald`. + +### Milestone 3: Documentation, full validation, and atomic handoff + +At the end of this milestone, the docs explain the models' source and limits, +all focused tests and repository lint pass, the diff contains no secret or +duration field, and one signed commit records the implementation. + +From the repository root, run: + + ./.agent/run.sh ./build/debug/test/qdmi/devices/sc/\ + mqt-core-qdmi-sc-device-test + ./.agent/run.sh ./build/debug/test/qdmi/registry/\ + mqt-core-qdmi-registry-test + ./.agent/run.sh ./build/debug/test/qdmi/driver/\ + mqt-core-qdmi-driver-test + ./.agent/run.sh ctest --test-dir build/debug --output-on-failure \ + -R 'mqt-core-qdmi-(runtime-file|configuration-rejects)' + ./.agent/run.sh uvx nox -s lint + git diff --check + git status --short + +Also inspect the JSON mechanically: + + jq -e ' + .operations | all( + (has("duration") | not) and + (.siteOverrides | all(has("duration") | not)) + ) + ' json/sc/iqm-garnet.json json/sc/iqm-emerald.json + +Both `jq` invocations must print `true`. Search the final diff for common token, +credential, and calibration-identifier field names before committing; there must +be no match in either asset. + +## Validation and Acceptance + +The implementation is accepted when: + +- Garnet parses as 20 sites and 30 ordered topology edges, and Emerald parses as + 54 sites and 90 ordered topology edges. +- Both assets expose exactly `r`, `cz`, and `measure`; all recorded per-locus + fidelities remain available. +- Garnet exposes 20 T1 and 20 T2 values. Emerald exposes 53 T1 and 54 T2 values. +- Site indices remain zero-based while reported names are `QB1` through `QB20` + or `QB54`, respectively. +- No operation or locus in either model reports a duration. +- The IDs `mqt.sc.iqm.garnet` and `mqt.sc.iqm.emerald` resolve to the SC + provider plus the correct packaged JSON file in a build-tree registry. +- The two JSON files are included in the provider's runtime-file property and + install rules. +- Empty IDs/files and duplicate configuration IDs fail during CMake + configuration, while a valid additional configuration builds and installs. +- Existing unnamed SC configurations remain backward compatible. +- Public documentation records the retrieval date, field provenance, and + snapshot limitation. This ExecPlan records the technical source and + sanitization without claiming that the calibration is current. +- Focused C++ tests, repository lint, and `git diff --check` pass. + +## Idempotence and Recovery + +All configuration, build, test, and lint commands are repeatable. The checked-in +snapshot is authoritative for this change; validation must not rewrite it from a +live service. If configuration fails midway, rerun CMake through `.agent/run.sh` +and rebuild the named targets. Do not delete another task's worktree or build +directory. + +No external GitHub mutation is authorized by this plan. Do not push, open or +edit a pull request, comment, resolve threads, or merge. Do not persist or print +credentials while validating provenance. + +## Outcomes & Retrospective + +IQM-01 is complete. The SC schema remains version 1 and now carries optional +site names without changing unnamed configurations. Garnet and Emerald are +installed beside the existing provider, discoverable by stable IDs, and retain +the exact reviewed topology/calibration data plus provider-facing qubit names. +Durations remain absent. + +Validation built the SC provider, registry, and driver targets with LLVM/MLIR +22.1.3. The SC binary passed 41 tests with one pre-existing optional job-ID test +skipped; the registry passed 15 tests and the driver passed 114. Eight +configure/build/install tests covered valid runtime-file packaging plus empty +and duplicate configuration rejection. A runtime-component install smoke check +contained both IQM JSON files and the SC manifest. Repository lint and final +diff/secret/duration checks passed. + +No external GitHub action was taken. The changelog entry intentionally has no +pull request link because no replacement pull request exists yet; publication +must add that reference in a revision-scoped follow-up before release. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc63ad14e..d422bb4b47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ releases may include breaking changes. ### Added +- ✨ Bundle reusable IQM Garnet and Emerald superconducting device models with + stable QDMI registry IDs ([#1992]) ([**@burgholzer**]) - ✨ Add compiler-wide scoped global-phase normalization with exact modifier semantics and synthesis integration ([#1986]) ([**@burgholzer**]) - ✨ Expose compressed vector and matrix DD serialization through bytes-based @@ -705,6 +707,7 @@ for previous changelogs._ +[#1992]: https://github.com/munich-quantum-toolkit/core/pull/1992 [#1986]: https://github.com/munich-quantum-toolkit/core/pull/1986 [#1984]: https://github.com/munich-quantum-toolkit/core/pull/1984 [#1983]: https://github.com/munich-quantum-toolkit/core/pull/1983 diff --git a/cmake/AddMQTQDMIDevice.cmake b/cmake/AddMQTQDMIDevice.cmake index 392e059036..951975090f 100644 --- a/cmake/AddMQTQDMIDevice.cmake +++ b/cmake/AddMQTQDMIDevice.cmake @@ -22,7 +22,7 @@ endfunction() # Configure and register a relocatable built-in QDMI device. The generated fragment is emitted # beside the runtime library in both build and install trees. function(mqt_configure_qdmi_device target) - cmake_parse_arguments(ARG "" "ID;PREFIX" "RUNTIME_FILES" ${ARGN}) + cmake_parse_arguments(ARG "" "ID;PREFIX" "RUNTIME_FILES;CONFIGURATIONS" ${ARGN}) if(NOT TARGET ${target}) message(FATAL_ERROR "Unknown QDMI device target: ${target}") endif() @@ -38,12 +38,65 @@ function(mqt_configure_qdmi_device target) _mqt_qdmi_json_escape(device_id "${ARG_ID}") _mqt_qdmi_json_escape(device_prefix "${ARG_PREFIX}") + set(runtime_file_names) + foreach(runtime_file IN LISTS ARG_RUNTIME_FILES) + get_filename_component(runtime_file_name "${runtime_file}" NAME) + list(APPEND runtime_file_names "${runtime_file_name}") + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${runtime_file}" + "$/${runtime_file_name}") + endforeach() + + set(device_entries + " {\n \"id\": \"${device_id}\",\n \"library\": \"$\",\n \"prefix\": \"${device_prefix}\",\n \"enabled\": true\n }" + ) + set(configuration_ids "${ARG_ID}") + foreach(configuration IN LISTS ARG_CONFIGURATIONS) + string(REPLACE "|" ";" configuration_parts "${configuration}") + list(LENGTH configuration_parts configuration_length) + if(NOT configuration_length EQUAL 2) + message( + FATAL_ERROR + "QDMI configuration '${configuration}' must use the form '|'" + ) + endif() + list(GET configuration_parts 0 configuration_id) + list(GET configuration_parts 1 configuration_file) + if(configuration_id STREQUAL "" OR configuration_file STREQUAL "") + message( + FATAL_ERROR + "QDMI configuration '${configuration}' must use a non-empty device ID and runtime file name" + ) + endif() + list(FIND configuration_ids "${configuration_id}" configuration_id_index) + if(NOT configuration_id_index EQUAL -1) + message(FATAL_ERROR "Duplicate QDMI device ID '${configuration_id}'") + endif() + list(APPEND configuration_ids "${configuration_id}") + list(FIND runtime_file_names "${configuration_file}" runtime_file_index) + if(runtime_file_index EQUAL -1) + message( + FATAL_ERROR + "QDMI configuration '${configuration_id}' refers to unknown runtime file '${configuration_file}'" + ) + endif() + _mqt_qdmi_json_escape(configuration_id "${configuration_id}") + _mqt_qdmi_json_escape(configuration_file "${configuration_file}") + string( + APPEND + device_entries + ",\n {\n \"id\": \"${configuration_id}\",\n \"library\": \"$\",\n \"prefix\": \"${device_prefix}\",\n \"enabled\": true,\n \"session\": {\n \"device-config\": {\n \"file\": \"${configuration_file}\"\n }\n }\n }" + ) + endforeach() + set(fragment "${CMAKE_CURRENT_BINARY_DIR}/$/${target}.qdmi.json") file( GENERATE OUTPUT "${fragment}" CONTENT - "{\n \"schema-version\": 1,\n \"qdmi\": {\n \"devices\": [\n {\n \"id\": \"${device_id}\",\n \"library\": \"$\",\n \"prefix\": \"${device_prefix}\",\n \"enabled\": true\n }\n ]\n }\n}\n" + "{\n \"schema-version\": 1,\n \"qdmi\": {\n \"devices\": [\n${device_entries}\n ]\n }\n}\n" ) add_custom_command( @@ -51,16 +104,6 @@ function(mqt_configure_qdmi_device target) POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${fragment}" "$/${target}.qdmi.json") - set(runtime_file_names) - foreach(runtime_file IN LISTS ARG_RUNTIME_FILES) - get_filename_component(runtime_file_name "${runtime_file}" NAME) - list(APPEND runtime_file_names "${runtime_file_name}") - add_custom_command( - TARGET ${target} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${runtime_file}" - "$/${runtime_file_name}") - endforeach() set_target_properties( ${target} PROPERTIES QDMI_DEVICE_ID "${ARG_ID}" diff --git a/docs/qdmi/sc_device.md b/docs/qdmi/sc_device.md index e872275259..833657056a 100644 --- a/docs/qdmi/sc_device.md +++ b/docs/qdmi/sc_device.md @@ -35,7 +35,7 @@ and fidelity, and optional tuple-specific overrides. "durationUnit": {"unit": "ns", "scaleFactor": 1.0}, "qubitProperties": { "defaults": {"t1": 100000, "t2": 150000}, - "overrides": [{"qubit": 1, "t1": 95000}] + "overrides": [{"qubit": 1, "name": "QB2", "t1": 95000}] }, "couplings": [[0, 1]], "operations": [ @@ -66,11 +66,32 @@ exact ordered edge in the coupling map. Every site override must select one of the operation's supported tuples and supply a duration, fidelity, or both. When operation duration or fidelity is queried, a matching tuple override wins -over the operation default. Missing data returns `QDMI_ERROR_NOTSUPPORTED`. -Qubit T1 and T2 use a per-qubit override first and the qubit default second. The -order of a configured site tuple is significant. Handles from another session -are rejected. +over the operation default. Missing data returns `QDMI_ERROR_NOTSUPPORTED`. Each +qubit override may also provide a non-empty site name. Qubit T1 and T2 use a +per-qubit override first and the qubit default second. The order of a configured +site tuple is significant. Handles from another session are rejected. The calibration values bundled in `json/sc/mqt-core-qdmi-sc-device.json` are synthetic examples for testing and documentation; they are not measurements of physical hardware. + +## Bundled IQM models + +The SC provider also installs `json/sc/iqm-garnet.json` and +`json/sc/iqm-emerald.json`. They model the 20-qubit, 30-edge Garnet and +54-qubit, 90-edge Emerald architectures and expose the portable IQM operation +set `r`, `cz`, and `measure`. Their stable registry IDs are `mqt.sc.iqm.garnet` +and `mqt.sc.iqm.emerald`. + +The snapshots were derived from authenticated IQM architecture and calibration +data retrieved on 2 August 2026 through +[QDMI-on-IQM](https://github.com/iqm-finland/QDMI-on-IQM). Site names and +topology came from each static architecture, operation loci from its default +dynamic architecture, and available T1, T2, and per-locus fidelities from its +default calibration-set quality metrics. Coherence times were rounded to the +nearest nanosecond and stored as integral values using unit `us` and scale +factor `0.001`. They are historical compiler-facing snapshots, not claims about +current hardware calibration. + +The IQM interface did not report operation durations, so the files intentionally +omit them. diff --git a/include/mqt-core/qdmi/devices/sc/Configuration.hpp b/include/mqt-core/qdmi/devices/sc/Configuration.hpp index 65c908e395..ae43bf9aa7 100644 --- a/include/mqt-core/qdmi/devices/sc/Configuration.hpp +++ b/include/mqt-core/qdmi/devices/sc/Configuration.hpp @@ -38,6 +38,7 @@ struct Device { struct QubitOverride : QubitCalibration { uint64_t qubit = 0; + std::optional name; }; struct QubitProperties { diff --git a/include/mqt-core/qdmi/devices/sc/Device.hpp b/include/mqt-core/qdmi/devices/sc/Device.hpp index cbd5117fa5..18d2ebc79d 100644 --- a/include/mqt-core/qdmi/devices/sc/Device.hpp +++ b/include/mqt-core/qdmi/devices/sc/Device.hpp @@ -30,6 +30,7 @@ struct MQT_SC_QDMI_Device_Session_impl_d; struct MQT_SC_QDMI_Site_impl_d { MQT_SC_QDMI_Device_Session_impl_d* owner = nullptr; uint64_t id = 0; + std::optional name; std::optional t1; std::optional t2; diff --git a/json/sc/iqm-emerald.json b/json/sc/iqm-emerald.json new file mode 100644 index 0000000000..2c1946d0ba --- /dev/null +++ b/json/sc/iqm-emerald.json @@ -0,0 +1,1208 @@ +{ + "schema-version": 1, + "name": "IQM Emerald", + "numQubits": 54, + "durationUnit": { + "unit": "us", + "scaleFactor": 0.001 + }, + "qubitProperties": { + "defaults": {}, + "overrides": [ + { + "qubit": 0, + "name": "QB1", + "t1": 46392, + "t2": 18969 + }, + { + "qubit": 1, + "name": "QB2", + "t1": 33007, + "t2": 16460 + }, + { + "qubit": 2, + "name": "QB3", + "t1": 38653, + "t2": 38725 + }, + { + "qubit": 3, + "name": "QB4", + "t1": 28816, + "t2": 11451 + }, + { + "qubit": 4, + "name": "QB5", + "t1": 47439, + "t2": 14665 + }, + { + "qubit": 5, + "name": "QB6", + "t1": 30969, + "t2": 11164 + }, + { + "qubit": 6, + "name": "QB7", + "t1": 58892, + "t2": 19023 + }, + { + "qubit": 7, + "name": "QB8", + "t1": 59127, + "t2": 49134 + }, + { + "qubit": 8, + "name": "QB9", + "t1": 44851, + "t2": 13052 + }, + { + "qubit": 9, + "name": "QB10", + "t1": 34595, + "t2": 23058 + }, + { + "qubit": 10, + "name": "QB11", + "t1": 49730, + "t2": 16047 + }, + { + "qubit": 11, + "name": "QB12", + "t1": 57990, + "t2": 18641 + }, + { + "qubit": 12, + "name": "QB13", + "t1": 37552, + "t2": 13574 + }, + { + "qubit": 13, + "name": "QB14", + "t1": 60939, + "t2": 15828 + }, + { + "qubit": 14, + "name": "QB15", + "t1": 53111, + "t2": 24942 + }, + { + "qubit": 15, + "name": "QB16", + "t1": 12839, + "t2": 5184 + }, + { + "qubit": 16, + "name": "QB17", + "t1": 47534, + "t2": 18994 + }, + { + "qubit": 17, + "name": "QB18", + "t1": 56827, + "t2": 16352 + }, + { + "qubit": 18, + "name": "QB19", + "t1": 66474, + "t2": 26253 + }, + { + "qubit": 19, + "name": "QB20", + "t1": 47973, + "t2": 13827 + }, + { + "qubit": 20, + "name": "QB21", + "t1": 72091, + "t2": 15125 + }, + { + "qubit": 21, + "name": "QB22", + "t1": 39443, + "t2": 14638 + }, + { + "qubit": 22, + "name": "QB23", + "t1": 55778, + "t2": 27195 + }, + { + "qubit": 23, + "name": "QB24", + "t1": 55772, + "t2": 22297 + }, + { + "qubit": 24, + "name": "QB25", + "t2": 6886 + }, + { + "qubit": 25, + "name": "QB26", + "t1": 26525, + "t2": 7568 + }, + { + "qubit": 26, + "name": "QB27", + "t1": 63437, + "t2": 11303 + }, + { + "qubit": 27, + "name": "QB28", + "t1": 62264, + "t2": 8956 + }, + { + "qubit": 28, + "name": "QB29", + "t1": 61288, + "t2": 15118 + }, + { + "qubit": 29, + "name": "QB30", + "t1": 57094, + "t2": 23073 + }, + { + "qubit": 30, + "name": "QB31", + "t1": 48601, + "t2": 14956 + }, + { + "qubit": 31, + "name": "QB32", + "t1": 72002, + "t2": 22335 + }, + { + "qubit": 32, + "name": "QB33", + "t1": 47763, + "t2": 8608 + }, + { + "qubit": 33, + "name": "QB34", + "t1": 63844, + "t2": 8466 + }, + { + "qubit": 34, + "name": "QB35", + "t1": 68596, + "t2": 15522 + }, + { + "qubit": 35, + "name": "QB36", + "t1": 63416, + "t2": 8020 + }, + { + "qubit": 36, + "name": "QB37", + "t1": 62283, + "t2": 17850 + }, + { + "qubit": 37, + "name": "QB38", + "t1": 58796, + "t2": 10178 + }, + { + "qubit": 38, + "name": "QB39", + "t1": 43527, + "t2": 29849 + }, + { + "qubit": 39, + "name": "QB40", + "t1": 66368, + "t2": 17218 + }, + { + "qubit": 40, + "name": "QB41", + "t1": 62758, + "t2": 2844 + }, + { + "qubit": 41, + "name": "QB42", + "t1": 81317, + "t2": 17700 + }, + { + "qubit": 42, + "name": "QB43", + "t1": 56373, + "t2": 10539 + }, + { + "qubit": 43, + "name": "QB44", + "t1": 54740, + "t2": 33183 + }, + { + "qubit": 44, + "name": "QB45", + "t1": 26947, + "t2": 11212 + }, + { + "qubit": 45, + "name": "QB46", + "t1": 70432, + "t2": 42362 + }, + { + "qubit": 46, + "name": "QB47", + "t1": 55818, + "t2": 11454 + }, + { + "qubit": 47, + "name": "QB48", + "t1": 68798, + "t2": 5847 + }, + { + "qubit": 48, + "name": "QB49", + "t1": 72418, + "t2": 18075 + }, + { + "qubit": 49, + "name": "QB50", + "t1": 64957, + "t2": 29958 + }, + { + "qubit": 50, + "name": "QB51", + "t1": 84468, + "t2": 29219 + }, + { + "qubit": 51, + "name": "QB52", + "t1": 75117, + "t2": 21134 + }, + { + "qubit": 52, + "name": "QB53", + "t1": 81721, + "t2": 18444 + }, + { + "qubit": 53, + "name": "QB54", + "t1": 38356, + "t2": 11444 + } + ] + }, + "couplings": [ + [0, 1], + [0, 4], + [1, 5], + [2, 3], + [2, 8], + [3, 4], + [3, 9], + [4, 5], + [4, 10], + [5, 6], + [5, 11], + [6, 12], + [7, 8], + [7, 15], + [8, 9], + [8, 16], + [9, 10], + [9, 17], + [10, 11], + [10, 18], + [11, 12], + [11, 19], + [12, 13], + [12, 20], + [13, 21], + [14, 15], + [14, 22], + [15, 16], + [15, 23], + [16, 17], + [16, 24], + [17, 18], + [17, 25], + [18, 19], + [18, 26], + [19, 20], + [19, 27], + [20, 21], + [20, 28], + [21, 29], + [22, 23], + [23, 24], + [23, 31], + [24, 25], + [24, 32], + [25, 26], + [25, 33], + [26, 27], + [26, 34], + [27, 28], + [27, 35], + [28, 29], + [28, 36], + [29, 30], + [29, 37], + [30, 38], + [31, 32], + [31, 39], + [32, 33], + [32, 40], + [33, 34], + [33, 41], + [34, 35], + [34, 42], + [35, 36], + [35, 43], + [36, 37], + [36, 44], + [37, 38], + [37, 45], + [39, 40], + [40, 41], + [40, 46], + [41, 42], + [41, 47], + [42, 43], + [42, 48], + [43, 44], + [43, 49], + [44, 45], + [44, 50], + [46, 47], + [47, 48], + [47, 51], + [48, 49], + [48, 52], + [49, 50], + [49, 53], + [51, 52], + [52, 53] + ], + "operations": [ + { + "name": "r", + "numQubits": 1, + "numParameters": 2, + "siteOverrides": [ + { + "sites": [0], + "fidelity": 0.9996837259582892 + }, + { + "sites": [1], + "fidelity": 0.9997052599579568 + }, + { + "sites": [2], + "fidelity": 0.999658146168424 + }, + { + "sites": [3], + "fidelity": 0.9996382180977418 + }, + { + "sites": [4], + "fidelity": 0.9997163301730092 + }, + { + "sites": [5], + "fidelity": 0.9993081871591356 + }, + { + "sites": [6], + "fidelity": 0.9994468373023766 + }, + { + "sites": [7], + "fidelity": 0.9997545944945864 + }, + { + "sites": [8], + "fidelity": 0.9996344151472129 + }, + { + "sites": [9], + "fidelity": 0.9994028358077222 + }, + { + "sites": [10], + "fidelity": 0.9997369849275862 + }, + { + "sites": [11], + "fidelity": 0.9997607298339284 + }, + { + "sites": [12], + "fidelity": 0.9995638022714364 + }, + { + "sites": [13], + "fidelity": 0.99973282233036 + }, + { + "sites": [14], + "fidelity": 0.9997443095078864 + }, + { + "sites": [15], + "fidelity": 0.998390759467938 + }, + { + "sites": [16], + "fidelity": 0.9996245569346616 + }, + { + "sites": [17], + "fidelity": 0.9997296669685454 + }, + { + "sites": [18], + "fidelity": 0.9992727053295768 + }, + { + "sites": [19], + "fidelity": 0.9997355273183044 + }, + { + "sites": [20], + "fidelity": 0.9997940915645592 + }, + { + "sites": [21], + "fidelity": 0.999713295982722 + }, + { + "sites": [22], + "fidelity": 0.9997576517990368 + }, + { + "sites": [23], + "fidelity": 0.9997351448227784 + }, + { + "sites": [24], + "fidelity": 0.9220039436040088 + }, + { + "sites": [25], + "fidelity": 0.999106430711988 + }, + { + "sites": [26], + "fidelity": 0.9997356212159578 + }, + { + "sites": [27], + "fidelity": 0.999747431092373 + }, + { + "sites": [28], + "fidelity": 0.9997570401314052 + }, + { + "sites": [29], + "fidelity": 0.9996119559220664 + }, + { + "sites": [30], + "fidelity": 0.9996406964898988 + }, + { + "sites": [31], + "fidelity": 0.9997828898342456 + }, + { + "sites": [32], + "fidelity": 0.9995917591656592 + }, + { + "sites": [33], + "fidelity": 0.999762795756679 + }, + { + "sites": [34], + "fidelity": 0.9992465640814856 + }, + { + "sites": [35], + "fidelity": 0.9997454406169174 + }, + { + "sites": [36], + "fidelity": 0.9976289815379576 + }, + { + "sites": [37], + "fidelity": 0.9996972469343436 + }, + { + "sites": [38], + "fidelity": 0.9998049596655614 + }, + { + "sites": [39], + "fidelity": 0.9998079523647964 + }, + { + "sites": [40], + "fidelity": 0.9996627803644492 + }, + { + "sites": [41], + "fidelity": 0.9992507642966924 + }, + { + "sites": [42], + "fidelity": 0.9997836605333504 + }, + { + "sites": [43], + "fidelity": 0.9993100166735815 + }, + { + "sites": [44], + "fidelity": 0.9996204579320964 + }, + { + "sites": [45], + "fidelity": 0.9996397465373394 + }, + { + "sites": [46], + "fidelity": 0.999620748967918 + }, + { + "sites": [47], + "fidelity": 0.9997172828117402 + }, + { + "sites": [48], + "fidelity": 0.9989578543033786 + }, + { + "sites": [49], + "fidelity": 0.9997024385275626 + }, + { + "sites": [50], + "fidelity": 0.9995567388383506 + }, + { + "sites": [51], + "fidelity": 0.9997402987838522 + }, + { + "sites": [52], + "fidelity": 0.9997563213467264 + }, + { + "sites": [53], + "fidelity": 0.999578650755719 + } + ] + }, + { + "name": "cz", + "numQubits": 2, + "numParameters": 0, + "siteOverrides": [ + { + "sites": [0, 1], + "fidelity": 0.9969413345034056 + }, + { + "sites": [0, 4], + "fidelity": 0.9971538791849028 + }, + { + "sites": [1, 5], + "fidelity": 0.9896068069584034 + }, + { + "sites": [2, 3], + "fidelity": 0.9936850385964238 + }, + { + "sites": [2, 8], + "fidelity": 0.9963780209952412 + }, + { + "sites": [3, 4], + "fidelity": 0.9939031989226854 + }, + { + "sites": [3, 9], + "fidelity": 0.9970910907254354 + }, + { + "sites": [4, 5], + "fidelity": 0.996991775771158 + }, + { + "sites": [4, 10], + "fidelity": 0.9974597649803834 + }, + { + "sites": [5, 6], + "fidelity": 0.9966308505035064 + }, + { + "sites": [5, 11], + "fidelity": 0.9941798555018222 + }, + { + "sites": [6, 12], + "fidelity": 0.9956867925342664 + }, + { + "sites": [7, 8], + "fidelity": 0.9976130955357776 + }, + { + "sites": [7, 15], + "fidelity": 0.9927742975291184 + }, + { + "sites": [8, 9], + "fidelity": 0.9936731656682896 + }, + { + "sites": [8, 16], + "fidelity": 0.9970517105492036 + }, + { + "sites": [9, 10], + "fidelity": 0.9975956000466732 + }, + { + "sites": [9, 17], + "fidelity": 0.9944571851924452 + }, + { + "sites": [10, 11], + "fidelity": 0.9983917808888104 + }, + { + "sites": [10, 18], + "fidelity": 0.9950968161349752 + }, + { + "sites": [11, 12], + "fidelity": 0.96312952210938 + }, + { + "sites": [11, 19], + "fidelity": 0.9893629174089708 + }, + { + "sites": [12, 13], + "fidelity": 0.9940207675618336 + }, + { + "sites": [12, 20], + "fidelity": 0.995107544118774 + }, + { + "sites": [13, 21], + "fidelity": 0.9944177501984252 + }, + { + "sites": [14, 15], + "fidelity": 0.996034253387076 + }, + { + "sites": [15, 16], + "fidelity": 0.9950864680626792 + }, + { + "sites": [15, 23], + "fidelity": 0.9965054309654308 + }, + { + "sites": [16, 17], + "fidelity": 0.9957804025185316 + }, + { + "sites": [17, 18], + "fidelity": 0.9949181486814976 + }, + { + "sites": [17, 25], + "fidelity": 0.992047426076022 + }, + { + "sites": [18, 19], + "fidelity": 0.9920871546478374 + }, + { + "sites": [18, 26], + "fidelity": 0.9938891759644176 + }, + { + "sites": [19, 20], + "fidelity": 0.995357196393145 + }, + { + "sites": [19, 27], + "fidelity": 0.9976887326012306 + }, + { + "sites": [20, 21], + "fidelity": 0.9950802073855424 + }, + { + "sites": [20, 28], + "fidelity": 0.9978913041787768 + }, + { + "sites": [21, 29], + "fidelity": 0.9976827959004356 + }, + { + "sites": [22, 23], + "fidelity": 0.995369943200364 + }, + { + "sites": [25, 26], + "fidelity": 0.9955806042140616 + }, + { + "sites": [25, 33], + "fidelity": 0.9958010088606108 + }, + { + "sites": [26, 27], + "fidelity": 0.9962345356717062 + }, + { + "sites": [26, 34], + "fidelity": 0.9981417551356184 + }, + { + "sites": [27, 28], + "fidelity": 0.9967739645334112 + }, + { + "sites": [27, 35], + "fidelity": 0.9980532728665198 + }, + { + "sites": [28, 29], + "fidelity": 0.9977659471572182 + }, + { + "sites": [28, 36], + "fidelity": 0.9982152000974854 + }, + { + "sites": [29, 30], + "fidelity": 0.9920766762220788 + }, + { + "sites": [29, 37], + "fidelity": 0.9918246356284744 + }, + { + "sites": [30, 38], + "fidelity": 0.994813078599712 + }, + { + "sites": [31, 32], + "fidelity": 0.9967666143627752 + }, + { + "sites": [31, 39], + "fidelity": 0.998131814461782 + }, + { + "sites": [32, 33], + "fidelity": 0.9974524240802696 + }, + { + "sites": [32, 40], + "fidelity": 0.9958471942184204 + }, + { + "sites": [33, 34], + "fidelity": 0.9974062683079248 + }, + { + "sites": [33, 41], + "fidelity": 0.9976248923184052 + }, + { + "sites": [34, 35], + "fidelity": 0.9959294668088978 + }, + { + "sites": [34, 42], + "fidelity": 0.9812245811750008 + }, + { + "sites": [35, 36], + "fidelity": 0.9980348808276452 + }, + { + "sites": [35, 43], + "fidelity": 0.9950018157241084 + }, + { + "sites": [36, 37], + "fidelity": 0.993699267633727 + }, + { + "sites": [36, 44], + "fidelity": 0.9959674850407992 + }, + { + "sites": [37, 38], + "fidelity": 0.9973622226740442 + }, + { + "sites": [37, 45], + "fidelity": 0.9976887076822556 + }, + { + "sites": [39, 40], + "fidelity": 0.9949481790019008 + }, + { + "sites": [40, 41], + "fidelity": 0.992872635595606 + }, + { + "sites": [40, 46], + "fidelity": 0.9974552435400168 + }, + { + "sites": [41, 42], + "fidelity": 0.9824111076495718 + }, + { + "sites": [41, 47], + "fidelity": 0.9965086263649008 + }, + { + "sites": [42, 43], + "fidelity": 0.996330798077716 + }, + { + "sites": [42, 48], + "fidelity": 0.9956021949824008 + }, + { + "sites": [43, 44], + "fidelity": 0.997855106272212 + }, + { + "sites": [43, 49], + "fidelity": 0.9971746806292596 + }, + { + "sites": [44, 45], + "fidelity": 0.9978944398345154 + }, + { + "sites": [44, 50], + "fidelity": 0.9982026716773316 + }, + { + "sites": [46, 47], + "fidelity": 0.9974461582526928 + }, + { + "sites": [47, 48], + "fidelity": 0.998320780696598 + }, + { + "sites": [47, 51], + "fidelity": 0.9902910606789695 + }, + { + "sites": [49, 50], + "fidelity": 0.9975735768660834 + }, + { + "sites": [51, 52], + "fidelity": 0.998132940868902 + }, + { + "sites": [52, 53], + "fidelity": 0.9979934112597808 + } + ] + }, + { + "name": "measure", + "numQubits": 1, + "numParameters": 0, + "siteOverrides": [ + { + "sites": [0], + "fidelity": 0.9918 + }, + { + "sites": [1], + "fidelity": 0.99165 + }, + { + "sites": [2], + "fidelity": 0.98575 + }, + { + "sites": [3], + "fidelity": 0.9845 + }, + { + "sites": [4], + "fidelity": 0.98875 + }, + { + "sites": [5], + "fidelity": 0.9506 + }, + { + "sites": [6], + "fidelity": 0.98965 + }, + { + "sites": [7], + "fidelity": 0.98915 + }, + { + "sites": [8], + "fidelity": 0.9928 + }, + { + "sites": [9], + "fidelity": 0.98985 + }, + { + "sites": [10], + "fidelity": 0.99345 + }, + { + "sites": [11], + "fidelity": 0.9931 + }, + { + "sites": [12], + "fidelity": 0.99355 + }, + { + "sites": [13], + "fidelity": 0.9885 + }, + { + "sites": [14], + "fidelity": 0.9889 + }, + { + "sites": [15], + "fidelity": 0.98155 + }, + { + "sites": [16], + "fidelity": 0.99385 + }, + { + "sites": [17], + "fidelity": 0.9886 + }, + { + "sites": [18], + "fidelity": 0.9903 + }, + { + "sites": [19], + "fidelity": 0.99475 + }, + { + "sites": [20], + "fidelity": 0.9911 + }, + { + "sites": [21], + "fidelity": 0.9895 + }, + { + "sites": [22], + "fidelity": 0.97955 + }, + { + "sites": [23], + "fidelity": 0.9885 + }, + { + "sites": [24], + "fidelity": 0.9842 + }, + { + "sites": [25], + "fidelity": 0.9655 + }, + { + "sites": [26], + "fidelity": 0.98735 + }, + { + "sites": [27], + "fidelity": 0.98175 + }, + { + "sites": [28], + "fidelity": 0.99005 + }, + { + "sites": [29], + "fidelity": 0.99185 + }, + { + "sites": [30], + "fidelity": 0.9878 + }, + { + "sites": [31], + "fidelity": 0.98825 + }, + { + "sites": [32], + "fidelity": 0.987 + }, + { + "sites": [33], + "fidelity": 0.98445 + }, + { + "sites": [34], + "fidelity": 0.9771 + }, + { + "sites": [35], + "fidelity": 0.98335 + }, + { + "sites": [36], + "fidelity": 0.98375 + }, + { + "sites": [37], + "fidelity": 0.9881 + }, + { + "sites": [38], + "fidelity": 0.99525 + }, + { + "sites": [39], + "fidelity": 0.98875 + }, + { + "sites": [40], + "fidelity": 0.98535 + }, + { + "sites": [41], + "fidelity": 0.9789 + }, + { + "sites": [42], + "fidelity": 0.98905 + }, + { + "sites": [43], + "fidelity": 0.98765 + }, + { + "sites": [44], + "fidelity": 0.9873 + }, + { + "sites": [45], + "fidelity": 0.98355 + }, + { + "sites": [46], + "fidelity": 0.98895 + }, + { + "sites": [47], + "fidelity": 0.98605 + }, + { + "sites": [48], + "fidelity": 0.96875 + }, + { + "sites": [49], + "fidelity": 0.9918 + }, + { + "sites": [50], + "fidelity": 0.9828 + }, + { + "sites": [51], + "fidelity": 0.9898 + }, + { + "sites": [52], + "fidelity": 0.9856 + }, + { + "sites": [53], + "fidelity": 0.98915 + } + ] + } + ] +} diff --git a/json/sc/iqm-garnet.json b/json/sc/iqm-garnet.json new file mode 100644 index 0000000000..8138b2c8c9 --- /dev/null +++ b/json/sc/iqm-garnet.json @@ -0,0 +1,469 @@ +{ + "schema-version": 1, + "name": "IQM Garnet", + "numQubits": 20, + "durationUnit": { + "unit": "us", + "scaleFactor": 0.001 + }, + "qubitProperties": { + "defaults": {}, + "overrides": [ + { + "qubit": 0, + "name": "QB1", + "t1": 26626, + "t2": 8376 + }, + { + "qubit": 1, + "name": "QB2", + "t1": 31464, + "t2": 7486 + }, + { + "qubit": 2, + "name": "QB3", + "t1": 19788, + "t2": 5840 + }, + { + "qubit": 3, + "name": "QB4", + "t1": 20631, + "t2": 8074 + }, + { + "qubit": 4, + "name": "QB5", + "t1": 39421, + "t2": 8333 + }, + { + "qubit": 5, + "name": "QB6", + "t1": 40760, + "t2": 5595 + }, + { + "qubit": 6, + "name": "QB7", + "t1": 40486, + "t2": 9095 + }, + { + "qubit": 7, + "name": "QB8", + "t1": 22847, + "t2": 7863 + }, + { + "qubit": 8, + "name": "QB9", + "t1": 39431, + "t2": 10938 + }, + { + "qubit": 9, + "name": "QB10", + "t1": 22077, + "t2": 5460 + }, + { + "qubit": 10, + "name": "QB11", + "t1": 40756, + "t2": 11069 + }, + { + "qubit": 11, + "name": "QB12", + "t1": 39781, + "t2": 14250 + }, + { + "qubit": 12, + "name": "QB13", + "t1": 38259, + "t2": 5252 + }, + { + "qubit": 13, + "name": "QB14", + "t1": 33608, + "t2": 6569 + }, + { + "qubit": 14, + "name": "QB15", + "t1": 39013, + "t2": 5953 + }, + { + "qubit": 15, + "name": "QB16", + "t1": 41590, + "t2": 6138 + }, + { + "qubit": 16, + "name": "QB17", + "t1": 41016, + "t2": 13593 + }, + { + "qubit": 17, + "name": "QB18", + "t1": 44688, + "t2": 5943 + }, + { + "qubit": 18, + "name": "QB19", + "t1": 46327, + "t2": 8782 + }, + { + "qubit": 19, + "name": "QB20", + "t1": 36131, + "t2": 22737 + } + ] + }, + "couplings": [ + [0, 1], + [0, 3], + [1, 4], + [2, 3], + [2, 7], + [3, 4], + [3, 8], + [4, 5], + [4, 9], + [5, 6], + [5, 10], + [6, 11], + [7, 8], + [7, 12], + [8, 9], + [8, 13], + [9, 10], + [9, 14], + [10, 11], + [10, 15], + [11, 16], + [12, 13], + [13, 14], + [13, 17], + [14, 15], + [14, 18], + [15, 16], + [15, 19], + [17, 18], + [18, 19] + ], + "operations": [ + { + "name": "r", + "numQubits": 1, + "numParameters": 2, + "siteOverrides": [ + { + "sites": [0], + "fidelity": 0.9989764855541426 + }, + { + "sites": [1], + "fidelity": 0.9994137341974704 + }, + { + "sites": [2], + "fidelity": 0.9988162826876488 + }, + { + "sites": [3], + "fidelity": 0.999275463615636 + }, + { + "sites": [4], + "fidelity": 0.9993874406823252 + }, + { + "sites": [5], + "fidelity": 0.9991834975710048 + }, + { + "sites": [6], + "fidelity": 0.9973521795708336 + }, + { + "sites": [7], + "fidelity": 0.9993508422282292 + }, + { + "sites": [8], + "fidelity": 0.99863732026566 + }, + { + "sites": [9], + "fidelity": 0.9986913070662058 + }, + { + "sites": [10], + "fidelity": 0.9994306432829452 + }, + { + "sites": [11], + "fidelity": 0.9962689684191476 + }, + { + "sites": [12], + "fidelity": 0.9972606059400604 + }, + { + "sites": [13], + "fidelity": 0.9992887068659668 + }, + { + "sites": [14], + "fidelity": 0.9991463242195284 + }, + { + "sites": [15], + "fidelity": 0.9966745165466736 + }, + { + "sites": [16], + "fidelity": 0.9993841985863008 + }, + { + "sites": [17], + "fidelity": 0.9991722904379012 + }, + { + "sites": [18], + "fidelity": 0.9996405112039688 + }, + { + "sites": [19], + "fidelity": 0.999593725030246 + } + ] + }, + { + "name": "cz", + "numQubits": 2, + "numParameters": 0, + "siteOverrides": [ + { + "sites": [0, 1], + "fidelity": 0.9943350602403423 + }, + { + "sites": [0, 3], + "fidelity": 0.9928715569164268 + }, + { + "sites": [1, 4], + "fidelity": 0.9909991817411294 + }, + { + "sites": [2, 3], + "fidelity": 0.9949180529897732 + }, + { + "sites": [2, 7], + "fidelity": 0.9912364331308542 + }, + { + "sites": [3, 4], + "fidelity": 0.9954890495965448 + }, + { + "sites": [3, 8], + "fidelity": 0.9928434575218484 + }, + { + "sites": [4, 5], + "fidelity": 0.991448076779792 + }, + { + "sites": [4, 9], + "fidelity": 0.989613618448402 + }, + { + "sites": [5, 6], + "fidelity": 0.9900308941074192 + }, + { + "sites": [5, 10], + "fidelity": 0.9913980205867798 + }, + { + "sites": [6, 11], + "fidelity": 0.9981157273861604 + }, + { + "sites": [7, 8], + "fidelity": 0.9896080668164158 + }, + { + "sites": [7, 12], + "fidelity": 0.993811402272364 + }, + { + "sites": [8, 9], + "fidelity": 0.9874011987628732 + }, + { + "sites": [8, 13], + "fidelity": 0.9944623008406192 + }, + { + "sites": [9, 10], + "fidelity": 0.9910179943052172 + }, + { + "sites": [9, 14], + "fidelity": 0.9881207404127784 + }, + { + "sites": [10, 11], + "fidelity": 0.9987871076255316 + }, + { + "sites": [10, 15], + "fidelity": 0.9949952689115732 + }, + { + "sites": [11, 16], + "fidelity": 0.9988891343238776 + }, + { + "sites": [12, 13], + "fidelity": 0.9934219679946316 + }, + { + "sites": [13, 14], + "fidelity": 0.9928397790919078 + }, + { + "sites": [13, 17], + "fidelity": 0.9949536678366192 + }, + { + "sites": [14, 15], + "fidelity": 0.99401170644631 + }, + { + "sites": [14, 18], + "fidelity": 0.9934856904331918 + }, + { + "sites": [15, 16], + "fidelity": 0.9958018845677588 + }, + { + "sites": [15, 19], + "fidelity": 0.99470226480463 + }, + { + "sites": [17, 18], + "fidelity": 0.9967902526632172 + }, + { + "sites": [18, 19], + "fidelity": 0.9977112949748272 + } + ] + }, + { + "name": "measure", + "numQubits": 1, + "numParameters": 0, + "siteOverrides": [ + { + "sites": [0], + "fidelity": 0.9817 + }, + { + "sites": [1], + "fidelity": 0.97535 + }, + { + "sites": [2], + "fidelity": 0.97275 + }, + { + "sites": [3], + "fidelity": 0.9881 + }, + { + "sites": [4], + "fidelity": 0.9774 + }, + { + "sites": [5], + "fidelity": 0.9759 + }, + { + "sites": [6], + "fidelity": 0.9761 + }, + { + "sites": [7], + "fidelity": 0.9757 + }, + { + "sites": [8], + "fidelity": 0.9724 + }, + { + "sites": [9], + "fidelity": 0.9807 + }, + { + "sites": [10], + "fidelity": 0.9824 + }, + { + "sites": [11], + "fidelity": 0.98425 + }, + { + "sites": [12], + "fidelity": 0.9728 + }, + { + "sites": [13], + "fidelity": 0.97175 + }, + { + "sites": [14], + "fidelity": 0.97115 + }, + { + "sites": [15], + "fidelity": 0.97975 + }, + { + "sites": [16], + "fidelity": 0.9814 + }, + { + "sites": [17], + "fidelity": 0.9847 + }, + { + "sites": [18], + "fidelity": 0.9702 + }, + { + "sites": [19], + "fidelity": 0.98535 + } + ] + } + ] +} diff --git a/src/qdmi/devices/sc/CMakeLists.txt b/src/qdmi/devices/sc/CMakeLists.txt index 6876e67ab9..b37cf5f20b 100644 --- a/src/qdmi/devices/sc/CMakeLists.txt +++ b/src/qdmi/devices/sc/CMakeLists.txt @@ -77,7 +77,12 @@ if(NOT TARGET ${TARGET_NAME}) PREFIX ${QDMI_PREFIX} RUNTIME_FILES - ${PROJECT_SOURCE_DIR}/json/sc/mqt-core-qdmi-sc-device.json) + ${PROJECT_SOURCE_DIR}/json/sc/mqt-core-qdmi-sc-device.json + ${PROJECT_SOURCE_DIR}/json/sc/iqm-garnet.json + ${PROJECT_SOURCE_DIR}/json/sc/iqm-emerald.json + CONFIGURATIONS + "mqt.sc.iqm.garnet|iqm-garnet.json" + "mqt.sc.iqm.emerald|iqm-emerald.json") list(APPEND MQT_CORE_TARGETS ${TARGET_NAME}) endif() diff --git a/src/qdmi/devices/sc/Configuration.cpp b/src/qdmi/devices/sc/Configuration.cpp index 9dc81f05bf..f5d18f03f2 100644 --- a/src/qdmi/devices/sc/Configuration.cpp +++ b/src/qdmi/devices/sc/Configuration.cpp @@ -218,16 +218,20 @@ void validateFidelity(const std::optional& fidelity, const auto pointer = "$/qubitProperties/overrides/" + std::to_string(i); const auto& value = overrides[i]; object(value, source, pointer); - keys(value, {"qubit", "t1", "t2"}, source, pointer); + keys(value, {"qubit", "name", "t1", "t2"}, source, pointer); Device::QubitOverride entry; entry.qubit = required(value, "qubit", source, pointer); + entry.name = optional(value, "name", source, pointer); entry.t1 = optional(value, "t1", source, pointer); entry.t2 = optional(value, "t2", source, pointer); - if (entry.qubit >= result.numQubits || (entry.t1 && *entry.t1 == 0) || - (entry.t2 && *entry.t2 == 0) || (!entry.t1 && !entry.t2) || + if (entry.qubit >= result.numQubits || + (entry.name && entry.name->empty()) || + (entry.t1 && *entry.t1 == 0) || (entry.t2 && *entry.t2 == 0) || + (!entry.name && !entry.t1 && !entry.t2) || !overridden.emplace(entry.qubit).second) { fail(source, pointer, - "must select one unique valid qubit and override t1 or t2"); + "must select one unique valid qubit and override name, t1, or " + "t2 with valid values"); } result.qubitProperties.overrides.emplace_back(entry); } diff --git a/src/qdmi/devices/sc/Device.cpp b/src/qdmi/devices/sc/Device.cpp index 100586fb6f..a62a7955d9 100644 --- a/src/qdmi/devices/sc/Device.cpp +++ b/src/qdmi/devices/sc/Device.cpp @@ -90,6 +90,9 @@ int MQT_SC_QDMI_Device_Session_impl_d::init() { } for (const auto& override : configuration.qubitProperties.overrides) { auto& site = newSiteStorage.at(override.qubit); + if (override.name) { + site->name = override.name; + } if (override.t1) { site->t1 = override.t1; } @@ -302,6 +305,13 @@ int MQT_SC_QDMI_Site_impl_d::queryProperty(const QDMI_Site_Property property, } ADD_SINGLE_VALUE_PROPERTY(QDMI_SITE_PROPERTY_INDEX, uint64_t, id, property, size, value, sizeRet) + if (property == QDMI_SITE_PROPERTY_NAME) { + if (!name) { + return QDMI_ERROR_NOTSUPPORTED; + } + ADD_STRING_PROPERTY(QDMI_SITE_PROPERTY_NAME, name->c_str(), property, size, + value, sizeRet) + } if (property == QDMI_SITE_PROPERTY_T1) { if (!t1) { return QDMI_ERROR_NOTSUPPORTED; diff --git a/test/qdmi/devices/sc/CMakeLists.txt b/test/qdmi/devices/sc/CMakeLists.txt index 11aea2e84c..351ccdc96e 100644 --- a/test/qdmi/devices/sc/CMakeLists.txt +++ b/test/qdmi/devices/sc/CMakeLists.txt @@ -28,7 +28,9 @@ if(TARGET MQT::CoreQDMIScDeviceConfig AND TARGET MQT::CoreQDMIScDevice) target_compile_definitions( ${TARGET_NAME} PRIVATE MQT_CORE_VERSION="${MQT_CORE_VERSION}" - SC_DEVICE_JSON="${PROJECT_SOURCE_DIR}/json/sc/mqt-core-qdmi-sc-device.json") + SC_DEVICE_JSON="${PROJECT_SOURCE_DIR}/json/sc/mqt-core-qdmi-sc-device.json" + IQM_GARNET_JSON="${PROJECT_SOURCE_DIR}/json/sc/iqm-garnet.json" + IQM_EMERALD_JSON="${PROJECT_SOURCE_DIR}/json/sc/iqm-emerald.json") # On Windows, copy the provider and its runtime assets beside the test executable. if(WIN32) diff --git a/test/qdmi/devices/sc/test_configuration.cpp b/test/qdmi/devices/sc/test_configuration.cpp index 8dd6ffbbd5..7089657c5d 100644 --- a/test/qdmi/devices/sc/test_configuration.cpp +++ b/test/qdmi/devices/sc/test_configuration.cpp @@ -15,6 +15,8 @@ #include // NOLINT(misc-include-cleaner) #include +#include +#include #include #include #include @@ -64,6 +66,68 @@ TEST(ScConfigurationTest, ParsesBundledDeviceStrictly) { EXPECT_EQ(device.couplings.back(), (std::pair{89, 99})); } +TEST(ScConfigurationTest, ParsesIqmDeviceModels) { + const auto assertModel = [](const Device& device, const std::string& name, + const size_t qubits, const size_t couplings, + const size_t czLoci) { + EXPECT_EQ(device.name, name); + EXPECT_EQ(device.numQubits, qubits); + EXPECT_EQ(device.couplings.size(), couplings); + EXPECT_EQ(device.durationUnit.unit, "us"); + EXPECT_DOUBLE_EQ(device.durationUnit.scaleFactor, 0.001); + ASSERT_EQ(device.qubitProperties.overrides.size(), qubits); + for (size_t i = 0; i < qubits; ++i) { + const auto& qubit = device.qubitProperties.overrides[i]; + EXPECT_EQ(qubit.qubit, i); + ASSERT_TRUE(qubit.name); + EXPECT_EQ(*qubit.name, "QB" + std::to_string(i + 1)); + } + + ASSERT_EQ(device.operations.size(), 3); + EXPECT_EQ(device.operations[0].name, "r"); + EXPECT_EQ(device.operations[0].numParameters, 2); + EXPECT_EQ(device.operations[0].numQubits, 1); + EXPECT_EQ(device.operations[0].siteOverrides.size(), qubits); + EXPECT_EQ(device.operations[1].name, "cz"); + EXPECT_EQ(device.operations[1].numParameters, 0); + EXPECT_EQ(device.operations[1].numQubits, 2); + EXPECT_EQ(device.operations[1].siteOverrides.size(), czLoci); + EXPECT_EQ(device.operations[2].name, "measure"); + EXPECT_EQ(device.operations[2].numParameters, 0); + EXPECT_EQ(device.operations[2].numQubits, 1); + EXPECT_EQ(device.operations[2].siteOverrides.size(), qubits); + for (const auto& operation : device.operations) { + EXPECT_FALSE(operation.duration); + for (const auto& locus : operation.siteOverrides) { + EXPECT_FALSE(locus.duration); + EXPECT_TRUE(locus.fidelity); + } + } + }; + + const auto garnet = readJSON(IQM_GARNET_JSON); + assertModel(garnet, "IQM Garnet", 20, 30, 30); + EXPECT_EQ(std::ranges::count_if( + garnet.qubitProperties.overrides, + [](const auto& qubit) { return qubit.t1.has_value(); }), + 20); + EXPECT_EQ(std::ranges::count_if( + garnet.qubitProperties.overrides, + [](const auto& qubit) { return qubit.t2.has_value(); }), + 20); + + const auto emerald = readJSON(IQM_EMERALD_JSON); + assertModel(emerald, "IQM Emerald", 54, 90, 81); + EXPECT_EQ(std::ranges::count_if( + emerald.qubitProperties.overrides, + [](const auto& qubit) { return qubit.t1.has_value(); }), + 53); + EXPECT_EQ(std::ranges::count_if( + emerald.qubitProperties.overrides, + [](const auto& qubit) { return qubit.t2.has_value(); }), + 54); +} + TEST(ScConfigurationTest, RejectsTopLevelSchemaErrors) { expectInvalid([](auto& root) { root["unknown"] = true; }, "unknown"); expectInvalid([](auto& root) { root.erase("qubitProperties"); }, @@ -97,6 +161,30 @@ TEST(ScConfigurationTest, RejectsInvalidUnitsAndCalibration) { {{"qubit", 8}, {"t1", 0}}); }, "qubitProperties/overrides"); + expectInvalid( + [](auto& root) { + root["qubitProperties"]["overrides"].push_back( + {{"qubit", 8}, {"name", ""}}); + }, + "qubitProperties/overrides"); + expectInvalid( + [](auto& root) { + root["qubitProperties"]["overrides"].push_back({{"qubit", 8}}); + }, + "qubitProperties/overrides"); +} + +TEST(ScConfigurationTest, AcceptsOptionalSiteNames) { + auto root = bundledJson(); + root["qubitProperties"]["overrides"].push_back( + {{"qubit", 8}, {"name", "QB9"}}); + const auto device = readJSON(root.dump(), "site-name"); + const auto& qubitOverride = device.qubitProperties.overrides.back(); + EXPECT_EQ(qubitOverride.qubit, 8); + ASSERT_TRUE(qubitOverride.name); + EXPECT_EQ(*qubitOverride.name, "QB9"); + EXPECT_FALSE(qubitOverride.t1); + EXPECT_FALSE(qubitOverride.t2); } TEST(ScConfigurationTest, RejectsInvalidOrderedTopology) { diff --git a/test/qdmi/devices/sc/test_device.cpp b/test/qdmi/devices/sc/test_device.cpp index f05646419a..42ab394a29 100644 --- a/test/qdmi/devices/sc/test_device.cpp +++ b/test/qdmi/devices/sc/test_device.cpp @@ -105,7 +105,10 @@ constexpr auto CUSTOM_SC = R"({ "durationUnit": {"unit": "ns", "scaleFactor": 0.5}, "qubitProperties": { "defaults": {"t1": 100, "t2": 200}, - "overrides": [{"qubit": 1, "t1": 90}] + "overrides": [ + {"qubit": 0, "name": "QB1"}, + {"qubit": 1, "name": "QB2", "t1": 90} + ] }, "couplings": [[0, 1], [1, 0]], "operations": [{ @@ -170,6 +173,24 @@ queryOperations(MQT_SC_QDMI_Device_Session session) { } return operations; } + +[[nodiscard]] std::string querySiteName(MQT_SC_QDMI_Device_Session session, + MQT_SC_QDMI_Site site) { + size_t size = 0; + if (MQT_SC_QDMI_device_session_query_site_property( + session, site, QDMI_SITE_PROPERTY_NAME, 0, nullptr, &size) != + QDMI_SUCCESS) { + throw std::runtime_error("Failed to query site name size"); + } + std::string name(size, '\0'); + if (MQT_SC_QDMI_device_session_query_site_property( + session, site, QDMI_SITE_PROPERTY_NAME, size, name.data(), nullptr) != + QDMI_SUCCESS) { + throw std::runtime_error("Failed to query site name"); + } + name.resize(size - 1); + return name; +} } // namespace TEST(ScRuntimeConfiguration, ValidatesRawParameterStringsAndRetry) { @@ -258,6 +279,8 @@ TEST(ScRuntimeConfiguration, SessionsOwnIndependentModelsAndCalibration) { EXPECT_EQ(bundledQubits, 100); const auto sites = querySites(custom); + EXPECT_EQ(querySiteName(custom, sites[0]), "QB1"); + EXPECT_EQ(querySiteName(custom, sites[1]), "QB2"); uint64_t t1 = 0; ASSERT_EQ( MQT_SC_QDMI_device_session_query_site_property( @@ -302,6 +325,10 @@ TEST(ScRuntimeConfiguration, SessionsOwnIndependentModelsAndCalibration) { EXPECT_DOUBLE_EQ(fidelity, 0.9); auto* const bundledSite = querySites(bundled).front(); + EXPECT_EQ( + MQT_SC_QDMI_device_session_query_site_property( + bundled, bundledSite, QDMI_SITE_PROPERTY_NAME, 0, nullptr, nullptr), + QDMI_ERROR_NOTSUPPORTED); EXPECT_EQ( MQT_SC_QDMI_device_session_query_site_property( custom, bundledSite, QDMI_SITE_PROPERTY_INDEX, 0, nullptr, nullptr), diff --git a/test/qdmi/driver/CMakeLists.txt b/test/qdmi/driver/CMakeLists.txt index 625febfce7..dd2cf91693 100644 --- a/test/qdmi/driver/CMakeLists.txt +++ b/test/qdmi/driver/CMakeLists.txt @@ -140,4 +140,28 @@ if(TARGET MQT::CoreQDMIDriver) mqt-core-qdmi-runtime-file-install) set_tests_properties(mqt-core-qdmi-runtime-file-install-verify PROPERTIES FIXTURES_REQUIRED mqt-core-qdmi-runtime-file-install) + + function(add_qdmi_configuration_rejection_test name invalid_configuration) + set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/runtime-file-device-invalid-${name}") + set(configure_command + ${CMAKE_COMMAND} -S "${CMAKE_CURRENT_SOURCE_DIR}/runtime_file_device" -B "${build_dir}" -G + "${CMAKE_GENERATOR}" + "-DMQT_CORE_QDMI_HELPER=${PROJECT_SOURCE_DIR}/cmake/AddMQTQDMIDevice.cmake" + "-DMQT_CORE_QDMI_TEST_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + "-DMQT_CORE_QDMI_INVALID_CONFIGURATION=${invalid_configuration}" + "-DCMAKE_BUILD_TYPE=$") + if(CMAKE_GENERATOR_PLATFORM) + list(APPEND configure_command -A "${CMAKE_GENERATOR_PLATFORM}") + endif() + if(CMAKE_GENERATOR_TOOLSET) + list(APPEND configure_command -T "${CMAKE_GENERATOR_TOOLSET}") + endif() + add_test(NAME "mqt-core-qdmi-configuration-rejects-${name}" COMMAND ${configure_command}) + set_tests_properties("mqt-core-qdmi-configuration-rejects-${name}" PROPERTIES WILL_FAIL TRUE) + endfunction() + + add_qdmi_configuration_rejection_test(empty-id empty-id) + add_qdmi_configuration_rejection_test(empty-file empty-file) + add_qdmi_configuration_rejection_test(duplicate-base-id duplicate-base-id) + add_qdmi_configuration_rejection_test(duplicate-configured-id duplicate-configured-id) endif() diff --git a/test/qdmi/driver/runtime_file_device/CMakeLists.txt b/test/qdmi/driver/runtime_file_device/CMakeLists.txt index 40e6c3b574..334ae1ccfb 100644 --- a/test/qdmi/driver/runtime_file_device/CMakeLists.txt +++ b/test/qdmi/driver/runtime_file_device/CMakeLists.txt @@ -18,6 +18,17 @@ include("${MQT_CORE_QDMI_HELPER}") add_library(mqt-core-qdmi-runtime-file-device SHARED "${MQT_CORE_QDMI_TEST_SOURCE_DIR}/metadata_device.cpp") +set(configurations "test.runtime-file.variant|metadata-runtime.json") +if(MQT_CORE_QDMI_INVALID_CONFIGURATION STREQUAL "empty-id") + set(configurations "|metadata-runtime.json") +elseif(MQT_CORE_QDMI_INVALID_CONFIGURATION STREQUAL "empty-file") + set(configurations "test.runtime-file.variant|") +elseif(MQT_CORE_QDMI_INVALID_CONFIGURATION STREQUAL "duplicate-base-id") + set(configurations "test.runtime-file|metadata-runtime.json") +elseif(MQT_CORE_QDMI_INVALID_CONFIGURATION STREQUAL "duplicate-configured-id") + set(configurations "test.runtime-file.variant|metadata-runtime.json" + "test.runtime-file.variant|metadata-runtime.json") +endif() mqt_configure_qdmi_device( mqt-core-qdmi-runtime-file-device ID @@ -25,4 +36,6 @@ mqt_configure_qdmi_device( PREFIX TEST_RUNTIME RUNTIME_FILES - "${MQT_CORE_QDMI_TEST_SOURCE_DIR}/metadata-runtime.json") + "${MQT_CORE_QDMI_TEST_SOURCE_DIR}/metadata-runtime.json" + CONFIGURATIONS + ${configurations}) diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 3b01c91119..3b982cb172 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -868,8 +868,8 @@ TEST(ConfiguredDriverTest, ExposesWorkingDefinitionsAndIsolatesFailures) { ASSERT_EQ(QDMI_session_query_session_property( session, QDMI_SESSION_PROPERTY_DEVICES, 0, nullptr, &size), QDMI_SUCCESS); - ASSERT_EQ(size, 3 * sizeof(QDMI_Device)); - std::array devices{}; + ASSERT_EQ(size, 5 * sizeof(QDMI_Device)); + std::array devices{}; ASSERT_EQ(QDMI_session_query_session_property( session, QDMI_SESSION_PROPERTY_DEVICES, size, static_cast(devices.data()), nullptr), @@ -878,9 +878,9 @@ TEST(ConfiguredDriverTest, ExposesWorkingDefinitionsAndIsolatesFailures) { std::vector names; std::ranges::transform(devices, std::back_inserter(names), queryName); EXPECT_THAT(names, - testing::UnorderedElementsAre("MQT NA Default QDMI Device", - "MQT Core DDSIM QDMI Device", - "MQT SC Default QDMI Device")); + testing::UnorderedElementsAre( + "IQM Emerald", "IQM Garnet", "MQT NA Default QDMI Device", + "MQT Core DDSIM QDMI Device", "MQT SC Default QDMI Device")); QDMI_session_free(session); } diff --git a/test/qdmi/registry/test_device_registry.cpp b/test/qdmi/registry/test_device_registry.cpp index d9854cb005..593066d399 100644 --- a/test/qdmi/registry/test_device_registry.cpp +++ b/test/qdmi/registry/test_device_registry.cpp @@ -349,13 +349,30 @@ TEST(DeviceRegistry, DiscoversGeneratedBuildTreeManifests) { const ScopedEnvironmentVariable configJson("MQT_CORE_QDMI_CONFIG_JSON", ""); const qdmi::detail::DeviceRegistry registry; - ASSERT_EQ(registry.definitions().size(), 3); + ASSERT_EQ(registry.definitions().size(), 5); EXPECT_EQ(registry.definitions().at(0).id, "mqt.ddsim.default"); EXPECT_EQ(registry.definitions().at(1).id, "mqt.na.default"); EXPECT_EQ(registry.definitions().at(2).id, "mqt.sc.default"); + EXPECT_EQ(registry.definitions().at(3).id, "mqt.sc.iqm.emerald"); + EXPECT_EQ(registry.definitions().at(4).id, "mqt.sc.iqm.garnet"); for (const auto& definition : registry.definitions()) { EXPECT_TRUE(std::filesystem::is_regular_file(definition.library)); } + + const auto assertPackagedModel = [&](const std::string_view id, + const std::string_view filename) { + const auto* definition = findDefinition(registry, id); + ASSERT_NE(definition, nullptr); + ASSERT_TRUE(definition->session.deviceConfiguration); + const auto* file = std::get_if( + &*definition->session.deviceConfiguration); + ASSERT_NE(file, nullptr); + EXPECT_EQ(file->path.filename(), filename); + EXPECT_EQ(file->path.parent_path(), definition->library.parent_path()); + EXPECT_TRUE(std::filesystem::is_regular_file(file->path)); + }; + assertPackagedModel("mqt.sc.iqm.garnet", "iqm-garnet.json"); + assertPackagedModel("mqt.sc.iqm.emerald", "iqm-emerald.json"); } #endif