classiq 0.76.0__py3-none-any.whl → 0.78.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/applications/chemistry/chemistry_model_constructor.py +7 -6
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +9 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -3
- classiq/applications/iqae/__init__.py +0 -0
- classiq/applications/iqae/iqae.py +207 -0
- classiq/execution/__init__.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/applications/iqae/__init__.py +0 -0
- classiq/interface/applications/iqae/generic_iqae.py +222 -0
- classiq/interface/applications/iqae/iqae_result.py +45 -0
- classiq/interface/debug_info/debug_info.py +3 -0
- classiq/interface/executor/execution_result.py +1 -1
- classiq/interface/executor/user_budget.py +1 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +9 -3
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +6 -15
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +14 -5
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +5 -3
- classiq/interface/generator/generated_circuit_data.py +18 -7
- classiq/interface/ide/visual_model.py +2 -0
- classiq/interface/model/handle_binding.py +8 -0
- classiq/interface/model/model.py +3 -6
- classiq/interface/model/quantum_function_call.py +31 -1
- classiq/interface/model/quantum_statement.py +14 -1
- classiq/interface/source_reference.py +7 -2
- classiq/model_expansions/capturing/captured_vars.py +16 -6
- classiq/model_expansions/closure.py +1 -58
- classiq/model_expansions/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +4 -5
- classiq/model_expansions/evaluators/classical_expression.py +9 -9
- classiq/model_expansions/evaluators/parameter_types.py +19 -11
- classiq/model_expansions/expression_evaluator.py +20 -11
- classiq/model_expansions/generative_functions.py +1 -1
- classiq/model_expansions/interpreters/base_interpreter.py +27 -15
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +0 -16
- classiq/model_expansions/interpreters/generative_interpreter.py +4 -4
- classiq/model_expansions/quantum_operations/allocate.py +2 -2
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +3 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +91 -42
- classiq/model_expansions/quantum_operations/emitter.py +7 -7
- classiq/model_expansions/quantum_operations/function_calls_cache.py +84 -0
- classiq/model_expansions/scope.py +73 -13
- classiq/model_expansions/transformers/model_renamer.py +2 -2
- classiq/model_expansions/transformers/type_qualifier_inference.py +183 -0
- classiq/model_expansions/utils/text_utils.py +4 -2
- classiq/model_expansions/visitors/symbolic_param_inference.py +4 -15
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.py +1 -1
- classiq/qmod/builtins/classical_execution_primitives.py +1 -1
- classiq/qmod/create_model_function.py +21 -3
- classiq/qmod/global_declarative_switch.py +19 -0
- classiq/qmod/native/pretty_printer.py +4 -0
- classiq/qmod/pretty_print/pretty_printer.py +4 -0
- classiq/qmod/qfunc.py +31 -23
- classiq/qmod/qmod_variable.py +7 -4
- classiq/qmod/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +26 -19
- classiq/qmod/utilities.py +4 -0
- classiq/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +7 -6
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/METADATA +1 -1
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/RECORD +62 -55
- classiq/interface/executor/iqae_result.py +0 -17
- {classiq-0.76.0.dist-info → classiq-0.78.0.dist-info}/WHEEL +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import TYPE_CHECKING, Any, Union
|
3
3
|
|
4
|
-
|
4
|
+
import sympy
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqValueError
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
@@ -28,22 +28,20 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
28
28
|
self,
|
29
29
|
handle: HandleBinding,
|
30
30
|
element_type: "QuantumType",
|
31
|
-
element_size: int,
|
32
|
-
length: int,
|
31
|
+
element_size: Union[int, sympy.Basic],
|
32
|
+
length: Union[int, sympy.Basic],
|
33
33
|
) -> None:
|
34
34
|
super().__init__(handle, element_size * length)
|
35
35
|
self._length = length
|
36
36
|
self._element_type = element_type
|
37
37
|
self._element_size = element_size
|
38
38
|
|
39
|
-
def __getitem__(self, key:
|
39
|
+
def __getitem__(self, key: Any) -> "QmodSizedProxy":
|
40
40
|
return (
|
41
41
|
self._get_slice(key) if isinstance(key, slice) else self._get_subscript(key)
|
42
42
|
)
|
43
43
|
|
44
|
-
def _get_subscript(self, index:
|
45
|
-
if isinstance(index, Integer):
|
46
|
-
index = int(index)
|
44
|
+
def _get_subscript(self, index: Any) -> "QmodSizedProxy":
|
47
45
|
return self._element_type.get_proxy(
|
48
46
|
SubscriptHandleBinding(
|
49
47
|
base_handle=self.handle,
|
@@ -54,13 +52,6 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
54
52
|
def _get_slice(self, slice_: slice) -> "QmodSizedProxy":
|
55
53
|
if slice_.step is not None:
|
56
54
|
raise ClassiqValueError(ILLEGAL_SLICING_STEP_MSG)
|
57
|
-
if isinstance(slice_.start, Integer):
|
58
|
-
slice_ = slice(int(slice_.start), slice_.stop)
|
59
|
-
if isinstance(slice_.stop, Integer):
|
60
|
-
slice_ = slice(slice_.start, int(slice_.stop))
|
61
|
-
if not isinstance(slice_.start, int) or not isinstance(slice_.stop, int):
|
62
|
-
raise ClassiqValueError(ILLEGAL_SLICE_MSG)
|
63
|
-
|
64
55
|
return QmodQArrayProxy(
|
65
56
|
SlicedHandleBinding(
|
66
57
|
base_handle=self.handle,
|
@@ -77,7 +68,7 @@ class QmodQArrayProxy(NonSymbolicExpr, QmodSizedProxy):
|
|
77
68
|
return "Quantum array"
|
78
69
|
|
79
70
|
@property
|
80
|
-
def len(self) -> int:
|
71
|
+
def len(self) -> Union[int, sympy.Basic]:
|
81
72
|
return self._length
|
82
73
|
|
83
74
|
@property
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import Any, Optional
|
2
|
+
from typing import Any, Optional, Union
|
3
3
|
|
4
|
+
import sympy
|
4
5
|
from sympy import Symbol
|
5
6
|
from typing_extensions import Self
|
6
7
|
|
@@ -36,10 +37,18 @@ class QmodQBitProxy(QmodQScalarProxy):
|
|
36
37
|
|
37
38
|
class QmodQNumProxy(QmodQScalarProxy):
|
38
39
|
def __init__(
|
39
|
-
self,
|
40
|
+
self,
|
41
|
+
handle: HandleBinding,
|
42
|
+
size: Union[int, sympy.Basic],
|
43
|
+
fraction_digits: Union[int, sympy.Basic],
|
44
|
+
is_signed: Union[bool, sympy.Basic],
|
40
45
|
) -> None:
|
41
46
|
super().__init__(handle, size)
|
42
|
-
if
|
47
|
+
if (
|
48
|
+
isinstance(fraction_digits, int)
|
49
|
+
and isinstance(size, int)
|
50
|
+
and fraction_digits > size
|
51
|
+
):
|
43
52
|
raise ClassiqValueError(
|
44
53
|
f"Quantum numeric of size {size} cannot have {fraction_digits} "
|
45
54
|
f"fraction digits"
|
@@ -52,11 +61,11 @@ class QmodQNumProxy(QmodQScalarProxy):
|
|
52
61
|
return "Quantum numeric"
|
53
62
|
|
54
63
|
@property
|
55
|
-
def fraction_digits(self) -> int:
|
64
|
+
def fraction_digits(self) -> Union[int, sympy.Basic]:
|
56
65
|
return self._fraction_digits
|
57
66
|
|
58
67
|
@property
|
59
|
-
def is_signed(self) -> bool:
|
68
|
+
def is_signed(self) -> Union[bool, sympy.Basic]:
|
60
69
|
return self._is_signed
|
61
70
|
|
62
71
|
@property
|
@@ -1,17 +1,19 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import TYPE_CHECKING, Any
|
2
|
+
from typing import TYPE_CHECKING, Any, Union
|
3
|
+
|
4
|
+
import sympy
|
3
5
|
|
4
6
|
if TYPE_CHECKING:
|
5
7
|
from classiq.interface.model.handle_binding import HandleBinding
|
6
8
|
|
7
9
|
|
8
10
|
class QmodSizedProxy:
|
9
|
-
def __init__(self, handle: "HandleBinding", size: int) -> None:
|
11
|
+
def __init__(self, handle: "HandleBinding", size: Union[int, sympy.Basic]) -> None:
|
10
12
|
self._handle = handle
|
11
13
|
self._size = size
|
12
14
|
|
13
15
|
@property
|
14
|
-
def size(self) -> int:
|
16
|
+
def size(self) -> Union[int, sympy.Basic]:
|
15
17
|
return self._size
|
16
18
|
|
17
19
|
def __str__(self) -> str:
|
@@ -145,6 +145,8 @@ class StatementType(StrEnum):
|
|
145
145
|
POWER = "power"
|
146
146
|
INVERT = "invert"
|
147
147
|
WITHIN_APPLY = "within apply"
|
148
|
+
WITHIN = "within"
|
149
|
+
APPLY = "apply"
|
148
150
|
ASSIGN = "assign"
|
149
151
|
ASSIGN_AMPLITUDE = "assign amplitude"
|
150
152
|
PHASE = "phase"
|
@@ -161,6 +163,9 @@ STATEMENTS_NAME: dict[str, StatementType] = {
|
|
161
163
|
"Power": StatementType.POWER,
|
162
164
|
"Invert": StatementType.INVERT,
|
163
165
|
"WithinApply": StatementType.WITHIN_APPLY,
|
166
|
+
"Compute": StatementType.WITHIN,
|
167
|
+
"Action": StatementType.APPLY,
|
168
|
+
"Uncompute": StatementType.WITHIN,
|
164
169
|
ArithmeticOperationKind.Assignment.value: StatementType.ASSIGN,
|
165
170
|
"InplaceBinaryOperation": StatementType.ASSIGN,
|
166
171
|
"AmplitudeLoadingOperation": StatementType.ASSIGN_AMPLITUDE,
|
@@ -176,6 +181,7 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
176
181
|
children: list["FunctionDebugInfoInterface"]
|
177
182
|
relative_qubits: tuple[int, ...]
|
178
183
|
absolute_qubits: Optional[tuple[int, ...]] = Field(default=None)
|
184
|
+
control_variable: Optional[str] = Field(default=None)
|
179
185
|
is_basis_gate: Optional[bool] = Field(default=None)
|
180
186
|
is_inverse: bool = Field(default=False)
|
181
187
|
is_unitary: bool = Field(default=True, exclude=True)
|
@@ -205,14 +211,21 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
205
211
|
|
206
212
|
if isinstance(back_ref, QuantumFunctionCall):
|
207
213
|
name = generate_original_function_name(back_ref.func_name)
|
208
|
-
|
209
|
-
name += f" [{part_match.group(1)}]"
|
210
|
-
return name.removeprefix(ARITH_ENGINE_PREFIX)
|
214
|
+
return self.add_suffix_from_generated_name(generated_name, name)
|
211
215
|
|
212
216
|
statement_kind: str = back_ref.kind
|
213
217
|
if isinstance(back_ref, ArithmeticOperation):
|
214
218
|
statement_kind = back_ref.operation_kind.value
|
215
|
-
return
|
219
|
+
return self.add_suffix_from_generated_name(
|
220
|
+
generated_name, STATEMENTS_NAME[statement_kind]
|
221
|
+
)
|
222
|
+
|
223
|
+
def add_suffix_from_generated_name(self, generated_name: str, name: str) -> str:
|
224
|
+
if part_match := PART_SUFFIX_REGEX.match(generated_name):
|
225
|
+
suffix = f" [{part_match.group(1)}]"
|
226
|
+
else:
|
227
|
+
suffix = ""
|
228
|
+
return f"{name}{suffix}"
|
216
229
|
|
217
230
|
@property
|
218
231
|
def first_back_ref(self) -> Optional[ConcreteQuantumStatement]:
|
@@ -347,9 +360,7 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
347
360
|
if role is RegisterRole.INPUT:
|
348
361
|
return RegisterRole.OUTPUT
|
349
362
|
if role is RegisterRole.EXPLICIT_ZERO_INPUT or role is RegisterRole.ZERO_INPUT:
|
350
|
-
|
351
|
-
return RegisterRole.ZERO_OUTPUT
|
352
|
-
return RegisterRole.OUTPUT
|
363
|
+
return RegisterRole.ZERO_OUTPUT
|
353
364
|
if role is RegisterRole.AUXILIARY:
|
354
365
|
return RegisterRole.AUXILIARY
|
355
366
|
if role is RegisterRole.OUTPUT or role is RegisterRole.GARBAGE_OUTPUT:
|
@@ -15,6 +15,7 @@ from classiq.interface.helpers.versioned_model import VersionedModel
|
|
15
15
|
|
16
16
|
class OperationType(StrEnum):
|
17
17
|
REGULAR = "REGULAR"
|
18
|
+
INVISIBLE = "INVISIBLE"
|
18
19
|
ALLOCATE = "ALLOCATE"
|
19
20
|
FREE = "FREE"
|
20
21
|
BIND = "BIND"
|
@@ -124,6 +125,7 @@ class Operation(pydantic.BaseModel):
|
|
124
125
|
)
|
125
126
|
is_daggered: bool = pydantic.Field(default=False)
|
126
127
|
expanded: bool = pydantic.Field(default=False)
|
128
|
+
show_expanded_label: bool = pydantic.Field(default=False)
|
127
129
|
|
128
130
|
|
129
131
|
class ProgramVisualModel(VersionedModel):
|
@@ -355,3 +355,11 @@ ConcreteHandleBinding = Union[
|
|
355
355
|
SubscriptHandleBinding.model_rebuild()
|
356
356
|
SlicedHandleBinding.model_rebuild()
|
357
357
|
FieldHandleBinding.model_rebuild()
|
358
|
+
|
359
|
+
|
360
|
+
class HandlesList(ASTNode):
|
361
|
+
handles: list["GeneralHandle"]
|
362
|
+
|
363
|
+
|
364
|
+
GeneralHandle = Union[ConcreteHandleBinding, HandlesList]
|
365
|
+
HandlesList.model_rebuild()
|
classiq/interface/model/model.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from collections import Counter
|
2
2
|
from collections.abc import Mapping
|
3
|
-
from typing import Any, Literal, NewType
|
3
|
+
from typing import Any, Literal, NewType
|
4
4
|
|
5
5
|
import pydantic
|
6
6
|
|
@@ -9,7 +9,6 @@ from classiq.interface.debug_info.debug_info import DebugInfoCollection
|
|
9
9
|
from classiq.interface.exceptions import ClassiqValueError
|
10
10
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
11
11
|
from classiq.interface.generator.constant import Constant
|
12
|
-
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
13
12
|
from classiq.interface.generator.functions.port_declaration import (
|
14
13
|
PortDeclarationDirection,
|
15
14
|
)
|
@@ -103,9 +102,6 @@ class Model(VersionedModel, ASTNode):
|
|
103
102
|
functions_compilation_metadata: dict[str, CompilationMetadata] = pydantic.Field(
|
104
103
|
default_factory=dict
|
105
104
|
)
|
106
|
-
execution_parameters: Optional[dict[str, ConcreteClassicalType]] = pydantic.Field(
|
107
|
-
default=None, exclude=True
|
108
|
-
)
|
109
105
|
|
110
106
|
@property
|
111
107
|
def main_func(self) -> NativeFunctionDefinition:
|
@@ -184,11 +180,12 @@ class Model(VersionedModel, ASTNode):
|
|
184
180
|
)
|
185
181
|
return constants
|
186
182
|
|
187
|
-
def
|
183
|
+
def dump_no_metadata(self) -> dict[str, Any]:
|
188
184
|
return self.model_dump(
|
189
185
|
exclude={
|
190
186
|
"constraints",
|
191
187
|
"execution_preferences",
|
192
188
|
"preferences",
|
189
|
+
"functions_compilation_metadata",
|
193
190
|
},
|
194
191
|
)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections.abc import Iterable, Mapping, Sequence
|
2
|
+
from itertools import chain
|
2
3
|
from typing import (
|
3
4
|
Literal,
|
4
5
|
Optional,
|
@@ -15,7 +16,9 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
15
16
|
)
|
16
17
|
from classiq.interface.model.handle_binding import (
|
17
18
|
ConcreteHandleBinding,
|
19
|
+
GeneralHandle,
|
18
20
|
HandleBinding,
|
21
|
+
HandlesList,
|
19
22
|
)
|
20
23
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
21
24
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -31,6 +34,7 @@ ArgValue = Union[
|
|
31
34
|
Expression,
|
32
35
|
QuantumOperand,
|
33
36
|
ConcreteHandleBinding,
|
37
|
+
HandlesList,
|
34
38
|
]
|
35
39
|
|
36
40
|
|
@@ -146,6 +150,26 @@ class QuantumFunctionCall(QuantumOperation):
|
|
146
150
|
)
|
147
151
|
]
|
148
152
|
|
153
|
+
@property
|
154
|
+
def handles_with_directions(
|
155
|
+
self,
|
156
|
+
) -> Iterable[tuple[HandleBinding, PortDeclarationDirection]]:
|
157
|
+
return [(handle, param.direction) for handle, param in self.handles_with_params]
|
158
|
+
|
159
|
+
@property
|
160
|
+
def handles_with_params(
|
161
|
+
self,
|
162
|
+
) -> Iterable[tuple[HandleBinding, AnonPortDeclaration]]:
|
163
|
+
return [
|
164
|
+
(handle, param)
|
165
|
+
for arg, param in zip(
|
166
|
+
self.positional_args, self.func_decl.positional_arg_declarations
|
167
|
+
)
|
168
|
+
if isinstance(param, AnonPortDeclaration)
|
169
|
+
and isinstance(arg, (HandleBinding, HandlesList))
|
170
|
+
for handle in _get_handles(arg)
|
171
|
+
]
|
172
|
+
|
149
173
|
@property
|
150
174
|
def params(self) -> list[Expression]:
|
151
175
|
return [
|
@@ -161,7 +185,7 @@ class QuantumFunctionCall(QuantumOperation):
|
|
161
185
|
return [
|
162
186
|
param
|
163
187
|
for param in self.positional_args
|
164
|
-
if not isinstance(param, (Expression, HandleBinding))
|
188
|
+
if not isinstance(param, (Expression, HandleBinding, HandlesList))
|
165
189
|
]
|
166
190
|
|
167
191
|
@property
|
@@ -224,3 +248,9 @@ class QuantumFunctionCall(QuantumOperation):
|
|
224
248
|
f" for parameter {param_name}" if len(self.positional_args) > 1 else ""
|
225
249
|
)
|
226
250
|
return f"as an argument{param_text} of function {self.func_name!r}"
|
251
|
+
|
252
|
+
|
253
|
+
def _get_handles(var: GeneralHandle) -> Iterable[HandleBinding]:
|
254
|
+
if isinstance(var, HandleBinding):
|
255
|
+
return [var]
|
256
|
+
return chain.from_iterable(_get_handles(item) for item in var.handles)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from collections.abc import Mapping, Sequence
|
1
|
+
from collections.abc import Iterable, Mapping, Sequence
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from typing import Any, Callable, Optional
|
4
4
|
from uuid import UUID, uuid4
|
@@ -9,6 +9,9 @@ from typing_extensions import Self
|
|
9
9
|
|
10
10
|
from classiq.interface.ast_node import ASTNode
|
11
11
|
from classiq.interface.generator.expressions.expression import Expression
|
12
|
+
from classiq.interface.generator.functions.port_declaration import (
|
13
|
+
PortDeclarationDirection,
|
14
|
+
)
|
12
15
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
13
16
|
from classiq.interface.model.handle_binding import (
|
14
17
|
ConcreteHandleBinding,
|
@@ -90,6 +93,16 @@ class QuantumOperation(QuantumStatement):
|
|
90
93
|
def readable_outputs(self) -> Sequence[HandleMetadata]:
|
91
94
|
return [HandleMetadata(handle=handle) for handle in self.outputs]
|
92
95
|
|
96
|
+
@property
|
97
|
+
def handles_with_directions(
|
98
|
+
self,
|
99
|
+
) -> Iterable[tuple[HandleBinding, PortDeclarationDirection]]:
|
100
|
+
return (
|
101
|
+
[(handle, PortDeclarationDirection.Input) for handle in self.inputs]
|
102
|
+
+ [(handle, PortDeclarationDirection.Output) for handle in self.outputs]
|
103
|
+
+ [(handle, PortDeclarationDirection.Inout) for handle in self.inouts]
|
104
|
+
)
|
105
|
+
|
93
106
|
def set_generative_block(self, block_name: str, py_callable: Callable) -> None:
|
94
107
|
self._generative_blocks[block_name] = py_callable
|
95
108
|
|
@@ -33,11 +33,16 @@ class SourceReference(HashablePydanticBaseModel):
|
|
33
33
|
file_name: Optional[str] = pydantic.Field(default=None)
|
34
34
|
|
35
35
|
def __str__(self) -> str:
|
36
|
-
|
36
|
+
return f"{self.file_string()}{self.ref_inside_file()}"
|
37
|
+
|
38
|
+
def file_string(self) -> str:
|
39
|
+
return _prepare_file_string(self.file_name) if self.file_name else ""
|
40
|
+
|
41
|
+
def ref_inside_file(self) -> str:
|
37
42
|
start_character_string = (
|
38
43
|
f" character {self.start_column + 1}" if self.start_column > 0 else ""
|
39
44
|
)
|
40
|
-
return f"
|
45
|
+
return f"line {self.start_line + 1}{start_character_string}"
|
41
46
|
|
42
47
|
|
43
48
|
class SourceReferencedError(pydantic.BaseModel):
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import dataclasses
|
2
2
|
from collections.abc import Sequence
|
3
3
|
from dataclasses import dataclass, field
|
4
|
-
from typing import TYPE_CHECKING, Callable
|
4
|
+
from typing import TYPE_CHECKING, Callable, Union, cast
|
5
5
|
|
6
6
|
from typing_extensions import Self
|
7
7
|
|
@@ -21,6 +21,7 @@ from classiq.interface.model.classical_parameter_declaration import (
|
|
21
21
|
)
|
22
22
|
from classiq.interface.model.handle_binding import (
|
23
23
|
HandleBinding,
|
24
|
+
HandlesList,
|
24
25
|
NestedHandleBinding,
|
25
26
|
SlicedHandleBinding,
|
26
27
|
)
|
@@ -254,7 +255,7 @@ class CapturedVars:
|
|
254
255
|
|
255
256
|
def _conjugate_direction(
|
256
257
|
self,
|
257
|
-
source_direction: PortDirection
|
258
|
+
source_direction: Union[PortDirection, bool],
|
258
259
|
target_direction: PortDirection,
|
259
260
|
var_name: str,
|
260
261
|
) -> PortDirection:
|
@@ -653,12 +654,9 @@ def validate_args_are_not_propagated(
|
|
653
654
|
for handle in captured_vars
|
654
655
|
if isinstance(handle, HandleBinding)
|
655
656
|
}
|
656
|
-
arg_handles = {
|
657
|
-
demangle_handle(arg) for arg in args if isinstance(arg, HandleBinding)
|
658
|
-
}
|
659
657
|
violating_handles = [
|
660
658
|
f"{str(arg_handle)!r}"
|
661
|
-
for arg_handle in
|
659
|
+
for arg_handle in _get_all_handles(args)
|
662
660
|
if any(
|
663
661
|
arg_handle.overlaps(captured_handle) for captured_handle in captured_handles
|
664
662
|
)
|
@@ -669,6 +667,18 @@ def validate_args_are_not_propagated(
|
|
669
667
|
)
|
670
668
|
|
671
669
|
|
670
|
+
def _get_all_handles(args: Sequence[ArgValue]) -> set[HandleBinding]:
|
671
|
+
arg_handles: set[HandleBinding] = set()
|
672
|
+
for arg in args:
|
673
|
+
if isinstance(arg, HandleBinding):
|
674
|
+
arg_handles.add(demangle_handle(arg))
|
675
|
+
elif isinstance(arg, HandlesList):
|
676
|
+
arg_handles |= set(
|
677
|
+
map(demangle_handle, cast(list[HandleBinding], arg.handles))
|
678
|
+
)
|
679
|
+
return arg_handles
|
680
|
+
|
681
|
+
|
672
682
|
def validate_captured_directions(
|
673
683
|
captured_vars: CapturedVars, report_outin: bool = True
|
674
684
|
) -> None:
|
@@ -1,22 +1,11 @@
|
|
1
1
|
import dataclasses
|
2
|
-
import
|
3
|
-
from collections.abc import Collection, Sequence
|
2
|
+
from collections.abc import Sequence
|
4
3
|
from dataclasses import dataclass, field
|
5
|
-
from functools import singledispatch
|
6
4
|
from typing import Any, Optional
|
7
5
|
|
8
6
|
from typing_extensions import Self
|
9
7
|
|
10
8
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
11
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
12
|
-
ClassicalProxy,
|
13
|
-
)
|
14
|
-
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
15
|
-
ClassicalStructProxy,
|
16
|
-
)
|
17
|
-
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
18
|
-
get_proxy_type,
|
19
|
-
)
|
20
9
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
21
10
|
from classiq.interface.model.quantum_function_declaration import (
|
22
11
|
NamedParamsQuantumFunctionDeclaration,
|
@@ -27,10 +16,7 @@ from classiq.interface.model.quantum_statement import QuantumStatement
|
|
27
16
|
|
28
17
|
from classiq.model_expansions.capturing.captured_vars import CapturedVars
|
29
18
|
from classiq.model_expansions.scope import (
|
30
|
-
Evaluated,
|
31
|
-
QuantumSymbol,
|
32
19
|
Scope,
|
33
|
-
evaluated_to_str as evaluated_classical_param_to_str,
|
34
20
|
)
|
35
21
|
from classiq.qmod.builtins.functions import permute
|
36
22
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
@@ -67,13 +53,6 @@ class FunctionClosure(Closure):
|
|
67
53
|
raise ClassiqInternalExpansionError
|
68
54
|
return self._depth
|
69
55
|
|
70
|
-
# creates a unique id for the function closure based on the arguments values.
|
71
|
-
# The closure is changing across the interpreter flow so it's closure_id may change
|
72
|
-
@property
|
73
|
-
def closure_id(self) -> str:
|
74
|
-
signature = _generate_closure_id(self.scope.data.values())
|
75
|
-
return f"{self.name}__{signature}"
|
76
|
-
|
77
56
|
@property
|
78
57
|
def body(self) -> Sequence[QuantumStatement]:
|
79
58
|
if self.name == permute.func_decl.name:
|
@@ -134,39 +113,3 @@ class FunctionClosure(Closure):
|
|
134
113
|
@dataclass(frozen=True)
|
135
114
|
class GenerativeFunctionClosure(GenerativeClosure, FunctionClosure):
|
136
115
|
pass
|
137
|
-
|
138
|
-
|
139
|
-
def _generate_closure_id(evaluated_args: Collection[Evaluated]) -> str:
|
140
|
-
args_signature = [
|
141
|
-
_evaluated_arg_to_str(eval_arg.value) for eval_arg in evaluated_args
|
142
|
-
]
|
143
|
-
return json.dumps(args_signature)
|
144
|
-
|
145
|
-
|
146
|
-
@singledispatch
|
147
|
-
def _evaluated_arg_to_str(arg: Any) -> str:
|
148
|
-
if isinstance(arg, str):
|
149
|
-
return arg
|
150
|
-
if isinstance(arg, QuantumSymbol):
|
151
|
-
return _evaluated_quantum_symbol_to_str(arg)
|
152
|
-
if isinstance(arg, FunctionClosure):
|
153
|
-
return _evaluated_one_operand_to_str(arg)
|
154
|
-
if isinstance(arg, list) and arg and isinstance(arg[0], FunctionClosure):
|
155
|
-
return _evaluated_operands_list_to_str(arg)
|
156
|
-
if isinstance(arg, ClassicalProxy):
|
157
|
-
if isinstance(arg, ClassicalStructProxy):
|
158
|
-
return repr(arg.struct_declaration)
|
159
|
-
return repr(get_proxy_type(arg))
|
160
|
-
return evaluated_classical_param_to_str(arg)
|
161
|
-
|
162
|
-
|
163
|
-
def _evaluated_quantum_symbol_to_str(port: QuantumSymbol) -> str:
|
164
|
-
return port.quantum_type.model_dump_json(exclude_none=True, exclude={"name"})
|
165
|
-
|
166
|
-
|
167
|
-
def _evaluated_one_operand_to_str(operand: FunctionClosure) -> str:
|
168
|
-
return operand.closure_id
|
169
|
-
|
170
|
-
|
171
|
-
def _evaluated_operands_list_to_str(arg: list[FunctionClosure]) -> str:
|
172
|
-
return json.dumps([_evaluated_one_operand_to_str(ope) for ope in arg])
|
@@ -27,7 +27,7 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
27
27
|
|
28
28
|
from classiq.model_expansions.closure import FunctionClosure
|
29
29
|
from classiq.model_expansions.evaluators.type_type_match import check_signature_match
|
30
|
-
from classiq.model_expansions.scope import Evaluated,
|
30
|
+
from classiq.model_expansions.scope import Evaluated, QuantumVariable
|
31
31
|
from classiq.qmod.model_state_container import QMODULE
|
32
32
|
from classiq.qmod.qmod_parameter import CInt, get_qmod_type
|
33
33
|
|
@@ -77,7 +77,7 @@ def check_arg_type_match(
|
|
77
77
|
|
78
78
|
|
79
79
|
def _check_qvar_type_match(argument: Any, error_message: str) -> None:
|
80
|
-
if not isinstance(argument,
|
80
|
+
if not isinstance(argument, QuantumVariable):
|
81
81
|
raise ClassiqExpansionError(error_message)
|
82
82
|
|
83
83
|
|
@@ -7,13 +7,13 @@ from classiq.interface.model.port_declaration import AnonPortDeclaration
|
|
7
7
|
from classiq.interface.model.quantum_function_declaration import AnonPositionalArg
|
8
8
|
|
9
9
|
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
10
|
-
from classiq.model_expansions.scope import Evaluated,
|
10
|
+
from classiq.model_expansions.scope import Evaluated, QuantumVariable
|
11
11
|
|
12
12
|
|
13
13
|
def add_information_from_output_arguments(
|
14
14
|
parameters: Sequence[AnonPositionalArg],
|
15
15
|
args: list[Evaluated],
|
16
|
-
) ->
|
16
|
+
) -> None:
|
17
17
|
"""
|
18
18
|
This function propagates the quantum type information from the output arguments
|
19
19
|
to the arguments that were passed to it.
|
@@ -29,7 +29,7 @@ def add_information_from_output_arguments(
|
|
29
29
|
if not isinstance(parameter, AnonPortDeclaration):
|
30
30
|
continue
|
31
31
|
|
32
|
-
argument_as_quantum_symbol = argument.as_type(
|
32
|
+
argument_as_quantum_symbol = argument.as_type(QuantumVariable)
|
33
33
|
|
34
34
|
if parameter.direction != PortDeclarationDirection.Output:
|
35
35
|
continue
|
@@ -38,6 +38,5 @@ def add_information_from_output_arguments(
|
|
38
38
|
copy_type_information(
|
39
39
|
parameter.quantum_type,
|
40
40
|
argument_as_quantum_symbol.quantum_type,
|
41
|
-
str(argument_as_quantum_symbol
|
41
|
+
str(argument_as_quantum_symbol),
|
42
42
|
)
|
43
|
-
return args
|
@@ -5,6 +5,9 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
5
5
|
)
|
6
6
|
from classiq.interface.generator.expressions.expression import Expression
|
7
7
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
8
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
9
|
+
AnyClassicalValue,
|
10
|
+
)
|
8
11
|
from classiq.interface.model.handle_binding import HandleBinding
|
9
12
|
|
10
13
|
from classiq.model_expansions.expression_evaluator import evaluate
|
@@ -19,18 +22,15 @@ def evaluate_classical_expression(expr: Expression, scope: Scope) -> Evaluated:
|
|
19
22
|
if isinstance(evaluated.value, get_args(ExpressionValue))
|
20
23
|
} | {
|
21
24
|
name: EvaluatedExpression(
|
22
|
-
value=
|
25
|
+
value=(
|
26
|
+
evaluated.value.quantum_type.get_proxy(HandleBinding(name=name))
|
27
|
+
if evaluated.value.quantum_type.is_evaluated
|
28
|
+
else AnyClassicalValue(name)
|
29
|
+
)
|
23
30
|
)
|
24
31
|
for name, evaluated in all_symbols
|
25
32
|
if isinstance(evaluated.value, QuantumSymbol)
|
26
|
-
and evaluated.value.quantum_type.is_evaluated
|
27
|
-
}
|
28
|
-
uninitialized_locals = {
|
29
|
-
name
|
30
|
-
for name, evaluated in all_symbols
|
31
|
-
if isinstance(evaluated.value, QuantumSymbol)
|
32
|
-
and not evaluated.value.quantum_type.is_evaluated
|
33
33
|
}
|
34
34
|
|
35
|
-
ret = evaluate(expr, locals_dict
|
35
|
+
ret = evaluate(expr, locals_dict)
|
36
36
|
return Evaluated(value=ret.value)
|