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
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, NoReturn, cast
|
|
2
2
|
|
|
3
|
-
from classiq.interface.exceptions import
|
|
3
|
+
from classiq.interface.exceptions import (
|
|
4
|
+
ClassiqExpansionError,
|
|
5
|
+
)
|
|
4
6
|
from classiq.interface.generator.expressions.expression import Expression
|
|
7
|
+
from classiq.interface.generator.functions.classical_type import (
|
|
8
|
+
Bool,
|
|
9
|
+
ClassicalArray,
|
|
10
|
+
ClassicalTuple,
|
|
11
|
+
Integer,
|
|
12
|
+
)
|
|
5
13
|
from classiq.interface.model.allocate import Allocate
|
|
6
14
|
from classiq.interface.model.bind_operation import BindOperation
|
|
7
15
|
from classiq.interface.model.block import Block
|
|
@@ -20,9 +28,11 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
|
20
28
|
)
|
|
21
29
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
22
30
|
from classiq.interface.model.quantum_type import (
|
|
31
|
+
QuantumBit,
|
|
23
32
|
QuantumBitvector,
|
|
24
33
|
QuantumNumeric,
|
|
25
34
|
QuantumScalar,
|
|
35
|
+
QuantumType,
|
|
26
36
|
)
|
|
27
37
|
from classiq.interface.model.statement_block import StatementBlock
|
|
28
38
|
from classiq.interface.model.variable_declaration_statement import (
|
|
@@ -31,6 +41,18 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
|
31
41
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
32
42
|
|
|
33
43
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
44
|
+
from classiq.evaluators.qmod_node_evaluators.utils import (
|
|
45
|
+
QmodType,
|
|
46
|
+
array_len,
|
|
47
|
+
element_types,
|
|
48
|
+
is_numeric_type,
|
|
49
|
+
)
|
|
50
|
+
from classiq.evaluators.qmod_type_inference.classical_type_inference import (
|
|
51
|
+
infer_classical_type,
|
|
52
|
+
)
|
|
53
|
+
from classiq.evaluators.qmod_type_inference.quantum_type_comparison import (
|
|
54
|
+
compare_quantum_types,
|
|
55
|
+
)
|
|
34
56
|
from classiq.evaluators.qmod_type_inference.quantum_type_inference import (
|
|
35
57
|
inject_quantum_type_attributes_inplace,
|
|
36
58
|
)
|
|
@@ -43,13 +65,22 @@ from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_exp
|
|
|
43
65
|
validate_assignment_bool_expression,
|
|
44
66
|
)
|
|
45
67
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
46
|
-
from classiq.model_expansions.scope import ClassicalSymbol
|
|
68
|
+
from classiq.model_expansions.scope import ClassicalSymbol, QuantumSymbol
|
|
47
69
|
from classiq.qmod.builtins.functions.standard_gates import CX
|
|
48
70
|
|
|
49
71
|
if TYPE_CHECKING:
|
|
50
72
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
51
73
|
|
|
52
74
|
|
|
75
|
+
def _get_expr_type(op: QuantumAssignmentOperation) -> QmodType:
|
|
76
|
+
expr_val = op.expression.value.value
|
|
77
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
78
|
+
return expr_val.get_type(expr_val.root)
|
|
79
|
+
else:
|
|
80
|
+
expr_type = infer_classical_type(expr_val)
|
|
81
|
+
return expr_type
|
|
82
|
+
|
|
83
|
+
|
|
53
84
|
class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
54
85
|
def __init__(
|
|
55
86
|
self, interpreter: "BaseInterpreter", replace_assignment_if_needed: bool = False
|
|
@@ -60,14 +91,26 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
60
91
|
def emit(self, op: QuantumAssignmentOperation, /) -> bool:
|
|
61
92
|
result_symbol = self._interpreter.evaluate(op.result_var).value
|
|
62
93
|
if isinstance(result_symbol, ClassicalSymbol):
|
|
63
|
-
return
|
|
94
|
+
return self._emit_classical_assignment(op)
|
|
95
|
+
if isinstance(result_symbol.quantum_type, QuantumScalar):
|
|
96
|
+
return self._emit_scalar_assignment(op)
|
|
97
|
+
expr_val = op.expression.value.value
|
|
98
|
+
if isinstance(expr_val, QmodAnnotatedExpression) and isinstance(
|
|
99
|
+
expr_val.get_type(expr_val.root), QuantumType
|
|
100
|
+
):
|
|
101
|
+
return self._emit_quantum_var_quantum_expr_assignment(op)
|
|
102
|
+
return self._emit_quantum_var_classical_expr_assignment(op)
|
|
103
|
+
|
|
104
|
+
def _emit_classical_assignment(self, _: QuantumAssignmentOperation, /) -> bool:
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
def _emit_scalar_assignment(self, op: QuantumAssignmentOperation, /) -> bool:
|
|
108
|
+
result_symbol = self._interpreter.evaluate(op.result_var).value
|
|
64
109
|
result_type = result_symbol.quantum_type
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
f"{result_type.raw_qmod_type_name}"
|
|
70
|
-
)
|
|
110
|
+
|
|
111
|
+
expr_type = _get_expr_type(op)
|
|
112
|
+
if not is_numeric_type(expr_type) and not isinstance(expr_type, Bool):
|
|
113
|
+
self._raise_type_error(result_symbol, expr_type)
|
|
71
114
|
|
|
72
115
|
if not (
|
|
73
116
|
isinstance(op, ArithmeticOperation)
|
|
@@ -82,36 +125,73 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
82
125
|
)
|
|
83
126
|
convert_assignment_bool_expression(op)
|
|
84
127
|
|
|
85
|
-
|
|
86
|
-
if
|
|
128
|
+
quantum_expr_type = self._infer_scalar_expression_type(op)
|
|
129
|
+
if quantum_expr_type is None:
|
|
87
130
|
return False
|
|
88
131
|
|
|
89
132
|
if not result_type.is_instantiated:
|
|
90
|
-
if not inject_quantum_type_attributes_inplace(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
f"{str(result_symbol)!r} of type "
|
|
95
|
-
f"{result_symbol.quantum_type.qmod_type_name}"
|
|
96
|
-
)
|
|
133
|
+
if not inject_quantum_type_attributes_inplace(
|
|
134
|
+
quantum_expr_type, result_type
|
|
135
|
+
):
|
|
136
|
+
self._raise_type_error(result_symbol, expr_type)
|
|
97
137
|
return False
|
|
98
138
|
|
|
99
|
-
if isinstance(result_type,
|
|
100
|
-
|
|
139
|
+
if not isinstance(result_type, QuantumScalar) or not isinstance(
|
|
140
|
+
quantum_expr_type, QuantumScalar
|
|
101
141
|
):
|
|
102
|
-
|
|
103
|
-
if
|
|
142
|
+
return False
|
|
143
|
+
if isinstance(result_type, QuantumNumeric):
|
|
144
|
+
result_type.set_bounds(quantum_expr_type.get_bounds())
|
|
145
|
+
if self._same_numeric_attributes(result_type, quantum_expr_type):
|
|
104
146
|
return False
|
|
105
147
|
self._validate_declared_attributes(
|
|
106
|
-
result_type,
|
|
148
|
+
result_type, quantum_expr_type, str(op.result_var)
|
|
107
149
|
)
|
|
108
150
|
if not self._replace_assignment_if_needed:
|
|
109
151
|
return False
|
|
110
152
|
|
|
111
|
-
self._assign_to_inferred_var_and_bind(op, result_type,
|
|
153
|
+
self._assign_to_inferred_var_and_bind(op, result_type, quantum_expr_type)
|
|
112
154
|
return True
|
|
113
155
|
|
|
114
|
-
def
|
|
156
|
+
def _emit_quantum_var_quantum_expr_assignment(
|
|
157
|
+
self, op: QuantumAssignmentOperation, /
|
|
158
|
+
) -> bool:
|
|
159
|
+
result_symbol = self._interpreter.evaluate(op.result_var).value
|
|
160
|
+
result_type = result_symbol.quantum_type
|
|
161
|
+
expr_type = cast(QuantumType, _get_expr_type(op))
|
|
162
|
+
if not inject_quantum_type_attributes_inplace(
|
|
163
|
+
expr_type, result_type
|
|
164
|
+
) or not compare_quantum_types(result_type, expr_type):
|
|
165
|
+
self._raise_type_error(result_symbol, expr_type)
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
def _emit_quantum_var_classical_expr_assignment(
|
|
169
|
+
self, op: QuantumAssignmentOperation, /
|
|
170
|
+
) -> bool:
|
|
171
|
+
result_symbol = self._interpreter.evaluate(op.result_var).value
|
|
172
|
+
result_type = result_symbol.quantum_type
|
|
173
|
+
|
|
174
|
+
quantum_expr_type = self._infer_classical_array_expression_type(op)
|
|
175
|
+
if quantum_expr_type is None or not inject_quantum_type_attributes_inplace(
|
|
176
|
+
quantum_expr_type, result_type
|
|
177
|
+
):
|
|
178
|
+
self._raise_type_error(result_symbol, _get_expr_type(op))
|
|
179
|
+
|
|
180
|
+
return False
|
|
181
|
+
|
|
182
|
+
def _raise_type_error(
|
|
183
|
+
self, result_symbol: QuantumSymbol, expr_type: QmodType
|
|
184
|
+
) -> NoReturn:
|
|
185
|
+
raise ClassiqExpansionError(
|
|
186
|
+
f"Cannot assign expression of type "
|
|
187
|
+
f"{expr_type.qmod_type_name} to variable "
|
|
188
|
+
f"{str(result_symbol)!r} of type "
|
|
189
|
+
f"{result_symbol.quantum_type.qmod_type_name}"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def _infer_scalar_expression_type(
|
|
193
|
+
self, op: QuantumAssignmentOperation
|
|
194
|
+
) -> QuantumType | None:
|
|
115
195
|
expr = self._evaluate_expression(op.expression)
|
|
116
196
|
expr_val = expr.value.value
|
|
117
197
|
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
@@ -129,9 +209,33 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
129
209
|
).to_quantum_numeric()
|
|
130
210
|
return None
|
|
131
211
|
|
|
212
|
+
def _infer_classical_array_expression_type(
|
|
213
|
+
self, op: QuantumAssignmentOperation
|
|
214
|
+
) -> QuantumType | None:
|
|
215
|
+
expr = self._evaluate_expression(op.expression)
|
|
216
|
+
expr_val = expr.value.value
|
|
217
|
+
if isinstance(expr_val, QmodAnnotatedExpression):
|
|
218
|
+
root_type = expr_val.get_type(expr_val.root)
|
|
219
|
+
if isinstance(root_type, (ClassicalArray, ClassicalTuple)) and all(
|
|
220
|
+
isinstance(element_type, Integer)
|
|
221
|
+
for element_type in element_types(root_type)
|
|
222
|
+
):
|
|
223
|
+
list_len = array_len(root_type)
|
|
224
|
+
len_expr = (
|
|
225
|
+
Expression(expr=str(list_len)) if list_len is not None else None
|
|
226
|
+
)
|
|
227
|
+
return QuantumBitvector(element_type=QuantumBit(), length=len_expr)
|
|
228
|
+
return None
|
|
229
|
+
if isinstance(expr_val, list) and all(
|
|
230
|
+
element in (0, 1) for element in expr_val
|
|
231
|
+
):
|
|
232
|
+
length_expr = Expression(expr=str(len(expr_val)))
|
|
233
|
+
return QuantumBitvector(element_type=QuantumBit(), length=length_expr)
|
|
234
|
+
return None
|
|
235
|
+
|
|
132
236
|
@staticmethod
|
|
133
237
|
def _same_numeric_attributes(
|
|
134
|
-
result_type:
|
|
238
|
+
result_type: QuantumScalar, expression_type: QuantumScalar
|
|
135
239
|
) -> bool:
|
|
136
240
|
return (
|
|
137
241
|
result_type.size_in_bits == expression_type.size_in_bits
|
|
@@ -142,7 +246,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
142
246
|
|
|
143
247
|
@classmethod
|
|
144
248
|
def _validate_declared_attributes(
|
|
145
|
-
cls, result_type:
|
|
249
|
+
cls, result_type: QuantumScalar, expression_type: QuantumScalar, var: str
|
|
146
250
|
) -> None:
|
|
147
251
|
result_size, result_sign, result_fractions = (
|
|
148
252
|
result_type.size_in_bits,
|
|
@@ -97,6 +97,8 @@ class BindEmitter(Emitter[BindOperation]):
|
|
|
97
97
|
state = self._builder.current_block.captured_vars.get_state(
|
|
98
98
|
var_name, inp.defining_function
|
|
99
99
|
)
|
|
100
|
+
if state is None:
|
|
101
|
+
continue
|
|
100
102
|
if not state:
|
|
101
103
|
raise ClassiqExpansionError(
|
|
102
104
|
f"Cannot use uninitialized quantum variable "
|
|
@@ -112,6 +114,8 @@ class BindEmitter(Emitter[BindOperation]):
|
|
|
112
114
|
state = self._builder.current_block.captured_vars.get_state(
|
|
113
115
|
var_name, out.defining_function
|
|
114
116
|
)
|
|
117
|
+
if state is None:
|
|
118
|
+
continue
|
|
115
119
|
if state:
|
|
116
120
|
raise ClassiqExpansionError(
|
|
117
121
|
f"Cannot use initialized quantum variable "
|
|
@@ -12,9 +12,6 @@ from classiq.interface.debug_info.debug_info import (
|
|
|
12
12
|
new_function_debug_info_by_node,
|
|
13
13
|
)
|
|
14
14
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
15
|
-
from classiq.interface.generator.functions.port_declaration import (
|
|
16
|
-
PortDeclarationDirection,
|
|
17
|
-
)
|
|
18
15
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
|
19
16
|
from classiq.interface.helpers.text_utils import are, readable_list, s
|
|
20
17
|
from classiq.interface.model.block import Block
|
|
@@ -45,8 +42,6 @@ from classiq.evaluators.parameter_types import (
|
|
|
45
42
|
)
|
|
46
43
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
47
44
|
from classiq.model_expansions.capturing.captured_vars import (
|
|
48
|
-
INITIALIZED_VAR_MESSAGE,
|
|
49
|
-
UNINITIALIZED_VAR_MESSAGE,
|
|
50
45
|
validate_args_are_not_propagated,
|
|
51
46
|
)
|
|
52
47
|
from classiq.model_expansions.closure import Closure, FunctionClosure
|
|
@@ -109,12 +104,14 @@ def _validate_gen_args(
|
|
|
109
104
|
if (
|
|
110
105
|
isinstance(param, ClassicalParameterDeclaration)
|
|
111
106
|
and not param.classical_type.is_purely_declarative
|
|
112
|
-
and isinstance(arg.value, QmodAnnotatedExpression)
|
|
107
|
+
and isinstance(arg_val := arg.value, QmodAnnotatedExpression)
|
|
113
108
|
):
|
|
114
109
|
readable_expr = transform_expression(str(arg.value), {}, {}, one_line=True)
|
|
110
|
+
expr_type = arg_val.get_type(arg_val.root)
|
|
115
111
|
raise ClassiqExpansionError(
|
|
116
|
-
f"Cannot pass
|
|
117
|
-
f"parameter {param.name!r}"
|
|
112
|
+
f"Cannot pass {readable_expr!r} of type {expr_type.qmod_type_name} as "
|
|
113
|
+
f"parameter {param.name!r} of Python-type "
|
|
114
|
+
f"{param.classical_type.python_type_name}"
|
|
118
115
|
)
|
|
119
116
|
|
|
120
117
|
|
|
@@ -195,7 +192,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
|
|
|
195
192
|
) -> QuantumFunctionCall:
|
|
196
193
|
function = function.clone()
|
|
197
194
|
function = function.set_depth(self._builder.current_function.depth + 1)
|
|
198
|
-
self._validate_call_args(function.positional_arg_declarations, args)
|
|
199
195
|
evaluated_args = [self._interpreter.evaluate(arg) for arg in args]
|
|
200
196
|
_validate_cloning(evaluated_args)
|
|
201
197
|
_validate_runtime_args(evaluated_args, self._current_scope)
|
|
@@ -391,32 +387,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], ModelR
|
|
|
391
387
|
permutation=function.permutation,
|
|
392
388
|
)
|
|
393
389
|
|
|
394
|
-
def _validate_call_args(
|
|
395
|
-
self, params: Sequence[PositionalArg], args: list[ArgValue]
|
|
396
|
-
) -> None:
|
|
397
|
-
for param, arg in zip(params, args):
|
|
398
|
-
if not isinstance(param, PortDeclaration) or not isinstance(
|
|
399
|
-
arg, HandleBinding
|
|
400
|
-
):
|
|
401
|
-
continue
|
|
402
|
-
var_name = arg.name
|
|
403
|
-
symbol = self._interpreter.evaluate(var_name)
|
|
404
|
-
if (
|
|
405
|
-
not isinstance(symbol.value, QuantumSymbol)
|
|
406
|
-
or symbol.defining_function is None
|
|
407
|
-
):
|
|
408
|
-
continue
|
|
409
|
-
var_state = self._builder.current_block.captured_vars.get_state(
|
|
410
|
-
var_name, symbol.defining_function
|
|
411
|
-
)
|
|
412
|
-
if not var_state and param.direction in (
|
|
413
|
-
PortDeclarationDirection.Inout,
|
|
414
|
-
PortDeclarationDirection.Input,
|
|
415
|
-
):
|
|
416
|
-
raise ClassiqExpansionError(UNINITIALIZED_VAR_MESSAGE.format(var_name))
|
|
417
|
-
if var_state and param.direction == PortDeclarationDirection.Output:
|
|
418
|
-
raise ClassiqExpansionError(INITIALIZED_VAR_MESSAGE.format(var_name))
|
|
419
|
-
|
|
420
390
|
def _validate_type_modifiers(
|
|
421
391
|
self, func_context: FunctionContext, func_def: NativeFunctionDefinition
|
|
422
392
|
) -> None:
|
|
@@ -144,11 +144,8 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
|
144
144
|
expression: Expression,
|
|
145
145
|
*,
|
|
146
146
|
simplify: bool = False,
|
|
147
|
-
treat_qnum_as_float: bool = False,
|
|
148
147
|
) -> Expression:
|
|
149
|
-
expr_val = self._interpreter.evaluate(
|
|
150
|
-
expression, simplify=simplify, treat_qnum_as_float=treat_qnum_as_float
|
|
151
|
-
).value
|
|
148
|
+
expr_val = self._interpreter.evaluate(expression, simplify=simplify).value
|
|
152
149
|
new_expr = Expression(expr=str(expr_val))
|
|
153
150
|
new_expr._evaluated_expr = EvaluatedExpression(value=expr_val)
|
|
154
151
|
return new_expr
|
|
@@ -26,14 +26,12 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
|
26
26
|
*,
|
|
27
27
|
readable_expression_name: str | None = None,
|
|
28
28
|
simplify: bool = False,
|
|
29
|
-
treat_qnum_as_float: bool = False,
|
|
30
29
|
allow_link_time_vars: bool = True,
|
|
31
30
|
allow_runtime_vars: bool = True,
|
|
32
31
|
) -> None:
|
|
33
32
|
super().__init__(interpreter)
|
|
34
33
|
self._expression_name = expression_name
|
|
35
34
|
self._simplify = simplify
|
|
36
|
-
self._treat_qnum_as_float = treat_qnum_as_float
|
|
37
35
|
self._allow_link_time_vars = allow_link_time_vars
|
|
38
36
|
self._allow_runtime_vars = allow_runtime_vars
|
|
39
37
|
if (
|
|
@@ -49,7 +47,6 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
|
49
47
|
evaluated_expression = self._evaluate_expression(
|
|
50
48
|
expression,
|
|
51
49
|
simplify=self._simplify,
|
|
52
|
-
treat_qnum_as_float=self._treat_qnum_as_float,
|
|
53
50
|
)
|
|
54
51
|
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
|
55
52
|
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
|
@@ -21,9 +21,6 @@ from classiq.interface.model.invert import Invert
|
|
|
21
21
|
from classiq.interface.model.model_visitor import ModelStatementsVisitor
|
|
22
22
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
|
23
23
|
from classiq.interface.model.power import Power
|
|
24
|
-
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
|
25
|
-
AmplitudeLoadingOperation,
|
|
26
|
-
)
|
|
27
24
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
28
25
|
ArithmeticOperation,
|
|
29
26
|
)
|
|
@@ -147,12 +144,6 @@ class UncomputationSignatureInference(ModelStatementsVisitor):
|
|
|
147
144
|
else:
|
|
148
145
|
self._mark_as_non_const(arith.result_var.name, True)
|
|
149
146
|
|
|
150
|
-
def visit_AmplitudeLoadingOperation(
|
|
151
|
-
self, amp_load: AmplitudeLoadingOperation
|
|
152
|
-
) -> None:
|
|
153
|
-
self._mark_as_non_permutation()
|
|
154
|
-
self._mark_as_non_const(amp_load.result_var.name, False)
|
|
155
|
-
|
|
156
147
|
def visit_Control(self, control: Control) -> None:
|
|
157
148
|
self.visit(control.body)
|
|
158
149
|
if control.else_block is not None:
|
|
@@ -48,6 +48,10 @@ CORE_LIB_DECLS = [
|
|
|
48
48
|
integer_xor,
|
|
49
49
|
modular_add_constant,
|
|
50
50
|
real_xor_constant,
|
|
51
|
+
multiply,
|
|
52
|
+
multiply_constant,
|
|
53
|
+
canonical_multiply,
|
|
54
|
+
canonical_multiply_constant,
|
|
51
55
|
U,
|
|
52
56
|
CCX,
|
|
53
57
|
free,
|
|
@@ -61,6 +65,7 @@ CORE_LIB_DECLS = [
|
|
|
61
65
|
commuting_paulis_exponent,
|
|
62
66
|
suzuki_trotter,
|
|
63
67
|
unscheduled_suzuki_trotter,
|
|
68
|
+
sequential_suzuki_trotter,
|
|
64
69
|
exponentiate,
|
|
65
70
|
multi_suzuki_trotter,
|
|
66
71
|
parametric_suzuki_trotter,
|
|
@@ -111,6 +116,10 @@ __all__ = [ # noqa: RUF022
|
|
|
111
116
|
"add_inplace_right",
|
|
112
117
|
"apply",
|
|
113
118
|
"exponentiation_with_depth_constraint",
|
|
119
|
+
"multiply",
|
|
120
|
+
"multiply_constant",
|
|
121
|
+
"canonical_multiply",
|
|
122
|
+
"canonical_multiply_constant",
|
|
114
123
|
"free",
|
|
115
124
|
"drop",
|
|
116
125
|
"inplace_prepare_amplitudes",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Literal
|
|
2
2
|
|
|
3
|
+
from classiq.qmod.cparam import CInt
|
|
3
4
|
from classiq.qmod.qfunc import qfunc, qperm
|
|
4
5
|
from classiq.qmod.qmod_parameter import CArray, CBool, CReal
|
|
5
6
|
from classiq.qmod.qmod_variable import (
|
|
@@ -83,3 +84,133 @@ def integer_xor(left: Const[QArray[QBit]], right: QArray[QBit]) -> None:
|
|
|
83
84
|
@qperm(external=True)
|
|
84
85
|
def real_xor_constant(left: CReal, right: QNum) -> None:
|
|
85
86
|
pass
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@qperm(external=True)
|
|
90
|
+
def multiply(left: Const[QNum], right: Const[QNum], result: Output[QNum]) -> None:
|
|
91
|
+
"""
|
|
92
|
+
[Qmod core-library function]
|
|
93
|
+
|
|
94
|
+
Multiplies two quantum numeric variables:
|
|
95
|
+
|
|
96
|
+
$$
|
|
97
|
+
\\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
|
|
98
|
+
\\mapsto
|
|
99
|
+
\\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
|
|
100
|
+
\\left|\\text{left} \\cdot \\text{right} \\right\\rangle
|
|
101
|
+
$$
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
left: The first argument for the multiplication.
|
|
105
|
+
right: The second argument for the multiplication.
|
|
106
|
+
result: The quantum variable to hold the multiplication result.
|
|
107
|
+
"""
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@qperm(external=True)
|
|
112
|
+
def multiply_constant(left: CReal, right: Const[QNum], result: Output[QNum]) -> None:
|
|
113
|
+
"""
|
|
114
|
+
[Qmod core-library function]
|
|
115
|
+
|
|
116
|
+
Multiplies a quantum numeric variable with a constant:
|
|
117
|
+
|
|
118
|
+
$$
|
|
119
|
+
\\left|\\text{right}\\right\\rangle
|
|
120
|
+
\\mapsto
|
|
121
|
+
\\left|\\text{right}\\right\\rangle
|
|
122
|
+
\\left|\\text{left} \\cdot \\text{right} \\right\\rangle
|
|
123
|
+
$$
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
left: The constant argument for the multiplication.
|
|
127
|
+
right: The variable argument for the multiplication.
|
|
128
|
+
result: The quantum variable to hold the multiplication result.
|
|
129
|
+
"""
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@qperm(external=True)
|
|
134
|
+
def canonical_multiply(
|
|
135
|
+
left: Const[QArray],
|
|
136
|
+
extend_left: CBool,
|
|
137
|
+
right: Const[QArray],
|
|
138
|
+
extend_right: CBool,
|
|
139
|
+
result: QArray,
|
|
140
|
+
trim_result_lsb: CBool,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""
|
|
143
|
+
[Qmod core-library function]
|
|
144
|
+
|
|
145
|
+
Multiplies two quantum variables representing integers (signed or unsigned) into the
|
|
146
|
+
result variable which is assumed to start in the $|0\\rangle$ state.
|
|
147
|
+
|
|
148
|
+
If `trim_result_lsb` is `False`, applies the transformation:
|
|
149
|
+
|
|
150
|
+
$$
|
|
151
|
+
\\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
|
|
152
|
+
\\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
|
|
153
|
+
\\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
|
|
154
|
+
\\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
|
|
155
|
+
$$
|
|
156
|
+
|
|
157
|
+
If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
|
|
158
|
+
applies the transformation:
|
|
159
|
+
|
|
160
|
+
$$
|
|
161
|
+
\\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
|
|
162
|
+
\\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
|
|
163
|
+
\\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
|
|
164
|
+
\\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
|
|
165
|
+
$$
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
left: The first argument for the multiplication.
|
|
169
|
+
extend_left: Whether to sign-extend the left argument.
|
|
170
|
+
right: The second argument for the multiplication.
|
|
171
|
+
extend_right: Whether to sign-extend the right argument.
|
|
172
|
+
result: The quantum variable to hold the multiplication result.
|
|
173
|
+
trim_result_lsb: Whether to avoid computing the result's LSB.
|
|
174
|
+
"""
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@qperm(external=True)
|
|
179
|
+
def canonical_multiply_constant(
|
|
180
|
+
left: CInt,
|
|
181
|
+
right: Const[QArray],
|
|
182
|
+
extend_right: CBool,
|
|
183
|
+
result: QArray,
|
|
184
|
+
trim_result_lsb: CBool,
|
|
185
|
+
) -> None:
|
|
186
|
+
"""
|
|
187
|
+
[Qmod core-library function]
|
|
188
|
+
|
|
189
|
+
Multiplies a quantum variable representing an integer (signed or unsigned) with a
|
|
190
|
+
constant, into the result variable which is assumed to start in the $|0\\rangle$ state.
|
|
191
|
+
|
|
192
|
+
If `trim_result_lsb` is `False`, applies the transformation:
|
|
193
|
+
|
|
194
|
+
$$
|
|
195
|
+
\\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
|
|
196
|
+
\\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
|
|
197
|
+
\\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
|
|
198
|
+
$$
|
|
199
|
+
|
|
200
|
+
If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
|
|
201
|
+
applies the transformation:
|
|
202
|
+
|
|
203
|
+
$$
|
|
204
|
+
\\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
|
|
205
|
+
\\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
|
|
206
|
+
\\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
|
|
207
|
+
$$
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
left: The constant argument for the multiplication.
|
|
211
|
+
right: The variable argument for the multiplication.
|
|
212
|
+
extend_right: Whether to sign-extend the right argument.
|
|
213
|
+
result: The quantum variable to hold the multiplication result.
|
|
214
|
+
trim_result_lsb: Whether to avoid computing the result's LSB.
|
|
215
|
+
"""
|
|
216
|
+
pass
|
|
@@ -99,7 +99,7 @@ def multi_suzuki_trotter(
|
|
|
99
99
|
The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
|
|
100
100
|
|
|
101
101
|
Args:
|
|
102
|
-
hamiltonians: The
|
|
102
|
+
hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
|
|
103
103
|
evolution_coefficients: The hamiltonian coefficients (can be link-time).
|
|
104
104
|
order: The order of the Suzuki-Trotter decomposition.
|
|
105
105
|
repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
|
|
@@ -129,7 +129,37 @@ def unscheduled_suzuki_trotter(
|
|
|
129
129
|
The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
|
|
130
130
|
|
|
131
131
|
Args:
|
|
132
|
-
hamiltonians: The
|
|
132
|
+
hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
|
|
133
|
+
evolution_coefficients: The hamiltonian coefficients (can be link-time).
|
|
134
|
+
order: The order of the Suzuki-Trotter decomposition.
|
|
135
|
+
repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
|
|
136
|
+
qbv: The target quantum variable of the exponentiation.
|
|
137
|
+
"""
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@qfunc(external=True)
|
|
142
|
+
def sequential_suzuki_trotter(
|
|
143
|
+
hamiltonians: CArray[SparsePauliOp],
|
|
144
|
+
evolution_coefficients: CArray[CReal],
|
|
145
|
+
order: CInt,
|
|
146
|
+
repetitions: CInt,
|
|
147
|
+
qbv: QArray,
|
|
148
|
+
) -> None:
|
|
149
|
+
"""
|
|
150
|
+
[Qmod core-library function]
|
|
151
|
+
|
|
152
|
+
Applies the Suzuki-Trotter decomposition jointly to a sum of Hamiltonians
|
|
153
|
+
(represented as Pauli operators), each with its separate evolution coefficient,
|
|
154
|
+
approximating $\\exp{-iH_1t_1+H_2t_2+\\dots}$ with a specified order and number of
|
|
155
|
+
repetitions. Does not reorder the Pauli terms.
|
|
156
|
+
|
|
157
|
+
The Suzuki-Trotter decomposition is a method for approximating the exponential of a sum of operators by a product of exponentials of each operator.
|
|
158
|
+
The Suzuki-Trotter decomposition of a given order nullifies the error of the Taylor series expansion of the product of exponentials up to that order.
|
|
159
|
+
The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
|
|
133
163
|
evolution_coefficients: The hamiltonian coefficients (can be link-time).
|
|
134
164
|
order: The order of the Suzuki-Trotter decomposition.
|
|
135
165
|
repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
|