iqm-client 30.1.0__tar.gz → 31.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 (110) hide show
  1. {iqm_client-30.1.0 → iqm_client-31.0.0}/CHANGELOG.rst +22 -0
  2. {iqm_client-30.1.0 → iqm_client-31.0.0}/INTEGRATION_GUIDE.rst +13 -8
  3. {iqm_client-30.1.0 → iqm_client-31.0.0}/PKG-INFO +5 -1
  4. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/conf.py +9 -2
  5. {iqm_client-30.1.0 → iqm_client-31.0.0}/pyproject.toml +3 -3
  6. iqm_client-31.0.0/requirements/base.in.internal +2 -0
  7. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/base.txt +1 -0
  8. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/cirq.txt +1 -0
  9. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/cli.txt +1 -0
  10. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/qiskit.txt +1 -0
  11. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/iqm_device.py +1 -1
  12. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/iqm_device_metadata.py +1 -1
  13. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/iqm_sampler.py +1 -1
  14. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/optimizers.py +1 -1
  15. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/serialize.py +50 -41
  16. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/cli/cli.py +3 -3
  17. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/iqm_client.py +1 -1
  18. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/models.py +152 -361
  19. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/transpile.py +37 -31
  20. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/util.py +1 -1
  21. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/validation.py +23 -19
  22. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_circuit.py +1 -1
  23. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_circuit_validation.py +1 -1
  24. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_job.py +3 -2
  25. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_move_layout.py +3 -3
  26. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_provider.py +2 -1
  27. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_target.py +1 -1
  28. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_transpilation.py +2 -2
  29. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/move_gate.py +2 -2
  30. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/qiskit_to_iqm.py +32 -31
  31. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/transpiler_plugins.py +2 -2
  32. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/PKG-INFO +5 -1
  33. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/requires.txt +4 -0
  34. iqm_client-31.0.0/version.txt +1 -0
  35. iqm_client-30.1.0/requirements/base.in.internal +0 -1
  36. iqm_client-30.1.0/version.txt +0 -1
  37. {iqm_client-30.1.0 → iqm_client-31.0.0}/AUTHORS.rst +0 -0
  38. {iqm_client-30.1.0 → iqm_client-31.0.0}/CHANGELOG_cirq-iqm.rst +0 -0
  39. {iqm_client-30.1.0 → iqm_client-31.0.0}/CHANGELOG_cortex-cli.rst +0 -0
  40. {iqm_client-30.1.0 → iqm_client-31.0.0}/CHANGELOG_qiskit-iqm.rst +0 -0
  41. {iqm_client-30.1.0 → iqm_client-31.0.0}/LICENSE.txt +0 -0
  42. {iqm_client-30.1.0 → iqm_client-31.0.0}/MANIFEST.in +0 -0
  43. {iqm_client-30.1.0 → iqm_client-31.0.0}/README.rst +0 -0
  44. {iqm_client-30.1.0 → iqm_client-31.0.0}/docbuild +0 -0
  45. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/API.rst +0 -0
  46. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/_static/images/favicon.ico +0 -0
  47. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/_static/images/logo.png +0 -0
  48. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/_templates/autosummary-class-template.rst +0 -0
  49. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/_templates/autosummary-module-template.rst +0 -0
  50. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/authors.rst +0 -0
  51. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/changelog.rst +0 -0
  52. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/index.rst +0 -0
  53. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/integration_guide.rst +0 -0
  54. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/license.rst +0 -0
  55. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/readme.rst +0 -0
  56. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/user_guide_cirq.rst +0 -0
  57. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/user_guide_cli.rst +0 -0
  58. {iqm_client-30.1.0 → iqm_client-31.0.0}/docs/user_guide_qiskit.rst +0 -0
  59. {iqm_client-30.1.0 → iqm_client-31.0.0}/pytest.ini +0 -0
  60. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/base.in +0 -0
  61. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/cirq.in +0 -0
  62. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/cli.in +0 -0
  63. {iqm_client-30.1.0 → iqm_client-31.0.0}/requirements/qiskit.in +0 -0
  64. {iqm_client-30.1.0 → iqm_client-31.0.0}/setup.cfg +0 -0
  65. {iqm_client-30.1.0 → iqm_client-31.0.0}/setup.py +0 -0
  66. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/__init__.py +0 -0
  67. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/__init__.py +0 -0
  68. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/adonis.py +0 -0
  69. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/aphrodite.py +0 -0
  70. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/devices/apollo.py +0 -0
  71. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/examples/demo_adonis.py +0 -0
  72. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/examples/demo_apollo.py +0 -0
  73. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/examples/demo_common.py +0 -0
  74. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/examples/demo_iqm_execution.py +0 -0
  75. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/examples/usage.ipynb +0 -0
  76. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/extended_qasm_parser.py +0 -0
  77. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/iqm_gates.py +0 -0
  78. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/py.typed +0 -0
  79. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/cirq_iqm/transpiler.py +0 -0
  80. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/__init__.py +0 -0
  81. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/api.py +0 -0
  82. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/authentication.py +0 -0
  83. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/cli/__init__.py +0 -0
  84. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/cli/auth.py +0 -0
  85. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/cli/models.py +0 -0
  86. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/cli/token_manager.py +0 -0
  87. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/errors.py +0 -0
  88. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/iqm_client/py.typed +0 -0
  89. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/__init__.py +0 -0
  90. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/examples/__init__.py +0 -0
  91. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/examples/bell_measure.py +0 -0
  92. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/examples/resonance_example.py +0 -0
  93. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/examples/transpile_example.py +0 -0
  94. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/__init__.py +0 -0
  95. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_adonis.py +0 -0
  96. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_aphrodite.py +0 -0
  97. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_apollo.py +0 -0
  98. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_deneb.py +0 -0
  99. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/fake_garnet.py +0 -0
  100. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py +0 -0
  101. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_backend.py +0 -0
  102. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/iqm_naive_move_pass.py +0 -0
  103. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm/qiskit_iqm/py.typed +0 -0
  104. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/SOURCES.txt +0 -0
  105. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/dependency_links.txt +0 -0
  106. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/entry_points.txt +0 -0
  107. {iqm_client-30.1.0 → iqm_client-31.0.0}/src/iqm_client.egg-info/top_level.txt +0 -0
  108. {iqm_client-30.1.0 → iqm_client-31.0.0}/test +0 -0
  109. {iqm_client-30.1.0 → iqm_client-31.0.0}/tests/__init__.py +0 -0
  110. {iqm_client-30.1.0 → iqm_client-31.0.0}/tests/conftest.py +0 -0
@@ -2,6 +2,28 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Version 31.0.0 (2025-09-11)
6
+ ===========================
7
+
8
+ Breaking changes
9
+ ----------------
10
+
11
+ - Use :class:`iqm.pulse.Circuit` and :class:`iqm.pulse.CircuitOperation` as the new
12
+ circuit and instruction formats. The old :class:`Circuit`, :class:`Instruction` and :class:`NativeOperation` models defined in
13
+ :mod:`iqm.iqm_client.models` are removed. :issue:`SW-1663`
14
+ - The quantum operation parameters ``angle_t`` and ``phase_t`` (in units of full turns) are no longer supported.
15
+ Use ``angle`` and ``phase`` (in units of radians) instead. :issue:`SW-1663`
16
+ - :func:`iqm.cirq_iqm.serialize.instruction_to_operation` renamed to :func:`iqm.cirq_iqm.serialize.circuit_operation_to_operation`.
17
+ - :func:`iqm.cirq_iqm.serialize.map_operation` renamed to :func:`iqm.cirq_iqm.serialize.operation_to_circuit_operation`.
18
+
19
+ Version 30.2.0 (2025-09-03)
20
+ ===========================
21
+
22
+ Features
23
+ --------
24
+
25
+ - Enable ruff rule for missing annotations and mark exemptions.
26
+
5
27
  Version 30.1.0 (2025-08-28)
6
28
  ===========================
7
29
 
@@ -26,19 +26,23 @@ requires only the URL of the IQM quantum computer.
26
26
 
27
27
  iqm_client = IQMClient(server_url)
28
28
 
29
- To submit a quantum circuit for execution, it has to be specified using the :class:`.Circuit` class.
30
- The available native instructions are documented in the :class:`.Instruction` class.
29
+ To submit a quantum circuit for execution, it has to be specified using the
30
+ :class:`iqm.pulse.Circuit` class. The available native instructions are documented in
31
+ :mod:`iqm.iqm_client.models` and in :class:`iqm.pulse.CircuitOperation`.
31
32
 
32
33
  .. code-block:: python
33
34
 
34
- from iqm.iqm_client import Circuit, Instruction
35
+ from math import pi
36
+
37
+ from iqm.pulse.builder import CircuitOperation
38
+ from iqm.pulse.circuit_operations import Circuit
35
39
 
36
40
  instructions = (
37
- Instruction(
38
- name="prx", qubits=("QB1",), args={"phase_t": 0.7, "angle_t": 0.25}
41
+ CircuitOperation(
42
+ name="prx", locus=("QB1",), args={"phase": 1.4 * pi, "angle": 0.5 * pi}
39
43
  ),
40
- Instruction(name="cz", qubits=("QB1", "QB2"), args={}),
41
- Instruction(name="measure", qubits=("QB2",), args={"key": "Qubit 2"}),
44
+ CircuitOperation(name="cz", locus=("QB1", "QB2"), args={}),
45
+ CircuitOperation(name="measure", locus=("QB2",), args={"key": "Qubit 2"}),
42
46
  )
43
47
 
44
48
  circuit = Circuit(name="quantum_circuit", instructions=instructions)
@@ -143,7 +147,8 @@ A typical Star architecture use case would look something like this:
143
147
 
144
148
  .. code-block:: python
145
149
 
146
- from iqm.iqm_client import Circuit, IQMClient, simplify_architecture, transpile_insert_moves, transpile_remove_moves
150
+ from iqm.iqm_client import IQMClient, simplify_architecture, transpile_insert_moves, transpile_remove_moves
151
+ from iqm.pulse.circuit_operations import Circuit
147
152
 
148
153
  client = IQMClient(URL_TO_STAR_SERVER)
149
154
  dqa = client.get_dynamic_quantum_architecture()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-client
3
- Version: 30.1.0
3
+ Version: 31.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
@@ -218,6 +218,7 @@ License-File: LICENSE.txt
218
218
  License-File: AUTHORS.rst
219
219
  Requires-Dist: iqm-station-control-client<10,>=9
220
220
  Requires-Dist: iqm-exa-common<27,>=26
221
+ Requires-Dist: iqm-pulse<13,>=12
221
222
  Requires-Dist: numpy<3.0,>=1.26.4
222
223
  Requires-Dist: packaging==24.1
223
224
  Requires-Dist: pydantic<3.0,>=2.9.2
@@ -225,6 +226,7 @@ Requires-Dist: requests==2.32.3
225
226
  Provides-Extra: cirq
226
227
  Requires-Dist: iqm-station-control-client<10,>=9; extra == "cirq"
227
228
  Requires-Dist: iqm-exa-common<27,>=26; extra == "cirq"
229
+ Requires-Dist: iqm-pulse<13,>=12; extra == "cirq"
228
230
  Requires-Dist: cirq-core[contrib]~=1.2; extra == "cirq"
229
231
  Requires-Dist: ply==3.11; extra == "cirq"
230
232
  Requires-Dist: llvmlite>=0.44.0; extra == "cirq"
@@ -232,6 +234,7 @@ Requires-Dist: numba>=0.61.0; extra == "cirq"
232
234
  Provides-Extra: cli
233
235
  Requires-Dist: iqm-station-control-client<10,>=9; extra == "cli"
234
236
  Requires-Dist: iqm-exa-common<27,>=26; extra == "cli"
237
+ Requires-Dist: iqm-pulse<13,>=12; extra == "cli"
235
238
  Requires-Dist: click<9,>=8.1.6; extra == "cli"
236
239
  Requires-Dist: jsonschema>=4.6.0; extra == "cli"
237
240
  Requires-Dist: psutil>=5.9.2; extra == "cli"
@@ -240,6 +243,7 @@ Requires-Dist: python-daemon>=2.3.0; extra == "cli"
240
243
  Provides-Extra: qiskit
241
244
  Requires-Dist: iqm-station-control-client<10,>=9; extra == "qiskit"
242
245
  Requires-Dist: iqm-exa-common<27,>=26; extra == "qiskit"
246
+ Requires-Dist: iqm-pulse<13,>=12; extra == "qiskit"
243
247
  Requires-Dist: qiskit<=1.4.2,>=1.0; extra == "qiskit"
244
248
  Requires-Dist: qiskit-aer<0.18,>=0.13.1; extra == "qiskit"
245
249
 
@@ -160,16 +160,23 @@ intersphinx_mapping = {
160
160
  "numpy": ("https://numpy.org/doc/stable", None),
161
161
  "scipy": ("https://docs.scipy.org/doc/scipy", None),
162
162
  "qiskit": ("https://docs.quantum.ibm.com/api/qiskit", None),
163
+ "iqm.pulse": ("../iqm-pulse", "../../iqm-pulse/build/sphinx/objects.inv"),
163
164
  }
164
165
 
166
+ # update intersphinx_mapping so it reads inventory from gitlab pages, but
167
+ # generate links to the pages under local file path
168
+ # this is used only in `docs with generated links to local target` ci\cd job
165
169
  use_local_target = os.getenv("USE_LOCAL_TARGET", "").lower()
166
- if use_local_target != "true":
170
+ if use_local_target == "true":
171
+ intersphinx_mapping.update(
172
+ {"iqm.pulse": ("../iqm-pulse", "https://iqm.gitlab-pages.iqm.fi/qccsw/exa/exa-repo/iqm-pulse/objects.inv")}
173
+ )
174
+ else:
167
175
  extlinks = {
168
176
  "issue": ("https://jira.iqm.fi/browse/%s", "issue %s"),
169
177
  "mr": ("https://gitlab.iqm.fi/iqm/qccsw/exa/exa-repo/-/merge_requests/%s", "MR %s"),
170
178
  }
171
179
 
172
-
173
180
  # -- Options for sphinxcontrib.bibtex -------------------------------------------------
174
181
 
175
182
  # List of all bibliography files used.
@@ -72,7 +72,7 @@ nb_diff_ignore = [ "/metadata/language_info", "/metadata/widgets", "/cells/*/exe
72
72
 
73
73
  [tool.ruff.lint]
74
74
  ignore = [ "D203", "D213",]
75
- select = [ "E4", "E7", "E9", "E5", "F", "Q", "PL", "I", "D", "UP007", "UP006", "UP035",]
75
+ select = [ "E4", "E7", "E9", "E5", "F", "Q", "PL", "I", "D", "UP007", "UP006", "UP035", "ANN001", "ANN201", "ANN202",]
76
76
  unfixable = [ "F401",]
77
77
 
78
78
  [tool.ruff.lint.isort]
@@ -85,9 +85,9 @@ relative-imports-order = "closest-to-furthest"
85
85
  [tool.ruff.lint.per-file-ignores]
86
86
  "**/__init__.py" = [ "F401", "PLR0402",]
87
87
  "**/docs/*" = [ "E402", "D100",]
88
- "**/setup.py" = [ "D100", "D103", "I001",]
88
+ "**/setup.py" = [ "D100", "D103", "I001", "ANN201",]
89
89
  "**/src/*" = [ "PLR2004", "D400", "D415", "D205", "D401", "D417", "D100", "D101", "D107", "D102", "D105", "D103", "D404", "D104",]
90
- "**/tests/*" = [ "F632", "PLR2004", "PLR0402", "PLC0414", "D",]
90
+ "**/tests/*" = [ "F632", "PLR2004", "PLR0402", "PLC0414", "D", "ANN001", "ANN201", "ANN202",]
91
91
 
92
92
  [tool.ruff.lint.pylint]
93
93
  max-args = 8
@@ -0,0 +1,2 @@
1
+ iqm-pulse
2
+ iqm-station-control-client
@@ -1,5 +1,6 @@
1
1
  iqm-station-control-client>=9,<10
2
2
  iqm-exa-common>=26,<27
3
+ iqm-pulse>=12,<13
3
4
  numpy >= 1.26.4, < 3.0
4
5
  packaging == 24.1
5
6
  pydantic >= 2.9.2, <3.0
@@ -1,5 +1,6 @@
1
1
  iqm-station-control-client>=9,<10
2
2
  iqm-exa-common>=26,<27
3
+ iqm-pulse>=12,<13
3
4
  cirq-core[contrib] ~= 1.2
4
5
  ply == 3.11
5
6
  llvmlite >= 0.44.0
@@ -1,5 +1,6 @@
1
1
  iqm-station-control-client>=9,<10
2
2
  iqm-exa-common>=26,<27
3
+ iqm-pulse>=12,<13
3
4
  click >= 8.1.6, < 9
4
5
  jsonschema >= 4.6.0
5
6
  psutil >= 5.9.2
@@ -1,4 +1,5 @@
1
1
  iqm-station-control-client>=9,<10
2
2
  iqm-exa-common>=26,<27
3
+ iqm-pulse>=12,<13
3
4
  qiskit >= 1.0, <= 1.4.2
4
5
  qiskit-aer >= 0.13.1, < 0.18
@@ -364,5 +364,5 @@ class IQMDevice(devices.Device):
364
364
  if len(qubits_updated) != 0:
365
365
  raise ValueError(f"Circuit ends with a qubit state in the resonator {res!r}.")
366
366
 
367
- def __eq__(self, other):
367
+ def __eq__(self, other): # noqa: ANN001
368
368
  return self.__class__ == other.__class__ and self._metadata == other._metadata
@@ -166,5 +166,5 @@ class IQMDeviceMetadata(devices.DeviceMetadata):
166
166
  """Returns the ``cirq.Gateset`` of supported gates on this device."""
167
167
  return self._gateset
168
168
 
169
- def _value_equality_values_(self):
169
+ def _value_equality_values_(self): # noqa: ANN202
170
170
  return *super()._value_equality_values_(), self._gateset
@@ -85,7 +85,7 @@ class IQMSampler(cirq.work.Sampler):
85
85
  """Returns the device used by the sampler."""
86
86
  return self._device
87
87
 
88
- def close_client(self):
88
+ def close_client(self): # noqa: ANN201
89
89
  """Close IQMClient's session with the user authentication server. Discard the client."""
90
90
  if not self._client:
91
91
  return
@@ -92,7 +92,7 @@ class MergeOneParameterGroupGates(circuits.PointOptimizer):
92
92
  GATE_MERGING_TOLERANCE = 1e-10
93
93
 
94
94
  @classmethod
95
- def _normalize_par(cls, par):
95
+ def _normalize_par(cls, par): # noqa: ANN001
96
96
  """Normalizes the given parameter value to (-period/2, period/2]."""
97
97
  shift = cls.PERIOD / 2
98
98
  return operator.mod(par - shift, -cls.PERIOD) + shift
@@ -14,6 +14,8 @@
14
14
 
15
15
  """Helper functions for serializing and deserializing quantum circuits between Cirq and IQM circuit formats."""
16
16
 
17
+ from math import pi
18
+
17
19
  from cirq import Circuit, KeyCondition, NamedQid
18
20
  from cirq.ops import (
19
21
  ClassicallyControlledOperation,
@@ -26,9 +28,10 @@ from cirq.ops import (
26
28
  XPowGate,
27
29
  YPowGate,
28
30
  )
29
- from iqm import iqm_client
30
31
  from iqm.cirq_iqm.iqm_gates import IQMMoveGate
31
- from iqm.iqm_client import Instruction
32
+
33
+ import iqm.pulse
34
+ from iqm.pulse import CircuitOperation
32
35
 
33
36
  # Mapping from IQM operation names to cirq operations
34
37
  _IQM_CIRQ_OP_MAP: dict[str, tuple[type[Gate], ...]] = {
@@ -43,11 +46,11 @@ _IQM_CIRQ_OP_MAP: dict[str, tuple[type[Gate], ...]] = {
43
46
  }
44
47
 
45
48
 
46
- def instruction_to_operation(instr: Instruction) -> Operation:
47
- """Convert an IQM instruction to a Cirq Operation.
49
+ def circuit_operation_to_operation(circuit_operation: CircuitOperation) -> Operation:
50
+ """Convert an IQM circuit operation to a Cirq Operation.
48
51
 
49
52
  Args:
50
- instr: the IQM instruction
53
+ circuit_operation: the IQM circuit_operation
51
54
 
52
55
  Returns:
53
56
  Operation: the converted operation
@@ -56,23 +59,29 @@ def instruction_to_operation(instr: Instruction) -> Operation:
56
59
  OperationNotSupportedError When the circuit contains an unsupported operation.
57
60
 
58
61
  """
59
- if instr.name not in _IQM_CIRQ_OP_MAP:
60
- raise OperationNotSupportedError(f"Operation {instr.name} not supported.")
62
+ if circuit_operation.name not in _IQM_CIRQ_OP_MAP:
63
+ raise OperationNotSupportedError(f"Operation {circuit_operation.name} not supported.")
61
64
 
62
- qubits = [NamedQid(qubit, dimension=2) for qubit in instr.qubits]
65
+ qubits = [NamedQid(qubit, dimension=2) for qubit in circuit_operation.locus]
63
66
 
64
- if instr.name == "cc_prx":
67
+ if circuit_operation.name == "cc_prx":
65
68
  # special case
66
- args = {"exponent": 2 * instr.args["angle_t"], "phase_exponent": 2 * instr.args["phase_t"]}
69
+ args = {
70
+ "exponent": circuit_operation.args["angle"] / pi,
71
+ "phase_exponent": circuit_operation.args["phase"] / pi,
72
+ }
67
73
  # ignore feedback_qubit, we currently only support 1-qubit KeyConditions so it can be
68
74
  # added in serialize_circuit
69
- return PhasedXPowGate(**args)(*qubits).with_classical_controls(instr.args["feedback_key"])
70
-
71
- cirq_op = _IQM_CIRQ_OP_MAP[instr.name][0]
72
- if instr.name == "prx":
73
- args = {"exponent": 2 * instr.args["angle_t"], "phase_exponent": 2 * instr.args["phase_t"]}
74
- elif instr.name == "measure":
75
- args = {"num_qubits": len(qubits), "key": instr.args["key"]}
75
+ return PhasedXPowGate(**args)(*qubits).with_classical_controls(circuit_operation.args["feedback_key"])
76
+
77
+ cirq_op = _IQM_CIRQ_OP_MAP[circuit_operation.name][0]
78
+ if circuit_operation.name == "prx":
79
+ args = {
80
+ "exponent": circuit_operation.args["angle"] / pi,
81
+ "phase_exponent": circuit_operation.args["phase"] / pi,
82
+ }
83
+ elif circuit_operation.name == "measure":
84
+ args = {"num_qubits": len(qubits), "key": circuit_operation.args["key"]}
76
85
  # ignore feedback_key, in Cirq it has to be the same as key
77
86
  else:
78
87
  # cz, move, reset have no args
@@ -84,7 +93,7 @@ class OperationNotSupportedError(RuntimeError):
84
93
  """Raised when a given operation is not supported by the IQM server."""
85
94
 
86
95
 
87
- def map_operation(operation: Operation) -> Instruction:
96
+ def operation_to_circuit_operation(operation: Operation) -> CircuitOperation:
88
97
  """Map a Cirq Operation to the IQM data transfer format.
89
98
 
90
99
  Assumes the circuit has been transpiled so that it only contains operations natively supported by the
@@ -94,7 +103,7 @@ def map_operation(operation: Operation) -> Instruction:
94
103
  operation: a Cirq Operation
95
104
 
96
105
  Returns:
97
- Instruction: the converted operation
106
+ CircuitOperation: the converted operation
98
107
 
99
108
  Raises:
100
109
  OperationNotSupportedError When the circuit contains an unsupported operation.
@@ -102,25 +111,25 @@ def map_operation(operation: Operation) -> Instruction:
102
111
  """
103
112
  locus = tuple(qubit.name if isinstance(qubit, NamedQid) else str(qubit) for qubit in operation.qubits)
104
113
  if isinstance(operation.gate, (PhasedXPowGate, XPowGate, YPowGate)):
105
- return Instruction(
114
+ return CircuitOperation(
106
115
  name="prx",
107
- qubits=locus,
108
- args={"angle_t": operation.gate.exponent / 2, "phase_t": operation.gate.phase_exponent / 2},
116
+ locus=locus,
117
+ args={"angle": operation.gate.exponent * pi, "phase": operation.gate.phase_exponent * pi},
109
118
  )
110
119
  if isinstance(operation.gate, MeasurementGate):
111
120
  if any(operation.gate.full_invert_mask()):
112
121
  raise OperationNotSupportedError("Invert mask not supported")
113
122
 
114
- return Instruction(
123
+ return CircuitOperation(
115
124
  name="measure",
116
- qubits=locus,
125
+ locus=locus,
117
126
  args={"key": operation.gate.key},
118
127
  )
119
128
  if isinstance(operation.gate, CZPowGate):
120
129
  if operation.gate.exponent == 1.0:
121
- return Instruction(
130
+ return CircuitOperation(
122
131
  name="cz",
123
- qubits=locus,
132
+ locus=locus,
124
133
  args={},
125
134
  )
126
135
  raise OperationNotSupportedError(
@@ -128,14 +137,14 @@ def map_operation(operation: Operation) -> Instruction:
128
137
  )
129
138
 
130
139
  if isinstance(operation.gate, IQMMoveGate):
131
- return Instruction(
140
+ return CircuitOperation(
132
141
  name="move",
133
- qubits=locus,
142
+ locus=locus,
134
143
  args={},
135
144
  )
136
145
 
137
146
  if isinstance(operation.gate, ResetChannel):
138
- return Instruction(name="reset", qubits=locus)
147
+ return CircuitOperation(name="reset", locus=locus)
139
148
 
140
149
  if isinstance(operation, ClassicallyControlledOperation):
141
150
  if len(operation._conditions) > 1:
@@ -143,12 +152,12 @@ def map_operation(operation: Operation) -> Instruction:
143
152
  if not isinstance(operation._conditions[0], KeyCondition):
144
153
  raise OperationNotSupportedError("Only KeyConditions are supported as classical controls.")
145
154
  if isinstance(operation._sub_operation.gate, (PhasedXPowGate, XPowGate, YPowGate)):
146
- return Instruction(
155
+ return CircuitOperation(
147
156
  name="cc_prx",
148
- qubits=locus,
157
+ locus=locus,
149
158
  args={
150
- "angle_t": operation._sub_operation.gate.exponent / 2,
151
- "phase_t": operation._sub_operation.gate.phase_exponent / 2,
159
+ "angle": operation._sub_operation.gate.exponent * pi,
160
+ "phase": operation._sub_operation.gate.phase_exponent * pi,
152
161
  "feedback_qubit": "",
153
162
  "feedback_key": str(operation._conditions[0]),
154
163
  },
@@ -162,7 +171,7 @@ def map_operation(operation: Operation) -> Instruction:
162
171
  raise OperationNotSupportedError(f"{type(operation.gate)} not natively supported.")
163
172
 
164
173
 
165
- def serialize_circuit(circuit: Circuit) -> iqm_client.Circuit:
174
+ def serialize_circuit(circuit: Circuit) -> iqm.pulse.Circuit:
166
175
  """Serializes a quantum circuit into the IQM data transfer format.
167
176
 
168
177
  Args:
@@ -174,10 +183,10 @@ def serialize_circuit(circuit: Circuit) -> iqm_client.Circuit:
174
183
  """
175
184
  total_ops_list = [op for moment in circuit for op in moment]
176
185
  cc_prx_support = any(isinstance(op, ClassicallyControlledOperation) for op in total_ops_list)
177
- instructions = list(map(map_operation, total_ops_list))
186
+ instructions = tuple(map(operation_to_circuit_operation, total_ops_list))
178
187
 
179
188
  if cc_prx_support:
180
- mkey_to_measurement = {}
189
+ mkey_to_measurement: dict[str, CircuitOperation] = {}
181
190
  for inst in instructions:
182
191
  if inst.name == "measure":
183
192
  if inst.args["key"] in mkey_to_measurement:
@@ -190,15 +199,15 @@ def serialize_circuit(circuit: Circuit) -> iqm_client.Circuit:
190
199
  raise OperationNotSupportedError(
191
200
  f"cc_prx has feedback_key {feedback_key}, but no measure operation with that key precedes it."
192
201
  )
193
- if len(measurement.qubits) != 1:
202
+ if len(measurement.locus) != 1:
194
203
  raise OperationNotSupportedError("cc_prx must depend on the measurement result of a single qubit.")
195
- inst.args["feedback_qubit"] = measurement.qubits[0]
204
+ inst.args["feedback_qubit"] = measurement.locus[0]
196
205
  measurement.args["feedback_key"] = feedback_key
197
206
 
198
- return iqm_client.Circuit(name="Serialized from Cirq", instructions=instructions, metadata=None)
207
+ return iqm.pulse.Circuit(name="Serialized from Cirq", instructions=instructions, metadata=None)
199
208
 
200
209
 
201
- def deserialize_circuit(circuit: iqm_client.Circuit) -> Circuit:
210
+ def deserialize_circuit(circuit: iqm.pulse.Circuit) -> Circuit:
202
211
  """Deserializes a quantum circuit from the IQM data transfer format to a Cirq Circuit.
203
212
 
204
213
  Args:
@@ -210,7 +219,7 @@ def deserialize_circuit(circuit: iqm_client.Circuit) -> Circuit:
210
219
  """
211
220
  return Circuit(
212
221
  map(
213
- instruction_to_operation,
222
+ circuit_operation_to_operation,
214
223
  circuit.instructions,
215
224
  )
216
225
  )
@@ -58,7 +58,7 @@ class ClickLoggingHandler(logging.Handler):
58
58
  super().__init__(level=logging.NOTSET)
59
59
  self.formatter = logging.Formatter("%(message)s")
60
60
 
61
- def emit(self, record):
61
+ def emit(self, record): # noqa: ANN001, ANN201
62
62
  click.echo(self.format(record))
63
63
 
64
64
 
@@ -463,7 +463,7 @@ def auth() -> None:
463
463
  help="Location of the configuration file to be used.",
464
464
  )
465
465
  @click.option("-v", "--verbose", is_flag=True, help="Print extra information.")
466
- def status(config_file, verbose) -> None:
466
+ def status(config_file, verbose) -> None: # noqa: ANN001
467
467
  """Check status of authentication."""
468
468
  _set_log_level_by_verbosity(verbose)
469
469
 
@@ -503,7 +503,7 @@ def status(config_file, verbose) -> None:
503
503
  click.echo(f"Token manager: {click.style('NOT RUNNING', fg='red')}")
504
504
 
505
505
 
506
- def _validate_iqm_client_cli_auth_login(no_daemon, no_refresh, config_file) -> ConfigFile:
506
+ def _validate_iqm_client_cli_auth_login(no_daemon, no_refresh, config_file) -> ConfigFile: # noqa: ANN001
507
507
  """Checks if provided combination of auth login options is valid:
508
508
  - no_daemon and no_refresh are mutually exclusive
509
509
  - config file should pass validation
@@ -243,7 +243,7 @@ class IQMClient:
243
243
  # validate the circuit against the static information in iqm.iqm_client.models._SUPPORTED_OPERATIONS
244
244
  validate_circuit(circuit)
245
245
  except ValueError as e:
246
- raise CircuitValidationError(f"The circuit at index {i} failed the validation").with_traceback(
246
+ raise CircuitValidationError(f"The circuit at index {i} failed the validation: {e}").with_traceback(
247
247
  e.__traceback__
248
248
  )
249
249