classiq 0.102.0__py3-none-any.whl → 0.104.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.
- classiq/applications/chemistry/op_utils.py +32 -0
- classiq/evaluators/qmod_annotated_expression.py +1 -1
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
- classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
- classiq/execution/execution_session.py +1 -1
- classiq/execution/functions/__init__.py +3 -0
- classiq/execution/functions/_logging.py +19 -0
- classiq/execution/functions/constants.py +9 -0
- classiq/execution/functions/parse_provider_backend.py +90 -0
- classiq/execution/functions/sample.py +257 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +15 -0
- classiq/interface/backend/provider_config/providers/aqt.py +1 -1
- classiq/interface/backend/provider_config/providers/azure.py +1 -2
- classiq/interface/backend/provider_config/providers/ibm.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +3 -0
- classiq/interface/executor/result.py +9 -5
- classiq/interface/generator/arith/binary_ops.py +38 -2
- classiq/interface/generator/function_param_list.py +4 -2
- classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
- classiq/interface/generator/functions/classical_type.py +45 -0
- classiq/interface/generator/functions/type_name.py +23 -0
- classiq/interface/generator/generated_circuit_data.py +0 -2
- classiq/interface/generator/types/compilation_metadata.py +9 -0
- classiq/interface/hardware.py +1 -0
- classiq/interface/helpers/model_normalizer.py +42 -6
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/invert.py +8 -0
- classiq/interface/model/model_visitor.py +4 -2
- classiq/interface/model/quantum_type.py +21 -0
- classiq/interface/model/statement_block.py +0 -4
- classiq/model_expansions/capturing/captured_vars.py +16 -12
- classiq/model_expansions/function_builder.py +9 -1
- classiq/model_expansions/interpreters/base_interpreter.py +9 -8
- classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
- classiq/model_expansions/quantum_operations/bind.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
- classiq/model_expansions/quantum_operations/emitter.py +1 -4
- classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
- classiq/qmod/builtins/functions/__init__.py +9 -0
- classiq/qmod/builtins/functions/arithmetic.py +131 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -2
- classiq/qmod/builtins/operations.py +2 -38
- classiq/qmod/native/pretty_printer.py +1 -12
- classiq/qmod/pretty_print/pretty_printer.py +1 -17
- classiq/qmod/qmod_parameter.py +4 -0
- classiq/qmod/qmod_variable.py +38 -63
- classiq/qmod/quantum_function.py +43 -7
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
- classiq/qmod/semantics/validation/model_validation.py +7 -2
- classiq/qmod/symbolic_type.py +4 -2
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/METADATA +1 -1
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/RECORD +63 -59
- classiq/interface/generator/amplitude_loading.py +0 -103
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/WHEEL +0 -0
- {classiq-0.102.0.dist-info → classiq-0.104.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -74,6 +74,38 @@ def qubit_op_to_qmod(
|
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
def qmod_to_qubit_op(operator: SparsePauliOp) -> QubitOperator:
|
|
78
|
+
"""
|
|
79
|
+
Transforms Qmod's SparsePauliOp data structure to OpenFermion's QubitOperator data structure.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
operator (SparsePauliOp): The operator to be transformed
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
QubitOperator: The operator in OpenFermion's data structure
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
# Initiating the QubitOperator as the 0 operator
|
|
89
|
+
qo = QubitOperator()
|
|
90
|
+
for sparse_pauli_term in operator.terms:
|
|
91
|
+
# loop over all the IndexedPaulis
|
|
92
|
+
coeff = sparse_pauli_term.coefficient
|
|
93
|
+
if sparse_pauli_term.paulis:
|
|
94
|
+
qo.terms[
|
|
95
|
+
tuple(
|
|
96
|
+
[
|
|
97
|
+
(p.index, p.pauli.name)
|
|
98
|
+
for p in sparse_pauli_term.paulis # type: ignore[attr-defined]
|
|
99
|
+
if p.pauli is not Pauli.I
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
] = coeff
|
|
103
|
+
# Operator is the identity
|
|
104
|
+
else:
|
|
105
|
+
qo.terms[()] = coeff
|
|
106
|
+
return qo
|
|
107
|
+
|
|
108
|
+
|
|
77
109
|
_PAULIS_TO_XZ = {"I": (0, 0), "X": (1, 0), "Z": (0, 1), "Y": (1, 1)}
|
|
78
110
|
_XZ_TO_PAULIS = {(0, 0): "I", (1, 0): "X", (0, 1): "Z", (1, 1): "Y"}
|
|
79
111
|
|
|
@@ -207,7 +207,7 @@ class QmodAnnotatedExpression:
|
|
|
207
207
|
node = id(node)
|
|
208
208
|
return node in self._quantum_subscripts
|
|
209
209
|
|
|
210
|
-
def
|
|
210
|
+
def get_quantum_subscript(
|
|
211
211
|
self, node: ast.AST | QmodExprNodeId
|
|
212
212
|
) -> QuantumSubscriptAnnotation:
|
|
213
213
|
if isinstance(node, ast.AST):
|
|
@@ -77,7 +77,6 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
77
77
|
self,
|
|
78
78
|
expr_val: QmodAnnotatedExpression,
|
|
79
79
|
*,
|
|
80
|
-
treat_qnum_as_float: bool = False,
|
|
81
80
|
machine_precision: int = DEFAULT_MACHINE_PRECISION,
|
|
82
81
|
classical_struct_declarations: Sequence[StructDeclaration] | None = None,
|
|
83
82
|
enum_declarations: Sequence[EnumDeclaration] | None = None,
|
|
@@ -88,7 +87,6 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
88
87
|
scope: Mapping[str, Any] | None = None,
|
|
89
88
|
) -> None:
|
|
90
89
|
self._expr_val = expr_val
|
|
91
|
-
self._treat_qnum_as_float = treat_qnum_as_float
|
|
92
90
|
self._machine_precision = machine_precision
|
|
93
91
|
self._classical_struct_decls = nameables_to_dict(
|
|
94
92
|
classical_struct_declarations or []
|
|
@@ -114,9 +112,7 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
114
112
|
|
|
115
113
|
def visit_BinOp(self, node: ast.BinOp) -> None:
|
|
116
114
|
super().generic_visit(node)
|
|
117
|
-
eval_binary_op(
|
|
118
|
-
self._expr_val, node, self._treat_qnum_as_float, self._machine_precision
|
|
119
|
-
)
|
|
115
|
+
eval_binary_op(self._expr_val, node, self._machine_precision)
|
|
120
116
|
|
|
121
117
|
def visit_UnaryOp(self, node: ast.UnaryOp) -> None:
|
|
122
118
|
super().generic_visit(node)
|
|
@@ -164,7 +160,6 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
164
160
|
self._expr_val,
|
|
165
161
|
node,
|
|
166
162
|
func_name,
|
|
167
|
-
self._treat_qnum_as_float,
|
|
168
163
|
self._machine_precision,
|
|
169
164
|
)
|
|
170
165
|
return
|
|
@@ -256,7 +251,6 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
256
251
|
def evaluate_qmod_expression(
|
|
257
252
|
expr: str,
|
|
258
253
|
*,
|
|
259
|
-
treat_qnum_as_float: bool = False,
|
|
260
254
|
machine_precision: int = DEFAULT_MACHINE_PRECISION,
|
|
261
255
|
classical_struct_declarations: Sequence[StructDeclaration] | None = None,
|
|
262
256
|
enum_declarations: Sequence[EnumDeclaration] | None = None,
|
|
@@ -270,7 +264,6 @@ def evaluate_qmod_expression(
|
|
|
270
264
|
expr_value = QmodAnnotatedExpression(expr_ast)
|
|
271
265
|
QmodExpressionEvaluator(
|
|
272
266
|
expr_value,
|
|
273
|
-
treat_qnum_as_float=treat_qnum_as_float,
|
|
274
267
|
machine_precision=machine_precision,
|
|
275
268
|
classical_struct_declarations=classical_struct_declarations,
|
|
276
269
|
enum_declarations=enum_declarations,
|
|
@@ -122,7 +122,7 @@ class _InverseVarMaskTransformer(OutOfPlaceNodeTransformer):
|
|
|
122
122
|
|
|
123
123
|
class _SympyCompatibilityTransformer(OutOfPlaceNodeTransformer):
|
|
124
124
|
def visit_BoolOp(self, node: ast.BoolOp) -> ast.Call:
|
|
125
|
-
if len(node.values)
|
|
125
|
+
if len(node.values) < 2:
|
|
126
126
|
raise ClassiqInternalExpansionError
|
|
127
127
|
node = cast(ast.BoolOp, self.generic_visit(node))
|
|
128
128
|
if isinstance(node.op, ast.Or):
|
|
@@ -107,7 +107,7 @@ def _eval_type_attribute(
|
|
|
107
107
|
if isinstance(subject_type, QuantumNumeric):
|
|
108
108
|
if attr == "is_signed":
|
|
109
109
|
expr_val.set_type(node, Bool())
|
|
110
|
-
if subject_type.
|
|
110
|
+
if subject_type.has_constant_sign:
|
|
111
111
|
expr_val.set_value(node, subject_type.sign_value)
|
|
112
112
|
_remove_quantum_var(expr_val, subject)
|
|
113
113
|
elif subject_type.has_size_in_bits:
|
|
@@ -120,7 +120,7 @@ def _eval_type_attribute(
|
|
|
120
120
|
return
|
|
121
121
|
if attr == "fraction_digits":
|
|
122
122
|
expr_val.set_type(node, Integer())
|
|
123
|
-
if subject_type.
|
|
123
|
+
if subject_type.has_constant_fraction_digits:
|
|
124
124
|
expr_val.set_value(node, subject_type.fraction_digits_value)
|
|
125
125
|
_remove_quantum_var(expr_val, subject)
|
|
126
126
|
elif subject_type.has_size_in_bits:
|
|
@@ -50,7 +50,6 @@ def _validate_binary_op(
|
|
|
50
50
|
op: ast.AST,
|
|
51
51
|
left_type: QmodType,
|
|
52
52
|
right_type: QmodType,
|
|
53
|
-
treat_qnum_as_float: bool,
|
|
54
53
|
) -> None:
|
|
55
54
|
if not _binary_op_allowed(left_type, right_type, op):
|
|
56
55
|
raise ClassiqExpansionError(
|
|
@@ -76,20 +75,19 @@ def _validate_binary_op(
|
|
|
76
75
|
f"Binary operation {type(op).__name__!r} is not supported"
|
|
77
76
|
)
|
|
78
77
|
|
|
79
|
-
if
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
78
|
+
if isinstance(op, ast.FloorDiv) and (
|
|
79
|
+
not is_classical_type(left_type) or not is_classical_type(right_type)
|
|
80
|
+
):
|
|
81
|
+
raise ClassiqExpansionError(
|
|
82
|
+
f"{type(op).__name__!r} with quantum variables is not supported"
|
|
83
|
+
)
|
|
86
84
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
if not is_classical_type(right_type) and isinstance(
|
|
86
|
+
op, (ast.Div, ast.Mod, ast.Pow, ast.LShift, ast.RShift)
|
|
87
|
+
):
|
|
88
|
+
raise ClassiqExpansionError(
|
|
89
|
+
f"Right-hand side of binary operation {type(op).__name__!r} must be classical numeric value"
|
|
90
|
+
)
|
|
93
91
|
|
|
94
92
|
|
|
95
93
|
def _infer_binary_op_type(
|
|
@@ -98,7 +96,6 @@ def _infer_binary_op_type(
|
|
|
98
96
|
left_type: QmodType,
|
|
99
97
|
right_type: QmodType,
|
|
100
98
|
machine_precision: int,
|
|
101
|
-
treat_qnum_as_float: bool,
|
|
102
99
|
) -> QmodType:
|
|
103
100
|
op = node.op
|
|
104
101
|
|
|
@@ -113,19 +110,13 @@ def _infer_binary_op_type(
|
|
|
113
110
|
return Integer()
|
|
114
111
|
return Real()
|
|
115
112
|
|
|
116
|
-
left_attrs = get_numeric_attrs(
|
|
117
|
-
|
|
118
|
-
)
|
|
119
|
-
right_attrs = get_numeric_attrs(
|
|
120
|
-
expr_val, node.right, right_type, machine_precision, treat_qnum_as_float
|
|
121
|
-
)
|
|
113
|
+
left_attrs = get_numeric_attrs(expr_val, node.left, left_type, machine_precision)
|
|
114
|
+
right_attrs = get_numeric_attrs(expr_val, node.right, right_type, machine_precision)
|
|
122
115
|
|
|
123
116
|
if left_attrs is None or right_attrs is None:
|
|
124
117
|
return QuantumNumeric()
|
|
125
118
|
|
|
126
|
-
right_value = get_classical_value_for_arithmetic(
|
|
127
|
-
expr_val, node.right, right_type, treat_qnum_as_float
|
|
128
|
-
)
|
|
119
|
+
right_value = get_classical_value_for_arithmetic(expr_val, node.right, right_type)
|
|
129
120
|
|
|
130
121
|
if isinstance(op, ast.Add):
|
|
131
122
|
result_attrs = compute_result_attrs_add(
|
|
@@ -157,14 +148,14 @@ def _infer_binary_op_type(
|
|
|
157
148
|
return QuantumNumeric()
|
|
158
149
|
|
|
159
150
|
elif isinstance(op, ast.Mod):
|
|
160
|
-
if right_value is None
|
|
151
|
+
if right_value is None:
|
|
161
152
|
return QuantumNumeric()
|
|
162
153
|
result_attrs = compute_result_attrs_modulo(
|
|
163
154
|
left_attrs, right_attrs, machine_precision
|
|
164
155
|
)
|
|
165
156
|
|
|
166
157
|
elif isinstance(op, ast.Pow):
|
|
167
|
-
if right_value is None
|
|
158
|
+
if right_value is None:
|
|
168
159
|
return QuantumNumeric()
|
|
169
160
|
result_attrs = compute_result_attrs_power(
|
|
170
161
|
left_attrs, right_attrs, machine_precision
|
|
@@ -252,7 +243,6 @@ def _eval_binary_op_constant(
|
|
|
252
243
|
def eval_binary_op(
|
|
253
244
|
expr_val: QmodAnnotatedExpression,
|
|
254
245
|
node: ast.BinOp,
|
|
255
|
-
treat_qnum_as_float: bool,
|
|
256
246
|
machine_precision: int,
|
|
257
247
|
) -> None:
|
|
258
248
|
left = node.left
|
|
@@ -261,7 +251,7 @@ def eval_binary_op(
|
|
|
261
251
|
|
|
262
252
|
left_type = expr_val.get_type(left)
|
|
263
253
|
right_type = expr_val.get_type(right)
|
|
264
|
-
_validate_binary_op(op, left_type, right_type
|
|
254
|
+
_validate_binary_op(op, left_type, right_type)
|
|
265
255
|
|
|
266
256
|
inferred_type = _infer_binary_op_type(
|
|
267
257
|
expr_val,
|
|
@@ -269,7 +259,6 @@ def eval_binary_op(
|
|
|
269
259
|
left_type,
|
|
270
260
|
right_type,
|
|
271
261
|
machine_precision,
|
|
272
|
-
treat_qnum_as_float,
|
|
273
262
|
)
|
|
274
263
|
expr_val.set_type(node, inferred_type)
|
|
275
264
|
|
|
@@ -31,7 +31,6 @@ def _infer_min_max_op_type(
|
|
|
31
31
|
node: ast.Call,
|
|
32
32
|
func_name: str,
|
|
33
33
|
args_types: list[QmodType],
|
|
34
|
-
treat_qnum_as_float: bool,
|
|
35
34
|
machine_precision: int,
|
|
36
35
|
) -> QmodType:
|
|
37
36
|
if all(is_classical_type(arg_type) for arg_type in args_types):
|
|
@@ -41,9 +40,7 @@ def _infer_min_max_op_type(
|
|
|
41
40
|
|
|
42
41
|
args_attrs: list[NumericAttributes] = []
|
|
43
42
|
for arg, arg_type in zip(node.args, args_types):
|
|
44
|
-
attrs = get_numeric_attrs(
|
|
45
|
-
expr_val, arg, arg_type, machine_precision, treat_qnum_as_float
|
|
46
|
-
)
|
|
43
|
+
attrs = get_numeric_attrs(expr_val, arg, arg_type, machine_precision)
|
|
47
44
|
if attrs is None:
|
|
48
45
|
return QuantumNumeric()
|
|
49
46
|
args_attrs.append(attrs)
|
|
@@ -62,7 +59,6 @@ def eval_min_max_op(
|
|
|
62
59
|
expr_val: QmodAnnotatedExpression,
|
|
63
60
|
node: ast.Call,
|
|
64
61
|
func_name: str,
|
|
65
|
-
treat_qnum_as_float: bool,
|
|
66
62
|
machine_precision: int,
|
|
67
63
|
) -> None:
|
|
68
64
|
if len(node.args) < 1:
|
|
@@ -79,7 +75,6 @@ def eval_min_max_op(
|
|
|
79
75
|
node,
|
|
80
76
|
func_name,
|
|
81
77
|
args_types,
|
|
82
|
-
treat_qnum_as_float,
|
|
83
78
|
machine_precision,
|
|
84
79
|
)
|
|
85
80
|
expr_val.set_type(node, inferred_type)
|
|
@@ -21,14 +21,11 @@ def get_numeric_attrs(
|
|
|
21
21
|
node: ast.AST,
|
|
22
22
|
qmod_type: QmodType,
|
|
23
23
|
machine_precision: int,
|
|
24
|
-
treat_qnum_as_float: bool,
|
|
25
24
|
) -> NumericAttributes | None:
|
|
26
25
|
if isinstance(qmod_type, Bool):
|
|
27
26
|
return NumericAttributes.from_bounds(0, 1, 0, machine_precision)
|
|
28
27
|
if is_classical_type(qmod_type):
|
|
29
|
-
value = get_classical_value_for_arithmetic(
|
|
30
|
-
expr_val, node, qmod_type, treat_qnum_as_float
|
|
31
|
-
)
|
|
28
|
+
value = get_classical_value_for_arithmetic(expr_val, node, qmod_type)
|
|
32
29
|
if value is None:
|
|
33
30
|
return None
|
|
34
31
|
return NumericAttributes.from_constant(value, machine_precision)
|
|
@@ -44,7 +41,6 @@ def get_classical_value_for_arithmetic(
|
|
|
44
41
|
expr_val: QmodAnnotatedExpression,
|
|
45
42
|
node: ast.AST,
|
|
46
43
|
qmod_type: QmodType,
|
|
47
|
-
treat_qnum_as_float: bool,
|
|
48
44
|
) -> float | None:
|
|
49
45
|
if not is_classical_type(qmod_type):
|
|
50
46
|
return None
|
|
@@ -55,8 +51,6 @@ def get_classical_value_for_arithmetic(
|
|
|
55
51
|
if isinstance(value, sympy.Basic):
|
|
56
52
|
value = get_sympy_val(value)
|
|
57
53
|
if not isinstance(value, (int, float)):
|
|
58
|
-
if treat_qnum_as_float and isinstance(value, complex):
|
|
59
|
-
return None
|
|
60
54
|
raise ClassiqExpansionError(
|
|
61
55
|
"Arithmetic of quantum variables and non-real values is not supported"
|
|
62
56
|
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from classiq.interface.exceptions import (
|
|
2
|
+
ClassiqInternalExpansionError,
|
|
3
|
+
)
|
|
4
|
+
from classiq.interface.generator.expressions.expression import Expression
|
|
5
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
|
6
|
+
from classiq.interface.model.quantum_type import (
|
|
7
|
+
QuantumBit,
|
|
8
|
+
QuantumBitvector,
|
|
9
|
+
QuantumNumeric,
|
|
10
|
+
QuantumType,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _compare_expressions(expr1: Expression | None, expr2: Expression | None) -> bool:
|
|
15
|
+
if expr1 is None:
|
|
16
|
+
return expr2 is None
|
|
17
|
+
if expr2 is None:
|
|
18
|
+
return False
|
|
19
|
+
return expr1.expr == expr2.expr
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def compare_quantum_types(type_1: QuantumType, type_2: QuantumType) -> bool:
|
|
23
|
+
for qmod_type in (type_1, type_2):
|
|
24
|
+
if isinstance(qmod_type, TypeName) and not qmod_type.has_fields:
|
|
25
|
+
raise ClassiqInternalExpansionError("Quantum struct expected")
|
|
26
|
+
if isinstance(type_1, QuantumBit):
|
|
27
|
+
return isinstance(type_2, QuantumBit)
|
|
28
|
+
if isinstance(type_1, QuantumNumeric):
|
|
29
|
+
return (
|
|
30
|
+
isinstance(type_2, QuantumNumeric)
|
|
31
|
+
and _compare_expressions(type_1.size, type_2.size)
|
|
32
|
+
and _compare_expressions(type_1.is_signed, type_2.is_signed)
|
|
33
|
+
and _compare_expressions(type_1.fraction_digits, type_2.fraction_digits)
|
|
34
|
+
)
|
|
35
|
+
if isinstance(type_1, QuantumBitvector):
|
|
36
|
+
return (
|
|
37
|
+
isinstance(type_2, QuantumBitvector)
|
|
38
|
+
and _compare_expressions(type_1.length, type_2.length)
|
|
39
|
+
and compare_quantum_types(type_1.element_type, type_2.element_type)
|
|
40
|
+
)
|
|
41
|
+
if isinstance(type_1, TypeName):
|
|
42
|
+
return (
|
|
43
|
+
isinstance(type_2, TypeName)
|
|
44
|
+
and type_1.name == type_2.name
|
|
45
|
+
and all(
|
|
46
|
+
compare_quantum_types(field_type_1, field_type_2)
|
|
47
|
+
for field_type_1, field_type_2 in zip(
|
|
48
|
+
type_1.fields.values(), type_2.fields.values(), strict=True
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
raise ClassiqInternalExpansionError(f"Unexpected type {type(type_1).__name__}")
|
|
@@ -365,7 +365,7 @@ class ExecutionSession:
|
|
|
365
365
|
A list of tuples, each containing the estimated cost and the corresponding parameters for that iteration. `cost` is a float, and `parameters` is a dictionary matching the execution parameter format.
|
|
366
366
|
|
|
367
367
|
See Also:
|
|
368
|
-
The [
|
|
368
|
+
The [Execution Tutorial](https://docs.classiq.io/latest/getting-started/classiq_tutorial/execution_tutorial_part2/) has examples on using this method in variational quantum algorithms.
|
|
369
369
|
More information about [Hamiltonians](https://docs.classiq.io/latest/qmod-reference/language-reference/classical-types/#hamiltonians).
|
|
370
370
|
"""
|
|
371
371
|
_hamiltonian_deprecation_warning(cost_function)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
_logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _setup_logging() -> None:
|
|
7
|
+
if _logger.handlers:
|
|
8
|
+
return
|
|
9
|
+
|
|
10
|
+
handler = logging.StreamHandler()
|
|
11
|
+
formatter = logging.Formatter("%(message)s")
|
|
12
|
+
handler.setFormatter(formatter)
|
|
13
|
+
_logger.addHandler(handler)
|
|
14
|
+
_logger.setLevel(logging.INFO)
|
|
15
|
+
|
|
16
|
+
_logger.propagate = False
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_setup_logging()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from classiq.interface.hardware import Provider
|
|
2
|
+
|
|
3
|
+
_PROVIDER_BACKEND_SEPARATOR = "/"
|
|
4
|
+
|
|
5
|
+
_PROVIDER_TO_CANONICAL_NAME: dict[Provider, str] = {
|
|
6
|
+
Provider.IBM_QUANTUM: "ibm",
|
|
7
|
+
Provider.AZURE_QUANTUM: "azure",
|
|
8
|
+
Provider.AMAZON_BRAKET: "braket",
|
|
9
|
+
Provider.IONQ: "ionq",
|
|
10
|
+
Provider.CLASSIQ: "classiq",
|
|
11
|
+
Provider.GOOGLE: "google",
|
|
12
|
+
Provider.ALICE_AND_BOB: "alice&bob",
|
|
13
|
+
Provider.OQC: "oqc",
|
|
14
|
+
Provider.INTEL: "intel",
|
|
15
|
+
Provider.AQT: "aqt",
|
|
16
|
+
Provider.CINECA: "cineca",
|
|
17
|
+
Provider.SOFTBANK: "softbank",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_CANONICAL_NAMES_TO_PROVIDER: dict[str, Provider] = {
|
|
21
|
+
name: provider for provider, name in _PROVIDER_TO_CANONICAL_NAME.items()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _error_suggested_provider(provider_name: str) -> Provider | None:
|
|
26
|
+
"""
|
|
27
|
+
In the case that receive an incorrect provider name, return a possible suggestion.
|
|
28
|
+
"""
|
|
29
|
+
provider_name = provider_name.strip().lower()
|
|
30
|
+
for canonical_name in _CANONICAL_NAMES_TO_PROVIDER:
|
|
31
|
+
if canonical_name in provider_name:
|
|
32
|
+
return _CANONICAL_NAMES_TO_PROVIDER[canonical_name]
|
|
33
|
+
# Special cases
|
|
34
|
+
if "gcp" in provider_name:
|
|
35
|
+
return Provider.GOOGLE
|
|
36
|
+
if "microsoft" in provider_name:
|
|
37
|
+
return Provider.AZURE_QUANTUM
|
|
38
|
+
if "amazon" in provider_name or "aws" in provider_name:
|
|
39
|
+
return Provider.AMAZON_BRAKET
|
|
40
|
+
if "oxford" in provider_name:
|
|
41
|
+
return Provider.OQC
|
|
42
|
+
if "alice" in provider_name or "bob" in provider_name:
|
|
43
|
+
return Provider.ALICE_AND_BOB
|
|
44
|
+
if "alpine" in provider_name:
|
|
45
|
+
return Provider.AQT
|
|
46
|
+
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _parse_provider_backend(spec: str) -> tuple[Provider, str]:
|
|
51
|
+
"""
|
|
52
|
+
Parse a backend specification into (provider, backend). Provider is case-insensitive.
|
|
53
|
+
Backend must NOT contain the separator. If provider is not specified, it defaults to
|
|
54
|
+
Classiq.
|
|
55
|
+
"""
|
|
56
|
+
if not spec.strip():
|
|
57
|
+
raise ValueError("Backend specification must be a non-empty string")
|
|
58
|
+
|
|
59
|
+
spec = spec.strip()
|
|
60
|
+
|
|
61
|
+
if _PROVIDER_BACKEND_SEPARATOR not in spec:
|
|
62
|
+
return Provider.CLASSIQ, spec
|
|
63
|
+
|
|
64
|
+
provider_raw, backend = spec.split(_PROVIDER_BACKEND_SEPARATOR, 1)
|
|
65
|
+
|
|
66
|
+
if _PROVIDER_BACKEND_SEPARATOR in backend:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Backend name must not contain '{_PROVIDER_BACKEND_SEPARATOR}': '{backend}'"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
provider_key = provider_raw.strip().lower()
|
|
72
|
+
backend = backend.strip()
|
|
73
|
+
|
|
74
|
+
if not provider_key:
|
|
75
|
+
raise ValueError("Provider name cannot be empty")
|
|
76
|
+
if not backend:
|
|
77
|
+
raise ValueError("Backend name cannot be empty")
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
provider = _CANONICAL_NAMES_TO_PROVIDER[provider_key]
|
|
81
|
+
except KeyError:
|
|
82
|
+
error_message = f"Unrecognized provider '{provider_raw}'."
|
|
83
|
+
suggested_provider = _error_suggested_provider(provider_key)
|
|
84
|
+
if suggested_provider is not None:
|
|
85
|
+
error_message += (
|
|
86
|
+
f" Did you mean '{_PROVIDER_TO_CANONICAL_NAME[suggested_provider]}'?"
|
|
87
|
+
)
|
|
88
|
+
raise ValueError(error_message) from None
|
|
89
|
+
|
|
90
|
+
return provider, backend
|