classiq 0.66.1__py3-none-any.whl → 0.68.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/_internals/api_wrapper.py +5 -1
- classiq/_internals/async_utils.py +1 -1
- classiq/_internals/authentication/password_manager.py +1 -1
- classiq/_internals/client.py +1 -1
- classiq/applications/finance/finance_model_constructor.py +9 -0
- classiq/applications/grover/grover_model_constructor.py +10 -0
- classiq/applications/qnn/qlayer.py +8 -2
- classiq/applications/qsvm/qsvm_model_constructor.py +9 -0
- classiq/execution/execution_session.py +7 -3
- classiq/executor.py +7 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -1
- classiq/interface/chemistry/operator.py +1 -1
- classiq/interface/debug_info/debug_info.py +27 -0
- classiq/interface/exceptions.py +2 -5
- classiq/interface/generator/arith/argument_utils.py +1 -1
- classiq/interface/generator/arith/arithmetic.py +99 -2
- classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +3 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/functions/type_name.py +2 -2
- classiq/interface/generator/generated_circuit_data.py +38 -3
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/hva.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +8 -1
- classiq/interface/generator/quantum_program.py +18 -1
- classiq/interface/generator/reset.py +14 -0
- classiq/interface/generator/types/enum_declaration.py +33 -2
- classiq/interface/generator/ucc.py +1 -1
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/classical_if.py +2 -2
- classiq/interface/model/control.py +2 -2
- classiq/interface/model/invert.py +2 -2
- classiq/interface/model/power.py +2 -2
- classiq/interface/model/quantum_function_call.py +4 -0
- classiq/interface/model/quantum_statement.py +13 -0
- classiq/interface/model/repeat.py +2 -2
- classiq/interface/model/statement_block.py +1 -1
- classiq/interface/model/within_apply_operation.py +2 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +2 -1
- classiq/model_expansions/capturing/captured_vars.py +184 -54
- classiq/model_expansions/closure.py +6 -3
- classiq/model_expansions/evaluators/control.py +14 -38
- classiq/model_expansions/function_builder.py +19 -14
- classiq/model_expansions/generative_functions.py +7 -11
- classiq/model_expansions/interpreters/base_interpreter.py +14 -5
- classiq/model_expansions/interpreters/generative_interpreter.py +87 -26
- classiq/model_expansions/quantum_operations/allocate.py +9 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
- classiq/model_expansions/quantum_operations/bind.py +67 -14
- classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +79 -10
- classiq/model_expansions/quantum_operations/classicalif.py +10 -6
- classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
- classiq/model_expansions/quantum_operations/emitter.py +24 -3
- classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
- classiq/model_expansions/quantum_operations/repeat.py +9 -3
- classiq/model_expansions/quantum_operations/variable_decleration.py +13 -2
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
- classiq/open_library/functions/__init__.py +1 -2
- classiq/open_library/functions/amplitude_amplification.py +12 -9
- classiq/open_library/functions/discrete_sine_cosine_transform.py +16 -13
- classiq/open_library/functions/grover.py +11 -15
- classiq/open_library/functions/modular_exponentiation.py +7 -13
- classiq/open_library/functions/state_preparation.py +16 -17
- classiq/open_library/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +10 -2
- classiq/qmod/builtins/functions/__init__.py +3 -0
- classiq/qmod/builtins/functions/chemistry.py +6 -38
- classiq/qmod/builtins/functions/mid_circuit_measurement.py +15 -0
- classiq/qmod/quantum_expandable.py +30 -6
- classiq/qmod/quantum_function.py +4 -0
- classiq/qmod/semantics/annotation/call_annotation.py +8 -2
- classiq/qmod/semantics/annotation/model_annotation.py +9 -0
- classiq/qmod/semantics/error_manager.py +0 -6
- classiq/qmod/semantics/static_semantics_visitor.py +0 -347
- classiq/qmod/semantics/validation/types_validation.py +1 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/utilities.py +2 -1
- classiq/qmod/write_qmod.py +10 -7
- classiq/synthesis.py +20 -7
- {classiq-0.66.1.dist-info → classiq-0.68.0.dist-info}/METADATA +1 -1
- {classiq-0.66.1.dist-info → classiq-0.68.0.dist-info}/RECORD +86 -81
- classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
- classiq/qmod/semantics/validation/func_call_validation.py +0 -99
- classiq/qmod/semantics/validation/handle_validation.py +0 -85
- {classiq-0.66.1.dist-info → classiq-0.68.0.dist-info}/WHEEL +0 -0
@@ -4,6 +4,10 @@ from sympy import Equality
|
|
4
4
|
from sympy.core.numbers import Number
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqExpansionError
|
7
|
+
from classiq.interface.generator.arith.argument_utils import (
|
8
|
+
unsigned_integer_interpretation,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
7
11
|
from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
|
8
12
|
QmodQNumProxy,
|
9
13
|
QmodQScalarProxy,
|
@@ -31,14 +35,15 @@ def resolve_num_condition(condition: Equality) -> tuple[QmodSizedProxy, str]:
|
|
31
35
|
def _calculate_ctrl_state(ctrl: QmodSizedProxy, ctrl_val: float) -> str:
|
32
36
|
is_signed, fraction_places = _get_numeric_attributes(ctrl)
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
_validate_control_value_sign(ctrl, integer_ctrl_val, is_signed)
|
37
|
-
_validate_control_var_qubits(
|
38
|
-
ctrl, integer_ctrl_val, is_signed, fraction_places, ctrl_val
|
38
|
+
reg = RegisterArithmeticInfo(
|
39
|
+
size=ctrl.size, is_signed=is_signed, fraction_places=fraction_places
|
39
40
|
)
|
41
|
+
uint_ctrl_val = unsigned_integer_interpretation(ctrl_val, reg)
|
40
42
|
|
41
|
-
|
43
|
+
_validate_control_value_sign(ctrl, ctrl_val, is_signed)
|
44
|
+
_validate_control_var_qubits(ctrl, uint_ctrl_val, fraction_places, ctrl_val)
|
45
|
+
|
46
|
+
return _to_twos_complement(uint_ctrl_val, ctrl.size)
|
42
47
|
|
43
48
|
|
44
49
|
def _get_numeric_attributes(ctrl: QmodSizedProxy) -> tuple[bool, int]:
|
@@ -49,20 +54,8 @@ def _get_numeric_attributes(ctrl: QmodSizedProxy) -> tuple[bool, int]:
|
|
49
54
|
)
|
50
55
|
|
51
56
|
|
52
|
-
def _get_integer_ctrl_val(
|
53
|
-
ctrl: QmodSizedProxy, ctrl_val: float, fraction_places: int
|
54
|
-
) -> int:
|
55
|
-
unfractioned_ctrl_val = ctrl_val * 2**fraction_places
|
56
|
-
if unfractioned_ctrl_val != int(unfractioned_ctrl_val):
|
57
|
-
raise ClassiqExpansionError(
|
58
|
-
f"Variable {str(ctrl)!r} doesne't have enough fraction digits to "
|
59
|
-
f"represent control value {ctrl_val}"
|
60
|
-
)
|
61
|
-
return int(unfractioned_ctrl_val)
|
62
|
-
|
63
|
-
|
64
57
|
def _validate_control_value_sign(
|
65
|
-
ctrl: QmodSizedProxy, ctrl_val:
|
58
|
+
ctrl: QmodSizedProxy, ctrl_val: float, is_signed: bool
|
66
59
|
) -> None:
|
67
60
|
if not is_signed and ctrl_val < 0:
|
68
61
|
raise ClassiqExpansionError(
|
@@ -74,18 +67,17 @@ def _validate_control_value_sign(
|
|
74
67
|
def _validate_control_var_qubits(
|
75
68
|
ctrl: QmodSizedProxy,
|
76
69
|
ctrl_val: int,
|
77
|
-
is_signed: bool,
|
78
70
|
fraction_places: int,
|
79
71
|
orig_ctrl_val: float,
|
80
72
|
) -> None:
|
81
|
-
required_qubits =
|
73
|
+
required_qubits = _min_unsigned_bit_length(ctrl_val)
|
82
74
|
fraction_places_message = (
|
83
75
|
f" with {fraction_places} fraction digits" if fraction_places else ""
|
84
76
|
)
|
85
77
|
if ctrl.size < required_qubits:
|
86
78
|
raise ClassiqExpansionError(
|
87
79
|
f"Variable {str(ctrl)!r} has {ctrl.size} qubits{fraction_places_message} but control value "
|
88
|
-
f"{str(orig_ctrl_val if fraction_places else
|
80
|
+
f"{str(orig_ctrl_val if fraction_places else int(orig_ctrl_val))!r} requires at least {required_qubits} qubits{fraction_places_message}"
|
89
81
|
)
|
90
82
|
|
91
83
|
|
@@ -116,22 +108,6 @@ def _min_unsigned_bit_length(number: int) -> int:
|
|
116
108
|
raise e
|
117
109
|
|
118
110
|
|
119
|
-
def _min_signed_bit_length(number: int) -> int:
|
120
|
-
pos_val = abs(number)
|
121
|
-
is_whole = pos_val & (pos_val - 1) == 0
|
122
|
-
if number <= 0 and is_whole:
|
123
|
-
return _min_unsigned_bit_length(pos_val)
|
124
|
-
return _min_unsigned_bit_length(pos_val) + 1
|
125
|
-
|
126
|
-
|
127
|
-
def _min_bit_length(number: int, is_signed: bool) -> int:
|
128
|
-
return (
|
129
|
-
_min_signed_bit_length(number)
|
130
|
-
if is_signed
|
131
|
-
else _min_unsigned_bit_length(number)
|
132
|
-
)
|
133
|
-
|
134
|
-
|
135
111
|
def _to_twos_complement(value: int, bits: int) -> str:
|
136
112
|
if value >= 0:
|
137
113
|
return bin(value)[2:].zfill(bits)[::-1]
|
@@ -28,6 +28,7 @@ from classiq.interface.source_reference import SourceReference
|
|
28
28
|
from classiq.model_expansions.capturing.captured_vars import (
|
29
29
|
CapturedVars,
|
30
30
|
validate_captured_directions,
|
31
|
+
validate_end_state,
|
31
32
|
)
|
32
33
|
from classiq.model_expansions.closure import (
|
33
34
|
Closure,
|
@@ -142,7 +143,9 @@ class OperationBuilder:
|
|
142
143
|
@contextmanager
|
143
144
|
def block_context(self, block_name: str) -> Iterator[None]:
|
144
145
|
self._blocks.append(block_name)
|
145
|
-
|
146
|
+
block = Block()
|
147
|
+
block.captured_vars.set_parent(self.current_operation.captured_vars)
|
148
|
+
self._operations[-1].blocks[block_name] = block
|
146
149
|
yield
|
147
150
|
captured_vars = self.current_block.captured_vars
|
148
151
|
if (
|
@@ -150,14 +153,12 @@ class OperationBuilder:
|
|
150
153
|
and self.current_operation.name != WITHIN_APPLY_NAME
|
151
154
|
):
|
152
155
|
validate_captured_directions(
|
153
|
-
captured_vars.
|
154
|
-
self.
|
156
|
+
captured_vars.filter_var_decls(
|
157
|
+
self.current_block.variable_declarations
|
155
158
|
),
|
156
159
|
report_outin=False,
|
157
160
|
)
|
158
|
-
self.current_operation.captured_vars.update(
|
159
|
-
captured_vars.filter_vars(self.current_function)
|
160
|
-
)
|
161
|
+
self.current_operation.captured_vars.update(captured_vars)
|
161
162
|
self._blocks.pop()
|
162
163
|
|
163
164
|
@contextmanager
|
@@ -167,11 +168,17 @@ class OperationBuilder:
|
|
167
168
|
context: OperationContext
|
168
169
|
if isinstance(original_operation, FunctionClosure):
|
169
170
|
context = FunctionContext.create(original_operation)
|
171
|
+
context.closure.captured_vars.init_params(original_operation)
|
170
172
|
else:
|
171
173
|
context = OperationContext(closure=original_operation)
|
174
|
+
context.closure.captured_vars.set_parent(self.current_block.captured_vars)
|
172
175
|
self._operations.append(context)
|
173
176
|
yield context
|
174
177
|
self._finalize_within_apply()
|
178
|
+
if isinstance(self.current_operation, FunctionClosure):
|
179
|
+
validate_end_state(
|
180
|
+
self.current_operation, self.current_operation.captured_vars
|
181
|
+
)
|
175
182
|
self._propagate_captured_vars()
|
176
183
|
self._operations.pop()
|
177
184
|
|
@@ -179,21 +186,19 @@ class OperationBuilder:
|
|
179
186
|
if self.current_operation.name != WITHIN_APPLY_NAME:
|
180
187
|
return
|
181
188
|
within_captured_vars = self._operations[-1].blocks["within"].captured_vars
|
182
|
-
self.current_operation.captured_vars.update(
|
183
|
-
within_captured_vars.filter_vars(self.current_function).negate()
|
184
|
-
)
|
189
|
+
self.current_operation.captured_vars.update(within_captured_vars.negate())
|
185
190
|
|
186
191
|
def _propagate_captured_vars(self) -> None:
|
187
192
|
captured_vars = self.current_operation.captured_vars
|
188
193
|
if isinstance(self.current_operation, FunctionClosure):
|
189
|
-
captured_vars = captured_vars.
|
190
|
-
|
194
|
+
captured_vars = captured_vars.filter_vars(
|
195
|
+
self.current_function
|
196
|
+
).set_propagated()
|
197
|
+
validate_captured_directions(captured_vars)
|
191
198
|
if len(self._operations) < 2:
|
192
199
|
return
|
193
200
|
parent_block = self._operations[-2].blocks[self._blocks[-1]]
|
194
|
-
parent_block.captured_vars.update(
|
195
|
-
captured_vars.filter_vars(self.parent_function)
|
196
|
-
)
|
201
|
+
parent_block.captured_vars.update(captured_vars)
|
197
202
|
|
198
203
|
@contextmanager
|
199
204
|
def source_ref_context(
|
@@ -24,9 +24,7 @@ from classiq.qmod.generative import generative_mode_context, set_frontend_interp
|
|
24
24
|
from classiq.qmod.model_state_container import QMODULE
|
25
25
|
from classiq.qmod.qmod_parameter import CParamStruct
|
26
26
|
from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
|
27
|
-
from classiq.qmod.quantum_callable import QCallable
|
28
27
|
from classiq.qmod.quantum_expandable import (
|
29
|
-
QExpandable,
|
30
28
|
QTerminalCallable,
|
31
29
|
)
|
32
30
|
from classiq.qmod.quantum_function import QFunc
|
@@ -147,12 +145,10 @@ def emit_generative_statements(
|
|
147
145
|
translate_ast_arg_to_python_qmod(param, arg)
|
148
146
|
for param, arg in zip(operation.positional_arg_declarations, args)
|
149
147
|
]
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
):
|
158
|
-
generative_function._py_callable(*python_qmod_args)
|
148
|
+
with _InterpreterExpandable(interpreter):
|
149
|
+
set_frontend_interpreter(interpreter)
|
150
|
+
for block_name, generative_function in operation.generative_blocks.items():
|
151
|
+
with interpreter._builder.block_context(
|
152
|
+
block_name
|
153
|
+
), generative_mode_context(True):
|
154
|
+
generative_function._py_callable(*python_qmod_args)
|
@@ -144,7 +144,7 @@ class BaseInterpreter:
|
|
144
144
|
|
145
145
|
def process_exception(self, e: Exception) -> None:
|
146
146
|
if not isinstance(e, (ClassiqError, ValidationError)):
|
147
|
-
raise ClassiqInternalExpansionError(str(e)) from
|
147
|
+
raise ClassiqInternalExpansionError(str(e)) from e
|
148
148
|
prefix = ""
|
149
149
|
if not isinstance(e, ClassiqExpansionError):
|
150
150
|
prefix = f"{type(e).__name__}: "
|
@@ -212,8 +212,15 @@ class BaseInterpreter:
|
|
212
212
|
|
213
213
|
@evaluate.register
|
214
214
|
def evaluate_field_access(self, field_access: FieldHandleBinding) -> Evaluated:
|
215
|
-
base_value = self.evaluate(field_access.base_handle)
|
216
|
-
|
215
|
+
base_value = self.evaluate(field_access.base_handle).as_type(QuantumSymbol)
|
216
|
+
fields = base_value.fields
|
217
|
+
field_name = field_access.field
|
218
|
+
if field_name not in fields:
|
219
|
+
raise ClassiqExpansionError(
|
220
|
+
f"Struct {base_value.quantum_type.type_name} has no field "
|
221
|
+
f"{field_name!r}. Available fields: {', '.join(fields.keys())}"
|
222
|
+
)
|
223
|
+
return Evaluated(value=fields[field_name])
|
217
224
|
|
218
225
|
@abstractmethod
|
219
226
|
def emit(self, statement: QuantumStatement) -> None:
|
@@ -251,8 +258,10 @@ class BaseInterpreter:
|
|
251
258
|
(func_def := self._expanded_functions.get(operation.closure_id))
|
252
259
|
is not None
|
253
260
|
):
|
254
|
-
|
255
|
-
operation.captured_vars.
|
261
|
+
cached_closure = self._top_level_scope[func_def.name].value
|
262
|
+
operation.captured_vars.set(
|
263
|
+
cached_closure.captured_vars, cached_closure, operation
|
264
|
+
)
|
256
265
|
else:
|
257
266
|
self._expand_body(operation)
|
258
267
|
|
@@ -21,8 +21,11 @@ from classiq.interface.model.model import Model
|
|
21
21
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
22
22
|
from classiq.interface.model.phase_operation import PhaseOperation
|
23
23
|
from classiq.interface.model.power import Power
|
24
|
-
from classiq.interface.model.quantum_expressions.
|
25
|
-
|
24
|
+
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
25
|
+
AmplitudeLoadingOperation,
|
26
|
+
)
|
27
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
28
|
+
ArithmeticOperation,
|
26
29
|
)
|
27
30
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
28
31
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -55,7 +58,17 @@ from classiq.model_expansions.quantum_operations import (
|
|
55
58
|
VariableDeclarationStatementEmitter,
|
56
59
|
)
|
57
60
|
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
58
|
-
from classiq.model_expansions.quantum_operations.
|
61
|
+
from classiq.model_expansions.quantum_operations.assignment_result_processor import (
|
62
|
+
AssignmentResultProcessor,
|
63
|
+
)
|
64
|
+
from classiq.model_expansions.quantum_operations.block_evaluator import BlockEvaluator
|
65
|
+
from classiq.model_expansions.quantum_operations.composite_emitter import (
|
66
|
+
CompositeEmitter,
|
67
|
+
)
|
68
|
+
from classiq.model_expansions.quantum_operations.expression_evaluator import (
|
69
|
+
ExpressionEvaluator,
|
70
|
+
)
|
71
|
+
from classiq.model_expansions.quantum_operations.handle_evaluator import HandleEvaluator
|
59
72
|
from classiq.model_expansions.scope import Evaluated, Scope
|
60
73
|
from classiq.model_expansions.scope_initialization import (
|
61
74
|
add_constants_to_scope,
|
@@ -101,15 +114,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
101
114
|
closure_class = FunctionClosure
|
102
115
|
extra_args = {}
|
103
116
|
|
117
|
+
closure = closure_class.create(
|
118
|
+
name=func_decl.name,
|
119
|
+
positional_arg_declarations=func_decl.positional_arg_declarations,
|
120
|
+
body=function.body,
|
121
|
+
scope=Scope(parent=self._builder.current_scope),
|
122
|
+
lambda_external_vars=self._builder.current_block.captured_vars,
|
123
|
+
**extra_args,
|
124
|
+
)
|
104
125
|
return Evaluated(
|
105
|
-
value=
|
106
|
-
name=func_decl.name,
|
107
|
-
positional_arg_declarations=func_decl.positional_arg_declarations,
|
108
|
-
body=function.body,
|
109
|
-
scope=Scope(parent=self._builder.current_scope),
|
110
|
-
is_lambda=True,
|
111
|
-
**extra_args,
|
112
|
-
),
|
126
|
+
value=closure,
|
113
127
|
defining_function=self._builder.current_function,
|
114
128
|
)
|
115
129
|
|
@@ -133,15 +147,39 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
133
147
|
BindEmitter(self).emit(bind)
|
134
148
|
|
135
149
|
@emit.register
|
136
|
-
def
|
137
|
-
|
138
|
-
self,
|
150
|
+
def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
|
151
|
+
CompositeEmitter[AmplitudeLoadingOperation](
|
152
|
+
self,
|
153
|
+
[
|
154
|
+
HandleEvaluator(self, "result_var"),
|
155
|
+
ExpressionEvaluator(self, "expression"),
|
156
|
+
AssignmentResultProcessor(self),
|
157
|
+
],
|
158
|
+
).emit(op)
|
159
|
+
|
160
|
+
@emit.register
|
161
|
+
def _emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
162
|
+
self.emit_arithmetic_operation(op)
|
163
|
+
|
164
|
+
def emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
165
|
+
CompositeEmitter[ArithmeticOperation](
|
166
|
+
self,
|
167
|
+
[
|
168
|
+
HandleEvaluator(self, "result_var"),
|
169
|
+
ExpressionEvaluator(self, "expression"),
|
170
|
+
AssignmentResultProcessor(self),
|
171
|
+
],
|
139
172
|
).emit(op)
|
140
173
|
|
141
174
|
@emit.register
|
142
175
|
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
143
|
-
|
144
|
-
self,
|
176
|
+
CompositeEmitter[InplaceBinaryOperation](
|
177
|
+
self,
|
178
|
+
[
|
179
|
+
HandleEvaluator(self, "target"),
|
180
|
+
HandleEvaluator(self, "value"),
|
181
|
+
ExpressionEvaluator(self, "value"),
|
182
|
+
],
|
145
183
|
).emit(op)
|
146
184
|
|
147
185
|
@emit.register
|
@@ -156,37 +194,60 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
156
194
|
|
157
195
|
@emit.register
|
158
196
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
159
|
-
|
197
|
+
BlockEvaluator(
|
160
198
|
self,
|
161
199
|
WITHIN_APPLY_NAME,
|
162
|
-
|
200
|
+
"within",
|
201
|
+
"apply",
|
202
|
+
"compute",
|
203
|
+
"action",
|
163
204
|
).emit(within_apply)
|
164
205
|
|
165
206
|
@emit.register
|
166
207
|
def emit_invert(self, invert: Invert) -> None:
|
167
|
-
|
208
|
+
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
168
209
|
|
169
210
|
@emit.register
|
170
211
|
def emit_repeat(self, repeat: Repeat) -> None:
|
171
212
|
RepeatEmitter(self).emit(repeat)
|
172
213
|
|
173
214
|
@emit.register
|
215
|
+
def _emit_control(self, control: Control) -> None:
|
216
|
+
self.emit_control(control)
|
217
|
+
|
174
218
|
def emit_control(self, control: Control) -> None:
|
175
|
-
|
219
|
+
CompositeEmitter[Control](
|
176
220
|
self,
|
177
|
-
|
178
|
-
|
221
|
+
[
|
222
|
+
ExpressionEvaluator(self, "expression"),
|
223
|
+
BlockEvaluator(
|
224
|
+
self,
|
225
|
+
CONTROL_OPERATOR_NAME,
|
226
|
+
"body",
|
227
|
+
"else_block",
|
228
|
+
),
|
229
|
+
],
|
179
230
|
).emit(control)
|
180
231
|
|
181
232
|
@emit.register
|
182
233
|
def emit_power(self, power: Power) -> None:
|
183
|
-
|
184
|
-
|
185
|
-
|
234
|
+
CompositeEmitter[Power](
|
235
|
+
self,
|
236
|
+
[
|
237
|
+
ExpressionEvaluator(self, "power"),
|
238
|
+
BlockEvaluator(self, CONTROL_OPERATOR_NAME, "body"),
|
239
|
+
],
|
240
|
+
).emit(power)
|
186
241
|
|
187
242
|
@emit.register
|
188
243
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
189
|
-
|
244
|
+
CompositeEmitter[PhaseOperation](
|
245
|
+
self,
|
246
|
+
[
|
247
|
+
ExpressionEvaluator(self, "expression"),
|
248
|
+
ExpressionEvaluator(self, "theta"),
|
249
|
+
],
|
250
|
+
).emit(phase)
|
190
251
|
|
191
252
|
def _expand_body(self, operation: Closure) -> None:
|
192
253
|
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
@@ -12,8 +12,7 @@ from classiq.model_expansions.scope import QuantumSymbol
|
|
12
12
|
|
13
13
|
|
14
14
|
class AllocateEmitter(Emitter[Allocate]):
|
15
|
-
def emit(self, allocate: Allocate, /) ->
|
16
|
-
self._register_debug_info(allocate)
|
15
|
+
def emit(self, allocate: Allocate, /) -> bool:
|
17
16
|
target: QuantumSymbol = self._interpreter.evaluate(allocate.target).as_type(
|
18
17
|
QuantumSymbol
|
19
18
|
)
|
@@ -25,9 +24,15 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
25
24
|
|
26
25
|
size = self._get_var_size(target, allocate.size)
|
27
26
|
allocate = allocate.model_copy(
|
28
|
-
update=dict(
|
27
|
+
update=dict(
|
28
|
+
size=Expression(expr=str(size)),
|
29
|
+
target=target.handle,
|
30
|
+
back_ref=allocate.uuid,
|
31
|
+
)
|
29
32
|
)
|
33
|
+
self._register_debug_info(allocate)
|
30
34
|
self.emit_statement(allocate)
|
35
|
+
return True
|
31
36
|
|
32
37
|
def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> int:
|
33
38
|
if size is None:
|
@@ -66,4 +71,5 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
66
71
|
level=OperationLevel.QMOD_STATEMENT,
|
67
72
|
is_allocate_or_free=True,
|
68
73
|
port_to_passed_variable_map={"ARG": str(allocate.target)},
|
74
|
+
node=allocate._as_back_ref(),
|
69
75
|
)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
2
|
+
from classiq.interface.generator.functions.port_declaration import (
|
3
|
+
PortDeclarationDirection,
|
4
|
+
)
|
5
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
6
|
+
ArithmeticOperation,
|
7
|
+
ArithmeticOperationKind,
|
8
|
+
)
|
9
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
10
|
+
QuantumAssignmentOperation,
|
11
|
+
)
|
12
|
+
|
13
|
+
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
14
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
15
|
+
from classiq.model_expansions.scope import QuantumSymbol
|
16
|
+
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
17
|
+
|
18
|
+
|
19
|
+
class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
20
|
+
def emit(self, op: QuantumAssignmentOperation, /) -> bool:
|
21
|
+
if (
|
22
|
+
isinstance(op, ArithmeticOperation)
|
23
|
+
and op.operation_kind == ArithmeticOperationKind.Assignment
|
24
|
+
):
|
25
|
+
direction = PortDeclarationDirection.Output
|
26
|
+
self._update_result_type(op)
|
27
|
+
else:
|
28
|
+
direction = PortDeclarationDirection.Inout
|
29
|
+
self._capture_handle(op.result_var, direction)
|
30
|
+
return False
|
31
|
+
|
32
|
+
def _update_result_type(self, op: ArithmeticOperation) -> None:
|
33
|
+
expr = self._evaluate_expression(op.expression)
|
34
|
+
symbols = self._get_symbols_in_expression(expr)
|
35
|
+
expr_str = rename_variables(
|
36
|
+
expr.expr,
|
37
|
+
{str(symbol.handle): symbol.handle.identifier for symbol in symbols}
|
38
|
+
| {symbol.handle.qmod_expr: symbol.handle.identifier for symbol in symbols},
|
39
|
+
)
|
40
|
+
for symbol in symbols:
|
41
|
+
expr_str = expr_str.replace(
|
42
|
+
symbol.handle.qmod_expr, symbol.handle.identifier
|
43
|
+
)
|
44
|
+
result_type = compute_arithmetic_result_type(
|
45
|
+
expr_str,
|
46
|
+
{symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
|
47
|
+
self._machine_precision,
|
48
|
+
)
|
49
|
+
result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
50
|
+
copy_type_information(
|
51
|
+
result_type, result_symbol.quantum_type, str(op.result_var)
|
52
|
+
)
|
@@ -1,4 +1,7 @@
|
|
1
|
-
from classiq.interface.exceptions import
|
1
|
+
from classiq.interface.exceptions import (
|
2
|
+
ClassiqExpansionError,
|
3
|
+
ClassiqInternalExpansionError,
|
4
|
+
)
|
2
5
|
from classiq.interface.model.bind_operation import BindOperation
|
3
6
|
|
4
7
|
from classiq.model_expansions.evaluators.parameter_types import (
|
@@ -9,21 +12,12 @@ from classiq.model_expansions.evaluators.quantum_type_utils import (
|
|
9
12
|
validate_bind_targets,
|
10
13
|
)
|
11
14
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
12
|
-
from classiq.model_expansions.scope import QuantumSymbol
|
15
|
+
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
13
16
|
|
14
17
|
|
15
18
|
class BindEmitter(Emitter[BindOperation]):
|
16
|
-
def emit(self, bind: BindOperation, /) ->
|
17
|
-
inputs
|
18
|
-
self._interpreter.evaluate(arg).as_type(QuantumSymbol)
|
19
|
-
for arg in bind.in_handles
|
20
|
-
]
|
21
|
-
outputs: list[QuantumSymbol] = [
|
22
|
-
self._interpreter.evaluate(arg).as_type(QuantumSymbol)
|
23
|
-
for arg in bind.out_handles
|
24
|
-
]
|
25
|
-
inputs = evaluate_types_in_quantum_symbols(inputs, self._current_scope)
|
26
|
-
outputs = evaluate_types_in_quantum_symbols(outputs, self._current_scope)
|
19
|
+
def emit(self, bind: BindOperation, /) -> bool:
|
20
|
+
inputs, outputs = self._get_inputs_outputs(bind)
|
27
21
|
validate_bind_targets(bind, self._current_scope)
|
28
22
|
unsized_outputs = [
|
29
23
|
output for output in outputs if not output.quantum_type.has_size_in_bits
|
@@ -56,5 +50,64 @@ class BindEmitter(Emitter[BindOperation]):
|
|
56
50
|
)
|
57
51
|
|
58
52
|
self.emit_statement(
|
59
|
-
BindOperation(
|
53
|
+
BindOperation(
|
54
|
+
in_handles=bind.in_handles,
|
55
|
+
out_handles=bind.out_handles,
|
56
|
+
back_ref=bind.uuid,
|
57
|
+
)
|
60
58
|
)
|
59
|
+
return True
|
60
|
+
|
61
|
+
def _get_inputs_outputs(
|
62
|
+
self, bind: BindOperation
|
63
|
+
) -> tuple[list[QuantumSymbol], list[QuantumSymbol]]:
|
64
|
+
evaluated_inputs: list[Evaluated] = [
|
65
|
+
self._interpreter.evaluate(arg) for arg in bind.in_handles
|
66
|
+
]
|
67
|
+
evaluated_outputs: list[Evaluated] = [
|
68
|
+
self._interpreter.evaluate(arg) for arg in bind.out_handles
|
69
|
+
]
|
70
|
+
self._validate_handle_states(evaluated_inputs, evaluated_outputs)
|
71
|
+
inputs: list[QuantumSymbol] = [
|
72
|
+
input.as_type(QuantumSymbol) for input in evaluated_inputs
|
73
|
+
]
|
74
|
+
outputs: list[QuantumSymbol] = [
|
75
|
+
output.as_type(QuantumSymbol) for output in evaluated_outputs
|
76
|
+
]
|
77
|
+
inputs = evaluate_types_in_quantum_symbols(inputs, self._current_scope)
|
78
|
+
outputs = evaluate_types_in_quantum_symbols(outputs, self._current_scope)
|
79
|
+
return inputs, outputs
|
80
|
+
|
81
|
+
def _validate_handle_states(
|
82
|
+
self, inputs: list[Evaluated], outputs: list[Evaluated]
|
83
|
+
) -> None:
|
84
|
+
input_var_names: set[str] = set()
|
85
|
+
for inp in inputs:
|
86
|
+
if inp.defining_function is None:
|
87
|
+
raise ClassiqInternalExpansionError
|
88
|
+
var_name = inp.value.handle.name
|
89
|
+
input_var_names.add(var_name)
|
90
|
+
state = self._builder.current_block.captured_vars.get_state(
|
91
|
+
var_name, inp.defining_function
|
92
|
+
)
|
93
|
+
if not state:
|
94
|
+
raise ClassiqExpansionError(
|
95
|
+
f"Cannot use uninitialized quantum variable "
|
96
|
+
f"{inp.value.handle.name!r} on the left-hand side of a bind "
|
97
|
+
f"statement"
|
98
|
+
)
|
99
|
+
for out in outputs:
|
100
|
+
if out.defining_function is None:
|
101
|
+
raise ClassiqInternalExpansionError
|
102
|
+
var_name = out.value.handle.name
|
103
|
+
if var_name in input_var_names:
|
104
|
+
continue
|
105
|
+
state = self._builder.current_block.captured_vars.get_state(
|
106
|
+
var_name, out.defining_function
|
107
|
+
)
|
108
|
+
if state:
|
109
|
+
raise ClassiqExpansionError(
|
110
|
+
f"Cannot use initialized quantum variable "
|
111
|
+
f"{out.value.handle.name!r} on the right-hand side of a bind "
|
112
|
+
f"statement"
|
113
|
+
)
|