classiq 0.62.0__py3-none-any.whl → 0.63.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 +3 -0
- classiq/_internals/api_wrapper.py +6 -26
- classiq/_internals/client.py +1 -9
- classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -8
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +106 -27
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -2
- classiq/applications/grover/grover_model_constructor.py +1 -1
- classiq/applications/libraries/qmci_library.py +2 -1
- classiq/execution/execution_session.py +66 -96
- classiq/execution/jobs.py +3 -9
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +8 -5
- classiq/interface/backend/pydantic_backend.py +1 -1
- classiq/interface/chemistry/operator.py +0 -204
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/generated_circuit_data.py +22 -7
- classiq/interface/generator/model/model.py +3 -0
- classiq/interface/generator/model/preferences/preferences.py +13 -0
- classiq/interface/generator/quantum_function_call.py +4 -2
- classiq/interface/model/handle_binding.py +50 -5
- classiq/interface/model/quantum_type.py +16 -0
- classiq/interface/server/routes.py +1 -3
- classiq/model_expansions/capturing/captured_vars.py +102 -19
- classiq/model_expansions/closure.py +19 -56
- classiq/model_expansions/function_builder.py +13 -8
- classiq/model_expansions/generative_functions.py +15 -1
- classiq/model_expansions/interpreter.py +94 -32
- classiq/model_expansions/model_tables.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +61 -2
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +3 -10
- classiq/model_expansions/quantum_operations/emitter.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -2
- classiq/model_expansions/quantum_operations/repeat.py +4 -3
- classiq/model_expansions/scope.py +7 -1
- classiq/model_expansions/scope_initialization.py +34 -25
- classiq/model_expansions/transformers/var_splitter.py +57 -7
- classiq/open_library/__init__.py +4 -0
- classiq/open_library/functions/__init__.py +130 -0
- classiq/{qmod/builtins → open_library}/functions/amplitude_estimation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/discrete_sine_cosine_transform.py +6 -4
- classiq/{qmod/builtins → open_library}/functions/grover.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/linear_pauli_rotation.py +1 -1
- classiq/{qmod/builtins → open_library}/functions/modular_exponentiation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/qpe.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/state_preparation.py +6 -149
- classiq/{qmod/builtins → open_library}/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +81 -0
- classiq/{qmod/builtins → open_library}/functions/variational.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +4 -130
- classiq/qmod/builtins/functions/allocation.py +150 -0
- classiq/qmod/builtins/functions/arithmetic.py +0 -34
- classiq/qmod/builtins/functions/operators.py +0 -6
- classiq/qmod/create_model_function.py +8 -162
- classiq/qmod/generative.py +0 -16
- classiq/qmod/model_state_container.py +7 -0
- classiq/qmod/native/pretty_printer.py +10 -11
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/qfunc.py +11 -12
- classiq/qmod/qmod_variable.py +1 -3
- classiq/qmod/quantum_expandable.py +21 -0
- classiq/qmod/quantum_function.py +65 -3
- {classiq-0.62.0.dist-info → classiq-0.63.0.dist-info}/METADATA +1 -1
- {classiq-0.62.0.dist-info → classiq-0.63.0.dist-info}/RECORD +74 -71
- classiq/qmod/builtins/functions/utility_functions.py +0 -43
- /classiq/{qmod/builtins → open_library}/functions/hea.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qaoa_penalty.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qft_functions.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qsvt.py +0 -0
- {classiq-0.62.0.dist-info → classiq-0.63.0.dist-info}/WHEEL +0 -0
@@ -32,7 +32,7 @@ from classiq.interface.model.handle_binding import (
|
|
32
32
|
)
|
33
33
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
34
34
|
from classiq.interface.model.invert import Invert
|
35
|
-
from classiq.interface.model.model import Model
|
35
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
36
36
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
37
37
|
from classiq.interface.model.phase_operation import PhaseOperation
|
38
38
|
from classiq.interface.model.power import Power
|
@@ -93,11 +93,14 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
|
93
93
|
from classiq.model_expansions.scope_initialization import (
|
94
94
|
add_constants_to_scope,
|
95
95
|
add_entry_point_params_to_scope,
|
96
|
+
add_functions_to_scope,
|
97
|
+
add_generative_functions_to_scope,
|
96
98
|
get_main_renamer,
|
97
99
|
init_top_level_scope,
|
98
100
|
)
|
99
101
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
100
102
|
from classiq.qmod.builtins.functions import permute
|
103
|
+
from classiq.qmod.model_state_container import QMODULE, ModelStateContainer
|
101
104
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
102
105
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
103
106
|
|
@@ -107,22 +110,28 @@ class Interpreter:
|
|
107
110
|
self,
|
108
111
|
model: Model,
|
109
112
|
generative_functions: Optional[list[GenerativeQFunc]] = None,
|
110
|
-
|
113
|
+
is_normalizer: bool = False,
|
114
|
+
is_shallow: bool = False,
|
111
115
|
) -> None:
|
112
|
-
self.
|
116
|
+
self._is_normalizer = is_normalizer
|
117
|
+
self._is_shallow = is_shallow
|
113
118
|
self._model = model
|
114
119
|
self._top_level_scope = Scope()
|
115
|
-
self.
|
120
|
+
self._counted_name_allocator = CountedNameAllocator()
|
121
|
+
self._builder = OperationBuilder(
|
122
|
+
self._top_level_scope, self._counted_name_allocator
|
123
|
+
)
|
116
124
|
self._expanded_functions: dict[str, NativeFunctionDefinition] = {}
|
117
125
|
|
126
|
+
init_top_level_scope(model, generative_functions or [], self._top_level_scope)
|
118
127
|
self._main_renamer: Optional[ExpressionRenamer] = (
|
119
|
-
get_main_renamer(self.
|
128
|
+
get_main_renamer(self._get_function_declarations())
|
129
|
+
if self._is_normalizer
|
130
|
+
else None
|
131
|
+
)
|
132
|
+
self._functions_compilation_metadata: dict[str, CompilationMetadata] = dict(
|
133
|
+
self._model.functions_compilation_metadata
|
120
134
|
)
|
121
|
-
|
122
|
-
if generative_functions is None:
|
123
|
-
generative_functions = []
|
124
|
-
self._generative_functions = generative_functions
|
125
|
-
init_top_level_scope(model, generative_functions, self._top_level_scope)
|
126
135
|
self._expanded_functions_compilation_metadata: dict[
|
127
136
|
str, CompilationMetadata
|
128
137
|
] = defaultdict(CompilationMetadata)
|
@@ -130,13 +139,23 @@ class Interpreter:
|
|
130
139
|
self._error_manager: ErrorManager = ErrorManager()
|
131
140
|
|
132
141
|
def _expand_main_func(self) -> None:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
142
|
+
main_func = self._top_level_scope[MAIN_FUNCTION_NAME].value
|
143
|
+
closure_constructor: Any
|
144
|
+
if isinstance(main_func, GenerativeFunctionClosure):
|
145
|
+
closure_constructor = GenerativeFunctionClosure
|
146
|
+
extra_args = {
|
147
|
+
"generative_blocks": {"body": main_func.generative_blocks["body"]}
|
148
|
+
}
|
149
|
+
else:
|
150
|
+
closure_constructor = FunctionClosure
|
151
|
+
extra_args = {"body": main_func.body}
|
152
|
+
main_closure = closure_constructor.create(
|
153
|
+
name=main_func.name,
|
154
|
+
positional_arg_declarations=main_func.positional_arg_declarations,
|
137
155
|
scope=Scope(parent=self._top_level_scope),
|
138
156
|
expr_renamer=self._main_renamer,
|
139
157
|
_depth=0,
|
158
|
+
**extra_args,
|
140
159
|
)
|
141
160
|
|
142
161
|
add_entry_point_params_to_scope(
|
@@ -170,9 +189,9 @@ class Interpreter:
|
|
170
189
|
execution_preferences=self._model.execution_preferences,
|
171
190
|
functions=list(self._expanded_functions.values()),
|
172
191
|
constants=self._model.constants,
|
173
|
-
enums=
|
174
|
-
types=
|
175
|
-
qstructs=
|
192
|
+
enums=list(QMODULE.enum_decls.values()),
|
193
|
+
types=list(QMODULE.type_decls.values()),
|
194
|
+
qstructs=list(QMODULE.qstruct_decls.values()),
|
176
195
|
debug_info=self._model.debug_info,
|
177
196
|
functions_compilation_metadata=self._expanded_functions_compilation_metadata,
|
178
197
|
)
|
@@ -196,7 +215,9 @@ class Interpreter:
|
|
196
215
|
for idx, param in enumerate(function.func_decl.positional_arg_declarations)
|
197
216
|
]
|
198
217
|
func_decl = NamedParamsQuantumFunctionDeclaration(
|
199
|
-
name=
|
218
|
+
name=self._counted_name_allocator.allocate(
|
219
|
+
function.func_decl.name or "<lambda>"
|
220
|
+
),
|
200
221
|
positional_arg_declarations=renamed_params,
|
201
222
|
)
|
202
223
|
|
@@ -275,7 +296,7 @@ class Interpreter:
|
|
275
296
|
|
276
297
|
@emit.register
|
277
298
|
def emit_quantum_assignment_operation(self, op: QuantumAssignmentOperation) -> None:
|
278
|
-
if self.
|
299
|
+
if self._is_normalizer:
|
279
300
|
ShallowEmitter(
|
280
301
|
self, "assignment_operation", components=["expression", "result_var"]
|
281
302
|
).emit(op)
|
@@ -284,7 +305,7 @@ class Interpreter:
|
|
284
305
|
|
285
306
|
@emit.register
|
286
307
|
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
287
|
-
if self.
|
308
|
+
if self._is_normalizer:
|
288
309
|
ShallowEmitter(
|
289
310
|
self, "inplace_binary_operation", components=["target", "value"]
|
290
311
|
).emit(op)
|
@@ -303,7 +324,7 @@ class Interpreter:
|
|
303
324
|
|
304
325
|
@emit.register
|
305
326
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
306
|
-
if self.
|
327
|
+
if self._is_normalizer:
|
307
328
|
ShallowEmitter(
|
308
329
|
self,
|
309
330
|
WITHIN_APPLY_NAME,
|
@@ -314,7 +335,7 @@ class Interpreter:
|
|
314
335
|
|
315
336
|
@emit.register
|
316
337
|
def emit_invert(self, invert: Invert) -> None:
|
317
|
-
if self.
|
338
|
+
if self._is_normalizer:
|
318
339
|
ShallowEmitter(self, INVERT_OPERATOR_NAME, components=["body"]).emit(invert)
|
319
340
|
else:
|
320
341
|
InvertEmitter(self).emit(invert)
|
@@ -325,7 +346,7 @@ class Interpreter:
|
|
325
346
|
|
326
347
|
@emit.register
|
327
348
|
def emit_control(self, control: Control) -> None:
|
328
|
-
if self.
|
349
|
+
if self._is_normalizer:
|
329
350
|
ShallowEmitter(
|
330
351
|
self,
|
331
352
|
CONTROL_OPERATOR_NAME,
|
@@ -336,7 +357,7 @@ class Interpreter:
|
|
336
357
|
|
337
358
|
@emit.register
|
338
359
|
def emit_power(self, power: Power) -> None:
|
339
|
-
if self.
|
360
|
+
if self._is_normalizer:
|
340
361
|
ShallowEmitter(
|
341
362
|
self, CONTROL_OPERATOR_NAME, components=["power", "body"]
|
342
363
|
).emit(power)
|
@@ -345,7 +366,7 @@ class Interpreter:
|
|
345
366
|
|
346
367
|
@emit.register
|
347
368
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
348
|
-
if self.
|
369
|
+
if self._is_normalizer:
|
349
370
|
ShallowEmitter(self, "phase", components=["expression", "theta"]).emit(
|
350
371
|
phase
|
351
372
|
)
|
@@ -370,9 +391,11 @@ class Interpreter:
|
|
370
391
|
def _expand_operation(self, operation: Closure) -> OperationContext:
|
371
392
|
with self._builder.operation_context(operation) as context:
|
372
393
|
if isinstance(operation, FunctionClosure) and (
|
373
|
-
self._expanded_functions.get(operation.closure_id)
|
394
|
+
(func_def := self._expanded_functions.get(operation.closure_id))
|
395
|
+
is not None
|
374
396
|
):
|
375
|
-
|
397
|
+
captured_vars = self._top_level_scope[func_def.name].value.captured_vars
|
398
|
+
operation.captured_vars.update(captured_vars)
|
376
399
|
elif isinstance(operation, FunctionClosure) and operation.name == "permute":
|
377
400
|
# special expansion since permute is generative
|
378
401
|
self._expand_permute()
|
@@ -403,11 +426,50 @@ class Interpreter:
|
|
403
426
|
self._expand_block(calls, "body")
|
404
427
|
|
405
428
|
def _get_function_declarations(self) -> Sequence[QuantumFunctionDeclaration]:
|
406
|
-
return
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
429
|
+
return [
|
430
|
+
QuantumFunctionDeclaration(
|
431
|
+
name=func_closure.name,
|
432
|
+
positional_arg_declarations=func_closure.positional_arg_declarations,
|
433
|
+
)
|
434
|
+
for func in self._top_level_scope.values()
|
435
|
+
if isinstance(func_closure := func.value, FunctionClosure)
|
436
|
+
]
|
411
437
|
|
412
438
|
def add_constant(self, constant: Constant) -> None:
|
413
439
|
add_constants_to_scope([constant], self._top_level_scope)
|
440
|
+
|
441
|
+
def update_declarative_functions(
|
442
|
+
self,
|
443
|
+
functions: dict[str, NativeFunctionDefinition],
|
444
|
+
qmodule: ModelStateContainer,
|
445
|
+
) -> None:
|
446
|
+
add_functions_to_scope(list(functions.values()), self._top_level_scope)
|
447
|
+
for dec_func_name in functions:
|
448
|
+
if dec_func_name in qmodule.functions_compilation_metadata:
|
449
|
+
self._functions_compilation_metadata[dec_func_name] = (
|
450
|
+
qmodule.functions_compilation_metadata[dec_func_name]
|
451
|
+
)
|
452
|
+
|
453
|
+
def update_generative_functions(
|
454
|
+
self, generative_functions: dict[str, GenerativeQFunc]
|
455
|
+
) -> None:
|
456
|
+
add_generative_functions_to_scope(
|
457
|
+
list(generative_functions.values()), self._top_level_scope
|
458
|
+
)
|
459
|
+
for name, gen_func in generative_functions.items():
|
460
|
+
if gen_func.compilation_metadata is not None:
|
461
|
+
self._functions_compilation_metadata[name] = (
|
462
|
+
gen_func.compilation_metadata
|
463
|
+
)
|
464
|
+
|
465
|
+
def add_purely_declarative_function(self, function: FunctionClosure) -> None:
|
466
|
+
functions_to_add = [function.name] + QMODULE.function_dependencies[
|
467
|
+
function.name
|
468
|
+
]
|
469
|
+
for func in functions_to_add:
|
470
|
+
if func not in self._expanded_functions and func in QMODULE.native_defs:
|
471
|
+
self._expanded_functions[func] = QMODULE.native_defs[func]
|
472
|
+
if func in QMODULE.functions_compilation_metadata:
|
473
|
+
self._expanded_functions_compilation_metadata[func] = (
|
474
|
+
QMODULE.functions_compilation_metadata[func]
|
475
|
+
)
|
@@ -78,10 +78,14 @@ class SymbolTable:
|
|
78
78
|
@classmethod
|
79
79
|
def init_user_enums(cls, user_enums: list[EnumDeclaration]) -> None:
|
80
80
|
cls.enum_table = EnumTable(user_enums)
|
81
|
+
QMODULE.enum_decls = {enum_decl.name: enum_decl for enum_decl in user_enums}
|
81
82
|
|
82
83
|
@classmethod
|
83
84
|
def init_user_types(cls, user_types: list[StructDeclaration]) -> None:
|
84
85
|
cls.type_table = StructTable(user_types)
|
86
|
+
QMODULE.type_decls = {
|
87
|
+
struct_decl.name: struct_decl for struct_decl in user_types
|
88
|
+
}
|
85
89
|
|
86
90
|
@classmethod
|
87
91
|
def init_user_qstructs(cls, user_qstructs: list[QStructDeclaration]) -> None:
|
@@ -8,6 +8,9 @@ from typing import (
|
|
8
8
|
)
|
9
9
|
|
10
10
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
11
|
+
from classiq.interface.generator.functions.port_declaration import (
|
12
|
+
PortDeclarationDirection,
|
13
|
+
)
|
11
14
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
12
15
|
from classiq.interface.model.classical_parameter_declaration import (
|
13
16
|
ClassicalParameterDeclaration,
|
@@ -20,6 +23,10 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
20
23
|
NamedParamsQuantumFunctionDeclaration,
|
21
24
|
PositionalArg,
|
22
25
|
)
|
26
|
+
from classiq.interface.model.quantum_lambda_function import (
|
27
|
+
OperandIdentifier,
|
28
|
+
QuantumLambdaFunction,
|
29
|
+
)
|
23
30
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
24
31
|
from classiq.interface.model.variable_declaration_statement import (
|
25
32
|
VariableDeclarationStatement,
|
@@ -28,7 +35,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
28
35
|
from classiq.model_expansions.capturing.captured_vars import (
|
29
36
|
validate_args_are_not_propagated,
|
30
37
|
)
|
31
|
-
from classiq.model_expansions.closure import FunctionClosure
|
38
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeClosure
|
32
39
|
from classiq.model_expansions.evaluators.argument_types import (
|
33
40
|
add_information_from_output_arguments,
|
34
41
|
)
|
@@ -45,6 +52,7 @@ from classiq.model_expansions.quantum_operations.emitter import (
|
|
45
52
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
46
53
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
47
54
|
from classiq.qmod.builtins.functions import allocate, free
|
55
|
+
from classiq.qmod.model_state_container import QMODULE
|
48
56
|
|
49
57
|
if TYPE_CHECKING:
|
50
58
|
from classiq.model_expansions.interpreter import Interpreter
|
@@ -65,7 +73,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
65
73
|
self, name: str, body: Sequence[QuantumStatement]
|
66
74
|
) -> QuantumFunctionCall:
|
67
75
|
wrapping_function = FunctionClosure.create(
|
68
|
-
name=name,
|
76
|
+
name=self._counted_name_allocator.allocate(name),
|
69
77
|
body=body,
|
70
78
|
scope=Scope(parent=self._current_scope),
|
71
79
|
is_lambda=True,
|
@@ -98,6 +106,13 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
98
106
|
)
|
99
107
|
new_positional_arg_decls = new_declaration.positional_arg_declarations
|
100
108
|
is_atomic = function.is_atomic
|
109
|
+
if (
|
110
|
+
self._interpreter._is_shallow
|
111
|
+
and self._is_function_purely_declarative(function)
|
112
|
+
and self._are_args_purely_declarative(args)
|
113
|
+
):
|
114
|
+
is_atomic = True
|
115
|
+
self._interpreter.add_purely_declarative_function(function)
|
101
116
|
new_function_name = function.name
|
102
117
|
if not is_atomic: # perform monomorphization per interpreted parameters set
|
103
118
|
self._add_params_to_scope(
|
@@ -253,3 +268,47 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
253
268
|
evaluated_args,
|
254
269
|
),
|
255
270
|
)
|
271
|
+
|
272
|
+
def _is_function_purely_declarative(self, function: FunctionClosure) -> bool:
|
273
|
+
if function.name not in QMODULE.native_defs:
|
274
|
+
return False
|
275
|
+
|
276
|
+
if isinstance(function, GenerativeClosure):
|
277
|
+
return False
|
278
|
+
|
279
|
+
if any(
|
280
|
+
not param.quantum_type.is_instantiated
|
281
|
+
for param in function.positional_arg_declarations
|
282
|
+
if isinstance(param, PortDeclaration)
|
283
|
+
and param.direction == PortDeclarationDirection.Output
|
284
|
+
):
|
285
|
+
return False
|
286
|
+
|
287
|
+
dependencies = QMODULE.function_dependencies[function.name]
|
288
|
+
return self._are_identifiers_purely_declarative(dependencies)
|
289
|
+
|
290
|
+
def _are_args_purely_declarative(self, args: list[ArgValue]) -> bool:
|
291
|
+
if any(
|
292
|
+
isinstance(arg, (OperandIdentifier, QuantumLambdaFunction))
|
293
|
+
or (
|
294
|
+
isinstance(arg, list)
|
295
|
+
and any(
|
296
|
+
isinstance(item, (OperandIdentifier, QuantumLambdaFunction))
|
297
|
+
for item in arg
|
298
|
+
)
|
299
|
+
)
|
300
|
+
for arg in args
|
301
|
+
):
|
302
|
+
return False
|
303
|
+
|
304
|
+
dependencies = [arg for arg in args if isinstance(arg, str)]
|
305
|
+
dependencies += [
|
306
|
+
cast(str, item) for arg in args if isinstance(arg, list) for item in arg
|
307
|
+
]
|
308
|
+
return self._are_identifiers_purely_declarative(dependencies)
|
309
|
+
|
310
|
+
def _are_identifiers_purely_declarative(self, dependencies: list[str]) -> bool:
|
311
|
+
return not any(
|
312
|
+
isinstance(self._current_scope[dep].value, GenerativeClosure)
|
313
|
+
for dep in dependencies
|
314
|
+
)
|
@@ -45,7 +45,7 @@ class ClassicalIfEmitter(CallEmitter[ClassicalIf]):
|
|
45
45
|
return
|
46
46
|
|
47
47
|
then_else_func = FunctionClosure.create(
|
48
|
-
name=
|
48
|
+
name=self._counted_name_allocator.allocate("then" if condition else "else"),
|
49
49
|
body=body,
|
50
50
|
scope=Scope(parent=self._current_scope),
|
51
51
|
is_lambda=True,
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import cast
|
2
|
-
|
3
1
|
from sympy import Equality
|
4
2
|
from sympy.logic.boolalg import Boolean
|
5
3
|
from typing_extensions import TypeGuard
|
@@ -55,6 +53,9 @@ from classiq.qmod.builtins.functions.standard_gates import X
|
|
55
53
|
|
56
54
|
class ControlEmitter(ExpressionOperationEmitter[Control]):
|
57
55
|
def emit(self, control: Control, /) -> None:
|
56
|
+
validate_args_are_not_propagated(
|
57
|
+
extract_handles(control.expression), extract_handles(control.body)
|
58
|
+
)
|
58
59
|
condition = control.expression
|
59
60
|
arrays_with_subscript = self.split_symbols(
|
60
61
|
condition, self._counted_name_allocator.allocate
|
@@ -117,10 +118,6 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
117
118
|
scope=Scope(parent=self._current_scope),
|
118
119
|
)
|
119
120
|
context = self._expand_operation(control_operation)
|
120
|
-
validate_args_are_not_propagated(
|
121
|
-
control.var_handles,
|
122
|
-
extract_handles([block.statements for block in context.blocks.values()]),
|
123
|
-
)
|
124
121
|
self._update_control_state(control)
|
125
122
|
self.emit_statement(
|
126
123
|
control.model_copy(update=dict(body=context.statements("body")))
|
@@ -130,10 +127,6 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
130
127
|
wrapping_function = self._create_expanded_wrapping_function(
|
131
128
|
CONTROL_OPERATOR_NAME, control.body
|
132
129
|
)
|
133
|
-
validate_args_are_not_propagated(
|
134
|
-
control.var_handles,
|
135
|
-
cast(list[HandleBinding], wrapping_function.positional_args),
|
136
|
-
)
|
137
130
|
self._update_control_state(control)
|
138
131
|
self.emit_statement(control.model_copy(update=dict(body=[wrapping_function])))
|
139
132
|
|
@@ -54,7 +54,7 @@ class Emitter(Generic[QuantumStatementT]):
|
|
54
54
|
self._interpreter._expanded_functions_compilation_metadata
|
55
55
|
)
|
56
56
|
self._functions_compilation_metadata = (
|
57
|
-
self._interpreter.
|
57
|
+
self._interpreter._functions_compilation_metadata
|
58
58
|
)
|
59
59
|
|
60
60
|
@abstractmethod
|
@@ -123,8 +123,7 @@ class QuantumAssignmentOperationEmitter(
|
|
123
123
|
self, op: ArithmeticOperation
|
124
124
|
) -> tuple[ArithmeticOperation, Expression, bool]:
|
125
125
|
if (
|
126
|
-
|
127
|
-
or op.operation_kind
|
126
|
+
op.operation_kind
|
128
127
|
not in (
|
129
128
|
ArithmeticOperationKind.Assignment,
|
130
129
|
ArithmeticOperationKind.InplaceXor,
|
@@ -22,10 +22,11 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
22
22
|
raise ClassiqExpansionError(
|
23
23
|
f"repeat count must be non-negative, got {count}"
|
24
24
|
)
|
25
|
+
op_name = self._counted_name_allocator.allocate(REPEAT_OPERATOR_NAME)
|
25
26
|
for i in range(count):
|
26
|
-
self._emit_iteration(repeat, i)
|
27
|
+
self._emit_iteration(repeat, i, op_name)
|
27
28
|
|
28
|
-
def _emit_iteration(self, repeat: Repeat, i: int) -> None:
|
29
|
+
def _emit_iteration(self, repeat: Repeat, i: int, op_name: str) -> None:
|
29
30
|
closure_constructor: type[FunctionClosure]
|
30
31
|
extra_args: dict
|
31
32
|
if repeat.is_generative():
|
@@ -41,7 +42,7 @@ class RepeatEmitter(CallEmitter[Repeat]):
|
|
41
42
|
closure_constructor = FunctionClosure
|
42
43
|
extra_args = {}
|
43
44
|
iteration_function = closure_constructor.create(
|
44
|
-
name=
|
45
|
+
name=op_name,
|
45
46
|
positional_arg_declarations=[
|
46
47
|
ClassicalParameterDeclaration(
|
47
48
|
name=repeat.iter_var, classical_type=Integer()
|
@@ -163,8 +163,14 @@ class Evaluated: # FIXME: Merge with EvaluatedExpression if possible
|
|
163
163
|
return int(self.value)
|
164
164
|
|
165
165
|
def emit(self) -> ArgValue:
|
166
|
-
|
166
|
+
from classiq.model_expansions.closure import FunctionClosure
|
167
|
+
|
168
|
+
if isinstance(self.value, (QuantumSymbol, FunctionClosure)):
|
167
169
|
return self.value.emit()
|
170
|
+
if isinstance(self.value, list) and all(
|
171
|
+
isinstance(item, FunctionClosure) for item in self.value
|
172
|
+
):
|
173
|
+
return [item.emit() for item in self.value]
|
168
174
|
|
169
175
|
ret = Expression(expr=evaluated_to_str(self.value))
|
170
176
|
ret._evaluated_expr = EvaluatedExpression(value=self.value)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
+
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
from classiq.interface.exceptions import ClassiqError
|
4
5
|
from classiq.interface.generator.constant import Constant
|
@@ -12,7 +13,11 @@ from classiq.interface.model.handle_binding import HandleBinding
|
|
12
13
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model
|
13
14
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
14
15
|
from classiq.interface.model.port_declaration import PortDeclaration
|
15
|
-
from classiq.interface.model.quantum_function_declaration import
|
16
|
+
from classiq.interface.model.quantum_function_declaration import (
|
17
|
+
NamedParamsQuantumFunctionDeclaration,
|
18
|
+
PositionalArg,
|
19
|
+
QuantumFunctionDeclaration,
|
20
|
+
)
|
16
21
|
|
17
22
|
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
18
23
|
from classiq.model_expansions.evaluators.classical_expression import (
|
@@ -32,12 +37,14 @@ from classiq.qmod.quantum_function import GenerativeQFunc
|
|
32
37
|
|
33
38
|
|
34
39
|
def get_main_renamer(
|
35
|
-
|
40
|
+
func_decls: Sequence[QuantumFunctionDeclaration],
|
36
41
|
) -> ExpressionRenamer:
|
37
|
-
for
|
38
|
-
if
|
42
|
+
for func_decl in func_decls:
|
43
|
+
if func_decl.name == MAIN_FUNCTION_NAME:
|
44
|
+
if TYPE_CHECKING:
|
45
|
+
assert isinstance(func_decl, NamedParamsQuantumFunctionDeclaration)
|
39
46
|
return ExpressionRenamer.from_positional_arg_declarations(
|
40
|
-
|
47
|
+
func_decl.positional_arg_declarations, CPARAM_EXECUTION_SUFFIX
|
41
48
|
)
|
42
49
|
return ExpressionRenamer(var_mapping={})
|
43
50
|
|
@@ -49,32 +56,34 @@ def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
|
49
56
|
)
|
50
57
|
|
51
58
|
|
52
|
-
def
|
53
|
-
functions:
|
59
|
+
def add_functions_to_scope(
|
60
|
+
functions: Sequence[NativeFunctionDefinition], scope: Scope
|
54
61
|
) -> None:
|
55
62
|
for function in functions:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
if function.name not in scope:
|
64
|
+
scope[function.name] = Evaluated(
|
65
|
+
value=FunctionClosure.create(
|
66
|
+
name=function.name,
|
67
|
+
positional_arg_declarations=function.positional_arg_declarations,
|
68
|
+
body=function.body,
|
69
|
+
scope=Scope(parent=scope),
|
70
|
+
)
|
62
71
|
)
|
63
|
-
)
|
64
72
|
|
65
73
|
|
66
|
-
def
|
67
|
-
functions:
|
74
|
+
def add_generative_functions_to_scope(
|
75
|
+
functions: Sequence[GenerativeQFunc], scope: Scope
|
68
76
|
) -> None:
|
69
77
|
for function in functions:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
78
|
+
if function.func_decl.name not in scope:
|
79
|
+
scope[function.func_decl.name] = Evaluated(
|
80
|
+
value=GenerativeFunctionClosure.create(
|
81
|
+
name=function.func_decl.name,
|
82
|
+
positional_arg_declarations=function.func_decl.positional_arg_declarations,
|
83
|
+
scope=Scope(parent=scope),
|
84
|
+
generative_blocks={"body": function},
|
85
|
+
)
|
76
86
|
)
|
77
|
-
)
|
78
87
|
|
79
88
|
|
80
89
|
def _init_builtins_scope(scope: Scope) -> None:
|
@@ -129,7 +138,7 @@ def add_entry_point_params_to_scope(
|
|
129
138
|
def init_top_level_scope(
|
130
139
|
model: Model, generative_functions: list[GenerativeQFunc], scope: Scope
|
131
140
|
) -> None:
|
132
|
-
|
133
|
-
|
141
|
+
add_generative_functions_to_scope(generative_functions, scope)
|
142
|
+
add_functions_to_scope(model.functions, scope)
|
134
143
|
add_constants_to_scope(model.constants, scope)
|
135
144
|
_init_builtins_scope(scope)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import ast
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from itertools import chain
|
4
|
-
from typing import TYPE_CHECKING, Callable, TypeVar, cast
|
4
|
+
from typing import TYPE_CHECKING, Callable, Optional, TypeVar, cast
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import (
|
7
7
|
ClassiqExpansionError,
|
@@ -14,6 +14,7 @@ from classiq.interface.model.handle_binding import (
|
|
14
14
|
HandleBinding,
|
15
15
|
NestedHandleBinding,
|
16
16
|
SlicedHandleBinding,
|
17
|
+
SubscriptHandleBinding,
|
17
18
|
)
|
18
19
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
19
20
|
QuantumExpressionOperation,
|
@@ -125,12 +126,7 @@ class VarSplitter:
|
|
125
126
|
raise ClassiqExpansionError(
|
126
127
|
f"Could not determine the length of quantum array " f"{symbol.handle}."
|
127
128
|
)
|
128
|
-
target_slices =
|
129
|
-
target_part.start.to_int_value(): target_part.end.to_int_value()
|
130
|
-
for target_part in target_parts
|
131
|
-
if isinstance(target_part, SlicedHandleBinding)
|
132
|
-
and symbol.handle == target_part.base_handle
|
133
|
-
}
|
129
|
+
target_slices = self._get_target_slices(symbol, target_parts)
|
134
130
|
|
135
131
|
symbol_parts: list[QuantumSymbol] = []
|
136
132
|
idx = 0
|
@@ -151,6 +147,60 @@ class VarSplitter:
|
|
151
147
|
|
152
148
|
return symbol_parts
|
153
149
|
|
150
|
+
def _get_target_slices(
|
151
|
+
self, symbol: QuantumSymbol, target_parts: list[HandleBinding]
|
152
|
+
) -> dict[int, int]:
|
153
|
+
if TYPE_CHECKING:
|
154
|
+
assert isinstance(symbol.quantum_type, QuantumBitvector)
|
155
|
+
target_items = {
|
156
|
+
idx
|
157
|
+
for idx in range(symbol.quantum_type.length_value)
|
158
|
+
for target_part in target_parts
|
159
|
+
if target_part
|
160
|
+
in SubscriptHandleBinding(
|
161
|
+
base_handle=symbol.handle, index=Expression(expr=str(idx))
|
162
|
+
)
|
163
|
+
}
|
164
|
+
target_slices = {
|
165
|
+
target_part.start.to_int_value(): target_part.end.to_int_value()
|
166
|
+
for target_part in target_parts
|
167
|
+
if isinstance(target_part, SlicedHandleBinding)
|
168
|
+
and symbol.handle == target_part.base_handle
|
169
|
+
}
|
170
|
+
self._add_unused_indices_as_slices(symbol, target_items, target_slices)
|
171
|
+
return target_slices
|
172
|
+
|
173
|
+
@staticmethod
|
174
|
+
def _add_unused_indices_as_slices(
|
175
|
+
symbol: QuantumSymbol, target_items: set[int], target_slices: dict[int, int]
|
176
|
+
) -> None:
|
177
|
+
if TYPE_CHECKING:
|
178
|
+
assert isinstance(symbol.quantum_type, QuantumBitvector)
|
179
|
+
last_unused_idx: Optional[int] = None
|
180
|
+
array_length = symbol.quantum_type.length_value
|
181
|
+
idx = 0
|
182
|
+
|
183
|
+
while idx < array_length:
|
184
|
+
if (
|
185
|
+
idx in target_items or idx in target_slices
|
186
|
+
) and last_unused_idx is not None:
|
187
|
+
target_slices[last_unused_idx] = idx
|
188
|
+
last_unused_idx = None
|
189
|
+
|
190
|
+
if idx in target_slices:
|
191
|
+
if target_slices[idx] <= idx:
|
192
|
+
raise ClassiqInternalExpansionError
|
193
|
+
idx = target_slices[idx]
|
194
|
+
continue
|
195
|
+
|
196
|
+
if idx not in target_items and last_unused_idx is None:
|
197
|
+
last_unused_idx = idx
|
198
|
+
|
199
|
+
idx += 1
|
200
|
+
|
201
|
+
if last_unused_idx is not None:
|
202
|
+
target_slices[last_unused_idx] = array_length
|
203
|
+
|
154
204
|
def _get_struct_parts(
|
155
205
|
self, symbol: QuantumSymbol, target_parts: list[HandleBinding]
|
156
206
|
) -> list[QuantumSymbol]:
|