classiq 0.80.1__py3-none-any.whl → 0.82.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/analyzer/show_interactive_hack.py +10 -4
- classiq/analyzer/url_utils.py +4 -3
- classiq/applications/qnn/qlayer.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +0 -3
- classiq/interface/debug_info/debug_info.py +0 -1
- classiq/interface/executor/execution_preferences.py +2 -1
- classiq/interface/generator/compiler_keywords.py +2 -2
- classiq/interface/generator/expressions/atomic_expression_functions.py +11 -7
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +6 -2
- classiq/interface/generator/function_params.py +1 -1
- classiq/interface/generator/functions/classical_type.py +8 -0
- classiq/interface/generator/generated_circuit_data.py +1 -2
- classiq/interface/generator/quantum_program.py +13 -0
- classiq/interface/generator/types/compilation_metadata.py +14 -2
- classiq/interface/model/handle_binding.py +12 -2
- classiq/interface/model/quantum_type.py +12 -1
- classiq/interface/server/routes.py +0 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +1 -1
- classiq/model_expansions/capturing/captured_vars.py +123 -9
- classiq/model_expansions/closure.py +2 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +3 -18
- classiq/model_expansions/function_builder.py +1 -17
- classiq/model_expansions/interpreters/base_interpreter.py +2 -0
- classiq/model_expansions/quantum_operations/allocate.py +18 -7
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +4 -0
- classiq/model_expansions/quantum_operations/bind.py +2 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +27 -21
- classiq/model_expansions/quantum_operations/emitter.py +28 -0
- classiq/model_expansions/quantum_operations/function_calls_cache.py +1 -16
- classiq/model_expansions/transformers/type_qualifier_inference.py +220 -50
- classiq/model_expansions/visitors/symbolic_param_inference.py +0 -6
- classiq/open_library/functions/amplitude_amplification.py +3 -5
- classiq/open_library/functions/state_preparation.py +9 -0
- classiq/qmod/builtins/functions/__init__.py +3 -1
- classiq/qmod/builtins/functions/exponentiation.py +41 -3
- classiq/qmod/builtins/operations.py +65 -37
- classiq/qmod/declaration_inferrer.py +2 -1
- classiq/qmod/native/pretty_printer.py +12 -10
- classiq/qmod/pretty_print/pretty_printer.py +9 -9
- classiq/qmod/qfunc.py +11 -11
- classiq/qmod/quantum_expandable.py +4 -0
- classiq/qmod/semantics/error_manager.py +8 -2
- classiq/synthesis.py +6 -3
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/METADATA +1 -1
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/RECORD +47 -49
- classiq/interface/execution/resource_estimator.py +0 -7
- classiq/interface/execution/result.py +0 -5
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/WHEEL +0 -0
@@ -29,14 +29,7 @@ from classiq.model_expansions.capturing.captured_vars import (
|
|
29
29
|
validate_captured_directions,
|
30
30
|
validate_end_state,
|
31
31
|
)
|
32
|
-
from classiq.model_expansions.closure import
|
33
|
-
Closure,
|
34
|
-
FunctionClosure,
|
35
|
-
GenerativeFunctionClosure,
|
36
|
-
)
|
37
|
-
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
38
|
-
is_signature_monomorphic,
|
39
|
-
)
|
32
|
+
from classiq.model_expansions.closure import Closure, FunctionClosure
|
40
33
|
from classiq.model_expansions.scope import Scope
|
41
34
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
42
35
|
|
@@ -225,15 +218,6 @@ class OperationBuilder:
|
|
225
218
|
if name == MAIN_FUNCTION_NAME:
|
226
219
|
return name
|
227
220
|
|
228
|
-
if name in self.current_scope:
|
229
|
-
orig_func = self.current_scope[name].value
|
230
|
-
if (
|
231
|
-
isinstance(orig_func, FunctionClosure)
|
232
|
-
and not isinstance(orig_func, GenerativeFunctionClosure)
|
233
|
-
and is_signature_monomorphic(orig_func.positional_arg_declarations)
|
234
|
-
):
|
235
|
-
return name
|
236
|
-
|
237
221
|
for _ in self.current_scope:
|
238
222
|
name = self._counted_name_allocator.allocate(
|
239
223
|
f"{name}_{LAMBDA_KEYWORD + '_0_0_' if function_context.is_lambda else ''}{EXPANDED_KEYWORD}"
|
@@ -76,11 +76,15 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
76
76
|
target: QuantumSymbol,
|
77
77
|
op_update_dict: dict[str, Expression],
|
78
78
|
) -> None:
|
79
|
-
if
|
79
|
+
if target.quantum_type.is_evaluated:
|
80
|
+
expr = str(target.quantum_type.size_in_bits)
|
81
|
+
elif self._allow_symbolic_attrs:
|
82
|
+
expr = f"{target.handle}.size"
|
83
|
+
else:
|
80
84
|
raise ClassiqValueError(
|
81
85
|
f"Could not infer the size of variable {str(target.handle)!r}"
|
82
86
|
)
|
83
|
-
op_update_dict["size"] = Expression(expr=
|
87
|
+
op_update_dict["size"] = Expression(expr=expr)
|
84
88
|
|
85
89
|
def _handle_with_size(
|
86
90
|
self,
|
@@ -88,7 +92,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
88
92
|
size: Expression,
|
89
93
|
op_update_dict: dict[str, Expression],
|
90
94
|
) -> None:
|
91
|
-
size_value = self._interpret_size(size)
|
95
|
+
size_value = self._interpret_size(size, str(target.handle))
|
92
96
|
op_update_dict["size"] = Expression(expr=str(size_value))
|
93
97
|
|
94
98
|
if not isinstance(size_value, sympy.Basic):
|
@@ -106,12 +110,13 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
106
110
|
fraction_digits: Expression,
|
107
111
|
op_update_dict: dict[str, Expression],
|
108
112
|
) -> None:
|
113
|
+
var_name = str(target.handle)
|
109
114
|
if not isinstance(target.quantum_type, QuantumNumeric):
|
110
115
|
raise ClassiqValueError(
|
111
|
-
f"Non-numeric variable {
|
116
|
+
f"Non-numeric variable {var_name!r} cannot be allocated with numeric attributes"
|
112
117
|
)
|
113
118
|
|
114
|
-
size_value = self._interpret_size(size)
|
119
|
+
size_value = self._interpret_size(size, var_name)
|
115
120
|
op_update_dict["size"] = Expression(expr=str(size_value))
|
116
121
|
is_signed_value = self._interpret_is_signed(is_signed)
|
117
122
|
op_update_dict["is_signed"] = Expression(expr=str(is_signed_value))
|
@@ -130,12 +135,18 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
130
135
|
fraction_digits=op_update_dict["fraction_digits"],
|
131
136
|
),
|
132
137
|
target.quantum_type,
|
133
|
-
|
138
|
+
var_name,
|
134
139
|
)
|
135
140
|
|
136
|
-
def _interpret_size(
|
141
|
+
def _interpret_size(
|
142
|
+
self, size: Expression, var_name: str
|
143
|
+
) -> Union[int, float, sympy.Basic]:
|
137
144
|
size_value = self._interpreter.evaluate(size).value
|
138
145
|
if not self._allow_symbolic_attrs and not isinstance(size_value, (int, float)):
|
146
|
+
if size.expr == f"{var_name}.size":
|
147
|
+
raise ClassiqValueError(
|
148
|
+
f"Could not infer the size of variable {var_name!r}"
|
149
|
+
)
|
139
150
|
raise ClassiqValueError(
|
140
151
|
f"The number of allocated qubits must be an integer. Got "
|
141
152
|
f"{str(size_value)!r}"
|
@@ -78,7 +78,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
78
78
|
expr = self._evaluate_expression(op.expression)
|
79
79
|
if len(self._get_classical_vars_in_expression(expr)):
|
80
80
|
return None
|
81
|
+
|
81
82
|
symbols = self._get_symbols_in_expression(expr)
|
83
|
+
if any(not symbol.quantum_type.is_instantiated for symbol in symbols):
|
84
|
+
return None
|
85
|
+
|
82
86
|
expr_str = rename_variables(
|
83
87
|
expr.expr,
|
84
88
|
{str(symbol.handle): symbol.handle.identifier for symbol in symbols}
|
@@ -31,7 +31,8 @@ class BindEmitter(Emitter[BindOperation]):
|
|
31
31
|
|
32
32
|
def emit(self, bind: BindOperation, /) -> bool:
|
33
33
|
inputs, outputs = self._get_inputs_outputs(bind)
|
34
|
-
|
34
|
+
if not self._allow_symbolic_size:
|
35
|
+
validate_bind_targets(bind, self._current_scope)
|
35
36
|
self._process_var_sizes(bind, inputs, outputs)
|
36
37
|
|
37
38
|
for symbol in chain(inputs, outputs):
|
@@ -29,6 +29,7 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
29
29
|
PortDeclarationDirection,
|
30
30
|
)
|
31
31
|
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
32
|
+
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
32
33
|
from classiq.interface.helpers.backward_compatibility import zip_strict
|
33
34
|
from classiq.interface.helpers.text_utils import are, readable_list, s
|
34
35
|
from classiq.interface.model.classical_parameter_declaration import (
|
@@ -80,7 +81,7 @@ from classiq.model_expansions.scope import (
|
|
80
81
|
Scope,
|
81
82
|
)
|
82
83
|
from classiq.model_expansions.transformers.type_qualifier_inference import (
|
83
|
-
|
84
|
+
TypeQualifierValidation,
|
84
85
|
)
|
85
86
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
86
87
|
from classiq.qmod.pretty_print.expression_to_python import transform_expression
|
@@ -290,6 +291,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
290
291
|
context = self._expand_operation(function)
|
291
292
|
function_context = cast(FunctionContext, context)
|
292
293
|
function_def = self._create_function_definition(function_context, args)
|
294
|
+
self._validate_type_qualifiers(function_context, function_def)
|
293
295
|
self._expanded_functions[cache_key] = function_def
|
294
296
|
self._top_level_scope[function_def.name] = Evaluated(
|
295
297
|
value=function_context.closure.with_new_declaration(function_def)
|
@@ -320,20 +322,14 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
320
322
|
)
|
321
323
|
captured_ports = captured_vars.get_captured_parameters()
|
322
324
|
if len(captured_ports) == 0:
|
323
|
-
self._override_type_qualifier(function_context, func_def)
|
324
325
|
return func_def
|
325
326
|
func_def.positional_arg_declarations = list(
|
326
327
|
chain.from_iterable((func_def.positional_arg_declarations, captured_ports))
|
327
328
|
)
|
328
329
|
|
329
|
-
rewrite_mapping =
|
330
|
-
if function_context.is_lambda:
|
331
|
-
rewrite_mapping |= captured_vars.get_immediate_captured_mapping()
|
332
|
-
rewrite_mapping |= captured_vars.get_classical_captured_mapping()
|
330
|
+
rewrite_mapping = captured_vars.get_captured_mapping(function_context.is_lambda)
|
333
331
|
func_def.body = self.rewrite(func_def.body, rewrite_mapping)
|
334
332
|
|
335
|
-
self._override_type_qualifier(function_context, func_def)
|
336
|
-
|
337
333
|
return func_def
|
338
334
|
|
339
335
|
@staticmethod
|
@@ -419,9 +415,21 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
419
415
|
if var_state and param.direction == PortDeclarationDirection.Output:
|
420
416
|
raise ClassiqExpansionError(INITIALIZED_VAR_MESSAGE.format(var_name))
|
421
417
|
|
422
|
-
def
|
418
|
+
def _validate_type_qualifiers(
|
423
419
|
self, func_context: FunctionContext, func_def: NativeFunctionDefinition
|
424
420
|
) -> None:
|
421
|
+
if self._should_override_type_qualifiers(func_context):
|
422
|
+
self._override_type_qualifiers(func_def)
|
423
|
+
|
424
|
+
unchecked = self._functions_compilation_metadata.get(
|
425
|
+
func_context.name, CompilationMetadata()
|
426
|
+
).unchecked
|
427
|
+
TypeQualifierValidation(
|
428
|
+
skip_validation=self._interpreter.skip_type_modifier_validation
|
429
|
+
).run(func_def.port_declarations, func_def.body, unchecked)
|
430
|
+
|
431
|
+
@staticmethod
|
432
|
+
def _should_override_type_qualifiers(func_context: FunctionContext) -> bool:
|
425
433
|
"""
|
426
434
|
The type qualifier can be changed according to the operand passed to the
|
427
435
|
function. For example,
|
@@ -434,29 +442,27 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
434
442
|
"""
|
435
443
|
|
436
444
|
if func_context.is_lambda:
|
437
|
-
|
438
|
-
return
|
445
|
+
return True
|
439
446
|
|
440
447
|
orig_name = func_context.name
|
441
448
|
if (
|
442
449
|
orig_name == MAIN_FUNCTION_NAME
|
443
450
|
or orig_name not in func_context.closure.scope
|
444
451
|
):
|
445
|
-
return
|
452
|
+
return False
|
446
453
|
|
447
454
|
orig_func = func_context.closure.scope[orig_name].value
|
448
|
-
|
449
|
-
isinstance(
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
+
return not (
|
456
|
+
isinstance(orig_func, Closure)
|
457
|
+
and not any(
|
458
|
+
isinstance(param_decl, QuantumOperandDeclaration)
|
459
|
+
for param_decl in orig_func.positional_arg_declarations
|
460
|
+
)
|
461
|
+
)
|
455
462
|
|
456
463
|
@staticmethod
|
457
|
-
def
|
464
|
+
def _override_type_qualifiers(func_def: NativeFunctionDefinition) -> None:
|
458
465
|
# only override the qualifier if it's unspecified (not QFree or Const)
|
459
466
|
for port in func_def.port_declarations:
|
460
467
|
if port.type_qualifier is TypeQualifier.Quantum:
|
461
468
|
port.type_qualifier = TypeQualifier.Inferred
|
462
|
-
TypeQualifierInference().run(func_def.port_declarations, func_def.body)
|
@@ -184,6 +184,8 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
184
184
|
def _update_captured_classical_vars_in_expression(self, expr: Expression) -> None:
|
185
185
|
for var_name, var_type in self._get_classical_vars_in_expression(expr):
|
186
186
|
self._capture_classical_var(var_name, var_type)
|
187
|
+
for handle in self._get_quantum_type_attributes_in_expression(expr):
|
188
|
+
self._capture_quantum_type_attribute(handle)
|
187
189
|
|
188
190
|
def _update_captured_vars(self, op: QuantumOperation) -> None:
|
189
191
|
for handle, direction in op.handles_with_directions:
|
@@ -223,6 +225,17 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
223
225
|
defining_function=defining_function,
|
224
226
|
)
|
225
227
|
|
228
|
+
def _capture_quantum_type_attribute(self, handle: FieldHandleBinding) -> None:
|
229
|
+
if handle.name not in self._current_scope:
|
230
|
+
return
|
231
|
+
defining_function = self._current_scope[handle.name].defining_function
|
232
|
+
if defining_function is None:
|
233
|
+
raise ClassiqInternalExpansionError
|
234
|
+
self._builder.current_block.captured_vars.capture_quantum_type_attribute(
|
235
|
+
handle=handle,
|
236
|
+
defining_function=defining_function,
|
237
|
+
)
|
238
|
+
|
226
239
|
def _get_symbols_in_expression(self, expr: Expression) -> list[QuantumSymbol]:
|
227
240
|
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
228
241
|
vrc.visit(ast.parse(expr.expr))
|
@@ -258,3 +271,18 @@ class Emitter(Generic[QuantumStatementT], ABC):
|
|
258
271
|
)
|
259
272
|
}.items()
|
260
273
|
)
|
274
|
+
|
275
|
+
def _get_quantum_type_attributes_in_expression(
|
276
|
+
self, expr: Expression
|
277
|
+
) -> list[FieldHandleBinding]:
|
278
|
+
vrc = VarRefCollector(ignore_duplicated_handles=True, unevaluated=True)
|
279
|
+
vrc.visit(ast.parse(expr.expr))
|
280
|
+
return list(
|
281
|
+
dict.fromkeys(
|
282
|
+
handle
|
283
|
+
for handle in vrc.var_handles
|
284
|
+
if isinstance(handle, FieldHandleBinding)
|
285
|
+
and handle.field in CLASSICAL_ATTRIBUTES
|
286
|
+
and isinstance(self._current_scope[handle.name].value, QuantumSymbol)
|
287
|
+
)
|
288
|
+
)
|
@@ -11,10 +11,6 @@ from classiq.interface.generator.expressions.proxies.classical.classical_struct_
|
|
11
11
|
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
12
12
|
get_proxy_type,
|
13
13
|
)
|
14
|
-
from classiq.interface.generator.functions.port_declaration import (
|
15
|
-
PortDeclarationDirection,
|
16
|
-
)
|
17
|
-
from classiq.interface.model.port_declaration import PortDeclaration
|
18
14
|
from classiq.interface.model.quantum_function_declaration import (
|
19
15
|
NamedParamsQuantumFunctionDeclaration,
|
20
16
|
)
|
@@ -36,18 +32,7 @@ def get_func_call_cache_key(
|
|
36
32
|
raise ClassiqInternalExpansionError(
|
37
33
|
"Mismatch between number of args to number of arg declarations"
|
38
34
|
)
|
39
|
-
|
40
|
-
# output arguments cannot affect the morphization of the function, as their
|
41
|
-
# attributes are defined locally by the function, according to other arguments
|
42
|
-
non_outputs_args = [
|
43
|
-
arg
|
44
|
-
for arg_decl, arg in zip(decl.positional_arg_declarations, args)
|
45
|
-
if not (
|
46
|
-
isinstance(arg_decl, PortDeclaration)
|
47
|
-
and arg_decl.direction is PortDeclarationDirection.Output
|
48
|
-
)
|
49
|
-
]
|
50
|
-
return f"{decl.name}__{_evaluated_args_to_str(non_outputs_args)}"
|
35
|
+
return f"{decl.name}__{_evaluated_args_to_str(args)}"
|
51
36
|
|
52
37
|
|
53
38
|
def _evaluated_args_to_str(evaluated_args: list[Evaluated]) -> str:
|