classiq 0.69.0__py3-none-any.whl → 0.71.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/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +6 -0
- classiq/interface/chemistry/operator.py +1 -21
- classiq/interface/debug_info/debug_info.py +4 -0
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- classiq/interface/generator/circuit_code/circuit_code.py +4 -0
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
- classiq/interface/generator/expressions/expression_constants.py +0 -3
- classiq/interface/generator/expressions/expression_types.py +12 -4
- classiq/interface/generator/expressions/proxies/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +79 -0
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
- classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +35 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +34 -0
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
- classiq/interface/generator/functions/classical_type.py +24 -30
- classiq/interface/generator/functions/type_name.py +42 -2
- classiq/interface/generator/functions/type_qualifier.py +7 -0
- classiq/interface/generator/generated_circuit_data.py +22 -4
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_function_call.py +8 -1
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/generator/synthesis_execution_parameter.py +1 -0
- classiq/interface/generator/types/compilation_metadata.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/inplace_binary_operation.py +4 -0
- classiq/interface/model/model.py +3 -1
- classiq/interface/model/native_function_definition.py +0 -10
- 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 +37 -3
- 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/model_expansions/atomic_expression_functions_defs.py +9 -3
- classiq/model_expansions/capturing/captured_vars.py +156 -34
- classiq/model_expansions/evaluators/arg_type_match.py +4 -2
- classiq/model_expansions/evaluators/classical_expression.py +2 -2
- classiq/model_expansions/evaluators/classical_type_inference.py +70 -0
- classiq/model_expansions/evaluators/control.py +1 -1
- classiq/model_expansions/evaluators/parameter_types.py +72 -16
- classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
- classiq/model_expansions/expression_evaluator.py +3 -12
- classiq/model_expansions/function_builder.py +2 -8
- classiq/model_expansions/generative_functions.py +39 -3
- classiq/model_expansions/interpreters/base_interpreter.py +3 -4
- classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +46 -6
- classiq/model_expansions/quantum_operations/emitter.py +41 -0
- classiq/model_expansions/quantum_operations/expression_evaluator.py +4 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -14
- classiq/model_expansions/scope_initialization.py +32 -39
- classiq/model_expansions/transformers/model_renamer.py +13 -4
- classiq/model_expansions/visitors/variable_references.py +8 -4
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/lookup_table.py +58 -0
- classiq/qmod/__init__.py +3 -1
- classiq/qmod/declaration_inferrer.py +55 -25
- 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_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +189 -151
- classiq/qmod/quantum_function.py +3 -4
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +38 -0
- classiq/qmod/utilities.py +38 -1
- {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/METADATA +10 -12
- {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/RECORD +97 -82
- {classiq-0.69.0.dist-info → classiq-0.71.0.dist-info}/WHEEL +1 -1
- /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
- /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -3,15 +3,21 @@ from collections.abc import Sequence
|
|
3
3
|
from dataclasses import dataclass, field
|
4
4
|
from typing import TYPE_CHECKING
|
5
5
|
|
6
|
+
from typing_extensions import Self
|
7
|
+
|
6
8
|
from classiq.interface.enum_utils import StrEnum
|
7
9
|
from classiq.interface.exceptions import (
|
8
10
|
ClassiqExpansionError,
|
9
11
|
ClassiqInternalExpansionError,
|
10
12
|
)
|
11
13
|
from classiq.interface.generator.expressions.expression import Expression
|
14
|
+
from classiq.interface.generator.functions.classical_type import ClassicalType
|
12
15
|
from classiq.interface.generator.functions.port_declaration import (
|
13
16
|
PortDeclarationDirection,
|
14
17
|
)
|
18
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
19
|
+
ClassicalParameterDeclaration,
|
20
|
+
)
|
15
21
|
from classiq.interface.model.handle_binding import (
|
16
22
|
HandleBinding,
|
17
23
|
NestedHandleBinding,
|
@@ -19,6 +25,7 @@ from classiq.interface.model.handle_binding import (
|
|
19
25
|
)
|
20
26
|
from classiq.interface.model.port_declaration import PortDeclaration
|
21
27
|
from classiq.interface.model.quantum_function_call import ArgValue
|
28
|
+
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
22
29
|
from classiq.interface.model.quantum_type import QuantumBitvector, QuantumType
|
23
30
|
from classiq.interface.model.variable_declaration_statement import (
|
24
31
|
VariableDeclarationStatement,
|
@@ -28,7 +35,11 @@ from classiq.model_expansions.capturing.mangling_utils import (
|
|
28
35
|
demangle_handle,
|
29
36
|
mangle_captured_var_name,
|
30
37
|
)
|
31
|
-
from classiq.model_expansions.transformers.
|
38
|
+
from classiq.model_expansions.transformers.model_renamer import (
|
39
|
+
HandleRenaming,
|
40
|
+
SymbolRenaming,
|
41
|
+
)
|
42
|
+
from classiq.model_expansions.transformers.var_splitter import SymbolPart
|
32
43
|
|
33
44
|
if TYPE_CHECKING:
|
34
45
|
from classiq.model_expansions.closure import FunctionClosure
|
@@ -72,12 +83,29 @@ class PortDirection(StrEnum):
|
|
72
83
|
|
73
84
|
|
74
85
|
@dataclass(frozen=True)
|
75
|
-
class
|
86
|
+
class _Captured:
|
87
|
+
defining_function: "FunctionClosure"
|
88
|
+
is_propagated: bool
|
89
|
+
|
90
|
+
def change_defining_function(
|
91
|
+
self, new_defining_function: "FunctionClosure"
|
92
|
+
) -> Self:
|
93
|
+
return dataclasses.replace(self, defining_function=new_defining_function)
|
94
|
+
|
95
|
+
def set_propagated(self) -> Self:
|
96
|
+
return dataclasses.replace(self, is_propagated=True)
|
97
|
+
|
98
|
+
def update_propagation(self, other_captured_handle: Self) -> Self:
|
99
|
+
if self.is_propagated and not other_captured_handle.is_propagated:
|
100
|
+
return dataclasses.replace(self, is_propagated=False)
|
101
|
+
return self
|
102
|
+
|
103
|
+
|
104
|
+
@dataclass(frozen=True)
|
105
|
+
class _CapturedHandle(_Captured):
|
76
106
|
handle: HandleBinding
|
77
107
|
quantum_type: QuantumType
|
78
|
-
defining_function: "FunctionClosure"
|
79
108
|
direction: PortDirection
|
80
|
-
is_propagated: bool
|
81
109
|
|
82
110
|
@property
|
83
111
|
def mangled_name(self) -> str:
|
@@ -103,27 +131,33 @@ class _CapturedHandle:
|
|
103
131
|
def change_direction(self, new_direction: PortDirection) -> "_CapturedHandle":
|
104
132
|
return dataclasses.replace(self, direction=new_direction)
|
105
133
|
|
106
|
-
def change_defining_function(
|
107
|
-
self, new_defining_function: "FunctionClosure"
|
108
|
-
) -> "_CapturedHandle":
|
109
|
-
return dataclasses.replace(self, defining_function=new_defining_function)
|
110
|
-
|
111
|
-
def set_propagated(self) -> "_CapturedHandle":
|
112
|
-
return dataclasses.replace(self, is_propagated=True)
|
113
|
-
|
114
|
-
def update_propagation(
|
115
|
-
self, other_captured_handle: "_CapturedHandle"
|
116
|
-
) -> "_CapturedHandle":
|
117
|
-
if self.is_propagated and not other_captured_handle.is_propagated:
|
118
|
-
return dataclasses.replace(self, is_propagated=False)
|
119
|
-
return self
|
120
|
-
|
121
134
|
def set_symbol(
|
122
135
|
self, handle: HandleBinding, quantum_type: QuantumType
|
123
136
|
) -> "_CapturedHandle":
|
124
137
|
return dataclasses.replace(self, handle=handle, quantum_type=quantum_type)
|
125
138
|
|
126
139
|
|
140
|
+
@dataclass(frozen=True)
|
141
|
+
class _CapturedClassicalVar(_Captured):
|
142
|
+
name: str
|
143
|
+
classical_type: ClassicalType
|
144
|
+
defining_function: "FunctionClosure"
|
145
|
+
|
146
|
+
@property
|
147
|
+
def mangled_name(self) -> str:
|
148
|
+
return mangle_captured_var_name(
|
149
|
+
self.name,
|
150
|
+
self.defining_function.name,
|
151
|
+
self.defining_function.depth,
|
152
|
+
)
|
153
|
+
|
154
|
+
@property
|
155
|
+
def parameter_declaration(self) -> ClassicalParameterDeclaration:
|
156
|
+
return ClassicalParameterDeclaration(
|
157
|
+
name=self.mangled_name, classical_type=self.classical_type
|
158
|
+
)
|
159
|
+
|
160
|
+
|
127
161
|
HandleState = tuple[str, "FunctionClosure", bool]
|
128
162
|
|
129
163
|
|
@@ -131,6 +165,7 @@ HandleState = tuple[str, "FunctionClosure", bool]
|
|
131
165
|
class CapturedVars:
|
132
166
|
_captured_handles: list[_CapturedHandle] = field(default_factory=list)
|
133
167
|
_handle_states: list[HandleState] = field(default_factory=list)
|
168
|
+
_captured_classical_vars: list[_CapturedClassicalVar] = field(default_factory=list)
|
134
169
|
|
135
170
|
def capture_handle(
|
136
171
|
self,
|
@@ -332,16 +367,48 @@ class CapturedVars:
|
|
332
367
|
)
|
333
368
|
return merged_handle, merged_quantum_type
|
334
369
|
|
370
|
+
def capture_classical_var(
|
371
|
+
self,
|
372
|
+
var_name: str,
|
373
|
+
var_type: ClassicalType,
|
374
|
+
defining_function: "FunctionClosure",
|
375
|
+
) -> None:
|
376
|
+
self._capture_classical_var(
|
377
|
+
_CapturedClassicalVar(
|
378
|
+
name=var_name,
|
379
|
+
classical_type=var_type,
|
380
|
+
defining_function=defining_function,
|
381
|
+
is_propagated=False,
|
382
|
+
)
|
383
|
+
)
|
384
|
+
|
385
|
+
def _capture_classical_var(
|
386
|
+
self, captured_classical_var: _CapturedClassicalVar
|
387
|
+
) -> None:
|
388
|
+
for existing_captured_classical_var in self._captured_classical_vars:
|
389
|
+
if (
|
390
|
+
existing_captured_classical_var.name == captured_classical_var.name
|
391
|
+
and _same_closure(
|
392
|
+
existing_captured_classical_var.defining_function,
|
393
|
+
captured_classical_var.defining_function,
|
394
|
+
)
|
395
|
+
):
|
396
|
+
return
|
397
|
+
self._captured_classical_vars.append(captured_classical_var)
|
398
|
+
|
335
399
|
def update(self, other_captured_vars: "CapturedVars") -> None:
|
336
400
|
for captured_handle in other_captured_vars._captured_handles:
|
337
401
|
self._capture_handle(captured_handle)
|
402
|
+
for captured_classical_var in other_captured_vars._captured_classical_vars:
|
403
|
+
self._capture_classical_var(captured_classical_var)
|
338
404
|
|
339
405
|
def negate(self) -> "CapturedVars":
|
340
406
|
return CapturedVars(
|
341
407
|
_captured_handles=[
|
342
408
|
captured_handle.change_direction(captured_handle.direction.negate())
|
343
409
|
for captured_handle in self._captured_handles
|
344
|
-
]
|
410
|
+
],
|
411
|
+
_captured_classical_vars=self._captured_classical_vars,
|
345
412
|
)
|
346
413
|
|
347
414
|
def filter_vars(self, current_function: "FunctionClosure") -> "CapturedVars":
|
@@ -352,7 +419,14 @@ class CapturedVars:
|
|
352
419
|
if not _same_closure(
|
353
420
|
captured_handle.defining_function, current_function
|
354
421
|
)
|
355
|
-
]
|
422
|
+
],
|
423
|
+
_captured_classical_vars=[
|
424
|
+
captured_classical_var
|
425
|
+
for captured_classical_var in self._captured_classical_vars
|
426
|
+
if not _same_closure(
|
427
|
+
captured_classical_var.defining_function, current_function
|
428
|
+
)
|
429
|
+
],
|
356
430
|
)
|
357
431
|
|
358
432
|
def filter_var_decls(
|
@@ -367,7 +441,8 @@ class CapturedVars:
|
|
367
441
|
current_declared_vars is not None
|
368
442
|
and captured_handle.handle.name not in current_declared_vars
|
369
443
|
)
|
370
|
-
]
|
444
|
+
],
|
445
|
+
_captured_classical_vars=self._captured_classical_vars,
|
371
446
|
)
|
372
447
|
|
373
448
|
def set_propagated(self) -> "CapturedVars":
|
@@ -375,16 +450,37 @@ class CapturedVars:
|
|
375
450
|
_captured_handles=[
|
376
451
|
captured_handle.set_propagated()
|
377
452
|
for captured_handle in self._captured_handles
|
378
|
-
]
|
453
|
+
],
|
454
|
+
_captured_classical_vars=[
|
455
|
+
captured_classical_var.set_propagated()
|
456
|
+
for captured_classical_var in self._captured_classical_vars
|
457
|
+
],
|
379
458
|
)
|
380
459
|
|
381
|
-
def
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
460
|
+
def get_captured_parameters(self) -> list[PositionalArg]:
|
461
|
+
decls: list[PositionalArg]
|
462
|
+
decls = [
|
463
|
+
captured_classical_var.parameter_declaration
|
464
|
+
for captured_classical_var in self._captured_classical_vars
|
465
|
+
]
|
466
|
+
decls += [captured_handle.port for captured_handle in self._captured_handles]
|
467
|
+
return decls
|
468
|
+
|
469
|
+
def get_captured_args(self, current_function: "FunctionClosure") -> list[ArgValue]:
|
470
|
+
args: list[ArgValue]
|
471
|
+
args = [
|
472
|
+
Expression(
|
473
|
+
expr=(
|
474
|
+
captured_classical_var.name
|
475
|
+
if _same_closure(
|
476
|
+
current_function, captured_classical_var.defining_function
|
477
|
+
)
|
478
|
+
else captured_classical_var.mangled_name
|
479
|
+
)
|
480
|
+
)
|
481
|
+
for captured_classical_var in self._captured_classical_vars
|
482
|
+
]
|
483
|
+
args += [
|
388
484
|
(
|
389
485
|
captured_handle.handle
|
390
486
|
if _same_closure(current_function, captured_handle.defining_function)
|
@@ -392,9 +488,11 @@ class CapturedVars:
|
|
392
488
|
)
|
393
489
|
for captured_handle in self._captured_handles
|
394
490
|
]
|
491
|
+
return args
|
395
492
|
|
396
|
-
def get_captured_mapping(self) ->
|
397
|
-
|
493
|
+
def get_captured_mapping(self) -> SymbolRenaming:
|
494
|
+
mapping: SymbolRenaming
|
495
|
+
mapping = {
|
398
496
|
captured_handle.handle: [
|
399
497
|
SymbolPart(
|
400
498
|
source_handle=captured_handle.handle,
|
@@ -405,6 +503,17 @@ class CapturedVars:
|
|
405
503
|
for captured_handle in self._captured_handles
|
406
504
|
if not captured_handle.is_propagated
|
407
505
|
}
|
506
|
+
mapping |= {
|
507
|
+
(handle := HandleBinding(name=captured_classical_var.name)): [
|
508
|
+
HandleRenaming(
|
509
|
+
source_handle=handle,
|
510
|
+
target_var_name=captured_classical_var.mangled_name,
|
511
|
+
)
|
512
|
+
]
|
513
|
+
for captured_classical_var in self._captured_classical_vars
|
514
|
+
if not captured_classical_var.is_propagated
|
515
|
+
}
|
516
|
+
return mapping
|
408
517
|
|
409
518
|
def init_var(self, var_name: str, defining_function: "FunctionClosure") -> None:
|
410
519
|
self._handle_states.append((var_name, defining_function, False))
|
@@ -470,6 +579,7 @@ class CapturedVars:
|
|
470
579
|
return CapturedVars(
|
471
580
|
_captured_handles=list(self._captured_handles),
|
472
581
|
_handle_states=list(self._handle_states),
|
582
|
+
_captured_classical_vars=list(self._captured_classical_vars),
|
473
583
|
)
|
474
584
|
|
475
585
|
def set(
|
@@ -492,6 +602,14 @@ class CapturedVars:
|
|
492
602
|
self._handle_states.append((var, target_func, state))
|
493
603
|
else:
|
494
604
|
self._handle_states.append((var, defining_function, state))
|
605
|
+
self._captured_classical_vars = []
|
606
|
+
for captured_classical_var in other._captured_classical_vars:
|
607
|
+
if _same_closure(captured_classical_var.defining_function, source_func):
|
608
|
+
self._captured_classical_vars.append(
|
609
|
+
captured_classical_var.change_defining_function(target_func)
|
610
|
+
)
|
611
|
+
else:
|
612
|
+
self._captured_classical_vars.append(captured_classical_var)
|
495
613
|
|
496
614
|
|
497
615
|
def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") -> bool:
|
@@ -499,11 +617,15 @@ def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") ->
|
|
499
617
|
|
500
618
|
|
501
619
|
def validate_args_are_not_propagated(
|
502
|
-
args: Sequence[ArgValue], captured_vars: Sequence[
|
620
|
+
args: Sequence[ArgValue], captured_vars: Sequence[ArgValue]
|
503
621
|
) -> None:
|
504
622
|
if not captured_vars:
|
505
623
|
return
|
506
|
-
captured_handles = {
|
624
|
+
captured_handles = {
|
625
|
+
demangle_handle(handle)
|
626
|
+
for handle in captured_vars
|
627
|
+
if isinstance(handle, HandleBinding)
|
628
|
+
}
|
507
629
|
arg_handles = {
|
508
630
|
demangle_handle(arg) for arg in args if isinstance(arg, HandleBinding)
|
509
631
|
}
|
@@ -3,10 +3,12 @@ from enum import Enum
|
|
3
3
|
from typing import Any
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqExpansionError
|
6
|
-
from classiq.interface.generator.expressions.
|
7
|
-
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
6
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
8
7
|
QmodStructInstance,
|
9
8
|
)
|
9
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
10
|
+
QmodSizedProxy,
|
11
|
+
)
|
10
12
|
from classiq.interface.generator.functions.classical_type import (
|
11
13
|
StructMetaType,
|
12
14
|
)
|
@@ -23,13 +23,13 @@ def evaluate_classical_expression(expr: Expression, scope: Scope) -> Evaluated:
|
|
23
23
|
)
|
24
24
|
for name, evaluated in all_symbols
|
25
25
|
if isinstance(evaluated.value, QuantumSymbol)
|
26
|
-
and evaluated.value.quantum_type.
|
26
|
+
and evaluated.value.quantum_type.is_evaluated
|
27
27
|
}
|
28
28
|
uninitialized_locals = {
|
29
29
|
name
|
30
30
|
for name, evaluated in all_symbols
|
31
31
|
if isinstance(evaluated.value, QuantumSymbol)
|
32
|
-
and not evaluated.value.quantum_type.
|
32
|
+
and not evaluated.value.quantum_type.is_evaluated
|
33
33
|
}
|
34
34
|
|
35
35
|
ret = evaluate(expr, locals_dict, uninitialized_locals)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
from typing import Any, Union
|
2
|
+
|
3
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
4
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
5
|
+
ClassicalArrayProxy,
|
6
|
+
)
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
8
|
+
ClassicalStructProxy,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
11
|
+
QmodStructInstance,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.functions.classical_type import (
|
14
|
+
ClassicalArray,
|
15
|
+
ClassicalList,
|
16
|
+
ClassicalType,
|
17
|
+
)
|
18
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
19
|
+
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
20
|
+
|
21
|
+
|
22
|
+
def infer_classical_type(val: Any, classical_type: ClassicalType) -> ClassicalType:
|
23
|
+
if isinstance(classical_type, TypeName):
|
24
|
+
return _infer_classical_struct_type(val, classical_type)
|
25
|
+
if isinstance(classical_type, (ClassicalArray, ClassicalList)):
|
26
|
+
return _infer_classical_array_type(val, classical_type)
|
27
|
+
return classical_type
|
28
|
+
|
29
|
+
|
30
|
+
def _infer_classical_struct_type(val: Any, classical_type: TypeName) -> ClassicalType:
|
31
|
+
if not isinstance(val, (QmodStructInstance, ClassicalStructProxy)):
|
32
|
+
return classical_type
|
33
|
+
decl = val.struct_declaration
|
34
|
+
new_fields = {
|
35
|
+
field_name: infer_classical_type(field_val, field_type)
|
36
|
+
for (field_name, field_val), field_type in zip(
|
37
|
+
val.fields.items(),
|
38
|
+
decl.variables.values(),
|
39
|
+
strict=True,
|
40
|
+
)
|
41
|
+
}
|
42
|
+
new_classical_type = TypeName(name=decl.name)
|
43
|
+
new_classical_type.set_classical_struct_decl(
|
44
|
+
StructDeclaration(name=decl.name, variables=new_fields)
|
45
|
+
)
|
46
|
+
return new_classical_type
|
47
|
+
|
48
|
+
|
49
|
+
def _infer_classical_array_type(
|
50
|
+
val: Any, classical_type: Union[ClassicalArray, ClassicalList]
|
51
|
+
) -> ClassicalType:
|
52
|
+
if isinstance(val, list):
|
53
|
+
val_length = len(val)
|
54
|
+
elif isinstance(val, ClassicalArrayProxy):
|
55
|
+
val_length = val.length
|
56
|
+
else:
|
57
|
+
raise ClassiqExpansionError(f"Array expected, got {str(val)!r}")
|
58
|
+
if isinstance(classical_type, ClassicalArray) and val_length != classical_type.size:
|
59
|
+
raise ClassiqExpansionError(
|
60
|
+
f"Type mismatch: Argument has {val_length} items but "
|
61
|
+
f"{classical_type.size} expected"
|
62
|
+
)
|
63
|
+
return ClassicalArray(
|
64
|
+
element_type=(
|
65
|
+
infer_classical_type(val[0], classical_type.element_type)
|
66
|
+
if val_length > 0
|
67
|
+
else classical_type.element_type
|
68
|
+
),
|
69
|
+
size=val_length,
|
70
|
+
)
|
@@ -8,7 +8,7 @@ from classiq.interface.generator.arith.argument_utils import (
|
|
8
8
|
unsigned_integer_interpretation,
|
9
9
|
)
|
10
10
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
11
|
-
from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
|
11
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
12
12
|
QmodQNumProxy,
|
13
13
|
QmodQScalarProxy,
|
14
14
|
QmodSizedProxy,
|
@@ -1,9 +1,10 @@
|
|
1
|
-
from typing import Union
|
1
|
+
from typing import TypeVar, Union
|
2
2
|
|
3
3
|
from classiq.interface.exceptions import (
|
4
4
|
ClassiqExpansionError,
|
5
5
|
ClassiqInternalExpansionError,
|
6
6
|
)
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
8
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
8
9
|
from classiq.interface.generator.functions.port_declaration import (
|
9
10
|
PortDeclarationDirection,
|
@@ -11,6 +12,9 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
11
12
|
from classiq.interface.generator.functions.type_name import (
|
12
13
|
TypeName,
|
13
14
|
)
|
15
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
16
|
+
ClassicalParameterDeclaration,
|
17
|
+
)
|
14
18
|
from classiq.interface.model.port_declaration import PortDeclaration
|
15
19
|
from classiq.interface.model.quantum_function_declaration import (
|
16
20
|
PositionalArg,
|
@@ -28,11 +32,12 @@ from classiq.model_expansions.evaluators.arg_type_match import check_type_match
|
|
28
32
|
from classiq.model_expansions.evaluators.classical_expression import (
|
29
33
|
evaluate_classical_expression,
|
30
34
|
)
|
35
|
+
from classiq.model_expansions.evaluators.classical_type_inference import (
|
36
|
+
infer_classical_type,
|
37
|
+
)
|
31
38
|
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
32
39
|
copy_type_information,
|
33
40
|
set_element_type,
|
34
|
-
set_fraction_digits,
|
35
|
-
set_is_signed,
|
36
41
|
set_length,
|
37
42
|
set_size,
|
38
43
|
)
|
@@ -127,6 +132,14 @@ def _cast(
|
|
127
132
|
def _evaluate_type_from_arg(
|
128
133
|
parameter: PositionalArg, argument: Evaluated, inner_scope: Scope
|
129
134
|
) -> PositionalArg:
|
135
|
+
if isinstance(parameter, ClassicalParameterDeclaration):
|
136
|
+
return ClassicalParameterDeclaration(
|
137
|
+
name=parameter.name,
|
138
|
+
classical_type=infer_classical_type(
|
139
|
+
argument.value, parameter.classical_type
|
140
|
+
),
|
141
|
+
)
|
142
|
+
|
130
143
|
if not isinstance(parameter, PortDeclaration):
|
131
144
|
return parameter
|
132
145
|
|
@@ -162,9 +175,14 @@ def _evaluate_qarray_in_quantum_symbol(
|
|
162
175
|
)
|
163
176
|
set_element_type(type_to_update, new_element_type)
|
164
177
|
if type_to_update.length is not None:
|
165
|
-
new_length =
|
166
|
-
type_to_update.length,
|
167
|
-
|
178
|
+
new_length = _eval_expr(
|
179
|
+
type_to_update.length,
|
180
|
+
scope,
|
181
|
+
int,
|
182
|
+
type_to_update.type_name,
|
183
|
+
"length",
|
184
|
+
param_name,
|
185
|
+
)
|
168
186
|
set_length(type_to_update, new_length)
|
169
187
|
return type_to_update
|
170
188
|
|
@@ -173,23 +191,61 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
173
191
|
type_to_update: QuantumNumeric, scope: Scope, param_name: str
|
174
192
|
) -> QuantumNumeric:
|
175
193
|
if type_to_update.is_signed is not None:
|
176
|
-
new_is_sign =
|
177
|
-
type_to_update.is_signed,
|
178
|
-
|
179
|
-
|
194
|
+
new_is_sign = _eval_expr(
|
195
|
+
type_to_update.is_signed,
|
196
|
+
scope,
|
197
|
+
bool,
|
198
|
+
type_to_update.type_name,
|
199
|
+
"sign",
|
200
|
+
param_name,
|
201
|
+
)
|
202
|
+
type_to_update.is_signed = Expression(expr=str(new_is_sign))
|
180
203
|
if type_to_update.fraction_digits is not None:
|
181
|
-
new_fraction_digits =
|
182
|
-
type_to_update.fraction_digits,
|
183
|
-
|
184
|
-
|
204
|
+
new_fraction_digits = _eval_expr(
|
205
|
+
type_to_update.fraction_digits,
|
206
|
+
scope,
|
207
|
+
int,
|
208
|
+
type_to_update.type_name,
|
209
|
+
"fraction digits",
|
210
|
+
param_name,
|
211
|
+
)
|
212
|
+
type_to_update.fraction_digits = Expression(expr=str(new_fraction_digits))
|
185
213
|
if type_to_update.size is not None:
|
186
|
-
new_size =
|
187
|
-
|
214
|
+
new_size = _eval_expr(
|
215
|
+
type_to_update.size,
|
216
|
+
scope,
|
217
|
+
int,
|
218
|
+
type_to_update.type_name,
|
219
|
+
"size",
|
220
|
+
param_name,
|
188
221
|
)
|
189
222
|
set_size(type_to_update, new_size, param_name)
|
190
223
|
return type_to_update
|
191
224
|
|
192
225
|
|
226
|
+
_EXPR_TYPE = TypeVar("_EXPR_TYPE")
|
227
|
+
|
228
|
+
|
229
|
+
def _eval_expr(
|
230
|
+
expression: Expression,
|
231
|
+
scope: Scope,
|
232
|
+
expected_type: type[_EXPR_TYPE],
|
233
|
+
type_name: str,
|
234
|
+
attr_name: str,
|
235
|
+
param_name: str,
|
236
|
+
) -> _EXPR_TYPE:
|
237
|
+
val = evaluate_classical_expression(expression, scope).value
|
238
|
+
if expected_type is int and isinstance(val, float):
|
239
|
+
val = int(val)
|
240
|
+
if not isinstance(val, expected_type):
|
241
|
+
raise ClassiqExpansionError(
|
242
|
+
f"When inferring the type of parameter {param_name!r}: "
|
243
|
+
f"{type_name} {attr_name} must be {expected_type.__name__}, got "
|
244
|
+
f"{str(val)!r}"
|
245
|
+
)
|
246
|
+
return val
|
247
|
+
|
248
|
+
|
193
249
|
def _evaluate_qstruct_in_quantum_symbol(
|
194
250
|
type_to_update: TypeName, scope: Scope, param_name: str
|
195
251
|
) -> TypeName:
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from classiq.interface.exceptions import (
|
5
4
|
ClassiqExpansionError,
|
@@ -33,12 +32,11 @@ def copy_type_information(
|
|
33
32
|
if isinstance(to_type, QuantumBit):
|
34
33
|
set_size(to_type, from_type.size_in_bits, to_param_name)
|
35
34
|
elif isinstance(to_type, QuantumNumeric):
|
36
|
-
|
37
|
-
|
38
|
-
to_type
|
39
|
-
|
40
|
-
|
41
|
-
)
|
35
|
+
if to_type.size is None and isinstance(from_type, QuantumNumeric):
|
36
|
+
to_type.is_signed = Expression(expr=str(from_type.sign_value))
|
37
|
+
to_type.fraction_digits = Expression(
|
38
|
+
expr=str(from_type.fraction_digits_value)
|
39
|
+
)
|
42
40
|
set_size(to_type, from_type.size_in_bits, to_param_name)
|
43
41
|
elif isinstance(to_type, QuantumBitvector):
|
44
42
|
if isinstance(from_type, QuantumBitvector) and type( # noqa: E721
|
@@ -73,8 +71,8 @@ def set_size(quantum_type: QuantumType, size: int, param_name: str) -> None:
|
|
73
71
|
if isinstance(quantum_type, QuantumNumeric):
|
74
72
|
quantum_type.size = Expression(expr=str(size))
|
75
73
|
if not quantum_type.has_sign or not quantum_type.has_fraction_digits:
|
76
|
-
|
77
|
-
|
74
|
+
quantum_type.is_signed = Expression(expr="False")
|
75
|
+
quantum_type.fraction_digits = Expression(expr="0")
|
78
76
|
elif isinstance(quantum_type, QuantumBitvector):
|
79
77
|
if quantum_type.has_length:
|
80
78
|
if size % quantum_type.length_value != 0:
|
@@ -107,54 +105,6 @@ def set_size(quantum_type: QuantumType, size: int, param_name: str) -> None:
|
|
107
105
|
set_size(fields_without_size[0], size - predetermined_size_part, param_name)
|
108
106
|
|
109
107
|
|
110
|
-
def set_fraction_digits(
|
111
|
-
quantum_numeric: QuantumNumeric, fraction_digits: Optional[int], param_name: str
|
112
|
-
) -> None:
|
113
|
-
if fraction_digits is not None and fraction_digits < 0:
|
114
|
-
raise ClassiqExpansionError(
|
115
|
-
f"Number of fraction digits for {param_name!r} was deduced to be negative: "
|
116
|
-
f"{fraction_digits!r}"
|
117
|
-
)
|
118
|
-
|
119
|
-
if (
|
120
|
-
fraction_digits is not None
|
121
|
-
and quantum_numeric.fraction_digits is not None
|
122
|
-
and quantum_numeric.fraction_digits.is_evaluated()
|
123
|
-
and quantum_numeric.fraction_digits_value != fraction_digits
|
124
|
-
):
|
125
|
-
raise ClassiqExpansionError(
|
126
|
-
f"Fraction digits mismatch for variable {param_name!r} between declared "
|
127
|
-
f"fraction digits {quantum_numeric.fraction_digits_value!r} and assigned fraction "
|
128
|
-
f"digits {fraction_digits!r}"
|
129
|
-
)
|
130
|
-
|
131
|
-
if not (
|
132
|
-
quantum_numeric.fraction_digits is not None
|
133
|
-
and quantum_numeric.fraction_digits.is_evaluated()
|
134
|
-
):
|
135
|
-
quantum_numeric.fraction_digits = Expression(expr=str(fraction_digits or 0))
|
136
|
-
|
137
|
-
|
138
|
-
def set_is_signed(
|
139
|
-
quantum_numeric: QuantumNumeric, is_signed: Optional[bool], param_name: str
|
140
|
-
) -> None:
|
141
|
-
if (
|
142
|
-
is_signed is not None
|
143
|
-
and quantum_numeric.is_signed is not None
|
144
|
-
and quantum_numeric.is_signed.is_evaluated()
|
145
|
-
and quantum_numeric.sign_value != is_signed
|
146
|
-
):
|
147
|
-
raise ClassiqExpansionError(
|
148
|
-
f"Sign mismatch for variable {param_name!r} between declared sign {quantum_numeric.sign_value!r} and assigned sign {is_signed!r}"
|
149
|
-
)
|
150
|
-
|
151
|
-
if not (
|
152
|
-
quantum_numeric.is_signed is not None
|
153
|
-
and quantum_numeric.is_signed.is_evaluated()
|
154
|
-
):
|
155
|
-
quantum_numeric.is_signed = Expression(expr=str(is_signed or False))
|
156
|
-
|
157
|
-
|
158
108
|
def set_element_type(
|
159
109
|
quantum_array: QuantumBitvector, element_type: ConcreteQuantumType
|
160
110
|
) -> None:
|