classiq 0.60.0__py3-none-any.whl → 0.61.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/__init__.py +2 -0
- classiq/_internals/client.py +28 -1
- classiq/applications/__init__.py +1 -1
- classiq/applications/chemistry/__init__.py +7 -7
- classiq/applications/chemistry/chemistry_model_constructor.py +17 -6
- classiq/applications/combinatorial_optimization/__init__.py +7 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +197 -0
- classiq/applications/finance/finance_model_constructor.py +6 -6
- classiq/applications/grover/grover_model_constructor.py +3 -0
- classiq/applications/libraries/qmci_library.py +1 -10
- classiq/applications/qnn/__init__.py +1 -1
- classiq/applications/qnn/datasets/__init__.py +8 -8
- classiq/applications/qsvm/qsvm.py +1 -1
- classiq/execution/__init__.py +0 -2
- classiq/execution/execution_session.py +6 -0
- classiq/executor.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +12 -12
- classiq/interface/executor/execution_preferences.py +1 -1
- classiq/interface/generator/application_apis/chemistry_declarations.py +1 -1
- classiq/interface/generator/application_apis/finance_declarations.py +2 -2
- classiq/interface/generator/arith/arithmetic.py +16 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +4 -3
- classiq/interface/generator/expressions/expression_constants.py +3 -0
- classiq/interface/generator/generated_circuit_data.py +58 -20
- classiq/interface/generator/model/__init__.py +1 -1
- classiq/interface/generator/model/quantum_register.py +3 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +20 -32
- classiq/interface/ide/visual_model.py +1 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/model.py +2 -3
- classiq/interface/model/quantum_function_call.py +4 -7
- classiq/interface/model/quantum_function_declaration.py +7 -0
- classiq/interface/model/quantum_lambda_function.py +10 -1
- classiq/interface/model/quantum_type.py +3 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +3 -1
- classiq/model_expansions/capturing/captured_vars.py +24 -8
- classiq/model_expansions/capturing/mangling_utils.py +23 -15
- classiq/model_expansions/evaluators/arg_type_match.py +7 -7
- classiq/model_expansions/expression_evaluator.py +5 -2
- classiq/model_expansions/function_builder.py +21 -4
- classiq/model_expansions/generative_functions.py +12 -90
- classiq/model_expansions/interpreter.py +58 -11
- classiq/model_expansions/quantum_operations/call_emitter.py +19 -10
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +5 -31
- classiq/model_expansions/quantum_operations/emitter.py +27 -14
- classiq/model_expansions/quantum_operations/expression_operation.py +3 -5
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +57 -15
- classiq/model_expansions/quantum_operations/invert.py +1 -6
- classiq/model_expansions/quantum_operations/phase.py +2 -5
- classiq/model_expansions/quantum_operations/power.py +0 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +19 -30
- classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -1
- classiq/model_expansions/quantum_operations/shallow_emitter.py +155 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -14
- classiq/model_expansions/scope.py +10 -4
- classiq/model_expansions/scope_initialization.py +0 -11
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +7 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +12 -2
- classiq/model_expansions/transformers/ast_renamer.py +26 -0
- classiq/model_expansions/transformers/var_splitter.py +11 -12
- classiq/model_expansions/visitors/variable_references.py +20 -12
- classiq/qmod/builtins/classical_execution_primitives.py +6 -6
- classiq/qmod/builtins/classical_functions.py +10 -10
- classiq/qmod/builtins/functions/__init__.py +89 -103
- classiq/qmod/builtins/functions/amplitude_estimation.py +1 -1
- classiq/qmod/builtins/functions/arithmetic.py +1 -1
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +6 -6
- classiq/qmod/builtins/functions/grover.py +5 -5
- classiq/qmod/builtins/functions/hea.py +1 -1
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +2 -2
- classiq/qmod/builtins/functions/modular_exponentiation.py +8 -8
- classiq/qmod/builtins/functions/operators.py +1 -1
- classiq/qmod/builtins/functions/qaoa_penalty.py +5 -5
- classiq/qmod/builtins/functions/qft_functions.py +2 -2
- classiq/qmod/builtins/functions/qpe.py +9 -12
- classiq/qmod/builtins/functions/qsvt.py +177 -15
- classiq/qmod/builtins/functions/state_preparation.py +9 -9
- classiq/qmod/builtins/functions/swap_test.py +1 -1
- classiq/qmod/builtins/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/functions/variational.py +2 -2
- classiq/qmod/builtins/operations.py +3 -3
- classiq/qmod/builtins/structs.py +9 -9
- classiq/qmod/native/pretty_printer.py +17 -19
- classiq/qmod/pretty_print/pretty_printer.py +9 -6
- classiq/qmod/qmod_variable.py +2 -5
- classiq/qmod/quantum_expandable.py +18 -4
- classiq/qmod/quantum_function.py +19 -6
- classiq/qmod/semantics/static_semantics_visitor.py +34 -16
- classiq/qmod/semantics/validation/func_call_validation.py +9 -5
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
- classiq/qmod/symbolic.py +47 -47
- {classiq-0.60.0.dist-info → classiq-0.61.0.dist-info}/METADATA +1 -1
- {classiq-0.60.0.dist-info → classiq-0.61.0.dist-info}/RECORD +97 -94
- classiq/execution/qaoa.py +0 -86
- {classiq-0.60.0.dist-info → classiq-0.61.0.dist-info}/WHEEL +0 -0
@@ -9,6 +9,9 @@ from classiq.interface.generator.arith import arithmetic_expression_parser
|
|
9
9
|
from classiq.interface.generator.arith.arithmetic_expression_abc import (
|
10
10
|
ArithmeticExpressionABC,
|
11
11
|
)
|
12
|
+
from classiq.interface.generator.arith.arithmetic_expression_validator import (
|
13
|
+
is_constant,
|
14
|
+
)
|
12
15
|
from classiq.interface.generator.arith.arithmetic_param_getters import (
|
13
16
|
id2op,
|
14
17
|
operation_allows_target,
|
@@ -17,7 +20,9 @@ from classiq.interface.generator.arith.arithmetic_result_builder import (
|
|
17
20
|
ArithmeticResultBuilder,
|
18
21
|
)
|
19
22
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
23
|
+
from classiq.interface.generator.expressions.expression import Expression
|
20
24
|
from classiq.interface.model.quantum_type import (
|
25
|
+
QuantumNumeric,
|
21
26
|
QuantumType,
|
22
27
|
quantum_var_to_register,
|
23
28
|
register_info_to_quantum_type,
|
@@ -28,6 +33,10 @@ ARITHMETIC_EXPRESSION_RESULT_NAME: Final[str] = "expression_result"
|
|
28
33
|
ARITHMETIC_EXPRESSION_GARBAGE_NAME: Final[str] = "expression_garbage"
|
29
34
|
|
30
35
|
|
36
|
+
def is_zero(expr: str) -> bool:
|
37
|
+
return is_constant(expr) and float(expr) == 0
|
38
|
+
|
39
|
+
|
31
40
|
class Arithmetic(ArithmeticExpressionABC):
|
32
41
|
target: Optional[RegisterArithmeticInfo] = None
|
33
42
|
inputs_to_save: set[str] = pydantic.Field(default_factory=set)
|
@@ -99,7 +108,13 @@ def get_arithmetic_params(
|
|
99
108
|
|
100
109
|
def compute_arithmetic_result_type(
|
101
110
|
expr_str: str, var_types: dict[str, QuantumType], machine_precision: int
|
102
|
-
) ->
|
111
|
+
) -> QuantumNumeric:
|
112
|
+
if is_zero(expr_str):
|
113
|
+
return QuantumNumeric(
|
114
|
+
size=Expression(expr="1"),
|
115
|
+
is_signed=Expression(expr="False"),
|
116
|
+
fraction_digits=Expression(expr="0"),
|
117
|
+
)
|
103
118
|
arith_param = get_arithmetic_params(expr_str, var_types, machine_precision)
|
104
119
|
return register_info_to_quantum_type(
|
105
120
|
arith_param.outputs[ARITHMETIC_EXPRESSION_RESULT_NAME]
|
@@ -3,6 +3,7 @@ import re
|
|
3
3
|
from _ast import AST
|
4
4
|
from typing import Any, Optional, Union
|
5
5
|
|
6
|
+
from sympy import Expr
|
6
7
|
from typing_extensions import TypeAlias, get_args
|
7
8
|
|
8
9
|
from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
|
@@ -54,11 +55,11 @@ SupportedNodesTypes = Union[
|
|
54
55
|
DEFAULT_SUPPORTED_NODE_TYPES = get_args(SupportedNodesTypes)
|
55
56
|
|
56
57
|
|
57
|
-
def
|
58
|
+
def is_constant(expr: Union[str, Expr]) -> bool:
|
58
59
|
try:
|
59
60
|
float(expr)
|
60
61
|
return True
|
61
|
-
except ValueError:
|
62
|
+
except (ValueError, TypeError):
|
62
63
|
return False
|
63
64
|
|
64
65
|
|
@@ -94,7 +95,7 @@ class ExpressionValidator(ast.NodeVisitor):
|
|
94
95
|
@staticmethod
|
95
96
|
def _get_adjusted_expression(expression: str) -> str:
|
96
97
|
# This works around the simplification of the trivial expressions such as a + 0, 1 * a, etc.
|
97
|
-
if IDENITIFIER_REGEX.fullmatch(expression) or
|
98
|
+
if IDENITIFIER_REGEX.fullmatch(expression) or is_constant(expression):
|
98
99
|
return f"0 + {expression}"
|
99
100
|
return expression
|
100
101
|
|
@@ -20,3 +20,6 @@ BOOLEAN_LITERALS = {"True", "False"}
|
|
20
20
|
FORBIDDEN_LITERALS: set[str] = set(keyword.kwlist) - SUPPORTED_FUNC_NAMES
|
21
21
|
CPARAM_EXECUTION_SUFFIX: Final[str] = "_param"
|
22
22
|
RESERVED_EXPRESSIONS: frozenset[str] = frozenset({"i"})
|
23
|
+
CPARAM_EXECUTION_SUFFIX_PATTERN = (
|
24
|
+
rf"({CPARAM_EXECUTION_SUFFIX}|^({'|'.join(RESERVED_EXPRESSIONS)}))(_\d+)*$"
|
25
|
+
)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
from typing import
|
2
|
+
from typing import Literal, Optional, Union
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
from pydantic import ConfigDict
|
@@ -12,6 +12,12 @@ from classiq.interface.generator.synthesis_metadata.synthesis_execution_data imp
|
|
12
12
|
ExecutionData,
|
13
13
|
)
|
14
14
|
|
15
|
+
from classiq.model_expansions.capturing.mangling_utils import (
|
16
|
+
demangle_capture_name,
|
17
|
+
demangle_name,
|
18
|
+
is_captured_var_name,
|
19
|
+
)
|
20
|
+
|
15
21
|
_logger = logging.getLogger(__name__)
|
16
22
|
ParameterName = str
|
17
23
|
IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
|
@@ -52,6 +58,16 @@ class GeneratedRegister(pydantic.BaseModel):
|
|
52
58
|
def width(self) -> int:
|
53
59
|
return len(self)
|
54
60
|
|
61
|
+
@property
|
62
|
+
def is_captured(self) -> bool:
|
63
|
+
return is_captured_var_name(self.name)
|
64
|
+
|
65
|
+
@staticmethod
|
66
|
+
def demangle_name(name: str) -> str:
|
67
|
+
if is_captured_var_name(name):
|
68
|
+
return demangle_capture_name(name)
|
69
|
+
return demangle_name(name)
|
70
|
+
|
55
71
|
|
56
72
|
class GeneratedFunction(pydantic.BaseModel):
|
57
73
|
name: str
|
@@ -157,32 +173,54 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
157
173
|
for key, value in parameters.items()
|
158
174
|
]
|
159
175
|
|
160
|
-
def
|
161
|
-
for key, value in kwargs.items():
|
162
|
-
setattr(self, key, value)
|
163
|
-
|
164
|
-
def propagate_absolute_qubits(self) -> None:
|
176
|
+
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
165
177
|
if self.absolute_qubits is None:
|
166
|
-
return
|
167
|
-
|
168
|
-
|
169
|
-
register.
|
170
|
-
|
171
|
-
|
178
|
+
return self
|
179
|
+
|
180
|
+
updated_registers = [
|
181
|
+
register.model_copy(
|
182
|
+
update=dict(
|
183
|
+
qubit_indexes_absolute=list(
|
184
|
+
_get_absolute_from_relative(
|
185
|
+
self.absolute_qubits, tuple(register.qubit_indexes_relative)
|
186
|
+
)
|
187
|
+
)
|
172
188
|
)
|
173
189
|
)
|
190
|
+
for register in self.registers
|
191
|
+
]
|
192
|
+
updated_generated_function = (
|
193
|
+
self.generated_function.model_copy(update=dict(registers=updated_registers))
|
194
|
+
if self.generated_function
|
195
|
+
else None
|
196
|
+
)
|
174
197
|
|
198
|
+
updated_children: list[FunctionDebugInfoInterface] = []
|
175
199
|
for child in self.children:
|
176
|
-
|
177
|
-
|
200
|
+
updated_child = child.model_copy(
|
201
|
+
update=dict(
|
202
|
+
absolute_qubits=_get_absolute_from_relative(
|
203
|
+
self.absolute_qubits, child.relative_qubits
|
204
|
+
)
|
205
|
+
)
|
178
206
|
)
|
179
|
-
|
207
|
+
updated_children.append(updated_child.propagate_absolute_qubits())
|
180
208
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
209
|
+
return self.model_copy(
|
210
|
+
update=dict(
|
211
|
+
generated_function=updated_generated_function,
|
212
|
+
children=updated_children,
|
213
|
+
)
|
214
|
+
)
|
215
|
+
|
216
|
+
def inverse(self) -> "FunctionDebugInfoInterface":
|
217
|
+
inverted_children = [child.inverse() for child in self.children[::-1]]
|
218
|
+
return self.model_copy(
|
219
|
+
update=dict(
|
220
|
+
is_inverse=not self.is_inverse,
|
221
|
+
children=inverted_children,
|
222
|
+
)
|
223
|
+
)
|
186
224
|
|
187
225
|
|
188
226
|
def _get_absolute_from_relative(
|
@@ -26,26 +26,6 @@ class ControlledGate(_StandardGate): # type: ignore[misc]
|
|
26
26
|
num_ctrl_qubits: pydantic.PositiveInt = pydantic.Field(
|
27
27
|
default=DEFAULT_NUM_CTRL_QUBITS
|
28
28
|
)
|
29
|
-
|
30
|
-
def _create_ios(self) -> None:
|
31
|
-
_StandardGate._create_ios(self)
|
32
|
-
control = RegisterUserInput(
|
33
|
-
name=CONTROLLED_GATE_CONTROL, size=self.num_ctrl_qubits
|
34
|
-
)
|
35
|
-
self._inputs[CONTROLLED_GATE_CONTROL] = control
|
36
|
-
self._outputs[CONTROLLED_GATE_CONTROL] = control
|
37
|
-
|
38
|
-
def to_control_state(self) -> ControlState:
|
39
|
-
return ControlState(
|
40
|
-
name=CONTROLLED_GATE_CONTROL, num_ctrl_qubits=self.num_ctrl_qubits
|
41
|
-
)
|
42
|
-
|
43
|
-
|
44
|
-
class ControlledGateWithState(ControlledGate): # type: ignore[misc]
|
45
|
-
"""
|
46
|
-
Base model for controlled Gates with control over the controlled_state
|
47
|
-
"""
|
48
|
-
|
49
29
|
ctrl_state: CtrlState = pydantic.Field(
|
50
30
|
description="The control state in decimal or as a bit string (e.g. '1011'). If not specified, the control "
|
51
31
|
"state is 2**num_ctrl_qubits - 1.\n"
|
@@ -82,12 +62,20 @@ class ControlledGateWithState(ControlledGate): # type: ignore[misc]
|
|
82
62
|
)
|
83
63
|
return ControlState(name=CONTROLLED_GATE_CONTROL, ctrl_state=ctrl_state_str)
|
84
64
|
|
65
|
+
def _create_ios(self) -> None:
|
66
|
+
_StandardGate._create_ios(self)
|
67
|
+
control = RegisterUserInput(
|
68
|
+
name=CONTROLLED_GATE_CONTROL, size=self.num_ctrl_qubits
|
69
|
+
)
|
70
|
+
self._inputs[CONTROLLED_GATE_CONTROL] = control
|
71
|
+
self._outputs[CONTROLLED_GATE_CONTROL] = control
|
72
|
+
|
85
73
|
|
86
74
|
def _num_to_control_string(ctrl_state_int: int, num_ctrl_qubits: int) -> str:
|
87
75
|
return format(ctrl_state_int, f"0{num_ctrl_qubits}b")
|
88
76
|
|
89
77
|
|
90
|
-
class CXGate(
|
78
|
+
class CXGate(ControlledGate): # type: ignore[misc]
|
91
79
|
"""
|
92
80
|
The Controlled-X Gate
|
93
81
|
"""
|
@@ -98,7 +86,7 @@ class CXGate(ControlledGateWithState): # type: ignore[misc]
|
|
98
86
|
return 2
|
99
87
|
|
100
88
|
|
101
|
-
class CCXGate(
|
89
|
+
class CCXGate(ControlledGate): # type: ignore[misc]
|
102
90
|
"""
|
103
91
|
The Double Controlled-X Gate
|
104
92
|
"""
|
@@ -109,7 +97,7 @@ class CCXGate(ControlledGateWithState): # type: ignore[misc]
|
|
109
97
|
return 2
|
110
98
|
|
111
99
|
|
112
|
-
class C3XGate(
|
100
|
+
class C3XGate(ControlledGate): # type: ignore[misc]
|
113
101
|
"""
|
114
102
|
The X Gate controlled on 3 qubits
|
115
103
|
"""
|
@@ -121,7 +109,7 @@ class C3XGate(ControlledGateWithState): # type: ignore[misc]
|
|
121
109
|
return 2
|
122
110
|
|
123
111
|
|
124
|
-
class C4XGate(
|
112
|
+
class C4XGate(ControlledGate): # type: ignore[misc]
|
125
113
|
"""
|
126
114
|
The X Gate controlled on 4 qubits
|
127
115
|
"""
|
@@ -133,7 +121,7 @@ class C4XGate(ControlledGateWithState): # type: ignore[misc]
|
|
133
121
|
return 2
|
134
122
|
|
135
123
|
|
136
|
-
class CYGate(
|
124
|
+
class CYGate(ControlledGate): # type: ignore[misc]
|
137
125
|
"""
|
138
126
|
The Controlled-Y Gate
|
139
127
|
"""
|
@@ -142,7 +130,7 @@ class CYGate(ControlledGateWithState): # type: ignore[misc]
|
|
142
130
|
return 2
|
143
131
|
|
144
132
|
|
145
|
-
class CZGate(
|
133
|
+
class CZGate(ControlledGate): # type: ignore[misc]
|
146
134
|
"""
|
147
135
|
The Controlled-Z Gate
|
148
136
|
"""
|
@@ -151,7 +139,7 @@ class CZGate(ControlledGateWithState): # type: ignore[misc]
|
|
151
139
|
return 2
|
152
140
|
|
153
141
|
|
154
|
-
class CHGate(
|
142
|
+
class CHGate(ControlledGate): # type: ignore[misc]
|
155
143
|
"""
|
156
144
|
The Controlled-H Gate
|
157
145
|
"""
|
@@ -160,7 +148,7 @@ class CHGate(ControlledGateWithState): # type: ignore[misc]
|
|
160
148
|
return 2
|
161
149
|
|
162
150
|
|
163
|
-
class CSXGate(
|
151
|
+
class CSXGate(ControlledGate): # type: ignore[misc]
|
164
152
|
"""
|
165
153
|
The Controlled-SX Gate
|
166
154
|
"""
|
@@ -169,25 +157,25 @@ class CSXGate(ControlledGateWithState): # type: ignore[misc]
|
|
169
157
|
return 4
|
170
158
|
|
171
159
|
|
172
|
-
class CRXGate(
|
160
|
+
class CRXGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
|
173
161
|
"""
|
174
162
|
The Controlled-RX Gate
|
175
163
|
"""
|
176
164
|
|
177
165
|
|
178
|
-
class CRYGate(
|
166
|
+
class CRYGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
|
179
167
|
"""
|
180
168
|
The Controlled-RY Gate
|
181
169
|
"""
|
182
170
|
|
183
171
|
|
184
|
-
class CRZGate(
|
172
|
+
class CRZGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
|
185
173
|
"""
|
186
174
|
The Controlled-RZ Gate
|
187
175
|
"""
|
188
176
|
|
189
177
|
|
190
|
-
class CPhaseGate(
|
178
|
+
class CPhaseGate(ControlledGate, angles=["theta"]): # type: ignore[misc]
|
191
179
|
"""
|
192
180
|
The Controlled-Phase Gate
|
193
181
|
"""
|
@@ -1 +1 @@
|
|
1
|
-
INTERFACE_VERSION = "
|
1
|
+
INTERFACE_VERSION = "6"
|
classiq/interface/model/model.py
CHANGED
@@ -180,9 +180,8 @@ class Model(VersionedModel, ASTNode):
|
|
180
180
|
)
|
181
181
|
return constants
|
182
182
|
|
183
|
-
def
|
184
|
-
return self.
|
185
|
-
indent=2,
|
183
|
+
def dump_no_preferences_and_constraints(self) -> dict[str, Any]:
|
184
|
+
return self.model_dump(
|
186
185
|
exclude={
|
187
186
|
"constraints",
|
188
187
|
"execution_preferences",
|
@@ -7,7 +7,6 @@ from typing import (
|
|
7
7
|
|
8
8
|
import pydantic
|
9
9
|
|
10
|
-
from classiq.interface.ast_node import ASTNode
|
11
10
|
from classiq.interface.exceptions import ClassiqError, ClassiqValueError
|
12
11
|
from classiq.interface.generator.expressions.expression import Expression
|
13
12
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -21,7 +20,10 @@ from classiq.interface.model.port_declaration import AnonPortDeclaration
|
|
21
20
|
from classiq.interface.model.quantum_function_declaration import (
|
22
21
|
QuantumFunctionDeclaration,
|
23
22
|
)
|
24
|
-
from classiq.interface.model.quantum_lambda_function import
|
23
|
+
from classiq.interface.model.quantum_lambda_function import (
|
24
|
+
OperandIdentifier,
|
25
|
+
QuantumOperand,
|
26
|
+
)
|
25
27
|
from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
|
26
28
|
|
27
29
|
ArgValue = Union[
|
@@ -31,11 +33,6 @@ ArgValue = Union[
|
|
31
33
|
]
|
32
34
|
|
33
35
|
|
34
|
-
class OperandIdentifier(ASTNode):
|
35
|
-
name: str
|
36
|
-
index: Expression
|
37
|
-
|
38
|
-
|
39
36
|
class QuantumFunctionCall(QuantumOperation):
|
40
37
|
kind: Literal["QuantumFunctionCall"]
|
41
38
|
|
@@ -9,6 +9,7 @@ from typing import (
|
|
9
9
|
import pydantic
|
10
10
|
from pydantic import SerializeAsAny
|
11
11
|
from pydantic_core.core_schema import ValidationInfo
|
12
|
+
from typing_extensions import Self
|
12
13
|
|
13
14
|
from classiq.interface.exceptions import ClassiqInternalError
|
14
15
|
from classiq.interface.generator.arith.register_user_input import RegisterUserInput
|
@@ -171,6 +172,12 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
|
|
171
172
|
new_instance_data["kind"] = "QuantumOperandDeclaration"
|
172
173
|
return QuantumOperandDeclaration(**new_instance_data)
|
173
174
|
|
175
|
+
@property
|
176
|
+
def element_declaration(self) -> Self:
|
177
|
+
if not self.is_list:
|
178
|
+
raise ClassiqInternalError
|
179
|
+
return self.model_copy(update={"is_list": False})
|
180
|
+
|
174
181
|
|
175
182
|
AnonQuantumFunctionDeclaration.model_rebuild()
|
176
183
|
|
@@ -4,6 +4,7 @@ import pydantic
|
|
4
4
|
|
5
5
|
from classiq.interface.ast_node import ASTNode
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
8
|
from classiq.interface.model.quantum_function_declaration import (
|
8
9
|
AnonQuantumOperandDeclaration,
|
9
10
|
)
|
@@ -52,5 +53,13 @@ class QuantumLambdaFunction(ASTNode):
|
|
52
53
|
self._func_decl = fd
|
53
54
|
|
54
55
|
|
55
|
-
|
56
|
+
class OperandIdentifier(ASTNode):
|
57
|
+
name: str
|
58
|
+
index: Expression
|
59
|
+
|
60
|
+
def __str__(self) -> str:
|
61
|
+
return f"{self.name}[{self.index.expr}]"
|
62
|
+
|
63
|
+
|
64
|
+
QuantumCallable = Union[str, OperandIdentifier, QuantumLambdaFunction]
|
56
65
|
QuantumOperand = Union[QuantumCallable, list[QuantumCallable]]
|
@@ -159,7 +159,9 @@ class QuantumNumeric(QuantumScalar):
|
|
159
159
|
def _validate_fields(self) -> Self:
|
160
160
|
has_sign = self.is_signed is not None
|
161
161
|
has_fraction_digits = self.fraction_digits is not None
|
162
|
-
if has_sign and not has_fraction_digits or
|
162
|
+
if (has_sign and not has_fraction_digits) or (
|
163
|
+
not has_sign and has_fraction_digits
|
164
|
+
):
|
163
165
|
raise ClassiqValueError(
|
164
166
|
"Assign neither or both of is_signed and fraction_digits"
|
165
167
|
)
|
@@ -61,7 +61,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
61
61
|
for field_name, field_type in val.struct_declaration.variables.items()
|
62
62
|
}
|
63
63
|
|
64
|
-
if isinstance(val, Enum):
|
64
|
+
if isinstance(val, (Enum, int)):
|
65
65
|
return val
|
66
66
|
|
67
67
|
elif isinstance(qmod_type, ClassicalList):
|
@@ -147,6 +147,8 @@ def get_field(
|
|
147
147
|
proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
|
148
148
|
field: str,
|
149
149
|
) -> ExpressionValue:
|
150
|
+
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
151
|
+
return getattr(proxy, field)
|
150
152
|
if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
|
151
153
|
raise ClassiqExpansionError(
|
152
154
|
f"Cannot evaluate '{proxy}.{field}': Variable {str(proxy)!r} is not "
|
@@ -2,7 +2,7 @@ import dataclasses
|
|
2
2
|
from collections.abc import Iterator, Sequence
|
3
3
|
from contextlib import contextmanager
|
4
4
|
from dataclasses import dataclass, field
|
5
|
-
from typing import TYPE_CHECKING
|
5
|
+
from typing import TYPE_CHECKING, Optional
|
6
6
|
|
7
7
|
from classiq.interface.enum_utils import StrEnum
|
8
8
|
from classiq.interface.exceptions import (
|
@@ -16,12 +16,14 @@ from classiq.interface.model.handle_binding import HandleBinding, NestedHandleBi
|
|
16
16
|
from classiq.interface.model.port_declaration import PortDeclaration
|
17
17
|
from classiq.interface.model.quantum_function_call import ArgValue
|
18
18
|
from classiq.interface.model.quantum_type import QuantumType
|
19
|
+
from classiq.interface.model.variable_declaration_statement import (
|
20
|
+
VariableDeclarationStatement,
|
21
|
+
)
|
19
22
|
|
20
23
|
from classiq.model_expansions.capturing.mangling_utils import (
|
21
24
|
demangle_handle,
|
22
25
|
mangle_captured_var_name,
|
23
26
|
)
|
24
|
-
from classiq.model_expansions.scope import QuantumSymbol
|
25
27
|
from classiq.model_expansions.transformers.var_splitter import SymbolPart, SymbolParts
|
26
28
|
|
27
29
|
if TYPE_CHECKING:
|
@@ -71,7 +73,11 @@ class _CapturedHandle:
|
|
71
73
|
|
72
74
|
@property
|
73
75
|
def mangled_name(self) -> str:
|
74
|
-
return mangle_captured_var_name(
|
76
|
+
return mangle_captured_var_name(
|
77
|
+
self.handle.identifier,
|
78
|
+
self.defining_function.name,
|
79
|
+
self.defining_function.depth,
|
80
|
+
)
|
75
81
|
|
76
82
|
@property
|
77
83
|
def port(self) -> PortDeclaration:
|
@@ -211,7 +217,16 @@ class CapturedVars:
|
|
211
217
|
]
|
212
218
|
)
|
213
219
|
|
214
|
-
def
|
220
|
+
def filter_vars(
|
221
|
+
self,
|
222
|
+
current_function: "FunctionClosure",
|
223
|
+
current_declarations: Optional[list[VariableDeclarationStatement]] = None,
|
224
|
+
) -> "CapturedVars":
|
225
|
+
current_declared_vars = (
|
226
|
+
None
|
227
|
+
if current_declarations is None
|
228
|
+
else {decl.name for decl in current_declarations}
|
229
|
+
)
|
215
230
|
return CapturedVars(
|
216
231
|
_captured_handles=[
|
217
232
|
captured_handle
|
@@ -219,6 +234,10 @@ class CapturedVars:
|
|
219
234
|
if not _same_closure(
|
220
235
|
captured_handle.defining_function, current_function
|
221
236
|
)
|
237
|
+
or (
|
238
|
+
current_declared_vars is not None
|
239
|
+
and captured_handle.handle.name not in current_declared_vars
|
240
|
+
)
|
222
241
|
]
|
223
242
|
)
|
224
243
|
|
@@ -247,10 +266,7 @@ class CapturedVars:
|
|
247
266
|
|
248
267
|
def get_captured_mapping(self) -> SymbolParts:
|
249
268
|
return {
|
250
|
-
|
251
|
-
handle=captured_handle.handle,
|
252
|
-
quantum_type=captured_handle.quantum_type,
|
253
|
-
): [
|
269
|
+
captured_handle.handle: [
|
254
270
|
SymbolPart(
|
255
271
|
source_handle=captured_handle.handle,
|
256
272
|
target_var_name=captured_handle.mangled_name,
|
@@ -1,12 +1,9 @@
|
|
1
1
|
import re
|
2
|
-
from typing import
|
2
|
+
from typing import Optional
|
3
3
|
|
4
4
|
from classiq.interface.generator.compiler_keywords import CAPTURE_SUFFIX
|
5
5
|
from classiq.interface.model.handle_binding import HANDLE_ID_SEPARATOR, HandleBinding
|
6
6
|
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from classiq.model_expansions.closure import FunctionClosure
|
9
|
-
|
10
7
|
IDENTIFIER_PATTERN = r"[a-zA-Z_][a-zA-Z0-9_]*"
|
11
8
|
CAPTURE_PATTERN = re.compile(
|
12
9
|
rf"({IDENTIFIER_PATTERN}){CAPTURE_SUFFIX}{IDENTIFIER_PATTERN}__\d*"
|
@@ -15,24 +12,34 @@ ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
|
|
15
12
|
|
16
13
|
|
17
14
|
def mangle_captured_var_name(
|
18
|
-
var_name: str,
|
15
|
+
var_name: str, function_name: str, function_depth: int
|
19
16
|
) -> str:
|
20
|
-
return
|
21
|
-
f"{var_name}{CAPTURE_SUFFIX}{defining_function.name}__{defining_function.depth}"
|
22
|
-
)
|
17
|
+
return f"{var_name}{CAPTURE_SUFFIX}{function_name}__{function_depth}"
|
23
18
|
|
24
19
|
|
25
|
-
def
|
26
|
-
|
20
|
+
def _match_capture_pattern(name: str) -> Optional[re.Match[str]]:
|
21
|
+
return re.match(CAPTURE_PATTERN, name)
|
22
|
+
|
23
|
+
|
24
|
+
def is_captured_var_name(name: str) -> bool:
|
25
|
+
return _match_capture_pattern(name) is not None
|
26
|
+
|
27
|
+
|
28
|
+
def demangle_capture_name(name: str) -> str:
|
29
|
+
match = _match_capture_pattern(name)
|
27
30
|
return match.group(1) if match else name
|
28
31
|
|
29
32
|
|
30
33
|
def demangle_handle(handle: HandleBinding) -> HandleBinding:
|
31
|
-
|
34
|
+
demangled_name = demangle_name(handle.name)
|
35
|
+
return handle.rename(demangled_name)
|
36
|
+
|
37
|
+
|
38
|
+
def demangle_name(name: str) -> str:
|
32
39
|
if HANDLE_ID_SEPARATOR not in name:
|
33
|
-
return
|
40
|
+
return name
|
34
41
|
if ARRAY_CAST_SUFFIX in name:
|
35
|
-
return
|
42
|
+
return name.split(ARRAY_CAST_SUFFIX)[0]
|
36
43
|
name = re.sub(r"([^_])_\d+$", r"\1", name)
|
37
44
|
name_parts = name.split(HANDLE_ID_SEPARATOR)
|
38
45
|
new_name_parts = [name_parts[0]]
|
@@ -44,5 +51,6 @@ def demangle_handle(handle: HandleBinding) -> HandleBinding:
|
|
44
51
|
new_name_parts.append(f"[{part_left}:{part_right}]")
|
45
52
|
else:
|
46
53
|
new_name_parts.append(f".{part}")
|
47
|
-
new_name_parts = list(map(
|
48
|
-
|
54
|
+
new_name_parts = list(map(demangle_capture_name, new_name_parts))
|
55
|
+
new_name = "".join(new_name_parts)
|
56
|
+
return new_name
|
@@ -135,13 +135,13 @@ def _check_classical_type_match(
|
|
135
135
|
arg_struct_name = None if not arg_is_struct else argument.struct_declaration.name
|
136
136
|
if (
|
137
137
|
arg_is_qvar
|
138
|
-
or arg_is_builtin
|
139
|
-
and (type_is_struct or
|
140
|
-
or
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
138
|
+
or (arg_is_builtin and (type_is_struct or type_is_enum))
|
139
|
+
or (arg_is_struct and (not type_is_struct or arg_struct_name != type_name))
|
140
|
+
or (
|
141
|
+
arg_is_enum
|
142
|
+
and get_qmod_type(classical_type) != CInt
|
143
|
+
and (not type_is_enum or type(argument).__name__ != type_name)
|
144
|
+
)
|
145
145
|
):
|
146
146
|
raise ClassiqExpansionError(error_message)
|
147
147
|
|