classiq 0.80.1__py3-none-any.whl → 0.82.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classiq/analyzer/show_interactive_hack.py +10 -4
- classiq/analyzer/url_utils.py +4 -3
- classiq/applications/qnn/qlayer.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +0 -3
- classiq/interface/debug_info/debug_info.py +0 -1
- classiq/interface/executor/execution_preferences.py +2 -1
- classiq/interface/generator/compiler_keywords.py +2 -2
- classiq/interface/generator/expressions/atomic_expression_functions.py +11 -7
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +6 -2
- classiq/interface/generator/function_params.py +1 -1
- classiq/interface/generator/functions/classical_type.py +8 -0
- classiq/interface/generator/generated_circuit_data.py +1 -2
- classiq/interface/generator/quantum_program.py +13 -0
- classiq/interface/generator/types/compilation_metadata.py +14 -2
- classiq/interface/model/handle_binding.py +12 -2
- classiq/interface/model/quantum_type.py +12 -1
- classiq/interface/server/routes.py +0 -1
- classiq/model_expansions/atomic_expression_functions_defs.py +1 -1
- classiq/model_expansions/capturing/captured_vars.py +123 -9
- classiq/model_expansions/closure.py +2 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +3 -18
- classiq/model_expansions/function_builder.py +1 -17
- classiq/model_expansions/interpreters/base_interpreter.py +2 -0
- classiq/model_expansions/quantum_operations/allocate.py +18 -7
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +4 -0
- classiq/model_expansions/quantum_operations/bind.py +2 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +27 -21
- classiq/model_expansions/quantum_operations/emitter.py +28 -0
- classiq/model_expansions/quantum_operations/function_calls_cache.py +1 -16
- classiq/model_expansions/transformers/type_qualifier_inference.py +220 -50
- classiq/model_expansions/visitors/symbolic_param_inference.py +0 -6
- classiq/open_library/functions/amplitude_amplification.py +3 -5
- classiq/open_library/functions/state_preparation.py +9 -0
- classiq/qmod/builtins/functions/__init__.py +3 -1
- classiq/qmod/builtins/functions/exponentiation.py +41 -3
- classiq/qmod/builtins/operations.py +65 -37
- classiq/qmod/declaration_inferrer.py +2 -1
- classiq/qmod/native/pretty_printer.py +12 -10
- classiq/qmod/pretty_print/pretty_printer.py +9 -9
- classiq/qmod/qfunc.py +11 -11
- classiq/qmod/quantum_expandable.py +4 -0
- classiq/qmod/semantics/error_manager.py +8 -2
- classiq/synthesis.py +6 -3
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/METADATA +1 -1
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/RECORD +47 -49
- classiq/interface/execution/resource_estimator.py +0 -7
- classiq/interface/execution/result.py +0 -5
- {classiq-0.80.1.dist-info → classiq-0.82.0.dist-info}/WHEEL +0 -0
@@ -27,10 +27,16 @@ def is_classiq_studio() -> bool:
|
|
27
27
|
return bool(os.environ.get("OPENVSCODE"))
|
28
28
|
|
29
29
|
|
30
|
-
def get_app_url(
|
30
|
+
def get_app_url(
|
31
|
+
data_id: DataID, circuit: QuantumProgram, include_query: bool = True
|
32
|
+
) -> str:
|
31
33
|
return urljoin(
|
32
34
|
client_ide_base_url(),
|
33
|
-
circuit_page_uri(
|
35
|
+
circuit_page_uri(
|
36
|
+
circuit_id=data_id.id,
|
37
|
+
circuit_version=circuit.version,
|
38
|
+
include_query=include_query,
|
39
|
+
),
|
34
40
|
)
|
35
41
|
|
36
42
|
|
@@ -95,7 +101,7 @@ async def handle_remote_app(circuit: QuantumProgram, display_url: bool = True) -
|
|
95
101
|
|
96
102
|
renderer = get_visualization_renderer()
|
97
103
|
if display_url:
|
98
|
-
app_url = get_app_url(circuit_dataid, circuit)
|
104
|
+
app_url = get_app_url(circuit_dataid, circuit, include_query=False)
|
99
105
|
print(f"Quantum program link: {app_url}") # noqa: T201
|
100
106
|
await renderer(circuit_dataid, circuit)
|
101
107
|
|
@@ -111,7 +117,7 @@ async def _show_interactive(self: QuantumProgram, display_url: bool = True) -> N
|
|
111
117
|
Whether to print the url
|
112
118
|
|
113
119
|
Links:
|
114
|
-
[Visualization tool](https://docs.classiq.io/latest/
|
120
|
+
[Visualization tool](https://docs.classiq.io/latest/user-guide/analysis/quantum-program-visualization-tool/)
|
115
121
|
"""
|
116
122
|
await handle_remote_app(self, display_url)
|
117
123
|
|
classiq/analyzer/url_utils.py
CHANGED
@@ -24,8 +24,9 @@ def circuit_page_search_params(circuit_version: str) -> str:
|
|
24
24
|
)
|
25
25
|
|
26
26
|
|
27
|
-
def circuit_page_uri(circuit_id: str, circuit_version: str) -> str:
|
27
|
+
def circuit_page_uri(circuit_id: str, circuit_version: str, include_query: bool) -> str:
|
28
28
|
url = urljoin(f"{routes.ANALYZER_CIRCUIT_PAGE}/", circuit_id)
|
29
|
-
|
30
|
-
|
29
|
+
if include_query:
|
30
|
+
query_string = circuit_page_search_params(circuit_version)
|
31
|
+
url += QUERY_START_MARK + query_string
|
31
32
|
return url
|
classiq/interface/_version.py
CHANGED
@@ -30,9 +30,6 @@ class BackendPreferences(BaseModel):
|
|
30
30
|
"""
|
31
31
|
Preferences for the execution of the quantum program.
|
32
32
|
|
33
|
-
For more details, refer to:
|
34
|
-
[BackendPreferences](https://docs.classiq.io/latest/reference-manual/python-sdk/?h=backend#classiq.Preferences.backend_preferences)
|
35
|
-
|
36
33
|
Attributes:
|
37
34
|
backend_service_provider (str): Provider company or cloud for the requested backend.
|
38
35
|
backend_name (str): Name of the requested backend or target.
|
@@ -23,7 +23,6 @@ class FunctionDebugInfo(BaseModel):
|
|
23
23
|
name: str
|
24
24
|
statement_type: Union[StatementType, None] = None
|
25
25
|
is_inverse: bool = Field(default=False)
|
26
|
-
release_by_inverse: bool = Field(default=False)
|
27
26
|
control_variable: Optional[str] = Field(default=None)
|
28
27
|
port_to_passed_variable_map: dict[str, str] = Field(default_factory=dict)
|
29
28
|
node: Optional[ConcreteQuantumStatement] = None
|
@@ -29,7 +29,8 @@ class ExecutionPreferences(pydantic.BaseModel):
|
|
29
29
|
Execution preferences for running a quantum program.
|
30
30
|
|
31
31
|
For more details, refer to:
|
32
|
-
|
32
|
+
ExecutionPreferences example: [ExecutionPreferences](https://docs.classiq.io/latest/user-guide/execution/#execution-preferences)..
|
33
|
+
|
33
34
|
|
34
35
|
Attributes:
|
35
36
|
noise_properties (Optional[NoiseProperties]): Properties defining the noise in the quantum circuit. Defaults to `None`.
|
@@ -1,8 +1,8 @@
|
|
1
1
|
EXPANDED_KEYWORD = "expanded__"
|
2
2
|
CAPTURE_SUFFIX = "_captured__"
|
3
3
|
LAMBDA_KEYWORD = "lambda__"
|
4
|
-
INPLACE_ARITH_AUX_VAR_PREFIX = "
|
4
|
+
INPLACE_ARITH_AUX_VAR_PREFIX = "_tmp"
|
5
5
|
|
6
6
|
|
7
7
|
def generate_original_function_name(name: str) -> str:
|
8
|
-
return name.split(f"_{EXPANDED_KEYWORD}")[0]
|
8
|
+
return name.split(f"_{LAMBDA_KEYWORD}")[0].split(f"_{EXPANDED_KEYWORD}")[0]
|
@@ -1,20 +1,24 @@
|
|
1
1
|
SUPPORTED_PYTHON_BUILTIN_FUNCTIONS = {"len", "sum", "print"}
|
2
2
|
|
3
|
-
|
4
|
-
"do_div",
|
5
|
-
"do_slice",
|
6
|
-
"do_subscript",
|
3
|
+
CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS = {
|
7
4
|
"hypercube_entangler_graph",
|
8
5
|
"grid_entangler_graph",
|
9
6
|
"qft_const_adder_phase",
|
10
7
|
"log_normal_finance_post_process",
|
11
8
|
"gaussian_finance_post_process",
|
12
|
-
"get_type",
|
13
|
-
"struct_literal",
|
14
|
-
"get_field",
|
15
9
|
"molecule_problem_to_hamiltonian",
|
16
10
|
"fock_hamiltonian_problem_to_hamiltonian",
|
17
11
|
"molecule_ground_state_solution_post_process",
|
12
|
+
}
|
13
|
+
|
14
|
+
SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
|
15
|
+
*CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS,
|
16
|
+
"do_div",
|
17
|
+
"do_slice",
|
18
|
+
"do_subscript",
|
19
|
+
"get_type",
|
20
|
+
"struct_literal",
|
21
|
+
"get_field",
|
18
22
|
"mod_inverse",
|
19
23
|
}
|
20
24
|
|
@@ -64,8 +64,8 @@ class ClassicalSequenceProxy(NonSymbolicExpr, ClassicalProxy):
|
|
64
64
|
if _is_int(start_) and _is_int(stop_):
|
65
65
|
start = int(start_)
|
66
66
|
stop = int(stop_)
|
67
|
-
if start
|
68
|
-
raise ClassiqIndexError("Array slice has
|
67
|
+
if start > stop:
|
68
|
+
raise ClassiqIndexError("Array slice has negative length")
|
69
69
|
if start < 0 or (isinstance(self.length, int) and stop > self.length):
|
70
70
|
raise ClassiqIndexError("Array slice is out of bounds")
|
71
71
|
return self.get_slice_at(start_, stop_)
|
@@ -84,6 +84,10 @@ class ClassicalSequenceProxy(NonSymbolicExpr, ClassicalProxy):
|
|
84
84
|
)
|
85
85
|
if isinstance(self.length, int) and index >= self.length:
|
86
86
|
raise ClassiqIndexError("Array index is out of bounds")
|
87
|
+
if isinstance(index_, tuple):
|
88
|
+
raise ClassiqIndexError(
|
89
|
+
"list indices must be integers or slices, not tuple"
|
90
|
+
)
|
87
91
|
return self.get_subscript_at(index_)
|
88
92
|
|
89
93
|
def get_subscript_at(self, index: Any) -> ClassicalProxy:
|
@@ -47,7 +47,7 @@ END_BAD_REGISTER_ERROR_MSG = (
|
|
47
47
|
)
|
48
48
|
|
49
49
|
ALPHANUM_AND_UNDERSCORE = r"[0-9a-zA-Z_]*"
|
50
|
-
NAME_REGEX = rf"[a-zA-Z]{ALPHANUM_AND_UNDERSCORE}"
|
50
|
+
NAME_REGEX = rf"_?[a-zA-Z]{ALPHANUM_AND_UNDERSCORE}"
|
51
51
|
|
52
52
|
_UNVALIDATED_FUNCTIONS = ["Arithmetic", "CustomFunction"]
|
53
53
|
|
@@ -54,7 +54,7 @@ VISUALIZATION_HIDE_LIST = [
|
|
54
54
|
"stmt_block",
|
55
55
|
]
|
56
56
|
|
57
|
-
CONTROLLED_PREFIX = "
|
57
|
+
CONTROLLED_PREFIX = "c_"
|
58
58
|
|
59
59
|
|
60
60
|
def last_name_in_call_hierarchy(name: str) -> str:
|
@@ -189,7 +189,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
189
189
|
is_unitary: bool = Field(default=True, exclude=True)
|
190
190
|
uuid: Optional[UUID] = Field(default=None, exclude=True)
|
191
191
|
port_to_passed_variable_map: dict[str, str] = Field(default={})
|
192
|
-
release_by_inverse: bool = Field(default=False)
|
193
192
|
back_refs: StatementBlock = Field(default_factory=list)
|
194
193
|
|
195
194
|
model_config = ConfigDict(extra="allow")
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import uuid
|
2
|
+
import warnings
|
2
3
|
from datetime import datetime, timezone
|
3
4
|
from pathlib import Path
|
4
5
|
from typing import Optional, Union
|
@@ -8,6 +9,7 @@ from typing_extensions import TypeAlias
|
|
8
9
|
|
9
10
|
from classiq.interface.compression_utils import decompress
|
10
11
|
from classiq.interface.exceptions import (
|
12
|
+
ClassiqDeprecationWarning,
|
11
13
|
ClassiqMissingOutputFormatError,
|
12
14
|
ClassiqStateInitializationError,
|
13
15
|
)
|
@@ -72,6 +74,8 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
72
74
|
compressed_debug_info: Optional[bytes] = pydantic.Field(default=None)
|
73
75
|
program_id: str = pydantic.Field(default_factory=get_uuid_as_str)
|
74
76
|
execution_primitives_input: Optional[PrimitivesInput] = pydantic.Field(default=None)
|
77
|
+
synthesis_warnings: Optional[list[str]] = pydantic.Field(default=None)
|
78
|
+
should_warn: bool = pydantic.Field(default=False)
|
75
79
|
|
76
80
|
def __str__(self) -> str:
|
77
81
|
return self.model_dump_json(indent=2)
|
@@ -198,3 +202,12 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
198
202
|
FunctionDebugInfoInterface.model_validate(debug_info_dict)
|
199
203
|
for debug_info_dict in decompressed_debug_info_dict_list
|
200
204
|
]
|
205
|
+
|
206
|
+
def raise_warnings(self) -> None:
|
207
|
+
"""
|
208
|
+
Raises all warnings that were collected during synthesis.
|
209
|
+
"""
|
210
|
+
if self.synthesis_warnings is None:
|
211
|
+
return
|
212
|
+
for warning in self.synthesis_warnings:
|
213
|
+
warnings.warn(warning, ClassiqDeprecationWarning, stacklevel=2)
|
@@ -1,7 +1,19 @@
|
|
1
|
-
from pydantic import BaseModel, Field, NonNegativeInt
|
1
|
+
from pydantic import BaseModel, Field, NonNegativeInt, PrivateAttr
|
2
2
|
|
3
3
|
|
4
4
|
class CompilationMetadata(BaseModel):
|
5
5
|
should_synthesize_separately: bool = Field(default=False)
|
6
6
|
occurrences_number: NonNegativeInt = Field(default=1)
|
7
|
-
|
7
|
+
_occupation_number: NonNegativeInt = PrivateAttr(default=0)
|
8
|
+
unchecked: list[str] = Field(default_factory=list)
|
9
|
+
atomic_qualifiers: list[str] = Field(
|
10
|
+
default_factory=list, exclude=True
|
11
|
+
) # TODO remove after deprecation https://classiq.atlassian.net/browse/CLS-2671 atomic_qualifiers: list[str] = Field(default_factory=list)
|
12
|
+
|
13
|
+
@property
|
14
|
+
def occupation_number(self) -> NonNegativeInt:
|
15
|
+
return self._occupation_number
|
16
|
+
|
17
|
+
@occupation_number.setter
|
18
|
+
def occupation_number(self, value: NonNegativeInt) -> None:
|
19
|
+
self._occupation_number = value
|
@@ -12,6 +12,12 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
12
12
|
HANDLE_ID_SEPARATOR = "___"
|
13
13
|
|
14
14
|
|
15
|
+
def _get_expr_id(expr: Expression) -> str:
|
16
|
+
if expr.expr.isidentifier() or expr.expr.isnumeric():
|
17
|
+
return expr.expr
|
18
|
+
return str(abs(hash(expr.expr)))
|
19
|
+
|
20
|
+
|
15
21
|
class HandleBinding(ASTNode):
|
16
22
|
name: str = Field(default=None)
|
17
23
|
model_config = ConfigDict(frozen=True, extra="forbid")
|
@@ -131,7 +137,10 @@ class SubscriptHandleBinding(NestedHandleBinding):
|
|
131
137
|
|
132
138
|
@property
|
133
139
|
def identifier(self) -> str:
|
134
|
-
return
|
140
|
+
return (
|
141
|
+
f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}"
|
142
|
+
f"{_get_expr_id(self.index)}"
|
143
|
+
)
|
135
144
|
|
136
145
|
def collapse(self) -> HandleBinding:
|
137
146
|
if isinstance(self.base_handle, SlicedHandleBinding):
|
@@ -216,7 +225,8 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
216
225
|
@property
|
217
226
|
def identifier(self) -> str:
|
218
227
|
return (
|
219
|
-
f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}
|
228
|
+
f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}"
|
229
|
+
f"{_get_expr_id(self.start)}_{_get_expr_id(self.end)}"
|
220
230
|
)
|
221
231
|
|
222
232
|
def collapse(self) -> HandleBinding:
|
@@ -5,7 +5,10 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
5
5
|
from typing_extensions import Self
|
6
6
|
|
7
7
|
from classiq.interface.ast_node import HashableASTNode
|
8
|
-
from classiq.interface.exceptions import
|
8
|
+
from classiq.interface.exceptions import (
|
9
|
+
ClassiqInternalExpansionError,
|
10
|
+
ClassiqValueError,
|
11
|
+
)
|
9
12
|
from classiq.interface.generator.arith import number_utils
|
10
13
|
from classiq.interface.generator.arith.register_user_input import (
|
11
14
|
RegisterArithmeticInfo,
|
@@ -214,6 +217,14 @@ class QuantumNumeric(QuantumScalar):
|
|
214
217
|
)
|
215
218
|
return self
|
216
219
|
|
220
|
+
def set_size_in_bits(self, val: int) -> None:
|
221
|
+
super().set_size_in_bits(val)
|
222
|
+
if self.size is not None:
|
223
|
+
if self.size.is_evaluated() and self.size.value == val:
|
224
|
+
return
|
225
|
+
raise ClassiqInternalExpansionError("Numeric size mismatch")
|
226
|
+
self.size = Expression(expr=str(val))
|
227
|
+
|
217
228
|
@property
|
218
229
|
def has_sign(self) -> bool:
|
219
230
|
return self.is_signed is not None
|
@@ -65,7 +65,6 @@ ASSIGN_PARAMETERS_FULL_PATH = QUANTUM_PROGRAM_PREFIX + ASSIGN_PARAMETERS_SUFFIX
|
|
65
65
|
|
66
66
|
ANALYZER_FULL_PATH = ANALYZER_PREFIX + TASKS_SUFFIX
|
67
67
|
ANALYZER_RB_FULL_PATH = ANALYZER_PREFIX + TASK_RB_SUFFIX
|
68
|
-
GENERATE_RESOURCE_ESTIMATOR_REPORT = "/resource_estimator_report"
|
69
68
|
|
70
69
|
TASKS_SOLVE_EXACT_SUFFIX = "/tasks/solve_exact"
|
71
70
|
|
@@ -284,7 +284,7 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
284
284
|
length = value.length
|
285
285
|
else:
|
286
286
|
length = len(value)
|
287
|
-
if length != 2**index.size:
|
287
|
+
if not isinstance(length, sympy.Basic) and length != 2**index.size:
|
288
288
|
raise ClassiqExpansionError(
|
289
289
|
f"Quantum numeric subscript size mismatch: The quantum numeric has "
|
290
290
|
f"{index.size} qubits but the list size is {length} != 2**{index.size}"
|
@@ -11,7 +11,10 @@ from classiq.interface.exceptions import (
|
|
11
11
|
ClassiqInternalExpansionError,
|
12
12
|
)
|
13
13
|
from classiq.interface.generator.expressions.expression import Expression
|
14
|
-
from classiq.interface.generator.functions.classical_type import
|
14
|
+
from classiq.interface.generator.functions.classical_type import (
|
15
|
+
CLASSICAL_ATTRIBUTES_TYPES,
|
16
|
+
ClassicalType,
|
17
|
+
)
|
15
18
|
from classiq.interface.generator.functions.port_declaration import (
|
16
19
|
PortDeclarationDirection,
|
17
20
|
)
|
@@ -21,6 +24,7 @@ from classiq.interface.model.classical_parameter_declaration import (
|
|
21
24
|
ClassicalParameterDeclaration,
|
22
25
|
)
|
23
26
|
from classiq.interface.model.handle_binding import (
|
27
|
+
FieldHandleBinding,
|
24
28
|
HandleBinding,
|
25
29
|
HandlesList,
|
26
30
|
NestedHandleBinding,
|
@@ -172,6 +176,27 @@ class _CapturedClassicalVar(_Captured):
|
|
172
176
|
)
|
173
177
|
|
174
178
|
|
179
|
+
@dataclass(frozen=True)
|
180
|
+
class _CapturedQuantumTypeAttribute(_Captured):
|
181
|
+
handle: FieldHandleBinding
|
182
|
+
classical_type: ClassicalType
|
183
|
+
defining_function: "FunctionClosure"
|
184
|
+
|
185
|
+
@property
|
186
|
+
def mangled_name(self) -> str:
|
187
|
+
return mangle_captured_var_name(
|
188
|
+
self.handle.identifier,
|
189
|
+
self.defining_function.name,
|
190
|
+
self.defining_function.depth,
|
191
|
+
)
|
192
|
+
|
193
|
+
@property
|
194
|
+
def parameter_declaration(self) -> ClassicalParameterDeclaration:
|
195
|
+
return ClassicalParameterDeclaration(
|
196
|
+
name=self.mangled_name, classical_type=self.classical_type
|
197
|
+
)
|
198
|
+
|
199
|
+
|
175
200
|
HandleState = tuple[str, "FunctionClosure", bool]
|
176
201
|
|
177
202
|
|
@@ -180,6 +205,9 @@ class CapturedVars:
|
|
180
205
|
_captured_handles: list[_CapturedHandle] = field(default_factory=list)
|
181
206
|
_handle_states: list[HandleState] = field(default_factory=list)
|
182
207
|
_captured_classical_vars: list[_CapturedClassicalVar] = field(default_factory=list)
|
208
|
+
_captured_quantum_type_attributes: list[_CapturedQuantumTypeAttribute] = field(
|
209
|
+
default_factory=list
|
210
|
+
)
|
183
211
|
|
184
212
|
def capture_handle(
|
185
213
|
self,
|
@@ -410,11 +438,38 @@ class CapturedVars:
|
|
410
438
|
return
|
411
439
|
self._captured_classical_vars.append(captured_classical_var)
|
412
440
|
|
441
|
+
def capture_quantum_type_attribute(
|
442
|
+
self,
|
443
|
+
handle: FieldHandleBinding,
|
444
|
+
defining_function: "FunctionClosure",
|
445
|
+
) -> None:
|
446
|
+
self._capture_quantum_type_attribute(
|
447
|
+
_CapturedQuantumTypeAttribute(
|
448
|
+
handle=handle,
|
449
|
+
classical_type=CLASSICAL_ATTRIBUTES_TYPES[handle.field],
|
450
|
+
defining_function=defining_function,
|
451
|
+
is_propagated=False,
|
452
|
+
)
|
453
|
+
)
|
454
|
+
|
455
|
+
def _capture_quantum_type_attribute(
|
456
|
+
self, captured_qta: _CapturedQuantumTypeAttribute
|
457
|
+
) -> None:
|
458
|
+
for existing_captured_qta in self._captured_quantum_type_attributes:
|
459
|
+
if existing_captured_qta.handle == captured_qta.handle and _same_closure(
|
460
|
+
existing_captured_qta.defining_function,
|
461
|
+
captured_qta.defining_function,
|
462
|
+
):
|
463
|
+
return
|
464
|
+
self._captured_quantum_type_attributes.append(captured_qta)
|
465
|
+
|
413
466
|
def update(self, other_captured_vars: "CapturedVars") -> None:
|
414
467
|
for captured_handle in other_captured_vars._captured_handles:
|
415
468
|
self._capture_handle(captured_handle)
|
416
469
|
for captured_classical_var in other_captured_vars._captured_classical_vars:
|
417
470
|
self._capture_classical_var(captured_classical_var)
|
471
|
+
for captured_qta in other_captured_vars._captured_quantum_type_attributes:
|
472
|
+
self._capture_quantum_type_attribute(captured_qta)
|
418
473
|
|
419
474
|
def negate(self) -> "CapturedVars":
|
420
475
|
return CapturedVars(
|
@@ -422,7 +477,10 @@ class CapturedVars:
|
|
422
477
|
captured_handle.change_direction(captured_handle.direction.negate())
|
423
478
|
for captured_handle in self._captured_handles
|
424
479
|
],
|
425
|
-
_captured_classical_vars=self._captured_classical_vars,
|
480
|
+
_captured_classical_vars=list(self._captured_classical_vars),
|
481
|
+
_captured_quantum_type_attributes=list(
|
482
|
+
self._captured_quantum_type_attributes
|
483
|
+
),
|
426
484
|
)
|
427
485
|
|
428
486
|
def filter_vars(self, current_function: "FunctionClosure") -> "CapturedVars":
|
@@ -441,6 +499,11 @@ class CapturedVars:
|
|
441
499
|
captured_classical_var.defining_function, current_function
|
442
500
|
)
|
443
501
|
],
|
502
|
+
_captured_quantum_type_attributes=[
|
503
|
+
captured_qta
|
504
|
+
for captured_qta in self._captured_quantum_type_attributes
|
505
|
+
if not _same_closure(captured_qta.defining_function, current_function)
|
506
|
+
],
|
444
507
|
)
|
445
508
|
|
446
509
|
def filter_var_decls(
|
@@ -451,12 +514,14 @@ class CapturedVars:
|
|
451
514
|
_captured_handles=[
|
452
515
|
captured_handle
|
453
516
|
for captured_handle in self._captured_handles
|
454
|
-
if
|
455
|
-
current_declared_vars is not None
|
456
|
-
and captured_handle.handle.name not in current_declared_vars
|
457
|
-
)
|
517
|
+
if captured_handle.handle.name not in current_declared_vars
|
458
518
|
],
|
459
519
|
_captured_classical_vars=self._captured_classical_vars,
|
520
|
+
_captured_quantum_type_attributes=[
|
521
|
+
captured_qta
|
522
|
+
for captured_qta in self._captured_quantum_type_attributes
|
523
|
+
if (captured_qta.handle.name not in current_declared_vars)
|
524
|
+
],
|
460
525
|
)
|
461
526
|
|
462
527
|
def set_propagated(self) -> "CapturedVars":
|
@@ -469,6 +534,10 @@ class CapturedVars:
|
|
469
534
|
captured_classical_var.set_propagated()
|
470
535
|
for captured_classical_var in self._captured_classical_vars
|
471
536
|
],
|
537
|
+
_captured_quantum_type_attributes=[
|
538
|
+
captured_qta.set_propagated()
|
539
|
+
for captured_qta in self._captured_quantum_type_attributes
|
540
|
+
],
|
472
541
|
)
|
473
542
|
|
474
543
|
def get_captured_parameters(self) -> list[PositionalArg]:
|
@@ -477,6 +546,10 @@ class CapturedVars:
|
|
477
546
|
captured_classical_var.parameter_declaration
|
478
547
|
for captured_classical_var in self._captured_classical_vars
|
479
548
|
]
|
549
|
+
decls += [
|
550
|
+
captured_qta.parameter_declaration
|
551
|
+
for captured_qta in self._captured_quantum_type_attributes
|
552
|
+
]
|
480
553
|
decls += [captured_handle.port for captured_handle in self._captured_handles]
|
481
554
|
return decls
|
482
555
|
|
@@ -494,6 +567,16 @@ class CapturedVars:
|
|
494
567
|
)
|
495
568
|
for captured_classical_var in self._captured_classical_vars
|
496
569
|
]
|
570
|
+
args += [
|
571
|
+
Expression(
|
572
|
+
expr=(
|
573
|
+
str(captured_qta.handle)
|
574
|
+
if _same_closure(current_function, captured_qta.defining_function)
|
575
|
+
else captured_qta.mangled_name
|
576
|
+
)
|
577
|
+
)
|
578
|
+
for captured_qta in self._captured_quantum_type_attributes
|
579
|
+
]
|
497
580
|
args += [
|
498
581
|
(
|
499
582
|
captured_handle.handle
|
@@ -504,7 +587,7 @@ class CapturedVars:
|
|
504
587
|
]
|
505
588
|
return args
|
506
589
|
|
507
|
-
def
|
590
|
+
def _get_immediate_captured_mapping(self) -> SymbolRenaming:
|
508
591
|
return {
|
509
592
|
captured_handle.handle: [
|
510
593
|
SymbolPart(
|
@@ -517,7 +600,7 @@ class CapturedVars:
|
|
517
600
|
if not captured_handle.is_propagated
|
518
601
|
}
|
519
602
|
|
520
|
-
def
|
603
|
+
def _get_propagated_captured_mapping(self) -> SymbolRenaming:
|
521
604
|
return {
|
522
605
|
captured_handle.mangled_handle: [
|
523
606
|
SymbolPart(
|
@@ -529,7 +612,7 @@ class CapturedVars:
|
|
529
612
|
for captured_handle in self._captured_handles
|
530
613
|
}
|
531
614
|
|
532
|
-
def
|
615
|
+
def _get_classical_captured_mapping(self) -> SymbolRenaming:
|
533
616
|
return {
|
534
617
|
(handle := HandleBinding(name=captured_classical_var.name)): [
|
535
618
|
HandleRenaming(
|
@@ -541,6 +624,26 @@ class CapturedVars:
|
|
541
624
|
if not captured_classical_var.is_propagated
|
542
625
|
}
|
543
626
|
|
627
|
+
def _get_quantum_type_attributes_captured_mapping(self) -> SymbolRenaming:
|
628
|
+
return {
|
629
|
+
(handle := captured_qta.handle): [
|
630
|
+
HandleRenaming(
|
631
|
+
source_handle=handle,
|
632
|
+
target_var_name=captured_qta.mangled_name,
|
633
|
+
)
|
634
|
+
]
|
635
|
+
for captured_qta in self._captured_quantum_type_attributes
|
636
|
+
if not captured_qta.is_propagated
|
637
|
+
}
|
638
|
+
|
639
|
+
def get_captured_mapping(self, is_lambda: bool) -> SymbolRenaming:
|
640
|
+
rewrite_mapping = dict(self._get_propagated_captured_mapping())
|
641
|
+
if is_lambda:
|
642
|
+
rewrite_mapping |= self._get_immediate_captured_mapping()
|
643
|
+
rewrite_mapping |= self._get_classical_captured_mapping()
|
644
|
+
rewrite_mapping |= self._get_quantum_type_attributes_captured_mapping()
|
645
|
+
return rewrite_mapping
|
646
|
+
|
544
647
|
def init_var(self, var_name: str, defining_function: "FunctionClosure") -> None:
|
545
648
|
self._handle_states.append((var_name, defining_function, False))
|
546
649
|
|
@@ -606,6 +709,9 @@ class CapturedVars:
|
|
606
709
|
_captured_handles=list(self._captured_handles),
|
607
710
|
_handle_states=list(self._handle_states),
|
608
711
|
_captured_classical_vars=list(self._captured_classical_vars),
|
712
|
+
_captured_quantum_type_attributes=list(
|
713
|
+
self._captured_quantum_type_attributes
|
714
|
+
),
|
609
715
|
)
|
610
716
|
|
611
717
|
def set(
|
@@ -636,6 +742,14 @@ class CapturedVars:
|
|
636
742
|
)
|
637
743
|
else:
|
638
744
|
self._captured_classical_vars.append(captured_classical_var)
|
745
|
+
self._captured_quantum_type_attributes = []
|
746
|
+
for captured_qta in other._captured_quantum_type_attributes:
|
747
|
+
if _same_closure(captured_qta.defining_function, source_func):
|
748
|
+
self._captured_quantum_type_attributes.append(
|
749
|
+
captured_qta.change_defining_function(target_func)
|
750
|
+
)
|
751
|
+
else:
|
752
|
+
self._captured_quantum_type_attributes.append(captured_qta)
|
639
753
|
|
640
754
|
|
641
755
|
def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") -> bool:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import dataclasses
|
2
2
|
from collections.abc import Sequence
|
3
|
+
from copy import deepcopy
|
3
4
|
from dataclasses import dataclass, field
|
4
5
|
from typing import Any, Optional
|
5
6
|
|
@@ -104,6 +105,7 @@ class FunctionClosure(Closure):
|
|
104
105
|
scope=self.scope.clone(),
|
105
106
|
signature_scope=self.signature_scope.clone(),
|
106
107
|
captured_vars=self.captured_vars.clone(),
|
108
|
+
positional_arg_declarations=deepcopy(self.positional_arg_declarations),
|
107
109
|
)
|
108
110
|
|
109
111
|
def emit(self) -> QuantumCallable:
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from collections.abc import Sequence
|
2
|
-
|
3
1
|
from classiq.interface.exceptions import (
|
4
2
|
ClassiqExpansionError,
|
5
3
|
ClassiqInternalExpansionError,
|
@@ -11,8 +9,6 @@ from classiq.interface.generator.functions.type_name import (
|
|
11
9
|
)
|
12
10
|
from classiq.interface.model.bind_operation import BindOperation
|
13
11
|
from classiq.interface.model.inplace_binary_operation import BinaryOperation
|
14
|
-
from classiq.interface.model.port_declaration import PortDeclaration
|
15
|
-
from classiq.interface.model.quantum_function_declaration import PositionalArg
|
16
12
|
from classiq.interface.model.quantum_type import (
|
17
13
|
QuantumBit,
|
18
14
|
QuantumBitvector,
|
@@ -147,20 +143,16 @@ def set_length_by_size(
|
|
147
143
|
quantum_array.length = Expression(expr=str(size // element_size))
|
148
144
|
|
149
145
|
|
150
|
-
def validate_bind_targets(
|
151
|
-
bind: BindOperation, scope: Scope, allow_symbolic_size: bool
|
152
|
-
) -> None:
|
146
|
+
def validate_bind_targets(bind: BindOperation, scope: Scope) -> None:
|
153
147
|
illegal_qnum_bind_targets = []
|
154
148
|
for out_handle in bind.out_handles:
|
155
149
|
out_var = scope[out_handle.name].as_type(QuantumSymbol)
|
156
150
|
out_var_type = out_var.quantum_type
|
157
151
|
if not isinstance(out_var_type, QuantumNumeric):
|
158
152
|
continue
|
159
|
-
if
|
160
|
-
not allow_symbolic_size and not out_var_type.has_size_in_bits
|
161
|
-
):
|
153
|
+
if not out_var_type.has_size_in_bits:
|
162
154
|
illegal_qnum_bind_targets.append(str(out_var.handle))
|
163
|
-
elif not
|
155
|
+
elif not out_var_type.has_sign:
|
164
156
|
assert not out_var_type.has_fraction_digits
|
165
157
|
illegal_qnum_bind_targets.append(str(out_var.handle))
|
166
158
|
if len(illegal_qnum_bind_targets) > 0:
|
@@ -187,13 +179,6 @@ def get_inplace_op_scalar_as_numeric(
|
|
187
179
|
raise ClassiqInternalExpansionError(f"Unexpected scalar type {var.quantum_type}")
|
188
180
|
|
189
181
|
|
190
|
-
def is_signature_monomorphic(params: Sequence[PositionalArg]) -> bool:
|
191
|
-
return all(
|
192
|
-
isinstance(param, PortDeclaration) and param.quantum_type.is_evaluated
|
193
|
-
for param in params
|
194
|
-
)
|
195
|
-
|
196
|
-
|
197
182
|
def set_bounds(from_type: QuantumType, to_type: QuantumNumeric) -> None:
|
198
183
|
if not isinstance(from_type, QuantumNumeric):
|
199
184
|
to_type.reset_bounds()
|