classiq 0.76.0__py3-none-any.whl → 0.77.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/interface/_version.py +1 -1
- 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/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/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +3 -3
- 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/function_builder.py +45 -0
- classiq/model_expansions/generative_functions.py +1 -1
- classiq/model_expansions/interpreters/base_interpreter.py +15 -1
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +4 -3
- 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 +21 -11
- classiq/model_expansions/quantum_operations/emitter.py +1 -6
- classiq/model_expansions/scope.py +53 -3
- classiq/model_expansions/transformers/model_renamer.py +2 -2
- classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.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/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +26 -19
- classiq/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +7 -6
- {classiq-0.76.0.dist-info → classiq-0.77.0.dist-info}/METADATA +1 -1
- {classiq-0.76.0.dist-info → classiq-0.77.0.dist-info}/RECORD +44 -43
- {classiq-0.76.0.dist-info → classiq-0.77.0.dist-info}/WHEEL +0 -0
@@ -53,6 +53,7 @@ from classiq.qmod.builtins.structs import (
|
|
53
53
|
MoleculeProblem as QmodMoleculeProblem,
|
54
54
|
Position as QmodPosition,
|
55
55
|
)
|
56
|
+
from classiq.qmod.global_declarative_switch import set_global_declarative_switch
|
56
57
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
57
58
|
|
58
59
|
# isort: split
|
@@ -60,6 +61,11 @@ from classiq.qmod.utilities import qmod_val_to_expr_str
|
|
60
61
|
# This import causes a circular import if done earlier. We use isort: split to avoid it
|
61
62
|
from classiq.open_library.functions.hea import full_hea
|
62
63
|
|
64
|
+
with set_global_declarative_switch():
|
65
|
+
_FULL_HEA = cast(
|
66
|
+
NativeFunctionDefinition, full_hea.create_model().function_dict["full_hea"]
|
67
|
+
)
|
68
|
+
|
63
69
|
_LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
|
64
70
|
"+": "PLUS",
|
65
71
|
"-": "MINUS",
|
@@ -506,12 +512,7 @@ def construct_chemistry_model(
|
|
506
512
|
)
|
507
513
|
]
|
508
514
|
if isinstance(ansatz_parameters, HEAParameters):
|
509
|
-
chemistry_functions.append(
|
510
|
-
cast(
|
511
|
-
NativeFunctionDefinition,
|
512
|
-
full_hea.create_model().function_dict["full_hea"],
|
513
|
-
)
|
514
|
-
)
|
515
|
+
chemistry_functions.append(_FULL_HEA)
|
515
516
|
model = Model(
|
516
517
|
functions=chemistry_functions,
|
517
518
|
classical_execution_code=_get_chemistry_classical_code(
|
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -36,6 +36,14 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
|
|
36
36
|
)
|
37
37
|
from classiq.applications.combinatorial_optimization import OptimizerConfig, QAOAConfig
|
38
38
|
from classiq.open_library.functions.qaoa_penalty import qaoa_penalty
|
39
|
+
from classiq.qmod.global_declarative_switch import set_global_declarative_switch
|
40
|
+
|
41
|
+
with set_global_declarative_switch():
|
42
|
+
_LIBRARY_FUNCTIONS = [
|
43
|
+
f.model_dump()
|
44
|
+
for f in qaoa_penalty.create_model().functions
|
45
|
+
if f.name != "main"
|
46
|
+
]
|
39
47
|
|
40
48
|
|
41
49
|
def construct_combi_opt_py_model(
|
@@ -107,7 +115,7 @@ def construct_combi_opt_py_model(
|
|
107
115
|
),
|
108
116
|
],
|
109
117
|
),
|
110
|
-
*
|
118
|
+
*_LIBRARY_FUNCTIONS,
|
111
119
|
],
|
112
120
|
classical_execution_code=f"""
|
113
121
|
vqe_result = vqe(
|
@@ -24,6 +24,7 @@ from classiq.open_library.functions.utility_functions import (
|
|
24
24
|
from classiq.qmod.builtins.functions import RX
|
25
25
|
from classiq.qmod.builtins.operations import allocate, phase, repeat
|
26
26
|
from classiq.qmod.cparam import CReal
|
27
|
+
from classiq.qmod.create_model_function import create_model
|
27
28
|
from classiq.qmod.qfunc import qfunc
|
28
29
|
from classiq.qmod.qmod_parameter import CArray
|
29
30
|
from classiq.qmod.qmod_variable import Output, QVar
|
@@ -80,9 +81,9 @@ class CombinatorialProblem:
|
|
80
81
|
],
|
81
82
|
)
|
82
83
|
|
83
|
-
self.model_ =
|
84
|
-
constraints=constraints, preferences=preferences
|
85
|
-
)
|
84
|
+
self.model_ = create_model(
|
85
|
+
main, constraints=constraints, preferences=preferences
|
86
|
+
) # type:ignore[assignment]
|
86
87
|
return self.model_ # type:ignore[return-value]
|
87
88
|
|
88
89
|
def get_qprog(self) -> QuantumProgram:
|
classiq/interface/_version.py
CHANGED
@@ -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:
|
@@ -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:
|
@@ -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,7 +7,7 @@ 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(
|
@@ -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,6 @@ 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
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)
|
@@ -20,6 +20,7 @@ from classiq.interface.generator.functions.type_name import (
|
|
20
20
|
from classiq.interface.model.classical_parameter_declaration import (
|
21
21
|
ClassicalParameterDeclaration,
|
22
22
|
)
|
23
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
23
24
|
from classiq.interface.model.port_declaration import PortDeclaration
|
24
25
|
from classiq.interface.model.quantum_function_declaration import (
|
25
26
|
PositionalArg,
|
@@ -46,7 +47,12 @@ from classiq.model_expansions.evaluators.quantum_type_utils import (
|
|
46
47
|
set_length,
|
47
48
|
set_size,
|
48
49
|
)
|
49
|
-
from classiq.model_expansions.scope import
|
50
|
+
from classiq.model_expansions.scope import (
|
51
|
+
Evaluated,
|
52
|
+
QuantumSymbol,
|
53
|
+
QuantumVariable,
|
54
|
+
Scope,
|
55
|
+
)
|
50
56
|
|
51
57
|
|
52
58
|
def evaluate_parameter_types_from_args(
|
@@ -83,10 +89,10 @@ def _update_scope(
|
|
83
89
|
return
|
84
90
|
if parameter.direction is PortDeclarationDirection.Output:
|
85
91
|
return
|
86
|
-
|
92
|
+
quantum_var = argument.as_type(QuantumVariable)
|
87
93
|
casted_argument = _cast(
|
88
94
|
parameter.quantum_type,
|
89
|
-
|
95
|
+
quantum_var.quantum_type,
|
90
96
|
parameter.name,
|
91
97
|
)
|
92
98
|
closure.scope[parameter.name] = Evaluated(
|
@@ -120,12 +126,12 @@ def _update_operand_signature_environment(
|
|
120
126
|
|
121
127
|
|
122
128
|
def _cast(
|
123
|
-
|
129
|
+
parameter_type: QuantumType, argument_type: QuantumType, param_name: str
|
124
130
|
) -> QuantumSymbol:
|
125
|
-
updated_quantum_type =
|
126
|
-
_inject_quantum_arg_info_to_type(updated_quantum_type,
|
131
|
+
updated_quantum_type = parameter_type.model_copy()
|
132
|
+
_inject_quantum_arg_info_to_type(updated_quantum_type, argument_type, param_name)
|
127
133
|
return QuantumSymbol(
|
128
|
-
handle=
|
134
|
+
handle=HandleBinding(name=param_name), quantum_type=updated_quantum_type
|
129
135
|
)
|
130
136
|
|
131
137
|
|
@@ -148,7 +154,9 @@ def _evaluate_type_from_arg(
|
|
148
154
|
)
|
149
155
|
if parameter.direction != PortDeclarationDirection.Output:
|
150
156
|
updated_quantum_type = _inject_quantum_arg_info_to_type(
|
151
|
-
updated_quantum_type,
|
157
|
+
updated_quantum_type,
|
158
|
+
argument.as_type(QuantumVariable).quantum_type,
|
159
|
+
parameter.name,
|
152
160
|
)
|
153
161
|
return parameter.model_copy(update={"quantum_type": updated_quantum_type})
|
154
162
|
|
@@ -280,11 +288,11 @@ def evaluate_types_in_quantum_symbols(
|
|
280
288
|
|
281
289
|
|
282
290
|
def _inject_quantum_arg_info_to_type(
|
283
|
-
parameter_type: QuantumType,
|
291
|
+
parameter_type: QuantumType, argument_type: QuantumType, param_name: str
|
284
292
|
) -> QuantumType:
|
285
|
-
if
|
293
|
+
if argument_type.has_size_in_bits:
|
286
294
|
copy_type_information(
|
287
|
-
|
295
|
+
argument_type,
|
288
296
|
parameter_type,
|
289
297
|
param_name,
|
290
298
|
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import ast
|
2
2
|
from collections.abc import Mapping
|
3
3
|
from enum import EnumMeta
|
4
|
-
from typing import Any
|
4
|
+
from typing import Any
|
5
5
|
|
6
6
|
from sympy import SympifyError, sympify
|
7
7
|
|
@@ -50,11 +50,25 @@ def evaluate_constants_as_python(constants: list[Constant]) -> dict[str, Any]:
|
|
50
50
|
}
|
51
51
|
|
52
52
|
|
53
|
+
def _quick_eval(expr: str) -> Any:
|
54
|
+
try:
|
55
|
+
return int(expr)
|
56
|
+
except ValueError:
|
57
|
+
pass
|
58
|
+
try:
|
59
|
+
return float(expr)
|
60
|
+
except ValueError:
|
61
|
+
pass
|
62
|
+
return None
|
63
|
+
|
64
|
+
|
53
65
|
def evaluate(
|
54
|
-
expr: Expression,
|
55
|
-
locals_dict: Mapping[str, EvaluatedExpression],
|
56
|
-
uninitialized_locals: Optional[set[str]] = None,
|
66
|
+
expr: Expression, locals_dict: Mapping[str, EvaluatedExpression]
|
57
67
|
) -> EvaluatedExpression:
|
68
|
+
val = _quick_eval(expr.expr)
|
69
|
+
if val is not None:
|
70
|
+
return EvaluatedExpression(value=val)
|
71
|
+
|
58
72
|
model_locals: dict[str, ExpressionValue] = {}
|
59
73
|
model_locals.update(ATOMIC_EXPRESSION_FUNCTIONS)
|
60
74
|
model_locals.update(
|
@@ -65,9 +79,8 @@ def evaluate(
|
|
65
79
|
)
|
66
80
|
# locals override builtin-functions
|
67
81
|
model_locals.update({name: expr.value for name, expr in locals_dict.items()})
|
68
|
-
uninitialized_locals = uninitialized_locals or set()
|
69
82
|
|
70
|
-
_validate_undefined_vars(expr.expr, model_locals
|
83
|
+
_validate_undefined_vars(expr.expr, model_locals)
|
71
84
|
|
72
85
|
sympy_expr = translate_to_sympy(expr.expr)
|
73
86
|
try:
|
@@ -95,11 +108,8 @@ def evaluate(
|
|
95
108
|
|
96
109
|
|
97
110
|
def _validate_undefined_vars(
|
98
|
-
expr: str,
|
99
|
-
model_locals: dict[str, ExpressionValue],
|
100
|
-
uninitialized_locals: Optional[set[str]],
|
111
|
+
expr: str, model_locals: dict[str, ExpressionValue]
|
101
112
|
) -> None:
|
102
|
-
uninitialized_locals = uninitialized_locals or set()
|
103
113
|
id_visitor = _VarsCollector()
|
104
114
|
id_visitor.visit(ast.parse(expr))
|
105
115
|
identifiers = id_visitor.vars
|
@@ -108,7 +118,6 @@ def _validate_undefined_vars(
|
|
108
118
|
- model_locals.keys()
|
109
119
|
- set(SYMPY_SUPPORTED_EXPRESSIONS)
|
110
120
|
- set(symbolic.__all__)
|
111
|
-
- uninitialized_locals
|
112
121
|
)
|
113
122
|
|
114
123
|
if len(undefined_vars) == 1:
|