azure-quantum 2.1.1__tar.gz → 2.2.0.dev0__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 (90) hide show
  1. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/PKG-INFO +1 -1
  2. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_version.py +1 -1
  3. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/backend.py +54 -0
  4. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/ionq.py +8 -35
  5. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/qci.py +2 -24
  6. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/quantinuum.py +29 -4
  7. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/rigetti.py +2 -22
  8. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/job.py +29 -6
  9. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/provider.py +4 -4
  10. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/ionq.py +24 -19
  11. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/quantinuum.py +31 -25
  12. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/target.py +61 -1
  13. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/version.py +1 -1
  14. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure_quantum.egg-info/PKG-INFO +1 -1
  15. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/README.md +0 -0
  16. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/__init__.py +0 -0
  17. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_authentication/__init__.py +0 -0
  18. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_authentication/_chained.py +0 -0
  19. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_authentication/_default.py +0 -0
  20. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_authentication/_token.py +0 -0
  21. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/__init__.py +0 -0
  22. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_client.py +0 -0
  23. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_configuration.py +0 -0
  24. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_patch.py +0 -0
  25. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_serialization.py +0 -0
  26. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/_vendor.py +0 -0
  27. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/models/__init__.py +0 -0
  28. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/models/_enums.py +0 -0
  29. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/models/_models.py +0 -0
  30. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/models/_patch.py +0 -0
  31. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/operations/__init__.py +0 -0
  32. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/operations/_operations.py +0 -0
  33. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_client/operations/_patch.py +0 -0
  34. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_constants.py +0 -0
  35. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/_workspace_connection_params.py +0 -0
  36. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/argument_types/__init__.py +0 -0
  37. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/argument_types/types.py +0 -0
  38. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/chemistry/__init__.py +0 -0
  39. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/__init__.py +0 -0
  40. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/job.py +0 -0
  41. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/service.py +0 -0
  42. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/targets/__init__.py +0 -0
  43. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/targets/ionq.py +0 -0
  44. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/targets/quantinuum.py +0 -0
  45. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/cirq/targets/target.py +0 -0
  46. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/__init__.py +0 -0
  47. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/base_job.py +0 -0
  48. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/filtered_job.py +0 -0
  49. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/job.py +0 -0
  50. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/job_failed_with_results_error.py +0 -0
  51. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/session.py +0 -0
  52. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/workspace_item.py +0 -0
  53. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/job/workspace_item_factory.py +0 -0
  54. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/__init__.py +0 -0
  55. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/__init__.py +0 -0
  56. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/backends/microsoft.py +0 -0
  57. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/results/__init__.py +0 -0
  58. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/qiskit/results/resource_estimator.py +0 -0
  59. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/storage.py +0 -0
  60. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/__init__.py +0 -0
  61. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/__init__.py +0 -0
  62. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/elements/__init__.py +0 -0
  63. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/elements/dft/__init__.py +0 -0
  64. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/elements/dft/job.py +0 -0
  65. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/elements/dft/target.py +0 -0
  66. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/job.py +0 -0
  67. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/result.py +0 -0
  68. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/microsoft/target.py +0 -0
  69. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/params.py +0 -0
  70. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/pasqal/__init__.py +0 -0
  71. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/pasqal/result.py +0 -0
  72. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/pasqal/target.py +0 -0
  73. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/rigetti/__init__.py +0 -0
  74. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/rigetti/result.py +0 -0
  75. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/rigetti/target.py +0 -0
  76. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/target/target_factory.py +0 -0
  77. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure/quantum/workspace.py +0 -0
  78. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure_quantum.egg-info/SOURCES.txt +0 -0
  79. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure_quantum.egg-info/dependency_links.txt +0 -0
  80. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure_quantum.egg-info/requires.txt +0 -0
  81. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/azure_quantum.egg-info/top_level.txt +0 -0
  82. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-cirq.txt +0 -0
  83. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-dev.txt +0 -0
  84. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-pulser.txt +0 -0
  85. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-qiskit.txt +0 -0
  86. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-qsharp.txt +0 -0
  87. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements-quil.txt +0 -0
  88. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/requirements.txt +0 -0
  89. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/setup.cfg +0 -0
  90. {azure-quantum-2.1.1 → azure-quantum-2.2.0.dev0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: azure-quantum
3
- Version: 2.1.1
3
+ Version: 2.2.0.dev0
4
4
  Summary: Python client for Azure Quantum
5
5
  Home-page: https://github.com/microsoft/azure-quantum-python
6
6
  Author: Microsoft
@@ -6,4 +6,4 @@
6
6
  # Changes may cause incorrect behavior and will be lost if the code is regenerated.
7
7
  # --------------------------------------------------------------------------
8
8
 
9
- VERSION = "2.1.1"
9
+ VERSION = "2.2.0.dev0"
@@ -36,6 +36,25 @@ except ImportError:
36
36
  To install run: pip install azure-quantum[qiskit]"
37
37
  )
38
38
 
39
+ QIR_BASIS_GATES = [
40
+ "x",
41
+ "y",
42
+ "z",
43
+ "rx",
44
+ "ry",
45
+ "rz",
46
+ "h",
47
+ "swap",
48
+ "cx",
49
+ "cz",
50
+ "reset",
51
+ "s",
52
+ "sdg",
53
+ "t",
54
+ "tdg",
55
+ "measure",
56
+ ]
57
+
39
58
 
40
59
  class AzureBackendBase(Backend, SessionHost):
41
60
 
@@ -280,7 +299,11 @@ class AzureQirBackend(AzureBackendBase):
280
299
  "content_type": "qir.v1",
281
300
  "input_data_format": "qir.v1",
282
301
  "output_data_format": "microsoft.quantum-results.v2",
302
+ "is_default": True,
283
303
  }
304
+
305
+ def _basis_gates(self) -> List[str]:
306
+ return QIR_BASIS_GATES
284
307
 
285
308
  def run(
286
309
  self,
@@ -429,6 +452,37 @@ class AzureQirBackend(AzureBackendBase):
429
452
 
430
453
  return module.bitcode
431
454
 
455
+ def _estimate_cost_qir(self, circuits, shots, options={}):
456
+ """Estimate the cost for the given circuit."""
457
+ config = self.configuration()
458
+ input_params = self._get_input_params(options, shots=shots)
459
+
460
+ if not (isinstance(circuits, list)):
461
+ circuits = [circuits]
462
+
463
+ to_qir_kwargs = input_params.pop(
464
+ "to_qir_kwargs", config.azure.get("to_qir_kwargs", {"record_output": True})
465
+ )
466
+ targetCapability = input_params.pop(
467
+ "targetCapability",
468
+ self.options.get("targetCapability", "AdaptiveExecution"),
469
+ )
470
+
471
+ if not input_params.pop("skipTranspile", False):
472
+ # Set of gates supported by QIR targets.
473
+ circuits = transpile(
474
+ circuits, basis_gates=config.basis_gates, optimization_level=0
475
+ )
476
+
477
+
478
+ (module, _) = self._generate_qir(
479
+ circuits, targetCapability, **to_qir_kwargs
480
+ )
481
+
482
+ workspace = self.provider().get_workspace()
483
+ target = workspace.get_targets(self.name())
484
+ return target.estimate_cost(module, shots=shots)
485
+
432
486
 
433
487
  class AzureBackend(AzureBackendBase):
434
488
  """Base class for interfacing with a backend in Azure Quantum"""
@@ -20,7 +20,6 @@ from qiskit.providers.models import BackendConfiguration
20
20
  from qiskit.providers import Options, Provider
21
21
 
22
22
  from qiskit_ionq.helpers import (
23
- ionq_basis_gates,
24
23
  GATESET_MAP,
25
24
  qiskit_circ_to_ionq_circ,
26
25
  )
@@ -77,6 +76,10 @@ class IonQQirBackendBase(AzureQirBackend):
77
76
  }
78
77
  )
79
78
  return config
79
+
80
+ def estimate_cost(self, circuits, shots, options={}):
81
+ """Estimate the cost for the given circuit."""
82
+ return self._estimate_cost_qir(circuits, shots, options)
80
83
 
81
84
  def run(
82
85
  self,
@@ -103,7 +106,6 @@ class IonQSimulatorQirBackend(IonQQirBackendBase):
103
106
 
104
107
  def __init__(self, name: str, provider: "AzureQuantumProvider", **kwargs):
105
108
  """Base class for interfacing with an IonQ QIR Simulator backend"""
106
-
107
109
  default_config = BackendConfiguration.from_dict(
108
110
  {
109
111
  "backend_name": name,
@@ -112,7 +114,7 @@ class IonQSimulatorQirBackend(IonQQirBackendBase):
112
114
  "local": False,
113
115
  "coupling_map": None,
114
116
  "description": "IonQ simulator on Azure Quantum",
115
- "basis_gates": ionq_basis_gates,
117
+ "basis_gates": self._basis_gates(),
116
118
  "memory": False,
117
119
  "n_qubits": 29,
118
120
  "conditional": False,
@@ -135,7 +137,6 @@ class IonQAriaQirBackend(IonQQirBackendBase):
135
137
 
136
138
  def __init__(self, name: str, provider: "AzureQuantumProvider", **kwargs):
137
139
  """Base class for interfacing with an IonQ Aria QPU backend"""
138
-
139
140
  default_config = BackendConfiguration.from_dict(
140
141
  {
141
142
  "backend_name": name,
@@ -144,7 +145,7 @@ class IonQAriaQirBackend(IonQQirBackendBase):
144
145
  "local": False,
145
146
  "coupling_map": None,
146
147
  "description": "IonQ Aria QPU on Azure Quantum",
147
- "basis_gates": ionq_basis_gates,
148
+ "basis_gates": self._basis_gates(),
148
149
  "memory": False,
149
150
  "n_qubits": 23,
150
151
  "conditional": False,
@@ -167,7 +168,6 @@ class IonQForteQirBackend(IonQQirBackendBase):
167
168
 
168
169
  def __init__(self, name: str, provider: "AzureQuantumProvider", **kwargs):
169
170
  """Base class for interfacing with an IonQ Forte QPU backend"""
170
-
171
171
  default_config = BackendConfiguration.from_dict(
172
172
  {
173
173
  "backend_name": name,
@@ -176,7 +176,7 @@ class IonQForteQirBackend(IonQQirBackendBase):
176
176
  "local": False,
177
177
  "coupling_map": None,
178
178
  "description": "IonQ Forte QPU on Azure Quantum",
179
- "basis_gates": ionq_basis_gates,
179
+ "basis_gates": self._basis_gates(),
180
180
  "memory": False,
181
181
  "n_qubits": 35,
182
182
  "conditional": False,
@@ -241,7 +241,7 @@ class IonQBackend(AzureBackend):
241
241
  "provider_id": "ionq",
242
242
  "input_data_format": "ionq.circuit.v1",
243
243
  "output_data_format": "ionq.quantum-results.v1",
244
- "is_default": True,
244
+ "is_default": False,
245
245
  }
246
246
 
247
247
  def _prepare_job_metadata(self, circuit, **kwargs):
@@ -316,15 +316,6 @@ class IonQSimulatorNativeBackend(IonQSimulatorBackend):
316
316
  kwargs["gateset"] = "native"
317
317
  super().__init__(name, provider, **kwargs)
318
318
 
319
- def _azure_config(self) -> Dict[str, str]:
320
- config = super()._azure_config()
321
- config.update(
322
- {
323
- "is_default": False,
324
- }
325
- )
326
- return config
327
-
328
319
 
329
320
  class IonQAriaBackend(IonQBackend):
330
321
  backend_names = ("ionq.qpu.aria-1", "ionq.qpu.aria-2")
@@ -398,27 +389,9 @@ class IonQAriaNativeBackend(IonQAriaBackend):
398
389
  kwargs["gateset"] = "native"
399
390
  super().__init__(name, provider, **kwargs)
400
391
 
401
- def _azure_config(self) -> Dict[str, str]:
402
- config = super()._azure_config()
403
- config.update(
404
- {
405
- "is_default": False,
406
- }
407
- )
408
- return config
409
-
410
392
 
411
393
  class IonQForteNativeBackend(IonQForteBackend):
412
394
  def __init__(self, name: str, provider: "AzureQuantumProvider", **kwargs):
413
395
  if "gateset" not in kwargs:
414
396
  kwargs["gateset"] = "native"
415
397
  super().__init__(name, provider, **kwargs)
416
-
417
- def _azure_config(self) -> Dict[str, str]:
418
- config = super()._azure_config()
419
- config.update(
420
- {
421
- "is_default": False,
422
- }
423
- )
424
- return config
@@ -15,28 +15,6 @@ from .backend import (
15
15
  from qiskit.providers.models import BackendConfiguration
16
16
  from qiskit.providers import Options, Provider
17
17
 
18
- QIR_BASIS_GATES = [
19
- "measure",
20
- "m",
21
- "barrier",
22
- "cx",
23
- "cz",
24
- "h",
25
- "reset",
26
- "rx",
27
- "ry",
28
- "rz",
29
- "s",
30
- "sdg",
31
- "swap",
32
- "t",
33
- "tdg",
34
- "x",
35
- "y",
36
- "z",
37
- "id",
38
- ]
39
-
40
18
  if TYPE_CHECKING:
41
19
  from azure.quantum.qiskit import AzureQuantumProvider
42
20
 
@@ -110,7 +88,7 @@ class QCISimulatorBackend(QCIBackend):
110
88
  "local": False,
111
89
  "coupling_map": None,
112
90
  "description": "QCI simulator on Azure Quantum",
113
- "basis_gates": QIR_BASIS_GATES,
91
+ "basis_gates": self._basis_gates(),
114
92
  "memory": False,
115
93
  "n_qubits": 29,
116
94
  "conditional": True,
@@ -142,7 +120,7 @@ class QCIQPUBackend(QCIBackend):
142
120
  "local": False,
143
121
  "coupling_map": None,
144
122
  "description": "QCI QPU on Azure Quantum",
145
- "basis_gates": QIR_BASIS_GATES,
123
+ "basis_gates": self._basis_gates(),
146
124
  "memory": False,
147
125
  "n_qubits": 11,
148
126
  "conditional": True,
@@ -50,6 +50,24 @@ QUANTINUUM_BASIS_GATES = [
50
50
  "reset",
51
51
  ]
52
52
 
53
+ QUANTINUUM_QIR_BASIS_GATES = [
54
+ "x",
55
+ "y",
56
+ "z",
57
+ "rx",
58
+ "ry",
59
+ "rz",
60
+ "h",
61
+ "cx",
62
+ "cz",
63
+ "reset",
64
+ "s",
65
+ "sdg",
66
+ "t",
67
+ "tdg",
68
+ "measure",
69
+ ]
70
+
53
71
  QUANTINUUM_PROVIDER_ID = "quantinuum"
54
72
  QUANTINUUM_PROVIDER_NAME = "Quantinuum"
55
73
 
@@ -94,9 +112,16 @@ class QuantinuumQirBackendBase(AzureQirBackend):
94
112
  }
95
113
  )
96
114
  return config
115
+
116
+ def _basis_gates(self) -> List[str]:
117
+ return QUANTINUUM_QIR_BASIS_GATES
97
118
 
98
119
  def _get_n_qubits(self, name):
99
120
  return _get_n_qubits(name)
121
+
122
+ def estimate_cost(self, circuits, shots, options={}):
123
+ """Estimate the cost for the given circuit."""
124
+ return self._estimate_cost_qir(circuits, shots, options)
100
125
 
101
126
 
102
127
  class QuantinuumSyntaxCheckerQirBackend(QuantinuumQirBackendBase):
@@ -118,7 +143,7 @@ class QuantinuumSyntaxCheckerQirBackend(QuantinuumQirBackendBase):
118
143
  "local": False,
119
144
  "coupling_map": None,
120
145
  "description": f"Quantinuum Syntax Checker on Azure Quantum",
121
- "basis_gates": QUANTINUUM_BASIS_GATES,
146
+ "basis_gates": self._basis_gates(),
122
147
  "memory": True,
123
148
  "n_qubits": self._get_n_qubits(name),
124
149
  "conditional": False,
@@ -155,7 +180,7 @@ class QuantinuumEmulatorQirBackend(QuantinuumQirBackendBase):
155
180
  "local": False,
156
181
  "coupling_map": None,
157
182
  "description": f"Quantinuum emulator on Azure Quantum",
158
- "basis_gates": QUANTINUUM_BASIS_GATES,
183
+ "basis_gates": self._basis_gates(),
159
184
  "memory": True,
160
185
  "n_qubits": self._get_n_qubits(name),
161
186
  "conditional": False,
@@ -192,7 +217,7 @@ class QuantinuumQPUQirBackend(QuantinuumQirBackendBase):
192
217
  "local": False,
193
218
  "coupling_map": None,
194
219
  "description": f"Quantinuum QPU on Azure Quantum",
195
- "basis_gates": QUANTINUUM_BASIS_GATES,
220
+ "basis_gates": self._basis_gates(),
196
221
  "memory": True,
197
222
  "n_qubits": self._get_n_qubits(name),
198
223
  "conditional": False,
@@ -236,7 +261,7 @@ class QuantinuumBackend(AzureBackend):
236
261
  "provider_id": self._provider_id,
237
262
  "input_data_format": "honeywell.openqasm.v1",
238
263
  "output_data_format": "honeywell.quantum-results.v1",
239
- "is_default": True,
264
+ "is_default": False,
240
265
  }
241
266
 
242
267
  def _translate_input(self, circuit):
@@ -12,26 +12,6 @@ from .backend import AzureQirBackend
12
12
  from qiskit.providers.models import BackendConfiguration
13
13
  from qiskit.providers import Options, Provider
14
14
 
15
- QIR_BASIS_GATES = [
16
- "measure",
17
- "m",
18
- "cx",
19
- "cz",
20
- "h",
21
- "reset",
22
- "rx",
23
- "ry",
24
- "rz",
25
- "s",
26
- "sdg,"
27
- "t",
28
- "tdg",
29
- "x",
30
- "y",
31
- "z",
32
- "id",
33
- ]
34
-
35
15
  if TYPE_CHECKING:
36
16
  from azure.quantum.qiskit import AzureQuantumProvider
37
17
 
@@ -85,7 +65,7 @@ class RigettiSimulatorBackend(RigettiBackend):
85
65
  "local": False,
86
66
  "coupling_map": None,
87
67
  "description": "Rigetti simulator on Azure Quantum",
88
- "basis_gates": QIR_BASIS_GATES,
68
+ "basis_gates": self._basis_gates(),
89
69
  "memory": True,
90
70
  "n_qubits": RigettiTarget.num_qubits(name),
91
71
  "conditional": False,
@@ -117,7 +97,7 @@ class RigettiQPUBackend(RigettiBackend):
117
97
  "local": False,
118
98
  "coupling_map": None,
119
99
  "description": "Rigetti QPU on Azure Quantum",
120
- "basis_gates": QIR_BASIS_GATES,
100
+ "basis_gates": self._basis_gates(),
121
101
  "memory": True,
122
102
  "n_qubits": RigettiTarget.num_qubits(name),
123
103
  "conditional": False,
@@ -312,6 +312,26 @@ class AzureQuantumJob(JobV1):
312
312
  entry_point_names.append(entry_point["entryPoint"])
313
313
  return entry_point_names if len(entry_point_names) > 0 else ["main"]
314
314
 
315
+ def _get_headers(self):
316
+ headers = self._azure_job.details.metadata
317
+ if (not isinstance(headers, list)):
318
+ headers = [headers]
319
+
320
+ # This function will attempt to parse the header into a JSON object, and if the header is not a JSON object, we return the header itself
321
+ def tryParseJSON(header):
322
+ try:
323
+ json_object = json.loads(header)
324
+ except ValueError as e:
325
+ return header
326
+ return json_object
327
+
328
+ for header in headers:
329
+ del header['qiskit'] # we throw out the qiskit header as it is implied
330
+ for key in header.keys():
331
+ header[key] = tryParseJSON(header[key])
332
+ return headers
333
+
334
+
315
335
  def _format_microsoft_v2_results(self) -> List[Dict[str, Any]]:
316
336
  success = self._azure_job.details.status == "Succeeded"
317
337
 
@@ -326,10 +346,15 @@ class AzureQuantumJob(JobV1):
326
346
  entry_point_names = self._get_entry_point_names()
327
347
 
328
348
  results = self._translate_microsoft_v2_results()
329
-
349
+
330
350
  if len(results) != len(entry_point_names):
331
- raise ValueError("The number of experiment results does not match the number of experiment names")
351
+ raise ValueError("The number of experiment results does not match the number of entry point names")
352
+
353
+ headers = self._get_headers()
332
354
 
355
+ if len(results) != len(headers):
356
+ raise ValueError("The number of experiment results does not match the number of headers")
357
+
333
358
  status = self.status()
334
359
 
335
360
  return [{
@@ -338,7 +363,5 @@ class AzureQuantumJob(JobV1):
338
363
  "shots": total_count,
339
364
  "name": name,
340
365
  "status": status,
341
- "header": {
342
- "name": name
343
- }
344
- } for name, (total_count, result) in zip(entry_point_names, results)]
366
+ "header": header
367
+ } for name, (total_count, result), header in zip(entry_point_names, results, headers)]
@@ -129,9 +129,9 @@ see https://aka.ms/AQ/Docs/AddProvider"
129
129
  filtered_backends,
130
130
  )
131
131
  )
132
- # If default backends were found - return them, otherwise return the filtered_backends collection.
133
- # The latter case could happen where there's no default backend defined for the specified target.
134
- if len(default_backends) > 0:
132
+ # If default backends were found - return them, otherwise return the filtered_backends collection.
133
+ # The latter case could happen where there's no default backend defined for the specified target.
134
+ if len(default_backends) > 0:
135
135
  return default_backends
136
136
 
137
137
  return filtered_backends
@@ -277,7 +277,7 @@ see https://aka.ms/AQ/Docs/AddProvider"
277
277
  warnings.warn(
278
278
  f"Specified filters {unknown_filters} are not supported by the available backends."
279
279
  )
280
-
280
+
281
281
  backends = list(filter(filters, backends))
282
282
 
283
283
  return backends
@@ -12,6 +12,7 @@ from azure.quantum.target.target import (
12
12
  from azure.quantum.job.job import Job
13
13
  from azure.quantum.workspace import Workspace
14
14
  from azure.quantum._client.models import CostEstimate, UsageEvent
15
+ from typing import Union
15
16
 
16
17
  COST_1QUBIT_GATE_MAP = {
17
18
  "ionq.simulator" : 0.0,
@@ -123,7 +124,7 @@ class IonQ(Target):
123
124
 
124
125
  def estimate_cost(
125
126
  self,
126
- circuit: Dict[str, Any],
127
+ circuit: Union[Dict[str, Any], Any],
127
128
  num_shots: int = None,
128
129
  price_1q: float = None,
129
130
  price_2q: float = None,
@@ -174,20 +175,6 @@ class IonQ(Target):
174
175
  )
175
176
  shots = num_shots
176
177
 
177
- def is_1q_gate(gate: Dict[str, Any]):
178
- return "controls" not in gate and "control" not in gate
179
-
180
- def is_multi_q_gate(gate):
181
- return "controls" in gate or "control" in gate
182
-
183
- def num_2q_gates(gate):
184
- controls = gate.get("controls")
185
- if controls is None or len(controls) == 1:
186
- # Only one control qubit
187
- return 1
188
- # Multiple control qubits
189
- return 6 * (len(controls) - 2)
190
-
191
178
  # Get the costs for the gates depending on the provider if not specified
192
179
  if price_1q is None:
193
180
  price_1q = COST_1QUBIT_GATE_MAP[self.name]
@@ -198,10 +185,28 @@ class IonQ(Target):
198
185
  if min_price is None:
199
186
  min_price = MIN_PRICE_MAP[self.name]
200
187
 
201
- gates = circuit.get("circuit", [])
202
- N_1q = sum(map(is_1q_gate, gates))
203
- N_2q = sum(map(num_2q_gates, filter(is_multi_q_gate, gates)))
204
-
188
+ if (isinstance(circuit, Dict)):
189
+ def is_1q_gate(gate: Dict[str, Any]):
190
+ return "controls" not in gate and "control" not in gate
191
+
192
+ def is_multi_q_gate(gate):
193
+ return "controls" in gate or "control" in gate
194
+
195
+ def num_2q_gates(gate):
196
+ controls = gate.get("controls")
197
+ if controls is None or len(controls) == 1:
198
+ # Only one control qubit
199
+ return 1
200
+ # Multiple control qubits
201
+ return 6 * (len(controls) - 2)
202
+
203
+ gates = circuit.get("circuit", [])
204
+ N_1q = sum(map(is_1q_gate, gates))
205
+ N_2q = sum(map(num_2q_gates, filter(is_multi_q_gate, gates)))
206
+
207
+ else:
208
+ N_1q, N_2q, _ = Target._calculate_qir_module_gate_stats(circuit)
209
+
205
210
  price = (price_1q * N_1q + price_2q * N_2q) * shots
206
211
  price = max(price, min_price)
207
212
 
@@ -12,6 +12,7 @@ from azure.quantum.target.target import (
12
12
  from azure.quantum.job.job import Job
13
13
  from azure.quantum.workspace import Workspace
14
14
  from azure.quantum._client.models import CostEstimate, UsageEvent
15
+ from typing import Union
15
16
 
16
17
 
17
18
  class Quantinuum(Target):
@@ -98,7 +99,7 @@ class Quantinuum(Target):
98
99
 
99
100
  def estimate_cost(
100
101
  self,
101
- circuit: str = None,
102
+ circuit: Union[str, Any] = None,
102
103
  num_shots: int = None,
103
104
  N_1q: int = None,
104
105
  N_2q: int = None,
@@ -144,30 +145,35 @@ class Quantinuum(Target):
144
145
  )
145
146
  shots = num_shots
146
147
 
147
- if circuit is not None and (N_1q is None or N_2q is None or N_m is None):
148
- try:
149
- from qiskit.qasm2 import loads
150
- from qiskit.converters.circuit_to_dag import circuit_to_dag
151
-
152
- except ImportError:
153
- raise ImportError(
154
- "Missing dependency qiskit. Please run `pip install azure-quantum[qiskit]` " \
155
- "to estimate the circuit cost. Alternatively, specify the number of one-qubit and two-qubit " \
156
- "gates in the method input arguments.")
157
-
158
- else:
159
- from qiskit.dagcircuit.dagnode import DAGOpNode
160
- circuit_obj = loads(string=circuit)
161
- dag = circuit_to_dag(circuit=circuit_obj)
162
- N_1q, N_2q, N_m = 0, 0, 0
163
- for node in dag._multi_graph.nodes():
164
- if isinstance(node, DAGOpNode):
165
- if node.op.name in ["measure", "reset"]:
166
- N_m += 1
167
- elif node.op.num_qubits == 1:
168
- N_1q += 1
169
- else:
170
- N_2q += 1
148
+ # If we use passthrough, else assume QIR
149
+ if (isinstance(circuit, str)):
150
+ if circuit is not None and (N_1q is None or N_2q is None or N_m is None):
151
+ try:
152
+ from qiskit.qasm2 import loads
153
+ from qiskit.converters.circuit_to_dag import circuit_to_dag
154
+
155
+ except ImportError:
156
+ raise ImportError(
157
+ "Missing dependency qiskit. Please run `pip install azure-quantum[qiskit]` " \
158
+ "to estimate the circuit cost. Alternatively, specify the number of one-qubit and two-qubit " \
159
+ "gates in the method input arguments.")
160
+
161
+ else:
162
+ from qiskit.dagcircuit.dagnode import DAGOpNode
163
+ circuit_obj = loads(string=circuit)
164
+ dag = circuit_to_dag(circuit=circuit_obj)
165
+ N_1q, N_2q, N_m = 0, 0, 0
166
+ for node in dag._multi_graph.nodes():
167
+ if isinstance(node, DAGOpNode):
168
+ if node.op.name in ["measure", "reset"]:
169
+ N_m += 1
170
+ elif node.op.num_qubits == 1:
171
+ N_1q += 1
172
+ else:
173
+ N_2q += 1
174
+ else:
175
+ N_1q, N_2q, N_m = Target._calculate_qir_module_gate_stats(circuit)
176
+
171
177
 
172
178
  import re
173
179
  is_emulator_regex = re.compile("^.*(-sim|-[0-9]*e)$")
@@ -2,7 +2,8 @@
2
2
  # Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  # Licensed under the MIT License.
4
4
  ##
5
- from typing import TYPE_CHECKING, Any, Dict, Optional, Union, Type, Protocol, runtime_checkable
5
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, Type, Protocol, runtime_checkable
6
+ from dataclasses import dataclass
6
7
  import io
7
8
  import json
8
9
  import abc
@@ -26,6 +27,14 @@ class QirRepresentable(Protocol):
26
27
  def _repr_qir_(self, **kwargs: Any) -> bytes:
27
28
  raise NotImplementedError
28
29
 
30
+ @dataclass
31
+ class GateStats:
32
+ one_qubit_gates: int
33
+ multi_qubit_gates: int
34
+ measurement_gates: int
35
+
36
+ def __iter__(self):
37
+ return iter((self.one_qubit_gates, self.multi_qubit_gates, self.measurement_gates))
29
38
 
30
39
  class Target(abc.ABC, SessionHost):
31
40
 
@@ -327,6 +336,57 @@ target '{self.name}' of provider '{self.provider_id}' not found."
327
336
  def _get_azure_provider_id(self) -> str:
328
337
  return self.provider_id
329
338
 
339
+ @classmethod
340
+ def _calculate_qir_module_gate_stats(self, qir_module) -> GateStats:
341
+ try:
342
+ from pyqir import Module, is_qubit_type, is_result_type, entry_point, is_entry_point, Function
343
+
344
+ except ImportError:
345
+ raise ImportError(
346
+ "Missing optional 'qiskit' dependencies. \
347
+ To install run: pip install azure-quantum[qiskit]"
348
+ )
349
+
350
+ module: Module = qir_module
351
+
352
+ one_qubit_gates = 0
353
+ multi_qubit_gates = 0
354
+ measurement_gates = 0
355
+
356
+ function_entry_points: list[Function] = filter(is_entry_point, module.functions)
357
+
358
+ # Iterate over the blocks and their instructions
359
+ for function in function_entry_points:
360
+ for block in function.basic_blocks:
361
+ for instruction in block.instructions:
362
+ qubit_count = 0
363
+ result_count = 0
364
+
365
+ # If the instruction is of type quantum rt, do not include this is the price calculation
366
+ if len(instruction.operands) > 0 and "__quantum__rt" not in instruction.operands[-1].name:
367
+ # Check each operand in the instruction
368
+ for operand in instruction.operands:
369
+ value_type = operand.type
370
+
371
+ if is_qubit_type(value_type):
372
+ qubit_count += 1
373
+ elif is_result_type(value_type):
374
+ result_count += 1
375
+
376
+ # Determine the type of gate based on the counts
377
+ if qubit_count == 1 and result_count == 0:
378
+ one_qubit_gates += 1
379
+ if qubit_count >= 2 and result_count == 0:
380
+ multi_qubit_gates += 1
381
+ if result_count > 0:
382
+ measurement_gates += 1
383
+
384
+ return GateStats (
385
+ one_qubit_gates,
386
+ multi_qubit_gates,
387
+ measurement_gates
388
+ )
389
+
330
390
 
331
391
  def _determine_shots_or_deprecated_num_shots(
332
392
  shots: int = None,
@@ -5,4 +5,4 @@
5
5
  # Copyright (c) Microsoft Corporation. All rights reserved.
6
6
  # Licensed under the MIT License.
7
7
  ##
8
- __version__ = "2.1.1"
8
+ __version__ = "2.2.0.dev0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: azure-quantum
3
- Version: 2.1.1
3
+ Version: 2.2.0.dev0
4
4
  Summary: Python client for Azure Quantum
5
5
  Home-page: https://github.com/microsoft/azure-quantum-python
6
6
  Author: Microsoft