azure-quantum 2.2.0.dev5__py3-none-any.whl → 2.3.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.
@@ -5,8 +5,11 @@ from azure.quantum.job.job import Job
5
5
  from azure.quantum.target.target import Target
6
6
  from azure.quantum.workspace import Workspace
7
7
  from azure.quantum.target.params import InputParams
8
- from typing import Any, Dict, Type, Union
8
+ from typing import Any, Dict, Type, Union, List
9
9
  from .job import MicrosoftElementsDftJob
10
+ from pathlib import Path
11
+ import copy
12
+ import json
10
13
 
11
14
 
12
15
  class MicrosoftElementsDft(Target):
@@ -73,15 +76,161 @@ class MicrosoftElementsDft(Target):
73
76
  if shots is not None:
74
77
  warnings.warn("The 'shots' parameter is ignored in Microsoft Elements Dft job.")
75
78
 
76
- return super().submit(
77
- input_data=input_data,
78
- name=name,
79
- shots=shots,
80
- input_params=input_params,
81
- **kwargs
82
- )
79
+ if isinstance(input_data, list):
80
+
81
+ qcschema_data = self._assemble_qcshema_from_files(input_data, input_params)
82
+
83
+ qcschema_blobs = {}
84
+ for i in range(len(qcschema_data)):
85
+ qcschema_blobs[f"inputData_{i}"] = self._encode_input_data(qcschema_data[i])
83
86
 
87
+ toc_str = self._create_table_of_contents(input_data, list(qcschema_blobs.keys()))
88
+ toc = self._encode_input_data(toc_str)
89
+
90
+ return self._get_job_class().from_input_data_container(
91
+ workspace=self.workspace,
92
+ name=name,
93
+ target=self.name,
94
+ input_data=toc,
95
+ batch_input_blobs=qcschema_blobs,
96
+ input_params={ 'numberOfFiles': len(qcschema_data), "inputFiles": list(qcschema_blobs.keys()), **input_params },
97
+ content_type=kwargs.pop('content_type', self.content_type),
98
+ encoding=kwargs.pop('encoding', self.encoding),
99
+ provider_id=self.provider_id,
100
+ input_data_format=kwargs.pop('input_data_format', 'microsoft.qc-schema.v1'),
101
+ output_data_format=kwargs.pop('output_data_format', self.output_data_format),
102
+ session_id=self.get_latest_session_id(),
103
+ **kwargs
104
+ )
105
+ else:
106
+ return super().submit(
107
+ input_data=input_data,
108
+ name=name,
109
+ shots=shots,
110
+ input_params=input_params,
111
+ **kwargs
112
+ )
113
+
114
+
115
+
116
+ @classmethod
117
+ def _assemble_qcshema_from_files(self, input_data: List[str], input_params: Dict) -> str:
118
+ """
119
+ Convert a list of files to a list of qcshema objects serialized in json.
120
+ """
121
+
122
+ qcshema_objects = []
123
+ for file in input_data:
124
+ file_path = Path(file)
125
+ if not file_path.exists():
126
+ raise FileNotFoundError(f"File {file} does not exist.")
127
+
128
+ file_data = file_path.read_text()
129
+ if file_path.suffix == '.xyz':
130
+ mol = self._xyz_to_qcschema_mol(file_data)
131
+ new_qcschema = self._new_qcshema( input_params, mol )
132
+ qcshema_objects.append(new_qcschema)
133
+ elif file_path.suffix == '.json':
134
+ if input_params is not None and len(input_params.keys()) > 0:
135
+ warnings.warn('Input parameters were given along with a QcSchema file which contains parameters, using QcSchema parameters as is.')
136
+ with open(file_path, 'r') as f:
137
+ qcshema_objects.append( json.load(f) )
138
+ else:
139
+ raise ValueError(f"File type '{file_path.suffix}' for file '{file_path}' is not supported. Please use xyz or QcSchema file formats.")
140
+
141
+ return qcshema_objects
142
+
143
+ @classmethod
144
+ def _new_qcshema( self, input_params: Dict[str,Any], mol: Dict[str,Any], ) -> Dict[str, Any]:
145
+ """
146
+ Create a new default qcshema object.
147
+ """
148
+
149
+ if input_params.get("driver") == "go":
150
+ copy_input_params = copy.deepcopy(input_params)
151
+ copy_input_params["driver"] = "gradient"
152
+ new_object = {
153
+ "schema_name": "qcschema_optimization_input",
154
+ "schema_version": 1,
155
+ "initial_molecule": mol,
156
+ }
157
+ if copy_input_params.get("keywords") and copy_input_params["keywords"].get("geometryOptimization"):
158
+ new_object["keywords"] = copy_input_params["keywords"].pop("geometryOptimization")
159
+ new_object["input_specification"] = copy_input_params
160
+ return new_object
161
+ elif input_params.get("driver") == "bomd":
162
+ copy_input_params = copy.deepcopy(input_params)
163
+ copy_input_params["driver"] = "gradient"
164
+ new_object = {
165
+ "schema_name": "madft_molecular_dynamics_input",
166
+ "schema_version": 1,
167
+ "initial_molecule": mol,
168
+ }
169
+ if copy_input_params.get("keywords") and copy_input_params["keywords"].get("molecularDynamics"):
170
+ new_object["keywords"] = copy_input_params["keywords"].pop("molecularDynamics")
171
+ new_object["input_specification"] = copy_input_params
172
+ return new_object
173
+ else:
174
+ new_object = copy.deepcopy(input_params)
175
+ new_object.update({
176
+ "schema_name": "qcschema_input",
177
+ "schema_version": 1,
178
+ "molecule": mol,
179
+ })
180
+ return new_object
181
+
182
+
183
+ @classmethod
184
+ def _xyz_to_qcschema_mol(self, file_data: str ) -> Dict[str, Any]:
185
+ """
186
+ Convert xyz format to qcschema molecule.
187
+ """
188
+
189
+ lines = file_data.split("\n")
190
+ if len(lines) < 3:
191
+ raise ValueError("Invalid xyz format.")
192
+ n_atoms = int(lines.pop(0))
193
+ comment = lines.pop(0)
194
+ mol = {
195
+ "geometry": [],
196
+ "symbols": [],
197
+ }
198
+ for line in lines:
199
+ if line:
200
+ elements = line.split()
201
+ if len(elements) < 4:
202
+ raise ValueError("Invalid xyz format.")
203
+ symbol, x, y, z = elements
204
+ mol["symbols"].append(symbol)
205
+ mol["geometry"] += [float(x), float(y), float(z)]
206
+ else:
207
+ break
208
+
209
+ if len(mol["symbols"]) != n_atoms:
210
+ raise ValueError("Number of inputs does not match the number of atoms in xyz file.")
211
+
212
+ return mol
84
213
 
85
214
  @classmethod
86
215
  def _get_job_class(cls) -> Type[Job]:
87
216
  return MicrosoftElementsDftJob
217
+
218
+ @classmethod
219
+ def _create_table_of_contents(cls, input_files: List[str], input_blobs: List[str]) -> Dict[str,Any]:
220
+ """Create the table of contents for a batched job that contains a description of file and the mapping between the file names and the blob names"""
221
+
222
+ assert len(input_files) == len(input_blobs), "Internal error: number of blobs is not that same as the number of files."
223
+
224
+ toc = []
225
+ for i in range(len(input_files)):
226
+ toc.append(
227
+ {
228
+ "inputFileName": input_files[i],
229
+ "qcschemaBlobName": input_blobs[i],
230
+ }
231
+ )
232
+
233
+ return {
234
+ "description": "This files contains the mapping between the xyz file name that were submitted and the qcschema blobs that are used for the calculation.",
235
+ "tableOfContents": toc,
236
+ }
@@ -13,29 +13,6 @@ from ...workspace import Workspace
13
13
  from ..params import InputParams, InputParamsItem, AutoValidatingParams, \
14
14
  validating_field
15
15
  from ..target import Target
16
- from . import MicrosoftEstimatorJob
17
-
18
- class QubitParams:
19
- """
20
- Resource estimator Qubit parameters.
21
- """
22
-
23
- GATE_US_E3 = "qubit_gate_us_e3"
24
- GATE_US_E4 = "qubit_gate_us_e4"
25
- GATE_NS_E3 = "qubit_gate_ns_e3"
26
- GATE_NS_E4 = "qubit_gate_ns_e4"
27
- MAJ_NS_E4 = "qubit_maj_ns_e4"
28
- MAJ_NS_E6 = "qubit_maj_ns_e6"
29
-
30
-
31
- class QECScheme:
32
- """
33
- Resource estimator QEC Scheme.
34
- """
35
-
36
- SURFACE_CODE = "surface_code"
37
- FLOQUET_CODE = "floquet_code"
38
-
39
16
 
40
17
  def _check_error_rate(name, value):
41
18
  if value <= 0.0 or value >= 1.0:
@@ -64,90 +41,6 @@ class MeasurementErrorRate(AutoValidatingParams):
64
41
  process: float = field(metadata={"validate": _check_error_rate})
65
42
  readout: float = field(metadata={"validate": _check_error_rate})
66
43
 
67
- @dataclass
68
- class MicrosoftEstimatorQubitParams(AutoValidatingParams):
69
- @staticmethod
70
- def check_instruction_set(name, value):
71
- if value not in ["gate-based", "gate_based", "GateBased", "gateBased",
72
- "Majorana", "majorana"]:
73
- raise ValueError(f"{name} must be GateBased or Majorana")
74
-
75
- name: Optional[str] = None
76
- instruction_set: Optional[str] = validating_field(check_instruction_set)
77
- one_qubit_measurement_time: Optional[str] = validating_field(check_time)
78
- two_qubit_joint_measurement_time: Optional[str] = \
79
- validating_field(check_time)
80
- one_qubit_gate_time: Optional[str] = validating_field(check_time)
81
- two_qubit_gate_time: Optional[str] = validating_field(check_time)
82
- t_gate_time: Optional[str] = validating_field(check_time)
83
- one_qubit_measurement_error_rate: Union[None, float, MeasurementErrorRate] = \
84
- validating_field(_check_error_rate_or_process_and_readout)
85
- two_qubit_joint_measurement_error_rate: Union[None, float, MeasurementErrorRate] = \
86
- validating_field(_check_error_rate_or_process_and_readout)
87
- one_qubit_gate_error_rate: Optional[float] = \
88
- validating_field(_check_error_rate)
89
- two_qubit_gate_error_rate: Optional[float] = \
90
- validating_field(_check_error_rate)
91
- t_gate_error_rate: Optional[float] = validating_field(_check_error_rate)
92
- idle_error_rate: Optional[float] = validating_field(_check_error_rate)
93
-
94
- _default_models = [QubitParams.GATE_US_E3, QubitParams.GATE_US_E4,
95
- QubitParams.GATE_NS_E3, QubitParams.GATE_NS_E4,
96
- QubitParams.MAJ_NS_E4, QubitParams.MAJ_NS_E6]
97
- _gate_based = ["gate-based", "gate_based", "GateBased", "gateBased"]
98
- _maj_based = ["Majorana", "majorana"]
99
-
100
- def post_validation(self, result):
101
- # check whether all fields have been specified in case a custom qubit
102
- # model is specified
103
- custom = result != {} and \
104
- (self.name is None or self.name not in self._default_models)
105
-
106
- # no further validation needed for non-custom models
107
- if not custom:
108
- return
109
-
110
- # instruction set must be set
111
- if self.instruction_set is None:
112
- raise LookupError("instruction_set must be set for custom qubit "
113
- "parameters")
114
-
115
- # NOTE at this point, we know that instruction set must have valid
116
- # value
117
- if self.one_qubit_measurement_time is None:
118
- raise LookupError("one_qubit_measurement_time must be set")
119
- if self.one_qubit_measurement_error_rate is None:
120
- raise LookupError("one_qubit_measurement_error_rate must be set")
121
-
122
- # this only needs to be checked for gate based qubits
123
- if self.instruction_set in self._gate_based:
124
- if self.one_qubit_gate_time is None:
125
- raise LookupError("one_qubit_gate_time must be set")
126
-
127
- def as_dict(self, validate=True) -> Dict[str, Any]:
128
- qubit_params = super().as_dict(validate)
129
- if len(qubit_params) != 0:
130
- if isinstance(self.one_qubit_measurement_error_rate, MeasurementErrorRate):
131
- qubit_params["oneQubitMeasurementErrorRate"] = \
132
- self.one_qubit_measurement_error_rate.as_dict(validate)
133
-
134
- if isinstance(self.two_qubit_joint_measurement_error_rate, MeasurementErrorRate):
135
- qubit_params["twoQubitJointMeasurementErrorRate"] = \
136
- self.two_qubit_joint_measurement_error_rate.as_dict(validate)
137
-
138
- return qubit_params
139
-
140
-
141
- @dataclass
142
- class MicrosoftEstimatorQecScheme(AutoValidatingParams):
143
- name: Optional[str] = None
144
- error_correction_threshold: Optional[float] = \
145
- validating_field(_check_error_rate)
146
- crossing_prefactor: Optional[float] = None
147
- logical_cycle_time: Optional[str] = None
148
- physical_qubits_per_logical_qubit: Optional[str] = None
149
-
150
-
151
44
  @dataclass
152
45
  class ProtocolSpecificDistillationUnitSpecification(AutoValidatingParams):
153
46
  num_unit_qubits: Optional[int] = None
@@ -247,225 +140,3 @@ class DistillationUnitSpecification(AutoValidatingParams):
247
140
  logical_qubit_specification_first_round_override_dict
248
141
 
249
142
  return specification_dict
250
-
251
-
252
- @dataclass
253
- class ErrorBudgetPartition(AutoValidatingParams):
254
- """
255
- Resource estimator error budget partition parameters.
256
- """
257
- logical: float = 0.001 / 3
258
- t_states: float = 0.001 / 3
259
- rotations: float = 0.001 / 3
260
-
261
-
262
- @dataclass
263
- class MicrosoftEstimatorConstraints(AutoValidatingParams):
264
- """
265
- Resource estimator constraints.
266
- """
267
-
268
- @staticmethod
269
- def at_least_one(name, value):
270
- if value < 1:
271
- raise ValueError(f"{name} must be at least 1")
272
-
273
- logical_depth_factor: Optional[float] = validating_field(at_least_one)
274
- max_t_factories: Optional[int] = validating_field(at_least_one)
275
- max_duration: Optional[int] = validating_field(check_time)
276
- max_physical_qubits: Optional[int] = validating_field(at_least_one)
277
-
278
- def post_validation(self, result):
279
- if self.max_duration is not None and self.max_physical_qubits is not None:
280
- raise LookupError("Both duration and number of physical qubits constraints are provided, but only one is allowe at a time.")
281
-
282
-
283
- @dataclass
284
- class MicrosoftEstimatorProfiling(AutoValidatingParams):
285
- @staticmethod
286
- def at_most_30(name, value):
287
- if value < 0 or value > 30:
288
- raise ValueError(f"{name} must be nonnegative and at most 30")
289
-
290
- call_stack_depth: Optional[int] = validating_field(at_most_30)
291
- inline_functions: Optional[bool] = None
292
-
293
-
294
- class MicrosoftEstimatorInputParamsItem(InputParamsItem):
295
- """
296
- Input params for microsoft.estimator target
297
-
298
- :ivar error_budget Total error budget for execution of the algorithm
299
- """
300
-
301
- def __init__(self):
302
- super().__init__()
303
-
304
- self.qubit_params: MicrosoftEstimatorQubitParams = \
305
- MicrosoftEstimatorQubitParams()
306
- self.qec_scheme: MicrosoftEstimatorQecScheme = \
307
- MicrosoftEstimatorQecScheme()
308
- self.distillation_unit_specifications = [] # type: List[DistillationUnitSpecification]
309
- self.constraints: MicrosoftEstimatorConstraints = \
310
- MicrosoftEstimatorConstraints()
311
- self.profiling: MicrosoftEstimatorProfiling = \
312
- MicrosoftEstimatorProfiling()
313
- self.error_budget: Optional[Union[float, ErrorBudgetPartition]] = None
314
-
315
- def as_dict(self, validate=True) -> Dict[str, Any]:
316
- result = super().as_dict(validate)
317
-
318
- qubit_params = self.qubit_params.as_dict(validate)
319
- if len(qubit_params) != 0:
320
- result["qubitParams"] = qubit_params
321
-
322
- qec_scheme = self.qec_scheme.as_dict(validate)
323
- if len(qec_scheme) != 0:
324
- result["qecScheme"] = qec_scheme
325
-
326
- for specification in self.distillation_unit_specifications:
327
- specification_dict = specification.as_dict(validate)
328
- if len(specification_dict) != 0:
329
- if result.get("distillationUnitSpecifications") is None:
330
- result["distillationUnitSpecifications"] = []
331
-
332
- result["distillationUnitSpecifications"].append(specification_dict)
333
-
334
- constraints = self.constraints.as_dict(validate)
335
- if len(constraints) != 0:
336
- result["constraints"] = constraints
337
-
338
- profiling = self.profiling.as_dict(validate)
339
- if len(profiling) != 0:
340
- result["profiling"] = profiling
341
-
342
- if self.error_budget is not None:
343
- if isinstance(self.error_budget, float) or \
344
- isinstance(self.error_budget, int):
345
- if validate and \
346
- (self.error_budget <= 0 or self.error_budget >= 1):
347
- message = "error_budget must be value between 0 and 1"
348
- raise ValueError(message)
349
- result["errorBudget"] = self.error_budget
350
- elif isinstance(self.error_budget, ErrorBudgetPartition):
351
- result["errorBudget"] = self.error_budget.as_dict(validate)
352
-
353
- return result
354
-
355
-
356
- class MicrosoftEstimatorParams(InputParams, MicrosoftEstimatorInputParamsItem):
357
- """
358
- Resource estimator input parameters.
359
- """
360
- def __init__(self, num_items: Optional[int] = None):
361
- InputParams.__init__(
362
- self,
363
- num_items=num_items,
364
- item_type=MicrosoftEstimatorInputParamsItem)
365
-
366
-
367
- class MicrosoftEstimator(Target):
368
- """
369
- Resource estimator target from the microsoft-qc provider.
370
- """
371
-
372
- target_names = [
373
- "microsoft.estimator"
374
- ]
375
-
376
- def __init__(
377
- self,
378
- workspace: "Workspace",
379
- name: str = "microsoft.estimator",
380
- **kwargs
381
- ):
382
- # There is only a single target name for this target
383
- assert name == self.target_names[0]
384
-
385
- # make sure to not pass argument twice
386
- kwargs.pop("provider_id", None)
387
-
388
- super().__init__(
389
- workspace=workspace,
390
- name=name,
391
- input_data_format="qir.v1",
392
- output_data_format="microsoft.resource-estimates.v1",
393
- provider_id="microsoft-qc",
394
- content_type=ContentType.json,
395
- target_profile="Adaptive_RI",
396
- **kwargs
397
- )
398
-
399
- def submit(
400
- self,
401
- input_data: Any,
402
- name: str = "azure-quantum-job",
403
- shots: int = None,
404
- input_params: Union[Dict[str, Any], InputParams, None] = None,
405
- **kwargs,
406
- ) -> Job:
407
- """
408
- Submit an estimation job.
409
-
410
- :param input_data: Input data
411
- :type input_data: Any
412
- :param name: Job name
413
- :type name: str
414
- :param shots: Number of shots. Ignored in estimation. Defaults to None
415
- :type shots: int
416
- :param input_params: Input parameters
417
- :type input_params: Dict[str, Any]
418
- :return: Azure Quantum job
419
- :rtype: Job
420
- """
421
-
422
- if shots is not None:
423
- warnings.warn("The 'shots' parameter is ignored in resource estimation job.")
424
-
425
- try:
426
- from qiskit import QuantumCircuit
427
- from qsharp import TargetProfile
428
- from qsharp.interop.qiskit import ResourceEstimatorBackend
429
- from pyqir import Context, Module
430
-
431
- if isinstance(input_data, QuantumCircuit):
432
- backend = ResourceEstimatorBackend()
433
- target_profile = TargetProfile.from_str(self.target_profile)
434
- qir_str = backend.qir(input_data, target_profile=target_profile)
435
- context = Context()
436
- module = Module.from_ir(context, qir_str)
437
- # Add NOOP for recording output tuples
438
- # the service isn't set up to handle any output recording calls
439
- # and the Q# compiler will always emit them.
440
- noop_tuple_record_output = """; NOOP the extern calls to recording output tuples
441
- define void @__quantum__rt__tuple_record_output(i64, i8*) {
442
- ret void
443
- }"""
444
- noop_tuple_record_output_module = Module.from_ir(
445
- context, noop_tuple_record_output
446
- )
447
- module.link(noop_tuple_record_output_module)
448
-
449
- err = module.verify()
450
- if err is not None:
451
- raise Exception(err)
452
- input_data = module.bitcode
453
- finally:
454
- return super().submit(
455
- input_data=input_data,
456
- name=name,
457
- shots=shots,
458
- input_params=input_params,
459
- **kwargs
460
- )
461
-
462
- @classmethod
463
- def _get_job_class(cls) -> Type[Job]:
464
- return MicrosoftEstimatorJob
465
-
466
- def _qir_output_data_format(self) -> str:
467
- """"Fallback output data format in case of QIR job submission."""
468
- return "microsoft.resource-estimates.v1"
469
-
470
- def make_params(self, num_items: Optional[int] = None):
471
- return MicrosoftEstimatorParams(num_items=num_items)
@@ -100,126 +100,3 @@ class Quantinuum(Target):
100
100
  input_params=input_params,
101
101
  **kwargs
102
102
  )
103
-
104
- def estimate_cost(
105
- self,
106
- circuit: Union[str, Any] = None,
107
- num_shots: int = None,
108
- N_1q: int = None,
109
- N_2q: int = None,
110
- N_m: int = None,
111
- shots: int = None,
112
- ) -> CostEstimate:
113
- """Estimate the cost in HQC for a given circuit.
114
- Optionally, you can provide the number of gate and measurement operations
115
- manually.
116
- The actual price charged by the provider may differ from this estimation.
117
-
118
- For the most current pricing details, see
119
- https://aka.ms/AQ/Quantinuum/Documentation
120
- Or find your workspace and view pricing options in the "Provider" tab
121
- of your workspace: https://aka.ms/aq/myworkspaces
122
-
123
- :param circuit: Quantum circuit in OpenQASM 2.0 format
124
- :type circuit: str
125
- :param num_shots: Number of shots for which to estimate costs
126
- :type num_shots: int
127
- :param N_1q: Number of one-qubit gates, if not specified,
128
- this is estimated from the circuit
129
- :type N_1q: int
130
- :param N_2q: Number of two-qubit gates, if not specified,
131
- this is estimated from the circuit
132
- :type N_2q: int
133
- :param N_m: Number of measurement operations, if not specified,
134
- this is estimated from the circuit
135
- :type N_m: int
136
- :param shots: Number of shots for which to estimate costs
137
- :type shots: int
138
- :raises ImportError: If N_1q, N_2q and N_m are not specified,
139
- this will require a qiskit installation.
140
- """
141
-
142
- if num_shots is None and shots is None:
143
- raise ValueError("The 'shots' parameter has to be specified")
144
-
145
- if num_shots is not None:
146
- warn(
147
- "The 'num_shots' parameter will be deprecated. Please, use 'shots' parameter instead.",
148
- category=DeprecationWarning,
149
- )
150
- shots = num_shots
151
-
152
- # If we use passthrough, else assume QIR
153
- if (isinstance(circuit, str)):
154
- if circuit is not None and (N_1q is None or N_2q is None or N_m is None):
155
- try:
156
- from qiskit.qasm2 import loads
157
- from qiskit.converters.circuit_to_dag import circuit_to_dag
158
-
159
- except ImportError:
160
- raise ImportError(
161
- "Missing dependency qiskit. Please run `pip install azure-quantum[qiskit]` " \
162
- "to estimate the circuit cost. Alternatively, specify the number of one-qubit and two-qubit " \
163
- "gates in the method input arguments.")
164
-
165
- else:
166
- from qiskit.dagcircuit.dagnode import DAGOpNode
167
- circuit_obj = loads(string=circuit)
168
- dag = circuit_to_dag(circuit=circuit_obj)
169
- N_1q, N_2q, N_m = 0, 0, 0
170
- for node in dag._multi_graph.nodes():
171
- if isinstance(node, DAGOpNode):
172
- if node.op.name in ["measure", "reset"]:
173
- N_m += 1
174
- elif node.op.num_qubits == 1:
175
- N_1q += 1
176
- else:
177
- N_2q += 1
178
- else:
179
- N_1q, N_2q, N_m = Target._calculate_qir_module_gate_stats(circuit)
180
-
181
-
182
- import re
183
- is_emulator_regex = re.compile("^.*(-sim|-[0-9]*e)$")
184
- is_syntax_checker_regex = re.compile("^.*(-apival|-[0-9]*sc)$")
185
-
186
- if is_emulator_regex.match(self.name):
187
- currency_code = "EHQC"
188
- else:
189
- currency_code = "HQC"
190
-
191
- if is_syntax_checker_regex.match(self.name):
192
- HQC = 0.0
193
- else:
194
- HQC = 5 + shots * (N_1q + 10 * N_2q + 5 * N_m) / 5000
195
-
196
- return CostEstimate(
197
- events=[
198
- UsageEvent(
199
- dimension_id="gates1q",
200
- dimension_name="1Q Gates",
201
- measure_unit="1q gates",
202
- amount_billed=0.0,
203
- amount_consumed=N_1q,
204
- unit_price=0.0
205
- ),
206
- UsageEvent(
207
- dimension_id="gates2q",
208
- dimension_name="2Q Gates",
209
- measure_unit="2q gates",
210
- amount_billed=0.0,
211
- amount_consumed=N_2q,
212
- unit_price=0.0
213
- ),
214
- UsageEvent(
215
- dimension_id="measops",
216
- dimension_name="Measurement operations",
217
- measure_unit="measurement operations",
218
- amount_billed=0.0,
219
- amount_consumed=N_m,
220
- unit_price=0.0
221
- )
222
- ],
223
- currency_code=currency_code,
224
- estimated_total=HQC
225
- )
@@ -30,6 +30,8 @@ class RigettiTarget(str, Enum):
30
30
  QVM = "rigetti.sim.qvm"
31
31
  """A simulator target for Quil. See https://github.com/quil-lang/qvm for more info."""
32
32
 
33
+ ANKAA_3 = "rigetti.qpu.ankaa-3"
34
+
33
35
  ANKAA_9Q_3 = "rigetti.qpu.ankaa-9q-3"
34
36
 
35
37
  def simulators() -> List[str]:
@@ -41,6 +43,7 @@ class RigettiTarget(str, Enum):
41
43
  def qpus() -> List[str]:
42
44
  """Returns a list of QPU targets"""
43
45
  return [
46
+ RigettiTarget.ANKAA_3.value,
44
47
  RigettiTarget.ANKAA_9Q_3.value,
45
48
  ]
46
49
 
@@ -49,6 +52,8 @@ class RigettiTarget(str, Enum):
49
52
 
50
53
  if target_name == RigettiTarget.QVM.value:
51
54
  return 20
55
+ elif target_name == RigettiTarget.ANKAA_3.value:
56
+ return 82
52
57
  elif target_name == RigettiTarget.ANKAA_9Q_3.value:
53
58
  return 9
54
59
  else: