azure-quantum 2.2.0.dev6__py3-none-any.whl → 2.4.0__py3-none-any.whl

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 (29) hide show
  1. azure/quantum/_client/_version.py +1 -1
  2. azure/quantum/_client/py.typed +1 -0
  3. azure/quantum/argument_types/__init__.py +1 -1
  4. azure/quantum/cirq/service.py +0 -30
  5. azure/quantum/cirq/targets/ionq.py +0 -31
  6. azure/quantum/cirq/targets/quantinuum.py +0 -20
  7. azure/quantum/qiskit/backends/__init__.py +0 -5
  8. azure/quantum/qiskit/backends/backend.py +2 -19
  9. azure/quantum/qiskit/backends/ionq.py +0 -15
  10. azure/quantum/qiskit/backends/quantinuum.py +1 -32
  11. azure/quantum/qiskit/job.py +2 -8
  12. azure/quantum/target/ionq.py +0 -111
  13. azure/quantum/target/microsoft/elements/dft/job.py +108 -2
  14. azure/quantum/target/microsoft/elements/dft/target.py +158 -8
  15. azure/quantum/target/microsoft/target.py +0 -329
  16. azure/quantum/target/quantinuum.py +0 -123
  17. azure/quantum/target/rigetti/target.py +5 -0
  18. azure/quantum/target/target.py +1 -11
  19. azure/quantum/version.py +1 -1
  20. {azure_quantum-2.2.0.dev6.dist-info → azure_quantum-2.4.0.dist-info}/METADATA +3 -3
  21. {azure_quantum-2.2.0.dev6.dist-info → azure_quantum-2.4.0.dist-info}/RECORD +23 -28
  22. {azure_quantum-2.2.0.dev6.dist-info → azure_quantum-2.4.0.dist-info}/WHEEL +1 -1
  23. azure/quantum/qiskit/backends/microsoft.py +0 -149
  24. azure/quantum/qiskit/results/__init__.py +0 -0
  25. azure/quantum/qiskit/results/resource_estimator.py +0 -25
  26. azure/quantum/target/microsoft/__init__.py +0 -15
  27. azure/quantum/target/microsoft/job.py +0 -35
  28. azure/quantum/target/microsoft/result.py +0 -497
  29. {azure_quantum-2.2.0.dev6.dist-info → azure_quantum-2.4.0.dist-info}/top_level.txt +0 -0
@@ -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.2.0.dev6"
9
+ VERSION = "2.4.0"
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561.
@@ -3,7 +3,7 @@
3
3
  # Licensed under the MIT License.
4
4
  ##
5
5
 
6
- """Defines argument types for Microsoft Estimator"""
6
+ """Defines argument types for QIR"""
7
7
 
8
8
  from .types import EmptyArray, Pauli, Range, Result
9
9
 
@@ -160,36 +160,6 @@ see https://aka.ms/AQ/Docs/AddProvider")
160
160
  name=name
161
161
  )
162
162
 
163
- def estimate_cost(
164
- self,
165
- program: cirq.Circuit,
166
- repetitions: int,
167
- target: str = None,
168
- param_resolver: cirq.ParamResolverOrSimilarType = cirq.ParamResolver({}),
169
- **kwargs
170
- ):
171
- """
172
- Estimate the cost for a given circuit.
173
-
174
- :param program: Cirq program or circuit
175
- :type program: cirq.Circuit
176
- :param repetitions: Number of measurement repetitions
177
- :type repetitions: int
178
- :param target: Target name, defaults to default_target
179
- :type target: str
180
- :param param_resolver: Cirq parameters, defaults to `cirq.ParamResolver({})`
181
- :type param_resolver: cirq.ParamResolverOrSimilarType
182
- """
183
-
184
- # Resolve parameters
185
- resolved_circuit = cirq.resolve_parameters(program, param_resolver)
186
- target = self.get_target(name=target)
187
- return target.estimate_cost(
188
- program=resolved_circuit,
189
- repetitions=repetitions,
190
- **kwargs
191
- )
192
-
193
163
  def run(
194
164
  self,
195
165
  program: cirq.Circuit,
@@ -119,37 +119,6 @@ are not installed, throw error with installation instructions."""
119
119
  job_dict = self._client._create_job_dict(azure_job)
120
120
  return CirqIonqJob(client=self._client, job_dict=job_dict)
121
121
 
122
- def estimate_cost(
123
- self,
124
- program: "cirq.Circuit",
125
- repetitions: int,
126
- price_1q: float = None,
127
- price_2q: float = None,
128
- min_price: float = None) -> float:
129
- """Estimate cost for running this program
130
-
131
- :param program: Cirq quantum program
132
- :type program: cirq.Circuit
133
- :param repetitions: Number of repetitions
134
- :type repetitions: int
135
- :param price_1q: The price of running a single-qubit gate.
136
- :type price_1q: float, optional
137
- :param price_2q: The price of running a double-qubit gate.
138
- :type price_2q: float, optional
139
- :param min_price: The minimum price for running a job.
140
- :type min_price: float, optional
141
- :return: Price estimate
142
- :rtype: float
143
- """
144
- serialized_program = self._translate_cirq_circuit(program)
145
- return super().estimate_cost(
146
- serialized_program.body,
147
- repetitions,
148
- price_1q=price_1q,
149
- price_2q=price_2q,
150
- min_price=min_price
151
- )
152
-
153
122
  def submit(
154
123
  self,
155
124
  program: "cirq.Circuit",
@@ -74,26 +74,6 @@ class QuantinuumTarget(Quantinuum, CirqTarget):
74
74
  meas.gate.key: [q.x for q in meas.qubits] for meas in measurements
75
75
  }
76
76
 
77
- def estimate_cost(
78
- self,
79
- program: str,
80
- repetitions: int
81
- ) -> float:
82
- """Estimate cost for running this program
83
-
84
- :param program: Cirq quantum program
85
- :type program: str, optional
86
- :param repetitions: Number of repetitions
87
- :type repetitions: int, optional
88
- :return: Price estimate in HQC
89
- :rtype: float
90
- """
91
- serialized_program = self._translate_circuit(program)
92
- return super().estimate_cost(
93
- circuit=serialized_program,
94
- shots=repetitions
95
- )
96
-
97
77
  def submit(
98
78
  self,
99
79
  program: "cirq.Circuit",
@@ -37,11 +37,6 @@ from azure.quantum.qiskit.backends.qci import (
37
37
  QCIQPUBackend,
38
38
  )
39
39
 
40
- from azure.quantum.qiskit.backends.microsoft import (
41
- MicrosoftBackend,
42
- MicrosoftResourceEstimationBackend,
43
- )
44
-
45
40
  from .backend import AzureBackendBase
46
41
 
47
42
  __all__ = [
@@ -440,6 +440,8 @@ class AzureQirBackend(AzureBackendBase):
440
440
  for circuit in circuits:
441
441
  qir_str = backend.qir(circuit)
442
442
  module = pyqir.Module.from_ir(context, qir_str)
443
+ entry_point = next(filter(pyqir.is_entry_point, module.functions))
444
+ entry_point.name = circuit.name
443
445
  llvm_module.link(module)
444
446
  err = llvm_module.verify()
445
447
  if err is not None:
@@ -498,25 +500,6 @@ class AzureQirBackend(AzureBackendBase):
498
500
 
499
501
  return str(module).encode("utf-8")
500
502
 
501
- def _estimate_cost_qir(
502
- self, circuits: Union[QuantumCircuit, List[QuantumCircuit]], shots, options={}
503
- ):
504
- """Estimate the cost for the given circuit."""
505
- input_params = self._get_input_params(options, shots=shots)
506
-
507
- if not (isinstance(circuits, list)):
508
- circuits = [circuits]
509
-
510
- skip_transpilation = input_params.pop("skipTranspile", False)
511
- target_profile = self._get_target_profile(input_params)
512
- module = self._generate_qir(
513
- circuits, target_profile, skip_transpilation=skip_transpilation
514
- )
515
-
516
- workspace = self.provider().get_workspace()
517
- target = workspace.get_targets(self.name())
518
- return target.estimate_cost(module, shots=shots)
519
-
520
503
  def _get_target_profile(self, input_params) -> TargetProfile:
521
504
  # Default to Adaptive_RI if not specified on the backend
522
505
  # this is really just a safeguard in case the backend doesn't have a default
@@ -77,10 +77,6 @@ class IonQQirBackendBase(AzureQirBackend):
77
77
  )
78
78
  return config
79
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)
83
-
84
80
  def run(
85
81
  self,
86
82
  run_input: Union[QuantumCircuit, List[QuantumCircuit]] = [],
@@ -265,17 +261,6 @@ class IonQBackend(AzureBackend):
265
261
  def gateset(self):
266
262
  return self.configuration().gateset
267
263
 
268
- def estimate_cost(self, circuit, shots):
269
- """Estimate the cost for the given circuit."""
270
- ionq_circ, _, _ = qiskit_circ_to_ionq_circ(circuit, gateset=self.gateset())
271
- input_data = {
272
- "qubits": circuit.num_qubits,
273
- "circuit": ionq_circ,
274
- }
275
- workspace = self.provider().get_workspace()
276
- target = workspace.get_targets(self.name())
277
- return target.estimate_cost(input_data, shots=shots)
278
-
279
264
 
280
265
  class IonQSimulatorBackend(IonQBackend):
281
266
  backend_names = ("ionq.simulator",)
@@ -60,7 +60,7 @@ def _get_n_qubits(name):
60
60
  if ".h1-" in name or "hqs-lt" in name:
61
61
  return 20
62
62
  if ".h2-" in name:
63
- return 32
63
+ return 56
64
64
  warnings.warn(
65
65
  UserWarning(f"Number of qubits not known for target {name}. Defaulting to 20."))
66
66
  return 20
@@ -99,10 +99,6 @@ class QuantinuumQirBackendBase(AzureQirBackend):
99
99
  def _get_n_qubits(self, name):
100
100
  return _get_n_qubits(name)
101
101
 
102
- def estimate_cost(self, circuits, shots, options={}):
103
- """Estimate the cost for the given circuit."""
104
- return self._estimate_cost_qir(circuits, shots, options)
105
-
106
102
 
107
103
  class QuantinuumSyntaxCheckerQirBackend(QuantinuumQirBackendBase):
108
104
  backend_names = (
@@ -248,33 +244,6 @@ class QuantinuumBackend(AzureBackend):
248
244
  """Translates the input values to the format expected by the AzureBackend."""
249
245
  return dumps(circuit)
250
246
 
251
- def estimate_cost(
252
- self, circuit: QuantumCircuit, shots: int = None, count: int = None
253
- ):
254
- """Estimate cost for running this circuit
255
-
256
- :param circuit: Qiskit quantum circuit
257
- :type circuit: QuantumCircuit
258
- :param shots: Shot count
259
- :type shots: int
260
- :param count: Shot count (alternative to 'shots')
261
- :type count: int
262
- """
263
- if count is not None:
264
- warnings.warn(
265
- "The 'count' parameter will be deprecated. Please, use 'shots' parameter instead.",
266
- category=DeprecationWarning,
267
- )
268
- shots = count
269
-
270
- if shots is None:
271
- raise ValueError("Missing input argument 'shots'.")
272
-
273
- input_data = dumps(circuit)
274
- workspace = self.provider().get_workspace()
275
- target = workspace.get_targets(self.name())
276
- return target.estimate_cost(input_data, shots=shots)
277
-
278
247
  def _get_n_qubits(self, name):
279
248
  return _get_n_qubits(name)
280
249
 
@@ -19,7 +19,6 @@ import ast
19
19
  import json
20
20
  import re
21
21
  from azure.quantum import Job
22
- from azure.quantum.qiskit.results.resource_estimator import make_estimator_result
23
22
 
24
23
  import logging
25
24
  logger = logging.getLogger(__name__)
@@ -38,7 +37,6 @@ MICROSOFT_OUTPUT_DATA_FORMAT = "microsoft.quantum-results.v1"
38
37
  MICROSOFT_OUTPUT_DATA_FORMAT_V2 = "microsoft.quantum-results.v2"
39
38
  IONQ_OUTPUT_DATA_FORMAT = "ionq.quantum-results.v1"
40
39
  QUANTINUUM_OUTPUT_DATA_FORMAT = "honeywell.quantum-results.v1"
41
- RESOURCE_ESTIMATOR_OUTPUT_DATA_FORMAT = "microsoft.resource-estimates.v1"
42
40
 
43
41
  class AzureQuantumJob(JobV1):
44
42
  def __init__(
@@ -96,10 +94,7 @@ class AzureQuantumJob(JobV1):
96
94
  "error_data" : None if self._azure_job.details.error_data is None else self._azure_job.details.error_data.as_dict()
97
95
  }
98
96
 
99
- if self._azure_job.details.output_data_format == RESOURCE_ESTIMATOR_OUTPUT_DATA_FORMAT:
100
- return make_estimator_result(result_dict)
101
- else:
102
- return Result.from_dict(result_dict)
97
+ return Result.from_dict(result_dict)
103
98
 
104
99
  def cancel(self):
105
100
  """Attempt to cancel the job."""
@@ -218,8 +213,7 @@ class AzureQuantumJob(JobV1):
218
213
 
219
214
  if isinstance(obj, tuple):
220
215
  # the outermost implied container is a tuple, and each item is
221
- # associated with a classical register. Azure and Qiskit order the
222
- # registers in opposite directions, so reverse here to match.
216
+ # associated with a classical register.
223
217
  return " ".join(
224
218
  [
225
219
  AzureQuantumJob._qir_to_qiskit_bitstring(term)
@@ -126,114 +126,3 @@ class IonQ(Target):
126
126
  input_params=input_params,
127
127
  **kwargs
128
128
  )
129
-
130
- def estimate_cost(
131
- self,
132
- circuit: Union[Dict[str, Any], Any],
133
- num_shots: int = None,
134
- price_1q: float = None,
135
- price_2q: float = None,
136
- min_price: float = None,
137
- shots: int = None
138
- ) -> CostEstimate:
139
- """Estimate the cost of submitting a circuit to IonQ targets.
140
- Optionally, you can provide the number of gate and measurement operations
141
- manually.
142
- The actual price charged by the provider may differ from this calculation.
143
-
144
- Specify pricing details for your area to get most accurate results.
145
- By default, this function charges depending on the target:
146
- ionq.qpu.aria-1:
147
- price_1q = 0.00022 USD for a single-qubit gate.
148
- price_2q = 0.00098 USD for a two-qubit gate.
149
- min_price = 1 USD, total minimum price per circuit.
150
-
151
- For the most current pricing details, see
152
- https://docs.microsoft.com/azure/quantum/provider-ionq#pricing
153
- or find your workspace and view pricing options in the "Provider" tab
154
- of your workspace: https://aka.ms/aq/myworkspaces
155
-
156
- :param circuit: Quantum circuit in IonQ JSON format (for examples,
157
- see: https://docs.ionq.com/#section/Sample-JSON-Circuits)
158
- :type circuit: Dict[str, Any]
159
- :param num_shots: Number of shots, defaults to None
160
- :type num_shots: int
161
- :param price_1q: The price of running a single-qubit gate
162
- for one shot.
163
- :type price_1q: float
164
- :param price_2q: The price of running a double-qubit gate
165
- for one shot.
166
- :type price_2q: float
167
- :param min_price: The minimum price for running a job.
168
- :type min_price: float
169
- :param shots: Number of shots, defaults to None
170
- :type shots: int
171
- """
172
-
173
- if num_shots is None and shots is None:
174
- raise ValueError("The 'shots' parameter has to be specified")
175
-
176
- if num_shots is not None:
177
- warn(
178
- "The 'num_shots' parameter will be deprecated. Please, use 'shots' parameter instead.",
179
- category=DeprecationWarning,
180
- )
181
- shots = num_shots
182
-
183
- # Get the costs for the gates depending on the provider if not specified
184
- if price_1q is None:
185
- price_1q = COST_1QUBIT_GATE_MAP[self.name]
186
-
187
- if price_2q is None:
188
- price_2q = COST_2QUBIT_GATE_MAP[self.name]
189
-
190
- if min_price is None:
191
- min_price = MIN_PRICE_MAP[self.name]
192
-
193
- if (isinstance(circuit, Dict)):
194
- def is_1q_gate(gate: Dict[str, Any]):
195
- return "controls" not in gate and "control" not in gate
196
-
197
- def is_multi_q_gate(gate):
198
- return "controls" in gate or "control" in gate
199
-
200
- def num_2q_gates(gate):
201
- controls = gate.get("controls")
202
- if controls is None or len(controls) == 1:
203
- # Only one control qubit
204
- return 1
205
- # Multiple control qubits
206
- return 6 * (len(controls) - 2)
207
-
208
- gates = circuit.get("circuit", [])
209
- N_1q = sum(map(is_1q_gate, gates))
210
- N_2q = sum(map(num_2q_gates, filter(is_multi_q_gate, gates)))
211
-
212
- else:
213
- N_1q, N_2q, _ = Target._calculate_qir_module_gate_stats(circuit)
214
-
215
- price = (price_1q * N_1q + price_2q * N_2q) * shots
216
- price = max(price, min_price)
217
-
218
- return CostEstimate(
219
- events = [
220
- UsageEvent(
221
- dimension_id="gs1q",
222
- dimension_name="1Q Gate Shot",
223
- measure_unit="1q gate shot",
224
- amount_billed=0.0,
225
- amount_consumed=N_1q * shots,
226
- unit_price=0.0
227
- ),
228
- UsageEvent(
229
- dimension_id="gs2q",
230
- dimension_name="2Q Gate Shot",
231
- measure_unit="2q gate shot",
232
- amount_billed=0.0,
233
- amount_consumed=N_2q * shots,
234
- unit_price=0.0
235
- )
236
- ],
237
- currency_code="USD",
238
- estimated_total=price
239
- )
@@ -1,8 +1,13 @@
1
1
  import collections.abc
2
- from typing import Any, Dict, Union
2
+ import logging
3
+ from typing import Any, Dict, Union, Optional
3
4
  from azure.quantum.job import JobFailedWithResultsError
5
+ from azure.quantum.job.base_job import BaseJob, ContentType
4
6
  from azure.quantum.job.job import Job, DEFAULT_TIMEOUT
5
7
  from azure.quantum._client.models import JobDetails
8
+ from azure.quantum.workspace import Workspace
9
+
10
+ logger = logging.getLogger(__name__)
6
11
 
7
12
  class MicrosoftElementsDftJob(Job):
8
13
  """
@@ -62,4 +67,105 @@ class MicrosoftElementsDftJob(Job):
62
67
  and "error" in failure_results["results"][0] \
63
68
  and isinstance(failure_results["results"][0]["error"], dict) \
64
69
  and "error_type" in failure_results["results"][0]["error"] \
65
- and "error_message" in failure_results["results"][0]["error"]
70
+ and "error_message" in failure_results["results"][0]["error"]
71
+
72
+ @classmethod
73
+ def from_input_data_container(
74
+ cls,
75
+ workspace: "Workspace",
76
+ name: str,
77
+ target: str,
78
+ input_data: bytes,
79
+ batch_input_blobs: Dict[str, bytes],
80
+ content_type: ContentType = ContentType.json,
81
+ blob_name: str = "inputData",
82
+ encoding: str = "",
83
+ job_id: str = None,
84
+ container_name: str = None,
85
+ provider_id: str = None,
86
+ input_data_format: str = None,
87
+ output_data_format: str = None,
88
+ input_params: Dict[str, Any] = None,
89
+ session_id: Optional[str] = None,
90
+ **kwargs
91
+ ) -> "BaseJob":
92
+ """Create a new Azure Quantum job based on a list of input_data.
93
+
94
+ :param workspace: Azure Quantum workspace to submit the input_data to
95
+ :type workspace: Workspace
96
+ :param name: Name of the job
97
+ :type name: str
98
+ :param target: Azure Quantum target
99
+ :type target: str
100
+ :param input_data: Raw input data to submit
101
+ :type input_data: Dict
102
+ :param blob_name: Dict of Input data json to gives a table of contents
103
+ :type batch_input_blobs: Dict
104
+ :param blob_name: Dict of QcSchema Data where the key is the blob name to store it in the container
105
+ :type blob_name: str
106
+ :param content_type: Content type, e.g. "application/json"
107
+ :type content_type: ContentType
108
+ :param encoding: input_data encoding, e.g. "gzip", defaults to empty string
109
+ :type encoding: str
110
+ :param job_id: Job ID, defaults to None
111
+ :type job_id: str
112
+ :param container_name: Container name, defaults to None
113
+ :type container_name: str
114
+ :param provider_id: Provider ID, defaults to None
115
+ :type provider_id: str
116
+ :param input_data_format: Input data format, defaults to None
117
+ :type input_data_format: str
118
+ :param output_data_format: Output data format, defaults to None
119
+ :type output_data_format: str
120
+ :param input_params: Input parameters, defaults to None
121
+ :type input_params: Dict[str, Any]
122
+ :param input_params: Input params for job
123
+ :type input_params: Dict[str, Any]
124
+ :return: Azure Quantum Job
125
+ :rtype: Job
126
+ """
127
+ # Generate job ID if not specified
128
+ if job_id is None:
129
+ job_id = cls.create_job_id()
130
+
131
+ # Create container if it does not yet exist
132
+ container_uri = workspace.get_container_uri(
133
+ job_id=job_id,
134
+ container_name=container_name
135
+ )
136
+ logger.debug(f"Container URI: {container_uri}")
137
+
138
+ # Upload Input Data
139
+ input_data_uri = cls.upload_input_data(
140
+ container_uri=container_uri,
141
+ input_data=input_data,
142
+ content_type=content_type,
143
+ blob_name=blob_name,
144
+ encoding=encoding,
145
+ )
146
+
147
+ # Upload data to container
148
+ for blob_name, input_data_item in batch_input_blobs.items():
149
+ cls.upload_input_data(
150
+ container_uri=container_uri,
151
+ input_data=input_data_item,
152
+ content_type=content_type,
153
+ blob_name=blob_name,
154
+ encoding=encoding,
155
+ )
156
+
157
+ # Create and submit job
158
+ return cls.from_storage_uri(
159
+ workspace=workspace,
160
+ job_id=job_id,
161
+ target=target,
162
+ input_data_uri=input_data_uri,
163
+ container_uri=container_uri,
164
+ name=name,
165
+ input_data_format=input_data_format,
166
+ output_data_format=output_data_format,
167
+ provider_id=provider_id,
168
+ input_params=input_params,
169
+ session_id=session_id,
170
+ **kwargs
171
+ )