classiq 0.70.0__py3-none-any.whl → 0.72.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/__init__.py +0 -6
- classiq/_internals/client.py +11 -1
- classiq/applications/chemistry/chemistry_model_constructor.py +18 -16
- classiq/applications/combinatorial_helpers/optimization_model.py +9 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +6 -1
- classiq/applications/finance/__init__.py +0 -3
- classiq/applications/qsvm/__init__.py +0 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +22 -0
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/debug_info/debug_info.py +4 -0
- classiq/interface/generator/expressions/expression_constants.py +0 -3
- classiq/interface/generator/expressions/expression_types.py +8 -3
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +5 -1
- classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
- classiq/interface/generator/functions/classical_type.py +1 -1
- classiq/interface/generator/functions/type_name.py +16 -0
- classiq/interface/generator/functions/type_qualifier.py +7 -0
- classiq/interface/generator/generated_circuit_data.py +14 -1
- classiq/interface/generator/hardware/hardware_data.py +3 -1
- classiq/interface/generator/quantum_function_call.py +8 -1
- classiq/interface/generator/synthesis_execution_parameter.py +1 -0
- classiq/interface/generator/transpiler_basis_gates.py +3 -1
- classiq/interface/generator/types/compilation_metadata.py +1 -0
- classiq/interface/hardware.py +1 -0
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/allocate.py +7 -0
- classiq/interface/model/block.py +12 -0
- classiq/interface/model/classical_if.py +4 -0
- classiq/interface/model/handle_binding.py +21 -0
- classiq/interface/model/inplace_binary_operation.py +4 -0
- classiq/interface/model/model.py +3 -1
- classiq/interface/model/phase_operation.py +4 -0
- classiq/interface/model/port_declaration.py +3 -0
- classiq/interface/model/power.py +4 -0
- classiq/interface/model/quantum_expressions/quantum_expression.py +4 -0
- classiq/interface/model/quantum_function_call.py +4 -0
- classiq/interface/model/quantum_function_declaration.py +1 -1
- classiq/interface/model/quantum_statement.py +5 -0
- classiq/interface/model/quantum_type.py +22 -0
- classiq/interface/model/repeat.py +4 -0
- classiq/interface/model/statement_block.py +3 -0
- classiq/interface/model/variable_declaration_statement.py +5 -0
- classiq/interface/server/routes.py +0 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
- classiq/model_expansions/capturing/captured_vars.py +156 -34
- classiq/model_expansions/closure.py +0 -9
- classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
- classiq/model_expansions/evaluators/parameter_types.py +20 -10
- classiq/model_expansions/expression_evaluator.py +0 -11
- classiq/model_expansions/function_builder.py +2 -8
- classiq/model_expansions/generative_functions.py +7 -30
- classiq/model_expansions/interpreters/base_interpreter.py +7 -8
- classiq/model_expansions/interpreters/generative_interpreter.py +33 -5
- classiq/model_expansions/quantum_operations/__init__.py +0 -2
- classiq/model_expansions/quantum_operations/block_evaluator.py +16 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +49 -6
- classiq/model_expansions/quantum_operations/emitter.py +64 -6
- classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_function_call.py +49 -0
- classiq/model_expansions/quantum_operations/repeat_block_evaluator.py +34 -0
- classiq/model_expansions/scope.py +33 -21
- classiq/model_expansions/scope_initialization.py +28 -32
- classiq/model_expansions/transformers/model_renamer.py +69 -63
- classiq/model_expansions/utils/sympy_utils.py +24 -0
- classiq/model_expansions/visitors/variable_references.py +1 -0
- classiq/qmod/__init__.py +3 -1
- classiq/qmod/builtins/functions/__init__.py +8 -0
- classiq/qmod/builtins/functions/allocation.py +36 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -5
- classiq/qmod/builtins/functions/mid_circuit_measurement.py +3 -0
- classiq/qmod/builtins/operations.py +2 -2
- classiq/qmod/declaration_inferrer.py +52 -24
- classiq/qmod/model_state_container.py +9 -0
- classiq/qmod/native/pretty_printer.py +25 -3
- classiq/qmod/pretty_print/pretty_printer.py +31 -14
- classiq/qmod/python_classical_type.py +12 -1
- classiq/qmod/qfunc.py +33 -8
- classiq/qmod/qmod_variable.py +188 -147
- classiq/qmod/quantum_function.py +3 -4
- classiq/qmod/semantics/validation/type_hints.py +19 -10
- classiq/qmod/symbolic.py +16 -3
- {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/METADATA +1 -1
- {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/RECORD +90 -91
- classiq/applications/finance/finance_model_constructor.py +0 -137
- classiq/applications/grover/__init__.py +0 -9
- classiq/applications/grover/grover_model_constructor.py +0 -167
- classiq/applications/libraries/__init__.py +0 -0
- classiq/applications/libraries/qmci_library.py +0 -22
- classiq/applications/qsvm/qsvm_model_constructor.py +0 -131
- classiq/model_expansions/quantum_operations/classicalif.py +0 -57
- classiq/model_expansions/quantum_operations/repeat.py +0 -62
- {classiq-0.70.0.dist-info → classiq-0.72.0.dist-info}/WHEEL +0 -0
@@ -7,8 +7,10 @@ from numpy.random import permutation
|
|
7
7
|
from classiq.interface.generator.constant import Constant
|
8
8
|
from classiq.interface.generator.expressions.expression import Expression
|
9
9
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
10
|
+
CLASSICAL_IF_OPERATOR_NAME,
|
10
11
|
CONTROL_OPERATOR_NAME,
|
11
12
|
INVERT_OPERATOR_NAME,
|
13
|
+
REPEAT_OPERATOR_NAME,
|
12
14
|
WITHIN_APPLY_NAME,
|
13
15
|
)
|
14
16
|
from classiq.interface.model.allocate import Allocate
|
@@ -52,9 +54,7 @@ from classiq.model_expansions.generative_functions import emit_generative_statem
|
|
52
54
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
53
55
|
from classiq.model_expansions.quantum_operations import (
|
54
56
|
BindEmitter,
|
55
|
-
ClassicalIfEmitter,
|
56
57
|
QuantumFunctionCallEmitter,
|
57
|
-
RepeatEmitter,
|
58
58
|
VariableDeclarationStatementEmitter,
|
59
59
|
)
|
60
60
|
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
@@ -69,6 +69,9 @@ from classiq.model_expansions.quantum_operations.expression_evaluator import (
|
|
69
69
|
ExpressionEvaluator,
|
70
70
|
)
|
71
71
|
from classiq.model_expansions.quantum_operations.handle_evaluator import HandleEvaluator
|
72
|
+
from classiq.model_expansions.quantum_operations.repeat_block_evaluator import (
|
73
|
+
RepeatBlockEvaluator,
|
74
|
+
)
|
72
75
|
from classiq.model_expansions.scope import Evaluated, Scope
|
73
76
|
from classiq.model_expansions.scope_initialization import (
|
74
77
|
add_constants_to_scope,
|
@@ -87,7 +90,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
87
90
|
generative_functions: list[GenerativeQFunc],
|
88
91
|
) -> None:
|
89
92
|
super().__init__(model)
|
90
|
-
add_generative_functions_to_scope(
|
93
|
+
add_generative_functions_to_scope(
|
94
|
+
generative_functions, self._top_level_scope, override_atomic=True
|
95
|
+
)
|
91
96
|
|
92
97
|
def evaluate_lambda(self, function: QuantumLambdaFunction) -> Evaluated:
|
93
98
|
renamed_params = [
|
@@ -189,8 +194,22 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
189
194
|
VariableDeclarationStatementEmitter(self).emit(variable_declaration)
|
190
195
|
|
191
196
|
@emit.register
|
197
|
+
def _emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
198
|
+
self.emit_classical_if(classical_if)
|
199
|
+
|
192
200
|
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
193
|
-
|
201
|
+
CompositeEmitter[ClassicalIf](
|
202
|
+
self,
|
203
|
+
[
|
204
|
+
ExpressionEvaluator(self, "condition"),
|
205
|
+
BlockEvaluator(
|
206
|
+
self,
|
207
|
+
CLASSICAL_IF_OPERATOR_NAME,
|
208
|
+
"then",
|
209
|
+
"else_",
|
210
|
+
),
|
211
|
+
],
|
212
|
+
).emit(classical_if)
|
194
213
|
|
195
214
|
@emit.register
|
196
215
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
@@ -208,8 +227,17 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
208
227
|
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
209
228
|
|
210
229
|
@emit.register
|
230
|
+
def _emit_repeat(self, repeat: Repeat) -> None:
|
231
|
+
self.emit_repeat(repeat)
|
232
|
+
|
211
233
|
def emit_repeat(self, repeat: Repeat) -> None:
|
212
|
-
|
234
|
+
CompositeEmitter[Repeat](
|
235
|
+
self,
|
236
|
+
[
|
237
|
+
ExpressionEvaluator(self, "count"),
|
238
|
+
RepeatBlockEvaluator(self, REPEAT_OPERATOR_NAME, "body"),
|
239
|
+
],
|
240
|
+
).emit(repeat)
|
213
241
|
|
214
242
|
@emit.register
|
215
243
|
def _emit_control(self, control: Control) -> None:
|
@@ -1,9 +1,7 @@
|
|
1
1
|
from classiq.model_expansions.quantum_operations.bind import BindEmitter
|
2
|
-
from classiq.model_expansions.quantum_operations.classicalif import ClassicalIfEmitter
|
3
2
|
from classiq.model_expansions.quantum_operations.quantum_function_call import (
|
4
3
|
QuantumFunctionCallEmitter,
|
5
4
|
)
|
6
|
-
from classiq.model_expansions.quantum_operations.repeat import RepeatEmitter
|
7
5
|
from classiq.model_expansions.quantum_operations.variable_decleration import (
|
8
6
|
VariableDeclarationStatementEmitter,
|
9
7
|
)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
2
|
from typing import TYPE_CHECKING
|
3
3
|
|
4
|
+
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
4
5
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
5
6
|
|
6
7
|
from classiq.model_expansions.closure import Closure
|
@@ -54,7 +55,8 @@ class BlockEvaluator(Emitter[QuantumOperation]):
|
|
54
55
|
}
|
55
56
|
block_closure = Closure(
|
56
57
|
name=self._operation_name,
|
57
|
-
scope=
|
58
|
+
scope=self.get_scope(op),
|
59
|
+
positional_arg_declarations=self.get_params(op),
|
58
60
|
blocks=blocks,
|
59
61
|
)
|
60
62
|
context = self._expand_operation(block_closure)
|
@@ -69,8 +71,20 @@ class BlockEvaluator(Emitter[QuantumOperation]):
|
|
69
71
|
blocks = [
|
70
72
|
block for block in self._block_names if op.has_generative_block(block)
|
71
73
|
]
|
72
|
-
context = self._expand_generative_context(
|
74
|
+
context = self._expand_generative_context(
|
75
|
+
op,
|
76
|
+
self._operation_name,
|
77
|
+
blocks,
|
78
|
+
self.get_params(op),
|
79
|
+
self.get_scope(op),
|
80
|
+
)
|
73
81
|
return {
|
74
82
|
_REVERSE_BLOCK_RENAMES.get(block, block): context.statements(block)
|
75
83
|
for block in blocks
|
76
84
|
}
|
85
|
+
|
86
|
+
def get_params(self, op: QuantumOperation) -> Sequence[PositionalArg]:
|
87
|
+
return []
|
88
|
+
|
89
|
+
def get_scope(self, op: QuantumOperation) -> Scope:
|
90
|
+
return Scope(parent=self._current_scope)
|
@@ -2,17 +2,32 @@ from collections.abc import Sequence
|
|
2
2
|
from itertools import chain, combinations
|
3
3
|
from typing import (
|
4
4
|
TYPE_CHECKING,
|
5
|
+
Any,
|
5
6
|
Generic,
|
6
7
|
cast,
|
7
8
|
)
|
8
9
|
from uuid import UUID
|
9
10
|
|
11
|
+
import sympy
|
12
|
+
|
10
13
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
11
14
|
from classiq.interface.exceptions import ClassiqExpansionError
|
15
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
16
|
+
AnyClassicalValue,
|
17
|
+
)
|
18
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
19
|
+
ClassicalProxy,
|
20
|
+
)
|
21
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
22
|
+
QmodStructInstance,
|
23
|
+
)
|
12
24
|
from classiq.interface.generator.functions.port_declaration import (
|
13
25
|
PortDeclarationDirection,
|
14
26
|
)
|
15
27
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
28
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
29
|
+
ClassicalParameterDeclaration,
|
30
|
+
)
|
16
31
|
from classiq.interface.model.handle_binding import HandleBinding
|
17
32
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
18
33
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -75,6 +90,16 @@ def _validate_cloning(evaluated_args: list[Evaluated]) -> None:
|
|
75
90
|
)
|
76
91
|
|
77
92
|
|
93
|
+
def _is_symbolic(arg: Any) -> bool:
|
94
|
+
if isinstance(arg, list):
|
95
|
+
return any(_is_symbolic(item) for item in arg)
|
96
|
+
if isinstance(arg, QmodStructInstance):
|
97
|
+
return any(_is_symbolic(item) for item in arg.fields.values())
|
98
|
+
if isinstance(arg, sympy.Basic):
|
99
|
+
return len(arg.free_symbols) > 0
|
100
|
+
return isinstance(arg, (ClassicalProxy, AnyClassicalValue))
|
101
|
+
|
102
|
+
|
78
103
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSplitter):
|
79
104
|
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
80
105
|
Emitter.__init__(self, interpreter)
|
@@ -197,7 +222,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
197
222
|
].occurrences_number += 1
|
198
223
|
return function_def
|
199
224
|
|
200
|
-
function_def = self._create_function_definition(function_context)
|
225
|
+
function_def = self._create_function_definition(function_context, args)
|
201
226
|
self._expanded_functions[closure_id] = function_def
|
202
227
|
self._top_level_scope[function_def.name] = Evaluated(
|
203
228
|
value=function_context.closure.with_new_declaration(function_def)
|
@@ -210,14 +235,23 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
210
235
|
return function_def
|
211
236
|
|
212
237
|
def _create_function_definition(
|
213
|
-
self, function_context: FunctionContext
|
238
|
+
self, function_context: FunctionContext, args: list[Evaluated]
|
214
239
|
) -> NativeFunctionDefinition:
|
215
|
-
|
240
|
+
params = [
|
241
|
+
param
|
242
|
+
for arg, param in zip(args, function_context.positional_arg_declarations)
|
243
|
+
if isinstance(param, PortDeclaration)
|
244
|
+
or (
|
245
|
+
isinstance(param, ClassicalParameterDeclaration)
|
246
|
+
and _is_symbolic(arg.value)
|
247
|
+
)
|
248
|
+
]
|
249
|
+
func_def = self._builder.create_definition(function_context, params)
|
216
250
|
|
217
251
|
captured_vars = function_context.closure.captured_vars.filter_vars(
|
218
252
|
function_context.closure
|
219
253
|
)
|
220
|
-
captured_ports = captured_vars.
|
254
|
+
captured_ports = captured_vars.get_captured_parameters()
|
221
255
|
if len(captured_ports) == 0:
|
222
256
|
return func_def
|
223
257
|
func_def.positional_arg_declarations = list(
|
@@ -239,15 +273,22 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
239
273
|
closure: FunctionClosure,
|
240
274
|
) -> None:
|
241
275
|
for parameter, argument in zip(parameters, arguments):
|
276
|
+
param_handle = HandleBinding(name=parameter.name)
|
242
277
|
if isinstance(argument.value, QuantumSymbol):
|
243
278
|
assert isinstance(parameter, PortDeclaration)
|
244
279
|
closure.scope[parameter.name] = Evaluated(
|
245
280
|
QuantumSymbol(
|
246
|
-
handle=
|
281
|
+
handle=param_handle,
|
247
282
|
quantum_type=parameter.quantum_type,
|
248
283
|
),
|
249
284
|
defining_function=closure,
|
250
285
|
)
|
286
|
+
elif _is_symbolic(argument.value):
|
287
|
+
assert isinstance(parameter, ClassicalParameterDeclaration)
|
288
|
+
closure.scope[parameter.name] = Evaluated(
|
289
|
+
value=parameter.classical_type.get_classical_proxy(param_handle),
|
290
|
+
defining_function=closure,
|
291
|
+
)
|
251
292
|
else:
|
252
293
|
closure.scope[parameter.name] = argument
|
253
294
|
|
@@ -264,7 +305,9 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
264
305
|
return [arg.emit() for arg in evaluated_args]
|
265
306
|
|
266
307
|
positional_args = [
|
267
|
-
arg.emit()
|
308
|
+
arg.emit()
|
309
|
+
for arg in evaluated_args
|
310
|
+
if isinstance(arg.value, QuantumSymbol) or _is_symbolic(arg.value)
|
268
311
|
]
|
269
312
|
|
270
313
|
return positional_args
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import ast
|
2
2
|
from abc import ABC, abstractmethod
|
3
|
+
from collections.abc import Sequence
|
3
4
|
from typing import (
|
4
5
|
TYPE_CHECKING,
|
5
6
|
Generic,
|
@@ -19,14 +20,22 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
19
20
|
EvaluatedExpression,
|
20
21
|
)
|
21
22
|
from classiq.interface.generator.expressions.expression import Expression
|
23
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
24
|
+
ClassicalProxy,
|
25
|
+
)
|
26
|
+
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
27
|
+
get_proxy_type,
|
28
|
+
)
|
29
|
+
from classiq.interface.generator.functions.classical_type import ClassicalType
|
22
30
|
from classiq.interface.generator.functions.port_declaration import (
|
23
31
|
PortDeclarationDirection,
|
24
32
|
)
|
25
33
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
26
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
34
|
+
from classiq.interface.model.handle_binding import HandleBinding, NestedHandleBinding
|
27
35
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
28
36
|
from classiq.interface.model.quantum_function_declaration import (
|
29
37
|
NamedParamsQuantumFunctionDeclaration,
|
38
|
+
PositionalArg,
|
30
39
|
)
|
31
40
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
32
41
|
|
@@ -103,17 +112,20 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
103
112
|
op: QuantumOperation,
|
104
113
|
context_name: str,
|
105
114
|
block_names: Union[None, str, list[str]] = None,
|
106
|
-
|
115
|
+
params: Optional[Sequence[PositionalArg]] = None,
|
116
|
+
scope: Optional[Scope] = None,
|
107
117
|
) -> OperationContext:
|
108
118
|
if isinstance(block_names, str):
|
109
119
|
block_names = [block_names]
|
110
120
|
block_names = block_names or ["body"]
|
111
|
-
func_decl =
|
112
|
-
name=context_name
|
121
|
+
func_decl = NamedParamsQuantumFunctionDeclaration(
|
122
|
+
name=context_name,
|
123
|
+
positional_arg_declarations=[] if params is None else params,
|
113
124
|
)
|
125
|
+
_scope = Scope(parent=self._current_scope) if scope is None else scope
|
114
126
|
gen_closure = GenerativeClosure(
|
115
127
|
name=func_decl.name,
|
116
|
-
scope=
|
128
|
+
scope=_scope,
|
117
129
|
blocks={},
|
118
130
|
generative_blocks={
|
119
131
|
block_name: GenerativeQFunc(
|
@@ -121,6 +133,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
121
133
|
)
|
122
134
|
for block_name in block_names
|
123
135
|
},
|
136
|
+
positional_arg_declarations=func_decl.positional_arg_declarations,
|
124
137
|
)
|
125
138
|
context = self._interpreter._expand_operation(gen_closure)
|
126
139
|
op.clear_generative_blocks()
|
@@ -145,6 +158,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
145
158
|
return new_expression
|
146
159
|
|
147
160
|
def emit_statement(self, statement: QuantumStatement) -> None:
|
161
|
+
self._update_captured_classical_vars(statement)
|
148
162
|
if isinstance(statement, QuantumOperation):
|
149
163
|
self._update_captured_vars(statement)
|
150
164
|
if statement.uuid not in self._interpreter._model.debug_info:
|
@@ -153,6 +167,14 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
153
167
|
)
|
154
168
|
self._builder.emit_statement(statement)
|
155
169
|
|
170
|
+
def _update_captured_classical_vars(self, stmt: QuantumStatement) -> None:
|
171
|
+
for expr in stmt.expressions:
|
172
|
+
self._update_captured_classical_vars_in_expression(expr)
|
173
|
+
|
174
|
+
def _update_captured_classical_vars_in_expression(self, expr: Expression) -> None:
|
175
|
+
for var_name, var_type in self._get_classical_vars_in_expression(expr):
|
176
|
+
self._capture_classical_var(var_name, var_type)
|
177
|
+
|
156
178
|
def _update_captured_vars(self, op: QuantumOperation) -> None:
|
157
179
|
handles = (
|
158
180
|
[(handle, PortDeclarationDirection.Input) for handle in op.inputs]
|
@@ -167,6 +189,12 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
167
189
|
) -> None:
|
168
190
|
if handle.name not in self._current_scope:
|
169
191
|
return
|
192
|
+
if not handle.is_constant():
|
193
|
+
self._update_captured_classical_vars_in_expression(
|
194
|
+
Expression(expr=str(handle))
|
195
|
+
)
|
196
|
+
while isinstance(handle, NestedHandleBinding) and not handle.is_constant():
|
197
|
+
handle = handle.base_handle
|
170
198
|
defining_function = self._current_scope[handle.name].defining_function
|
171
199
|
if defining_function is None:
|
172
200
|
raise ClassiqInternalExpansionError
|
@@ -178,8 +206,20 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
178
206
|
direction=direction,
|
179
207
|
)
|
180
208
|
|
209
|
+
def _capture_classical_var(self, var_name: str, var_type: ClassicalType) -> None:
|
210
|
+
if var_name not in self._current_scope:
|
211
|
+
return
|
212
|
+
defining_function = self._current_scope[var_name].defining_function
|
213
|
+
if defining_function is None:
|
214
|
+
raise ClassiqInternalExpansionError
|
215
|
+
self._builder.current_block.captured_vars.capture_classical_var(
|
216
|
+
var_name=var_name,
|
217
|
+
var_type=var_type,
|
218
|
+
defining_function=defining_function,
|
219
|
+
)
|
220
|
+
|
181
221
|
def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
|
182
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
222
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
183
223
|
vrc.visit(ast.parse(expr.expr))
|
184
224
|
handles = dict.fromkeys(
|
185
225
|
handle
|
@@ -187,3 +227,21 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
187
227
|
if isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
188
228
|
)
|
189
229
|
return [self._interpreter.evaluate(handle).value for handle in handles]
|
230
|
+
|
231
|
+
def _get_classical_vars_in_expression(
|
232
|
+
self, expr: Expression
|
233
|
+
) -> list[tuple[str, ClassicalType]]:
|
234
|
+
vrc = VarRefCollector(
|
235
|
+
ignore_duplicated_handles=True, ignore_sympy_symbols=True, unevaluated=True
|
236
|
+
)
|
237
|
+
vrc.visit(ast.parse(expr.expr))
|
238
|
+
return list(
|
239
|
+
{
|
240
|
+
handle.name: get_proxy_type(proxy)
|
241
|
+
for handle in vrc.var_handles
|
242
|
+
if handle.name in self._current_scope
|
243
|
+
and isinstance(
|
244
|
+
proxy := self._current_scope[handle.name].value, ClassicalProxy
|
245
|
+
)
|
246
|
+
}.items()
|
247
|
+
)
|
@@ -26,6 +26,10 @@ class ExpressionEvaluator(Emitter[QuantumOperation]):
|
|
26
26
|
)
|
27
27
|
for symbol in self._get_symbols_in_expression(evaluated_expression):
|
28
28
|
self._capture_handle(symbol.handle, PortDeclarationDirection.Inout)
|
29
|
+
for var_name, var_type in self._get_classical_vars_in_expression(
|
30
|
+
evaluated_expression
|
31
|
+
):
|
32
|
+
self._capture_classical_var(var_name, var_type)
|
29
33
|
op = op.model_copy(
|
30
34
|
update={self._expression_name: evaluated_expression, "back_ref": op.uuid}
|
31
35
|
)
|
@@ -18,7 +18,7 @@ class HandleEvaluator(Emitter[QuantumOperation]):
|
|
18
18
|
handle = getattr(op, self._handle_name)
|
19
19
|
if not isinstance(handle, HandleBinding):
|
20
20
|
return False
|
21
|
-
evaluated_handle = self._interpreter.evaluate(handle).value.handle
|
21
|
+
evaluated_handle = self._interpreter.evaluate(handle).value.handle.collapse()
|
22
22
|
if handle == evaluated_handle:
|
23
23
|
return False
|
24
24
|
op = op.model_copy(
|
@@ -1,6 +1,14 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
2
|
|
3
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
4
|
+
from classiq.interface.generator.expressions.expression import Expression
|
5
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
6
|
+
ClassicalScalarProxy,
|
7
|
+
)
|
8
|
+
from classiq.interface.model.classical_if import ClassicalIf
|
3
9
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
10
|
+
from classiq.interface.model.quantum_lambda_function import OperandIdentifier
|
11
|
+
from classiq.interface.model.quantum_statement import QuantumStatement
|
4
12
|
|
5
13
|
from classiq.model_expansions.closure import FunctionClosure
|
6
14
|
from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
|
@@ -19,6 +27,10 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
19
27
|
self._model = self._interpreter._model
|
20
28
|
|
21
29
|
def emit(self, call: QuantumFunctionCall, /) -> bool:
|
30
|
+
if isinstance(call.function, OperandIdentifier):
|
31
|
+
index_val = self._interpreter.evaluate(call.function.index).value
|
32
|
+
if isinstance(index_val, ClassicalScalarProxy):
|
33
|
+
return self._emit_symbolic_lambda_list(call, index_val)
|
22
34
|
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
23
35
|
args = call.positional_args
|
24
36
|
with ErrorManager().call(function.name):
|
@@ -27,6 +39,43 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
27
39
|
)
|
28
40
|
return True
|
29
41
|
|
42
|
+
def _emit_symbolic_lambda_list(
|
43
|
+
self, call: QuantumFunctionCall, index: ClassicalScalarProxy
|
44
|
+
) -> bool:
|
45
|
+
if TYPE_CHECKING:
|
46
|
+
assert isinstance(call.function, OperandIdentifier)
|
47
|
+
funcs = self._interpreter.evaluate(call.function.name).value
|
48
|
+
if not isinstance(funcs, list):
|
49
|
+
raise ClassiqInternalExpansionError(
|
50
|
+
f"Unexpected lambda list type {type(funcs).__name__!r}"
|
51
|
+
)
|
52
|
+
self._interpreter.emit(self._create_recursive_if(call, index, len(funcs)))
|
53
|
+
return True
|
54
|
+
|
55
|
+
@staticmethod
|
56
|
+
def _create_recursive_if(
|
57
|
+
call: QuantumFunctionCall, index: ClassicalScalarProxy, num_funcs: int
|
58
|
+
) -> QuantumStatement:
|
59
|
+
if TYPE_CHECKING:
|
60
|
+
assert isinstance(call.function, OperandIdentifier)
|
61
|
+
stmt: list[QuantumStatement] = []
|
62
|
+
for idx in reversed(range(num_funcs)):
|
63
|
+
stmt = [
|
64
|
+
ClassicalIf(
|
65
|
+
condition=Expression(expr=f"{index} == {idx}"),
|
66
|
+
then=[
|
67
|
+
QuantumFunctionCall(
|
68
|
+
function=OperandIdentifier(
|
69
|
+
name=call.function.name, index=Expression(expr=str(idx))
|
70
|
+
),
|
71
|
+
positional_args=call.positional_args,
|
72
|
+
)
|
73
|
+
],
|
74
|
+
else_=stmt,
|
75
|
+
)
|
76
|
+
]
|
77
|
+
return stmt[0]
|
78
|
+
|
30
79
|
|
31
80
|
class DeclarativeQuantumFunctionCallEmitter(
|
32
81
|
QuantumFunctionCallEmitter, DeclarativeCallEmitter
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
5
|
+
ClassicalScalarProxy,
|
6
|
+
)
|
7
|
+
from classiq.interface.generator.functions.classical_type import Integer
|
8
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
9
|
+
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
10
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
11
|
+
from classiq.interface.model.repeat import Repeat
|
12
|
+
|
13
|
+
from classiq import ClassicalParameterDeclaration
|
14
|
+
from classiq.model_expansions.quantum_operations.block_evaluator import BlockEvaluator
|
15
|
+
from classiq.model_expansions.scope import Evaluated, Scope
|
16
|
+
|
17
|
+
|
18
|
+
class RepeatBlockEvaluator(BlockEvaluator):
|
19
|
+
def get_params(self, op: QuantumOperation) -> Sequence[PositionalArg]:
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
assert isinstance(op, Repeat)
|
22
|
+
return [
|
23
|
+
ClassicalParameterDeclaration(name=op.iter_var, classical_type=Integer())
|
24
|
+
]
|
25
|
+
|
26
|
+
def get_scope(self, op: QuantumOperation) -> Scope:
|
27
|
+
if TYPE_CHECKING:
|
28
|
+
assert isinstance(op, Repeat)
|
29
|
+
scope = super().get_scope(op)
|
30
|
+
scope[op.iter_var] = Evaluated(
|
31
|
+
value=ClassicalScalarProxy(HandleBinding(name=op.iter_var), Integer()),
|
32
|
+
defining_function=self._builder.current_function,
|
33
|
+
)
|
34
|
+
return scope
|
@@ -1,13 +1,10 @@
|
|
1
1
|
import itertools
|
2
|
-
import re
|
3
2
|
from collections import UserDict
|
4
3
|
from collections.abc import Iterator
|
5
4
|
from dataclasses import dataclass
|
6
5
|
from functools import singledispatch
|
7
6
|
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
8
7
|
|
9
|
-
from sympy import Symbol
|
10
|
-
|
11
8
|
from classiq.interface.exceptions import (
|
12
9
|
ClassiqExpansionError,
|
13
10
|
ClassiqInternalExpansionError,
|
@@ -16,8 +13,8 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
16
13
|
EvaluatedExpression,
|
17
14
|
)
|
18
15
|
from classiq.interface.generator.expressions.expression import Expression
|
19
|
-
from classiq.interface.generator.expressions.
|
20
|
-
|
16
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
17
|
+
ClassicalScalarProxy,
|
21
18
|
)
|
22
19
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
23
20
|
QmodStructInstance,
|
@@ -53,28 +50,38 @@ class QuantumSymbol:
|
|
53
50
|
def emit(self) -> HandleBinding:
|
54
51
|
return self.handle
|
55
52
|
|
56
|
-
def __getitem__(
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
def __getitem__(
|
54
|
+
self, item: Union[slice, int, ClassicalScalarProxy]
|
55
|
+
) -> "QuantumSymbol":
|
56
|
+
if isinstance(item, slice):
|
57
|
+
return self._slice(item.start, item.stop)
|
58
|
+
return self._subscript(item)
|
61
59
|
|
62
|
-
def _slice(
|
60
|
+
def _slice(
|
61
|
+
self,
|
62
|
+
start: Union[int, ClassicalScalarProxy],
|
63
|
+
end: Union[int, ClassicalScalarProxy],
|
64
|
+
) -> "QuantumSymbol":
|
63
65
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
64
66
|
raise ClassiqExpansionError(
|
65
67
|
f"{self.quantum_type.type_name} is not subscriptable"
|
66
68
|
)
|
67
|
-
if
|
69
|
+
if TYPE_CHECKING:
|
70
|
+
assert self.quantum_type.length is not None
|
71
|
+
if isinstance(start, int) and isinstance(end, int) and start >= end:
|
68
72
|
raise ClassiqExpansionError(
|
69
73
|
f"{self.quantum_type.type_name} slice '{self.handle}[{start}:{end}]' "
|
70
74
|
f"has non-positive length"
|
71
75
|
)
|
72
|
-
|
73
|
-
|
76
|
+
if (isinstance(start, int) and start < 0) or (
|
77
|
+
isinstance(end, int)
|
78
|
+
and self.quantum_type.length.is_constant()
|
79
|
+
and end > self.quantum_type.length_value
|
80
|
+
):
|
74
81
|
raise ClassiqExpansionError(
|
75
82
|
f"Slice [{start}:{end}] is out of bounds for "
|
76
83
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
77
|
-
f"length {
|
84
|
+
f"length {self.quantum_type.length_value})"
|
78
85
|
)
|
79
86
|
return QuantumSymbol(
|
80
87
|
handle=SlicedHandleBinding(
|
@@ -88,17 +95,24 @@ class QuantumSymbol:
|
|
88
95
|
),
|
89
96
|
)
|
90
97
|
|
91
|
-
def _subscript(self, index: int) -> "QuantumSymbol":
|
98
|
+
def _subscript(self, index: Union[int, ClassicalScalarProxy]) -> "QuantumSymbol":
|
92
99
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
93
100
|
raise ClassiqExpansionError(
|
94
101
|
f"{self.quantum_type.type_name} is not subscriptable"
|
95
102
|
)
|
96
|
-
|
97
|
-
|
103
|
+
if TYPE_CHECKING:
|
104
|
+
assert self.quantum_type.length is not None
|
105
|
+
if isinstance(index, int) and (
|
106
|
+
index < 0
|
107
|
+
or (
|
108
|
+
self.quantum_type.length.is_constant()
|
109
|
+
and index >= self.quantum_type.length_value
|
110
|
+
)
|
111
|
+
):
|
98
112
|
raise ClassiqExpansionError(
|
99
113
|
f"Index {index} is out of bounds for "
|
100
114
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
101
|
-
f"length {
|
115
|
+
f"length {self.quantum_type.length})"
|
102
116
|
)
|
103
117
|
return QuantumSymbol(
|
104
118
|
handle=SubscriptHandleBinding(
|
@@ -204,8 +218,6 @@ class Scope(EvaluatedUserDict):
|
|
204
218
|
return self.data[name]
|
205
219
|
if self._parent is not None:
|
206
220
|
return self._parent[name]
|
207
|
-
if re.search(CPARAM_EXECUTION_SUFFIX_PATTERN, name):
|
208
|
-
return Evaluated(value=Symbol(name))
|
209
221
|
raise ClassiqExpansionError(f"Variable {name!r} is undefined")
|
210
222
|
|
211
223
|
def __contains__(self, item: Any) -> bool:
|