classiq 0.71.0__py3-none-any.whl → 0.72.1__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/generator/expressions/expression_types.py +4 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +135 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
- classiq/interface/generator/generated_circuit_data.py +13 -0
- classiq/interface/generator/hardware/hardware_data.py +3 -1
- classiq/interface/generator/transpiler_basis_gates.py +3 -1
- classiq/interface/hardware.py +1 -0
- classiq/interface/model/handle_binding.py +21 -0
- classiq/interface/server/routes.py +0 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +35 -13
- classiq/model_expansions/closure.py +0 -9
- classiq/model_expansions/evaluators/parameter_types.py +6 -10
- classiq/model_expansions/interpreters/base_interpreter.py +4 -4
- 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 +4 -1
- classiq/model_expansions/quantum_operations/emitter.py +26 -9
- 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 +34 -14
- classiq/model_expansions/scope_initialization.py +8 -4
- 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/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/model_state_container.py +9 -0
- classiq/qmod/symbolic.py +16 -3
- {classiq-0.71.0.dist-info → classiq-0.72.1.dist-info}/METADATA +1 -1
- {classiq-0.71.0.dist-info → classiq-0.72.1.dist-info}/RECORD +46 -51
- 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.71.0.dist-info → classiq-0.72.1.dist-info}/WHEEL +0 -0
@@ -79,11 +79,6 @@ def _update_scope(
|
|
79
79
|
if parameter.direction is PortDeclarationDirection.Output:
|
80
80
|
return
|
81
81
|
quantum_symbol = argument.as_type(QuantumSymbol)
|
82
|
-
if not quantum_symbol.quantum_type.has_size_in_bits:
|
83
|
-
raise ClassiqExpansionError(
|
84
|
-
f"Argument {str(quantum_symbol.emit())!r} to function {closure.name!r} "
|
85
|
-
f"is not initialized"
|
86
|
-
)
|
87
82
|
casted_argument = _cast(
|
88
83
|
parameter.quantum_type,
|
89
84
|
quantum_symbol,
|
@@ -274,9 +269,10 @@ def evaluate_types_in_quantum_symbols(
|
|
274
269
|
def _inject_quantum_arg_info_to_type(
|
275
270
|
parameter_type: QuantumType, quantum_symbol: QuantumSymbol, param_name: str
|
276
271
|
) -> QuantumType:
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
272
|
+
if quantum_symbol.quantum_type.has_size_in_bits:
|
273
|
+
copy_type_information(
|
274
|
+
quantum_symbol.quantum_type,
|
275
|
+
parameter_type,
|
276
|
+
param_name,
|
277
|
+
)
|
282
278
|
return parameter_type
|
@@ -158,7 +158,7 @@ class BaseInterpreter:
|
|
158
158
|
expr = evaluate_classical_expression(expression, self._builder.current_scope)
|
159
159
|
if not isinstance(expr.value, sympy.Basic):
|
160
160
|
return expr
|
161
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
161
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
162
162
|
vrc.visit(ast.parse(str(expr.value)))
|
163
163
|
for handle in vrc.var_handles:
|
164
164
|
if handle.name in self._builder.current_scope and isinstance(
|
@@ -189,8 +189,8 @@ class BaseInterpreter:
|
|
189
189
|
quantum_variable = self.evaluate(sliced_handle_binding.base_handle).as_type(
|
190
190
|
QuantumSymbol
|
191
191
|
)
|
192
|
-
start = self.evaluate(sliced_handle_binding.start).
|
193
|
-
end = self.evaluate(sliced_handle_binding.end).
|
192
|
+
start = self.evaluate(sliced_handle_binding.start).value
|
193
|
+
end = self.evaluate(sliced_handle_binding.end).value
|
194
194
|
return Evaluated(value=quantum_variable[start:end])
|
195
195
|
|
196
196
|
@evaluate.register
|
@@ -200,7 +200,7 @@ class BaseInterpreter:
|
|
200
200
|
@evaluate.register
|
201
201
|
def evaluate_subscript_handle(self, subscript: SubscriptHandleBinding) -> Evaluated:
|
202
202
|
base_value = self.evaluate(subscript.base_handle)
|
203
|
-
index_value = self.evaluate(subscript.index).
|
203
|
+
index_value = self.evaluate(subscript.index).value
|
204
204
|
return Evaluated(value=base_value.value[index_value])
|
205
205
|
|
206
206
|
@evaluate.register
|
@@ -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)
|
@@ -12,6 +12,9 @@ import sympy
|
|
12
12
|
|
13
13
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
14
14
|
from classiq.interface.exceptions import ClassiqExpansionError
|
15
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
16
|
+
AnyClassicalValue,
|
17
|
+
)
|
15
18
|
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
16
19
|
ClassicalProxy,
|
17
20
|
)
|
@@ -94,7 +97,7 @@ def _is_symbolic(arg: Any) -> bool:
|
|
94
97
|
return any(_is_symbolic(item) for item in arg.fields.values())
|
95
98
|
if isinstance(arg, sympy.Basic):
|
96
99
|
return len(arg.free_symbols) > 0
|
97
|
-
return isinstance(arg, ClassicalProxy)
|
100
|
+
return isinstance(arg, (ClassicalProxy, AnyClassicalValue))
|
98
101
|
|
99
102
|
|
100
103
|
class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSplitter):
|
@@ -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,
|
@@ -30,10 +31,11 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
30
31
|
PortDeclarationDirection,
|
31
32
|
)
|
32
33
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
33
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
34
|
+
from classiq.interface.model.handle_binding import HandleBinding, NestedHandleBinding
|
34
35
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
35
36
|
from classiq.interface.model.quantum_function_declaration import (
|
36
37
|
NamedParamsQuantumFunctionDeclaration,
|
38
|
+
PositionalArg,
|
37
39
|
)
|
38
40
|
from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
|
39
41
|
|
@@ -110,17 +112,20 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
110
112
|
op: QuantumOperation,
|
111
113
|
context_name: str,
|
112
114
|
block_names: Union[None, str, list[str]] = None,
|
113
|
-
|
115
|
+
params: Optional[Sequence[PositionalArg]] = None,
|
116
|
+
scope: Optional[Scope] = None,
|
114
117
|
) -> OperationContext:
|
115
118
|
if isinstance(block_names, str):
|
116
119
|
block_names = [block_names]
|
117
120
|
block_names = block_names or ["body"]
|
118
|
-
func_decl =
|
119
|
-
name=context_name
|
121
|
+
func_decl = NamedParamsQuantumFunctionDeclaration(
|
122
|
+
name=context_name,
|
123
|
+
positional_arg_declarations=[] if params is None else params,
|
120
124
|
)
|
125
|
+
_scope = Scope(parent=self._current_scope) if scope is None else scope
|
121
126
|
gen_closure = GenerativeClosure(
|
122
127
|
name=func_decl.name,
|
123
|
-
scope=
|
128
|
+
scope=_scope,
|
124
129
|
blocks={},
|
125
130
|
generative_blocks={
|
126
131
|
block_name: GenerativeQFunc(
|
@@ -128,6 +133,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
128
133
|
)
|
129
134
|
for block_name in block_names
|
130
135
|
},
|
136
|
+
positional_arg_declarations=func_decl.positional_arg_declarations,
|
131
137
|
)
|
132
138
|
context = self._interpreter._expand_operation(gen_closure)
|
133
139
|
op.clear_generative_blocks()
|
@@ -163,8 +169,11 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
163
169
|
|
164
170
|
def _update_captured_classical_vars(self, stmt: QuantumStatement) -> None:
|
165
171
|
for expr in stmt.expressions:
|
166
|
-
|
167
|
-
|
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)
|
168
177
|
|
169
178
|
def _update_captured_vars(self, op: QuantumOperation) -> None:
|
170
179
|
handles = (
|
@@ -180,6 +189,12 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
180
189
|
) -> None:
|
181
190
|
if handle.name not in self._current_scope:
|
182
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
|
183
198
|
defining_function = self._current_scope[handle.name].defining_function
|
184
199
|
if defining_function is None:
|
185
200
|
raise ClassiqInternalExpansionError
|
@@ -204,7 +219,7 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
204
219
|
)
|
205
220
|
|
206
221
|
def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
|
207
|
-
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
222
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
208
223
|
vrc.visit(ast.parse(expr.expr))
|
209
224
|
handles = dict.fromkeys(
|
210
225
|
handle
|
@@ -216,7 +231,9 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
216
231
|
def _get_classical_vars_in_expression(
|
217
232
|
self, expr: Expression
|
218
233
|
) -> list[tuple[str, ClassicalType]]:
|
219
|
-
vrc = VarRefCollector(
|
234
|
+
vrc = VarRefCollector(
|
235
|
+
ignore_duplicated_handles=True, ignore_sympy_symbols=True, unevaluated=True
|
236
|
+
)
|
220
237
|
vrc.visit(ast.parse(expr.expr))
|
221
238
|
return list(
|
222
239
|
{
|
@@ -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
|
@@ -13,6 +13,9 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
13
13
|
EvaluatedExpression,
|
14
14
|
)
|
15
15
|
from classiq.interface.generator.expressions.expression import Expression
|
16
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
17
|
+
ClassicalScalarProxy,
|
18
|
+
)
|
16
19
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
17
20
|
QmodStructInstance,
|
18
21
|
)
|
@@ -47,28 +50,38 @@ class QuantumSymbol:
|
|
47
50
|
def emit(self) -> HandleBinding:
|
48
51
|
return self.handle
|
49
52
|
|
50
|
-
def __getitem__(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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)
|
55
59
|
|
56
|
-
def _slice(
|
60
|
+
def _slice(
|
61
|
+
self,
|
62
|
+
start: Union[int, ClassicalScalarProxy],
|
63
|
+
end: Union[int, ClassicalScalarProxy],
|
64
|
+
) -> "QuantumSymbol":
|
57
65
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
58
66
|
raise ClassiqExpansionError(
|
59
67
|
f"{self.quantum_type.type_name} is not subscriptable"
|
60
68
|
)
|
61
|
-
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:
|
62
72
|
raise ClassiqExpansionError(
|
63
73
|
f"{self.quantum_type.type_name} slice '{self.handle}[{start}:{end}]' "
|
64
74
|
f"has non-positive length"
|
65
75
|
)
|
66
|
-
|
67
|
-
|
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
|
+
):
|
68
81
|
raise ClassiqExpansionError(
|
69
82
|
f"Slice [{start}:{end}] is out of bounds for "
|
70
83
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
71
|
-
f"length {
|
84
|
+
f"length {self.quantum_type.length_value})"
|
72
85
|
)
|
73
86
|
return QuantumSymbol(
|
74
87
|
handle=SlicedHandleBinding(
|
@@ -82,17 +95,24 @@ class QuantumSymbol:
|
|
82
95
|
),
|
83
96
|
)
|
84
97
|
|
85
|
-
def _subscript(self, index: int) -> "QuantumSymbol":
|
98
|
+
def _subscript(self, index: Union[int, ClassicalScalarProxy]) -> "QuantumSymbol":
|
86
99
|
if not isinstance(self.quantum_type, QuantumBitvector):
|
87
100
|
raise ClassiqExpansionError(
|
88
101
|
f"{self.quantum_type.type_name} is not subscriptable"
|
89
102
|
)
|
90
|
-
|
91
|
-
|
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
|
+
):
|
92
112
|
raise ClassiqExpansionError(
|
93
113
|
f"Index {index} is out of bounds for "
|
94
114
|
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
95
|
-
f"length {
|
115
|
+
f"length {self.quantum_type.length})"
|
96
116
|
)
|
97
117
|
return QuantumSymbol(
|
98
118
|
handle=SubscriptHandleBinding(
|
@@ -58,14 +58,18 @@ def add_functions_to_scope(
|
|
58
58
|
|
59
59
|
|
60
60
|
def add_generative_functions_to_scope(
|
61
|
-
functions: Sequence[GenerativeQFunc], scope: Scope
|
61
|
+
functions: Sequence[GenerativeQFunc], scope: Scope, override_atomic: bool = False
|
62
62
|
) -> None:
|
63
63
|
for function in functions:
|
64
64
|
name = function.func_decl.name
|
65
|
-
if
|
66
|
-
|
65
|
+
if (
|
66
|
+
name == MAIN_FUNCTION_NAME
|
67
|
+
or name not in scope
|
68
|
+
or (override_atomic and scope[name].value.is_atomic)
|
69
|
+
):
|
70
|
+
scope[name] = Evaluated(
|
67
71
|
value=GenerativeFunctionClosure.create(
|
68
|
-
name=
|
72
|
+
name=name,
|
69
73
|
positional_arg_declarations=function.func_decl.positional_arg_declarations,
|
70
74
|
scope=Scope(parent=scope),
|
71
75
|
generative_blocks={"body": function},
|