iqm-client 32.1.1__tar.gz → 33.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. {iqm_client-32.1.1 → iqm_client-33.0.0}/CHANGELOG.rst +44 -7
  2. iqm_client-33.0.0/INTEGRATION_GUIDE.rst +228 -0
  3. iqm_client-33.0.0/MANIFEST.in +4 -0
  4. {iqm_client-32.1.1/src/iqm_client.egg-info → iqm_client-33.0.0}/PKG-INFO +4 -14
  5. iqm_client-33.0.0/docs/changelog.rst +8 -0
  6. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/index.rst +1 -2
  7. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/user_guide_cirq.rst +6 -4
  8. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/user_guide_qiskit.rst +34 -39
  9. {iqm_client-32.1.1 → iqm_client-33.0.0}/pyproject.toml +3 -4
  10. iqm_client-33.0.0/requirements/base.txt +7 -0
  11. iqm_client-33.0.0/requirements/cirq.txt +7 -0
  12. iqm_client-33.0.0/requirements/cli.txt +6 -0
  13. iqm_client-33.0.0/requirements/qiskit.in +2 -0
  14. iqm_client-33.0.0/requirements/qiskit.txt +3 -0
  15. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/iqm_device_metadata.py +2 -1
  16. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/examples/demo_common.py +1 -1
  17. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/examples/demo_iqm_execution.py +3 -3
  18. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/iqm_sampler.py +47 -29
  19. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/serialize.py +1 -1
  20. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/transpiler.py +3 -1
  21. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/iqm_client/__init__.py +0 -2
  22. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/iqm_client/errors.py +6 -17
  23. iqm_client-33.0.0/src/iqm/iqm_client/iqm_client.py +538 -0
  24. iqm_client-33.0.0/src/iqm/iqm_client/models.py +403 -0
  25. iqm_client-33.0.0/src/iqm/iqm_client/py.typed +0 -0
  26. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/iqm_client/transpile.py +11 -8
  27. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/iqm_client/validation.py +18 -9
  28. iqm_client-33.0.0/src/iqm/iqm_server_client/__init__.py +14 -0
  29. iqm_client-33.0.0/src/iqm/iqm_server_client/errors.py +6 -0
  30. iqm_client-33.0.0/src/iqm/iqm_server_client/iqm_server_client.py +755 -0
  31. iqm_client-33.0.0/src/iqm/iqm_server_client/models.py +179 -0
  32. iqm_client-33.0.0/src/iqm/iqm_server_client/py.typed +0 -0
  33. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/__init__.py +8 -0
  34. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/examples/bell_measure.py +2 -2
  35. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/examples/transpile_example.py +9 -4
  36. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_adonis.py +2 -1
  37. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_aphrodite.py +2 -1
  38. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_apollo.py +2 -1
  39. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_deneb.py +2 -1
  40. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py +8 -7
  41. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_backend.py +3 -4
  42. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_circuit_validation.py +8 -7
  43. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_job.py +106 -88
  44. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_move_layout.py +2 -1
  45. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_naive_move_pass.py +114 -55
  46. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_provider.py +49 -36
  47. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_target.py +4 -6
  48. iqm_client-33.0.0/src/iqm/qiskit_iqm/py.typed +0 -0
  49. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/qiskit_to_iqm.py +62 -25
  50. {iqm_client-32.1.1 → iqm_client-33.0.0/src/iqm_client.egg-info}/PKG-INFO +4 -14
  51. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm_client.egg-info/SOURCES.txt +8 -4
  52. iqm_client-33.0.0/src/iqm_client.egg-info/requires.txt +23 -0
  53. iqm_client-33.0.0/tests/__init__.py +0 -0
  54. iqm_client-33.0.0/tests/conftest.py +219 -0
  55. iqm_client-33.0.0/version.txt +1 -0
  56. iqm_client-32.1.1/INTEGRATION_GUIDE.rst +0 -202
  57. iqm_client-32.1.1/MANIFEST.in +0 -9
  58. iqm_client-32.1.1/docbuild +0 -1
  59. iqm_client-32.1.1/docs/changelog.rst +0 -2
  60. iqm_client-32.1.1/requirements/base.txt +0 -7
  61. iqm_client-32.1.1/requirements/cirq.txt +0 -7
  62. iqm_client-32.1.1/requirements/cli.txt +0 -8
  63. iqm_client-32.1.1/requirements/qiskit.in +0 -2
  64. iqm_client-32.1.1/requirements/qiskit.txt +0 -5
  65. iqm_client-32.1.1/src/iqm/iqm_client/api.py +0 -90
  66. iqm_client-32.1.1/src/iqm/iqm_client/authentication.py +0 -206
  67. iqm_client-32.1.1/src/iqm/iqm_client/iqm_client.py +0 -941
  68. iqm_client-32.1.1/src/iqm/iqm_client/models.py +0 -994
  69. iqm_client-32.1.1/src/iqm_client.egg-info/requires.txt +0 -33
  70. iqm_client-32.1.1/test +0 -1
  71. iqm_client-32.1.1/tests/conftest.py +0 -149
  72. iqm_client-32.1.1/version.txt +0 -1
  73. {iqm_client-32.1.1 → iqm_client-33.0.0}/AUTHORS.rst +0 -0
  74. {iqm_client-32.1.1 → iqm_client-33.0.0}/CHANGELOG_cirq-iqm.rst +0 -0
  75. {iqm_client-32.1.1 → iqm_client-33.0.0}/CHANGELOG_cortex-cli.rst +0 -0
  76. {iqm_client-32.1.1 → iqm_client-33.0.0}/CHANGELOG_qiskit-iqm.rst +0 -0
  77. {iqm_client-32.1.1 → iqm_client-33.0.0}/LICENSE.txt +0 -0
  78. {iqm_client-32.1.1 → iqm_client-33.0.0}/README.rst +0 -0
  79. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/API.rst +0 -0
  80. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/_static/images/favicon.ico +0 -0
  81. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/_static/images/logo.png +0 -0
  82. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/_templates/autosummary-class-template.rst +0 -0
  83. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/_templates/autosummary-module-template.rst +0 -0
  84. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/authors.rst +0 -0
  85. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/conf.py +0 -0
  86. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/integration_guide.rst +0 -0
  87. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/license.rst +0 -0
  88. {iqm_client-32.1.1 → iqm_client-33.0.0}/docs/readme.rst +0 -0
  89. {iqm_client-32.1.1 → iqm_client-33.0.0}/pytest.ini +0 -0
  90. {iqm_client-32.1.1 → iqm_client-33.0.0}/requirements/base.in +0 -0
  91. {iqm_client-32.1.1 → iqm_client-33.0.0}/requirements/base.in.internal +0 -0
  92. {iqm_client-32.1.1 → iqm_client-33.0.0}/requirements/cirq.in +0 -0
  93. /iqm_client-32.1.1/src/iqm/cirq_iqm/py.typed → /iqm_client-33.0.0/requirements/cirq.in.internal +0 -0
  94. {iqm_client-32.1.1 → iqm_client-33.0.0}/requirements/cli.in +0 -0
  95. /iqm_client-32.1.1/src/iqm/iqm_client/py.typed → /iqm_client-33.0.0/requirements/cli.in.internal +0 -0
  96. /iqm_client-32.1.1/src/iqm/qiskit_iqm/py.typed → /iqm_client-33.0.0/requirements/qiskit.in.internal +0 -0
  97. {iqm_client-32.1.1 → iqm_client-33.0.0}/setup.cfg +0 -0
  98. {iqm_client-32.1.1 → iqm_client-33.0.0}/setup.py +0 -0
  99. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/__init__.py +0 -0
  100. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/__init__.py +0 -0
  101. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/adonis.py +0 -0
  102. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/aphrodite.py +0 -0
  103. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/apollo.py +0 -0
  104. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/devices/iqm_device.py +0 -0
  105. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/examples/demo_adonis.py +0 -0
  106. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/examples/demo_apollo.py +0 -0
  107. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/examples/usage.ipynb +0 -0
  108. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/extended_qasm_parser.py +0 -0
  109. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/iqm_gates.py +0 -0
  110. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/cirq_iqm/optimizers.py +0 -0
  111. /iqm_client-32.1.1/tests/__init__.py → /iqm_client-33.0.0/src/iqm/cirq_iqm/py.typed +0 -0
  112. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/iqm_client/util.py +0 -0
  113. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/examples/__init__.py +0 -0
  114. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/__init__.py +0 -0
  115. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_garnet.py +0 -0
  116. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_circuit.py +0 -0
  117. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/iqm_transpilation.py +0 -0
  118. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/move_gate.py +0 -0
  119. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm/qiskit_iqm/transpiler_plugins.py +0 -0
  120. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm_client.egg-info/dependency_links.txt +0 -0
  121. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm_client.egg-info/entry_points.txt +0 -0
  122. {iqm_client-32.1.1 → iqm_client-33.0.0}/src/iqm_client.egg-info/top_level.txt +0 -0
@@ -1,11 +1,48 @@
1
- =========
2
- Changelog
3
- =========
4
-
5
- Version 32.1.1 (2025-10-27)
1
+ Version 33.0.0 (2025-11-19)
6
2
  ===========================
7
3
 
8
- - Bump version for 4.3.1 release. No functional changes.
4
+ Breaking changes
5
+ ----------------
6
+
7
+ - :class:`.IQMClient` now connects to IQM Server instead of directly to Station Control service.
8
+ - The ``url`` init parameter for :class:`.IQMClient` is replaced by ``iqm_server_url``.
9
+ In addition the class can take the ``quantum_computer`` parameter to connect to a specific
10
+ quantum computer on a server with several. If your IQM Server instance only has one quantum computer,
11
+ you can leave this parameter to its default value.
12
+ - The ``timeout_secs`` parameter is removed for all :class:`.IQMClient` methods, value from the
13
+ :envvar:`IQM_CLIENT_REQUESTS_TIMEOUT` environment variable is used instead (default 120 seconds).
14
+ - :meth:`IQMClient.get_quality_metric_set` and :meth:`IQMClient.get_calibration_set` now return
15
+ slightly different data models with more complete observation data.
16
+ - Circuit and job related models have been moved to :mod:`iqm.station_control.interface.models`
17
+ from IQM client models, to avoid code duplication and use the same models in all SW
18
+ components. Imports have to be updated.
19
+ - :meth:`IQMClient.submit_circuits` no longer has the parameter ``custom_settings``. Use Pulla if
20
+ you need this functionalty.
21
+ - :meth:`IQMClient.submit_circuits` and :meth:`IQMClient.submit_run_request` now return a
22
+ :class:`.CircuitJob` object instead of the plain job ID. The job object contains the job ID,
23
+ and provides methods for monitoring the job's state and retrieving its results.
24
+ - :meth:`IQMClient.get_run` is replaced by :meth:`IQMClient.get_job`, which returns a
25
+ :class:`.CircuitJob` object. The job results can be queried using :class:`CircuitJob.result`.
26
+ - :meth:`IQMClient.get_run_status` is removed, you can check the job object for its status using
27
+ :class:`CircuitJob.update`.
28
+ - :meth:`IQMClient.wait_for_compilation` and :meth:`IQMClient.wait_for_results` are removed,
29
+ use :class:`CircuitJob.wait_for_completion` instead.
30
+ - :meth:`IQMClient.get_run_counts` is replaced by :meth:`IQMClient.get_job_measurement_counts`.
31
+ - :meth:`IQMClient.abort_job` is replaced by :meth:`IQMClient.cancel_job`.
32
+ - The :mod:`iqm.iqm_server_client.authentication` module including :class:`TokenManager` has been moved to
33
+ :mod:`iqm.station_control.client.authentication`, and its API has slightly changed.
34
+
35
+ Features
36
+ --------
37
+
38
+ - ``iqm-client`` integration guide updated.
39
+ - :meth:`IQMClient.submit_circuits` and :meth:`IQMClient.submit_run_request` have a new parameter,
40
+ ``use_timeslot``, which indicates if the job should be submitted to a timeslot queue or the
41
+ shared on-demand queue.
42
+ - Minimal changes to support Qiskit v2.0 and v2.1 :issue:`SW-1735`.
43
+ - Deprecation warning for Qiskit versions < 2.0.
44
+ - Bugfix in the transpile example to select qubits from the largest connected subgraph of the backend so that the code works when running against a disconnected graph.
45
+ - Identified potential bug with semantic equivalence of transpiled circuits when using the IQMNaiveMovePass. Tests are temporarily marked as expected to fail. :issue:`SW-1999`.
9
46
 
10
47
  Version 32.1.0 (2025-10-13)
11
48
  ===========================
@@ -478,7 +515,7 @@ Version 23.1.0 (2025-04-07)
478
515
  Features
479
516
  --------
480
517
 
481
- - Fix package version in published docs footers, :issue:`SW-1392`.
518
+ - Fix package version in published docs footers, :issue:`SW-1392`.
482
519
 
483
520
  Version 23.0.0 (2025-04-04)
484
521
  ===========================
@@ -0,0 +1,228 @@
1
+ =================
2
+ Integration Guide
3
+ =================
4
+
5
+ ``iqm-client`` is the Python client for connecting to IQM's quantum computers, for application-level
6
+ quantum computing frameworks. For examples of integrations maintained by IQM, please refer to the
7
+ :ref:`Qiskit <User guide Qiskit>` and :ref:`Cirq <User guide Cirq>` packages.
8
+
9
+ IQM client offers the functionality to submit quantum circuit execution jobs to the quantum computer,
10
+ track the statuses of jobs, and query various properties of the quantum computer.
11
+
12
+ The following sections illustrate how to integrate IQM quantum computers into your quantum computing
13
+ framework.
14
+
15
+
16
+ Authentication
17
+ --------------
18
+
19
+ IQM uses bearer token authentication to manage access to quantum computers.
20
+ Get your personal API token from the IQM Server web dashboard. The generated token can be provided to
21
+ IQM client via an environment variable :envvar:`IQM_TOKEN`.
22
+ Alternatively, the token can be provided as the ``token`` argument to :class:`.IQMClient` constructor.
23
+
24
+
25
+ Code example
26
+ ------------
27
+
28
+ The connection to an IQM Server instance is managed by an :class:`.IQMClient` instance.
29
+ Initialization is simple, and in case you perform the authentication
30
+ using the :envvar:`IQM_TOKEN` environment variable, it only requires the URL of IQM Server:
31
+
32
+ .. code-block:: python
33
+
34
+ from iqm.iqm_client import IQMClient
35
+
36
+ server_url = "https://<IQM_SERVER_URL>"
37
+ iqm_client = IQMClient(server_url)
38
+
39
+ To submit a quantum circuit for execution, it has to be specified using the
40
+ :class:`iqm.pulse.Circuit` class. The available native instructions are documented in
41
+ :mod:`iqm.iqm_client.models` and in :class:`iqm.pulse.CircuitOperation`.
42
+
43
+ .. code-block:: python
44
+
45
+ from math import pi
46
+
47
+ from iqm.pulse.builder import CircuitOperation
48
+ from iqm.pulse.circuit_operations import Circuit
49
+
50
+ instructions = (
51
+ CircuitOperation(
52
+ name="prx", locus=("QB1",), args={"phase": 1.4 * pi, "angle": 0.5 * pi}
53
+ ),
54
+ CircuitOperation(name="cz", locus=("QB1", "QB2"), args={}),
55
+ CircuitOperation(name="measure", locus=("QB2",), args={"key": "Qubit 2"}),
56
+ )
57
+
58
+ circuit = Circuit(name="quantum_circuit", instructions=instructions)
59
+
60
+ Then the circuit(s) can be submitted to the server using :meth:`.IQMClient.submit_circuits`.
61
+ Upon successful submission the method returns a :class:`.CircuitJob` object that can be used
62
+ to track the progress of the job. This is a convenience, the only thing that is really needed
63
+ to access the job on IQM Server is the unique job ID in :attr:`.CircuitJob.job_id`.
64
+ You can pass the job ID to :meth:`.IQMClient.get_job` to get a new :class:`.CircuitJob` object for the job.
65
+
66
+ To query the status of the job, use :meth:`.CircuitJob.update`. It will update the job object and
67
+ return its current status. The different job statuses are documented in :class:`.JobStatus`.
68
+
69
+ .. code-block:: python
70
+
71
+ job = iqm_client.submit_circuits([circuit], shots=1000)
72
+ print(job.job_id)
73
+
74
+ job_status = job.update()
75
+ print(job_status)
76
+
77
+
78
+ Eventually the job will end up in one of the terminal statuses:
79
+ ``"completed"``, ``"failed"``, or ``"cancelled"``.
80
+ You can either periodically query the status, or use :meth:`.CircuitJob.wait_for_completion`
81
+ which will block and poll the job status until it hits a terminal status, which is then returned.
82
+
83
+ When the status is ``"completed"``, you can use :meth:`.CircuitJob.result` to get the job results:
84
+
85
+ .. code-block:: python
86
+
87
+ job_status = job.wait_for_completion()
88
+ print(job_status)
89
+ job_result = job.result()
90
+
91
+ A job can be cancelled by calling :meth:`.CircuitJob.cancel`.
92
+
93
+
94
+ Job payload
95
+ -----------
96
+
97
+ A ``dict[str, Any]`` containing arbitrary metadata can be attached to :class:`iqm.pulse.Circuit`
98
+ before submitting it for execution.
99
+ The attached metadata should consist only of values of JSON serializable datatypes.
100
+ A utility function :func:`~.iqm_client.util.to_json_dict` can be used to convert supported datatypes,
101
+ e.g. :class:`numpy.ndarray`, to equivalent JSON serializable types.
102
+
103
+ The server stores the job payload (including the metadata), and it can be queried using
104
+ :meth:`.CircuitJob.payload`, which returns the submitted circuits (with their metadata), and
105
+ the various job parameters used.
106
+
107
+
108
+ Job metadata and errors
109
+ -----------------------
110
+
111
+ The server attaches its own metadata to the job, including details related to the compilation
112
+ and execution of the job. Important metadata items include
113
+
114
+ * :attr:`.CircuitJob.data.errors`: list of errors for a ``"failed"`` job
115
+ * :attr:`.CircuitJob.data.messages`: list of informational messages
116
+ * :attr:`.CircuitJob.data.timeline`: list of execution steps reached with their timestamps
117
+ * :attr:`.CircuitJob.data.compilation.calibration_set_id`: ID of the calibration set used in the execution
118
+
119
+
120
+ Job timeline
121
+ ~~~~~~~~~~~~
122
+
123
+ Each item in :attr:`.CircuitJob.data.timeline` is a :class:`.TimelineEntry`,
124
+ containing an execution step reached, a timestamp, and the source of the entry.
125
+ The steps in the timeline are more detailed than the job statuses.
126
+ For example, when the job is accepted, IQM Server adds a timestamp with the status ``"created"``.
127
+
128
+ The timeline entries also contain information about the lower-level job processing steps by
129
+ Station Control. For example, before the circuits can be executed they are compiled into instruction
130
+ schedules, indicated by the ``"compilation_started"`` and ``"compilation_ended"`` timestamps.
131
+ The actual execution of the job on the quantum hardware is indicated by the
132
+ ``"execution_started"`` and ``"execution_ended"`` timestamps.
133
+
134
+
135
+ Circuit transpilation
136
+ ---------------------
137
+
138
+ IQM does not provide an open source circuit transpilation library, so this will have to be supplied
139
+ by the quantum computing framework or a third party library. To obtain the necessary information
140
+ for circuit transpilation, :meth:`.IQMClient.get_dynamic_quantum_architecture` returns the names of the
141
+ QPU components (qubits and computational resonators), and the native operations available
142
+ in the given calibration set. This information should enable circuit transpilation for the
143
+ IQM Crystal quantum architectures.
144
+
145
+ The notable exception is the transpilation for the IQM Star quantum architectures, which have
146
+ computational resonators in addition to qubits. Some specialized transpilation logic involving
147
+ the MOVE gates specific to these architectures is provided, in the form of the functions
148
+ :func:`.transpile_insert_moves` and :func:`.transpile_remove_moves`.
149
+ See :mod:`iqm.iqm_client.transpile` for the details.
150
+
151
+ A typical Star architecture use case would look something like this:
152
+
153
+ .. code-block:: python
154
+
155
+ from iqm.iqm_client import IQMClient, simplify_architecture, transpile_insert_moves, transpile_remove_moves
156
+ from iqm.pulse.circuit_operations import Circuit
157
+
158
+ client = IQMClient(URL_TO_STAR_SERVER)
159
+ dqa = client.get_dynamic_quantum_architecture()
160
+ simplified_dqa = simplify_architecture(dqa)
161
+
162
+ # circuit valid for simplified_dqa
163
+ circuit = Circuit(name="quantum_circuit", instructions=[...])
164
+
165
+ # intended use
166
+ circuit_with_moves = transpile_insert_moves(circuit, dqa)
167
+ job = client.submit_circuits([circuit_with_moves])
168
+
169
+ # back to simplified dqa
170
+ circuit_without_moves = transpile_remove_moves(circuit_with_moves)
171
+ # circuit_without_moves is equivalent to circuit
172
+
173
+
174
+ Note on qubit mapping
175
+ ---------------------
176
+
177
+ We encourage to transpile circuits to use the physical IQM qubit names before submitting them to IQM
178
+ quantum computers. In case the quantum computing framework does not allow for this, providing a
179
+ qubit mapping can do the translation from the framework qubit names to IQM qubit names. Note that
180
+ qubit mapping is not supposed to be associated with individual circuits, but rather with the entire
181
+ job request to IQM Server. Typically, you would have some local representation of the QPU and
182
+ transpile the circuits against that representation, then use qubit mapping along with the generated
183
+ circuits to map from the local representation to the IQM representation of qubit names.
184
+ We discourage exposing this feature to end users of the quantum computing framework.
185
+
186
+ Note on circuit duration check
187
+ ------------------------------
188
+
189
+ Before performing circuit execution, IQM Server checks how long it would take to run each circuit.
190
+ If any circuit in a job would take too long to execute compared to the T2 time of the qubits,
191
+ the server will disqualify the job, not execute any circuits, and return a detailed error message.
192
+ In some special cases, it makes sense to adjust or disable this check using
193
+ the :attr:`max_circuit_duration_over_t2` attribute of :class:`.CircuitCompilationOptions`,
194
+ and then passing the options to :meth:`.IQMClient.submit_circuits`.
195
+
196
+ Note on environment variables
197
+ -----------------------------
198
+
199
+ Set :envvar:`IQM_CLIENT_REQUESTS_TIMEOUT` environment variable to override the network request
200
+ default timeout value (in seconds) for :class:`.IQMClient` methods. The default value is 120
201
+ seconds and might not be sufficient e.g. when fetching the results of a larger circuit job through
202
+ a slow network connection.
203
+
204
+ On Linux:
205
+
206
+ .. code-block:: bash
207
+
208
+ $ export IQM_CLIENT_REQUESTS_TIMEOUT=300
209
+
210
+ On Windows:
211
+
212
+ .. code-block:: batch
213
+
214
+ set IQM_CLIENT_REQUESTS_TIMEOUT=300
215
+
216
+ Set :envvar:`IQM_CLIENT_SECONDS_BETWEEN_CALLS` to control the polling interval (in seconds) when
217
+ waiting for a job to complete with :meth:`.CircuitJob.wait_for_completion`.
218
+ The default value is 1 second.
219
+
220
+ Set :envvar:`IQM_CLIENT_DEBUG=1` to print the run request when it is submitted for execution in
221
+ :meth:`.IQMClient.submit_circuits` or :meth:`.IQMClient.submit_run_request`. To inspect the run
222
+ request without sending it for execution, use :meth:`.IQMClient.create_run_request`.
223
+
224
+ Integration testing
225
+ -------------------
226
+
227
+ IQM provides a demo environment to test the integration against a mock quantum computer. If you'd
228
+ like to request access to that environment, please contact `IQM <info@meetiqm.com>`_.
@@ -0,0 +1,4 @@
1
+ include version.txt
2
+ include LICENSE.txt
3
+ prune tests/*
4
+ exclude .gitlab-ci.yml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-client
3
- Version: 32.1.1
3
+ Version: 33.0.0
4
4
  Summary: Client library for accessing an IQM quantum computer
5
5
  Author-email: IQM Finland Oy <developers@meetiqm.com>
6
6
  License: Apache License
@@ -216,35 +216,25 @@ Requires-Python: <3.13,>=3.10
216
216
  Description-Content-Type: text/x-rst
217
217
  License-File: LICENSE.txt
218
218
  License-File: AUTHORS.rst
219
- Requires-Dist: iqm-station-control-client<12,>=11
220
- Requires-Dist: iqm-exa-common<28,>=27
221
- Requires-Dist: iqm-pulse<13,>=12
222
219
  Requires-Dist: numpy<3.0,>=1.26.4
223
220
  Requires-Dist: packaging==24.1
224
221
  Requires-Dist: pydantic<3.0,>=2.9.2
225
222
  Requires-Dist: requests==2.32.3
223
+ Requires-Dist: iqm-pulse
224
+ Requires-Dist: iqm-station-control-client
226
225
  Provides-Extra: cirq
227
- Requires-Dist: iqm-station-control-client<12,>=11; extra == "cirq"
228
- Requires-Dist: iqm-exa-common<28,>=27; extra == "cirq"
229
- Requires-Dist: iqm-pulse<13,>=12; extra == "cirq"
230
226
  Requires-Dist: cirq-core[contrib]~=1.2; extra == "cirq"
231
227
  Requires-Dist: ply==3.11; extra == "cirq"
232
228
  Requires-Dist: llvmlite>=0.44.0; extra == "cirq"
233
229
  Requires-Dist: numba>=0.61.0; extra == "cirq"
234
230
  Provides-Extra: cli
235
- Requires-Dist: iqm-station-control-client<12,>=11; extra == "cli"
236
- Requires-Dist: iqm-exa-common<28,>=27; extra == "cli"
237
- Requires-Dist: iqm-pulse<13,>=12; extra == "cli"
238
231
  Requires-Dist: click<9,>=8.1.6; extra == "cli"
239
232
  Requires-Dist: jsonschema>=4.6.0; extra == "cli"
240
233
  Requires-Dist: psutil>=5.9.2; extra == "cli"
241
234
  Requires-Dist: types-psutil; extra == "cli"
242
235
  Requires-Dist: python-daemon>=2.3.0; extra == "cli"
243
236
  Provides-Extra: qiskit
244
- Requires-Dist: iqm-station-control-client<12,>=11; extra == "qiskit"
245
- Requires-Dist: iqm-exa-common<28,>=27; extra == "qiskit"
246
- Requires-Dist: iqm-pulse<13,>=12; extra == "qiskit"
247
- Requires-Dist: qiskit<=1.4.2,>=1.0; extra == "qiskit"
237
+ Requires-Dist: qiskit<2.2,>=1.0; extra == "qiskit"
248
238
  Requires-Dist: qiskit-aer<0.18,>=0.13.1; extra == "qiskit"
249
239
 
250
240
  IQM Client
@@ -0,0 +1,8 @@
1
+ .. _changelog:
2
+
3
+ =========
4
+ CHANGELOG
5
+ =========
6
+
7
+ .. include:: ../CHANGELOG.rst
8
+ :literal:
@@ -21,14 +21,13 @@ Contents
21
21
  integration_guide
22
22
  user_guide_qiskit
23
23
  user_guide_cirq
24
+ changelog
24
25
  license
25
26
  authors
26
27
 
27
28
  .. toctree::
28
29
  :maxdepth: 1
29
30
 
30
- changelog
31
-
32
31
 
33
32
  Indices and tables
34
33
  ==================
@@ -349,7 +349,7 @@ In this subsection we demonstrate how to run them on an IQM quantum computer.
349
349
 
350
350
  Cirq on IQM provides :class:`.IQMSampler`, a subclass of :class:`cirq.work.Sampler`, which is used
351
351
  to execute quantum circuits and decompose/route them for the architecture of the quantum computer.
352
- Once you have access to an IQM server you can create an :class:`.IQMSampler` instance and use its
352
+ Once you have access to an IQM Server you can create an :class:`.IQMSampler` instance and use its
353
353
  :meth:`~.IQMSampler.run` method to send a circuit for execution and retrieve the results:
354
354
 
355
355
  .. code-block:: python
@@ -358,7 +358,7 @@ Once you have access to an IQM server you can create an :class:`.IQMSampler` ins
358
358
 
359
359
  # circuit = ...
360
360
 
361
- sampler = IQMSampler(iqm_server_url)
361
+ sampler = IQMSampler(iqm_server_url, quantum_computer=quantum_computer)
362
362
  routed_circuit, _, _ = sampler.device.route_circuit(circuit)
363
363
  decomposed_circuit = sampler.device.decompose_circuit(routed_circuit)
364
364
  result = sampler.run(decomposed_circuit, repetitions=10)
@@ -366,7 +366,9 @@ Once you have access to an IQM server you can create an :class:`.IQMSampler` ins
366
366
 
367
367
 
368
368
  Note that the code snippet above assumes that you have set the variable ``iqm_server_url`` to the URL
369
- of the IQM server. Additionally, you can pass IQM backend specific options to the :class:`.IQMSampler` class.
369
+ of the IQM Server, and ``quantum_computer`` to the name of the quantum computer to use, if the IQM Server
370
+ has several. Leave it to ``None`` to use the default (or only) quantum computer of the server.
371
+ Additionally, you can pass IQM backend specific options to the :class:`.IQMSampler` class.
370
372
  The below table summarises the currently available options:
371
373
 
372
374
 
@@ -381,7 +383,7 @@ The below table summarises the currently available options:
381
383
  * - :attr:`calibration_set_id`
382
384
  - :class:`uuid.UUID`
383
385
  - "f7d9642e-b0ca-4f2d-af2a-30195bd7a76d"
384
- - Indicates the calibration set to use. Defaults to ``None``, which means the IQM server will use the
386
+ - Indicates the calibration set to use. Defaults to ``None``, which means the IQM Server will use the
385
387
  current default calibration set automatically.
386
388
  * - :attr:`compiler_options`
387
389
  - :class:`~iqm.iqm_client.models.CircuitCompilationOptions`
@@ -31,7 +31,7 @@ things are set up correctly.
31
31
  (Save Page As...)
32
32
  5. Install Qiskit on IQM as instructed below.
33
33
  6. Run the Jupyter notebook (or run
34
- ``python bell_measure.py --url https://<IQM server URL>``
34
+ ``python bell_measure.py --url https://<IQM Server URL>``
35
35
  if you decided to go for the Python script).
36
36
  7. If you're connecting to a real quantum computer, the output should show almost half of the
37
37
  measurements resulting in '00000' and almost half in '11111' - if this is the case, things are
@@ -115,7 +115,8 @@ Let's consider the following quantum circuit which prepares and measures a GHZ s
115
115
 
116
116
 
117
117
  To run this circuit on an IQM quantum computer you need to initialize an :class:`.IQMProvider`
118
- instance with the IQM server URL, use it to retrieve an :class:`.IQMBackend` instance representing
118
+ instance with the IQM Server URL (and possibly a quantum computer name, if there are several),
119
+ use it to retrieve an :class:`.IQMBackend` instance representing
119
120
  the quantum computer, and use Qiskit's :func:`~qiskit.compiler.transpile` function
120
121
  followed by :meth:`.IQMBackend.run` as usual. ``shots`` denotes the number of times the quantum
121
122
  circuit(s) are sampled:
@@ -126,7 +127,8 @@ circuit(s) are sampled:
126
127
  from iqm.qiskit_iqm import IQMProvider
127
128
 
128
129
  iqm_server_url = "https://<IQM SERVER>" # Replace this with the correct URL
129
- provider = IQMProvider(iqm_server_url)
130
+ quantum_computer = "<NAME>"
131
+ provider = IQMProvider(iqm_server_url, quantum_computer=quantum_computer)
130
132
  backend = provider.get_backend()
131
133
 
132
134
  transpiled_circuit = transpile(circuit, backend=backend)
@@ -151,8 +153,7 @@ circuit(s) are sampled:
151
153
  As of ``iqm-client >= 30.1.0``, structured quality metrics and calibration data are available to
152
154
  ``IQMTarget`` for improved transpilation. To import the latest valid quality metric data corresponding
153
155
  to the default calibration set into ``IQMTarget``, set ``use_metrics`` to ``True`` when initializing the
154
- class. For Resonance users, this data is not yet available via the Resonance API, so use the default setting
155
- of ``use_metrics`` of ``False``.
156
+ class.
156
157
 
157
158
  You can optionally provide IQMBackend specific options as additional keyword arguments to
158
159
  :meth:`.IQMBackend.run`, documented at :meth:`.IQMBackend.create_run_request`.
@@ -189,48 +190,42 @@ The results of a job that was executed on the IQM quantum computer, represented
189
190
  print(result.get_counts())
190
191
  print(result.get_memory())
191
192
 
192
- The result comes with some metadata, such as the :class:`~iqm.iqm_client.models.RunRequest` that
193
- produced it in ``result.request``. The request contains e.g. the qubit mapping and the ID of the
194
- calibration set that were used in the execution:
193
+ The result comes with some metadata, such as the contents of the request that
194
+ produced it. The executed circuit batch (in the native IQM format) can be found in ``result.circuits``,
195
+ and various execution parameters can be found in ``result.parameters``:
195
196
 
196
197
  .. code-block:: python
197
198
 
198
- print(result.request.qubit_mapping)
199
- print(result.request.calibration_set_id)
199
+ print(result.parameters.shots)
200
+ print(result.parameters.calibration_set_id)
200
201
 
201
202
  ::
202
203
 
203
- [
204
- SingleQubitMapping(logical_name='0', physical_name='QB1'),
205
- SingleQubitMapping(logical_name='1', physical_name='QB2'),
206
- SingleQubitMapping(logical_name='2', physical_name='QB3')
207
- ]
204
+ 1000
208
205
  1320eae6-f4e2-424d-b299-ef82d556d2c3
209
206
 
210
207
  Another piece of useful metadata are the timestamps of the various steps of processing the job. The
211
- timestamps are stored in the dict ``result.timestamps``. The job processing has three steps,
208
+ timestamps are stored in the list ``result.timeline``. The actual job processing has three main steps,
212
209
 
213
- * ``compile`` where the circuits are converted to instruction schedules,
214
- * ``submit`` where the instruction schedules are submitted for execution, and
215
- * ``execution`` where the instruction schedules are executed and the measurement results are returned.
210
+ * ``compilation`` where the circuits are converted to instruction schedules,
211
+ * ``execution`` where the instruction schedules are executed and the measurement results are returned, and
212
+ * ``post_processing`` where the results are converted to the format expected by the client.
216
213
 
217
- The dict contains a timestamp for the start and end of each step.
218
- For example, the timestamp of starting the circuit compilation is stored with key ``compile_start``.
219
- In the same way the other steps have their own timestamps with keys consisting of the step name and a ``_start`` or
220
- ``_end`` suffix. In addition to processing step timestamps, there are also timestamps for the job itself,
221
- ``job_start`` for when the job request was received by the server and ``job_end`` for when the job processing
214
+ The list contains a timestamp for the start and end of each step.
215
+ For example, the timestamp of starting the circuit compilation is stored with the status ``compilation_started``.
216
+ In the same way the other steps have their own timestamps with statuses consisting of the step name and a ``_started``
217
+ or ``_ended`` suffix. In addition to processing step timestamps, there are also timestamps for the job itself,
218
+ ``created`` for when the job request was accepted by the server and ``completed`` for when the job processing
222
219
  was finished.
223
220
 
224
221
  If the processing of the job is terminated before it is complete, for example due to an error, the timestamps of
225
- processing steps that were not taken are not present in the dict.
222
+ processing steps that were not taken are not present.
226
223
 
227
224
  For example:
228
225
 
229
226
  .. code-block:: python
230
227
 
231
- print(result.timestamps['job_start'])
232
- print(result.timestamps['compile_start'])
233
- print(result.timestamps['execution_end'])
228
+ print(result.timeline)
234
229
 
235
230
 
236
231
  Backend properties
@@ -453,7 +448,7 @@ Starting from the :ref:`GHZ circuit <GHZ_circuit>` we created above:
453
448
  from qiskit.compiler import transpile
454
449
  from iqm.qiskit_iqm import IQMProvider
455
450
 
456
- resonator_backend = IQMProvider("https://cocos.resonance.meetiqm.com/deneb").get_backend()
451
+ resonator_backend = IQMProvider("https://resonance.meetiqm.com", quantum_computer="sirius").get_backend()
457
452
  transpiled_circuit = transpile(circuit, resonator_backend)
458
453
 
459
454
  print(transpiled_circuit.draw(output='text', idle_wires=False))
@@ -705,17 +700,16 @@ a copy of the IQMFakeBackend instance with an updated error profile:
705
700
  Running a quantum circuit on a facade backend
706
701
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
707
702
 
708
- Circuits can be executed against a *mock environment*: an IQM server that has no real quantum computer hardware.
703
+ Circuits can be executed against a *mock environment*: an IQM Server that has no real quantum computer hardware.
709
704
  Results from such executions are just random bits. This may be useful when developing and testing software integrations.
710
705
 
711
706
  .. note::
712
707
 
713
708
  IQM Resonance typically provides a mock environment for each real quantum computer it has.
714
- For example, the URL
715
- https://cocos.resonance.meetiqm.com/garnet refers to a real quantum computer named Garnet,
716
- whereas https://cocos.resonance.meetiqm.com/garnet:mock refers to the corresponding mock environment.
709
+ For example, the name ``"garnet"`` refers to a real quantum computer named Garnet, whereas
710
+ ``"garnet:mock"`` refers to the corresponding mock environment.
717
711
 
718
- On-premises users should ask their admin whether a mock environment is available, and which IQM server
712
+ On-premises users should ask their admin whether a mock environment is available, and which IQM Server
719
713
  URL to use.
720
714
 
721
715
  Qiskit on IQM contains :class:`.IQMFacadeBackend`, which allows to combine a mock remote execution with a local
@@ -733,7 +727,7 @@ static quantum architecture (i.e. names of qubits, their connectivity, and the n
733
727
 
734
728
  .. important::
735
729
 
736
- When using a facade backend, the IQM server URL of :class:`IQMProvider` should always point to a mock environment
730
+ When using a facade backend, the IQM Server URL of :class:`IQMProvider` should always point to a mock environment
737
731
  rather than a real quantum computer, as the execution results from the server will be discarded and replaced by
738
732
  a locally simulated result generated by Qiskit Aer. If you use a real quantum computer with a facade backend,
739
733
  you will just waste your credits and/or computation time.
@@ -749,8 +743,9 @@ static quantum architecture (i.e. names of qubits, their connectivity, and the n
749
743
  circuit.cx(0, 1)
750
744
  circuit.measure_all()
751
745
 
752
- iqm_server_url = "https://cocos.resonance.meetiqm.com/garnet:mock" # Replace this with the correct mock env URL
753
- provider = IQMProvider(iqm_server_url)
746
+ iqm_server_url = "https://resonance.meetiqm.com"
747
+ quantum_computer = "garnet:mock" # Replace this with the correct mock env name
748
+ provider = IQMProvider(iqm_server_url, quantum_computer=quantum_computer)
754
749
  backend = provider.get_backend('facade_garnet')
755
750
  transpiled_circuit = transpile(circuit, backend=backend)
756
751
  job = backend.run(transpiled_circuit, shots=1000)
@@ -759,7 +754,7 @@ static quantum architecture (i.e. names of qubits, their connectivity, and the n
759
754
  .. note::
760
755
 
761
756
  When a classical register is added to the circuit, Qiskit fills it with classical bits of value 0 by default. If the
762
- register is not used later, and the circuit is submitted to the IQM server, the results will not contain those
763
- 0-filled bits. To make sure the facade backend returns results in the same format as a real IQM server,
757
+ register is not used later, and the circuit is submitted to the IQM Server, the results will not contain those
758
+ 0-filled bits. To make sure the facade backend returns results in the same format as a real IQM Server,
764
759
  :meth:`.IQMFacadeBackend.run` checks for the presence of unused classical registers, and fails with an error if there
765
760
  are any.
@@ -1,4 +1,3 @@
1
- # This file is managed by monotool.py, do not edit by hand
2
1
  [build-system]
3
2
  build-backend = "setuptools.build_meta"
4
3
  requires = [ "setuptools", "setuptools_scm[toml]",]
@@ -77,7 +76,7 @@ nb_diff_ignore = [ "/metadata/language_info", "/metadata/widgets", "/cells/*/exe
77
76
 
78
77
  [tool.ruff.lint]
79
78
  ignore = [ "D203", "D213",]
80
- select = [ "E4", "E7", "E9", "E5", "F", "Q", "PL", "I", "D", "UP007", "UP006", "UP035", "ANN001", "ANN201", "ANN202",]
79
+ select = [ "E4", "E7", "E9", "E5", "F", "Q", "PL", "I", "D", "UP007", "UP006", "UP035", "ANN001", "ANN201", "ANN202", "NPY201",]
81
80
  unfixable = [ "F401",]
82
81
 
83
82
  [tool.ruff.lint.isort]
@@ -88,10 +87,10 @@ known-third-party = [ "exa", "iqm",]
88
87
  relative-imports-order = "closest-to-furthest"
89
88
 
90
89
  [tool.ruff.lint.per-file-ignores]
91
- "**/__init__.py" = [ "F401", "PLR0402",]
90
+ "**/__init__.py" = [ "D104", "F401", "PLR0402",]
92
91
  "**/docs/*" = [ "E402", "D100",]
93
92
  "**/setup.py" = [ "D100", "D103", "I001", "ANN201",]
94
- "**/src/*" = [ "PLR2004", "D400", "D415", "D205", "D401", "D417", "D100", "D101", "D107", "D102", "D105", "D103", "D404", "D104",]
93
+ "**/src/*" = [ "PLR2004", "D400", "D415", "D205", "D401", "D417", "D100", "D107", "D105", "D102", "D404",]
95
94
  "**/tests/*" = [ "F632", "PLR2004", "PLR0402", "PLC0414", "D", "ANN001", "ANN201", "ANN202",]
96
95
 
97
96
  [tool.ruff.lint.pylint]
@@ -0,0 +1,7 @@
1
+ numpy >= 1.26.4, < 3.0
2
+ packaging == 24.1
3
+ pydantic >= 2.9.2, <3.0
4
+ requests == 2.32.3
5
+
6
+ iqm-pulse
7
+ iqm-station-control-client
@@ -0,0 +1,7 @@
1
+ cirq-core[contrib] ~= 1.2
2
+ ply == 3.11 # Required by cirq.contrib.qasm_import
3
+
4
+ # needed to avoid build errors
5
+ llvmlite >= 0.44.0
6
+ numba >= 0.61.0
7
+
@@ -0,0 +1,6 @@
1
+ click >= 8.1.6, < 9
2
+ jsonschema >= 4.6.0
3
+ psutil >= 5.9.2
4
+ types-psutil
5
+ python-daemon >= 2.3.0
6
+
@@ -0,0 +1,2 @@
1
+ qiskit >= 1.0, < 2.2
2
+ qiskit-aer >= 0.13.1, < 0.18
@@ -0,0 +1,3 @@
1
+ qiskit >= 1.0, < 2.2
2
+ qiskit-aer >= 0.13.1, < 0.18
3
+
@@ -20,9 +20,10 @@ from collections.abc import Iterable
20
20
  import cirq
21
21
  from cirq import Gate, NamedQid, devices, ops
22
22
  from iqm.cirq_iqm.serialize import _IQM_CIRQ_OP_MAP
23
- from iqm.iqm_client import DynamicQuantumArchitecture
24
23
  import networkx as nx
25
24
 
25
+ from iqm.station_control.interface.models import DynamicQuantumArchitecture
26
+
26
27
 
27
28
  @cirq.value.value_equality
28
29
  class IQMDeviceMetadata(devices.DeviceMetadata):