classiq 0.68.0__py3-none-any.whl → 0.70.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/_internals/api_wrapper.py +4 -8
- classiq/analyzer/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/jobs.py +2 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +8 -3
- classiq/interface/chemistry/operator.py +12 -28
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +11 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/circuit_code/circuit_code.py +4 -0
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
- classiq/interface/generator/expressions/expression_types.py +8 -2
- classiq/interface/generator/expressions/proxies/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +75 -0
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
- classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +31 -0
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
- classiq/interface/generator/functions/classical_type.py +34 -29
- classiq/interface/generator/functions/type_name.py +26 -2
- classiq/interface/generator/generated_circuit_data.py +84 -27
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +12 -1
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/native_function_definition.py +0 -10
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/model/quantum_type.py +15 -3
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
- classiq/model_expansions/evaluators/arg_type_match.py +4 -2
- classiq/model_expansions/evaluators/classical_expression.py +2 -2
- classiq/model_expansions/evaluators/control.py +1 -1
- classiq/model_expansions/evaluators/parameter_types.py +58 -16
- classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
- classiq/model_expansions/expression_evaluator.py +3 -1
- classiq/model_expansions/generative_functions.py +67 -7
- classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -6
- classiq/model_expansions/scope_initialization.py +20 -33
- classiq/model_expansions/transformers/model_renamer.py +13 -4
- classiq/model_expansions/visitors/variable_references.py +8 -4
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/amplitude_amplification.py +3 -7
- classiq/open_library/functions/discrete_sine_cosine_transform.py +4 -4
- classiq/open_library/functions/grover.py +2 -2
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/lookup_table.py +58 -0
- classiq/open_library/functions/modular_exponentiation.py +10 -20
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/declaration_inferrer.py +3 -1
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/qmod_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +11 -14
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +29 -0
- classiq/qmod/utilities.py +67 -2
- classiq/synthesis.py +9 -6
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/METADATA +10 -12
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/RECORD +95 -84
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/WHEEL +1 -1
- classiq/interface/execution/jobs.py +0 -31
- /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
- /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -11,13 +11,17 @@ from classiq.interface.generator.arith.register_user_input import (
|
|
11
11
|
RegisterUserInput,
|
12
12
|
)
|
13
13
|
from classiq.interface.generator.expressions.expression import Expression
|
14
|
-
from classiq.interface.generator.expressions.qmod_qarray_proxy import
|
15
|
-
|
14
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy import (
|
15
|
+
QmodQArrayProxy,
|
16
|
+
)
|
17
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
16
18
|
QmodQBitProxy,
|
17
19
|
QmodQNumProxy,
|
18
20
|
QmodQScalarProxy,
|
19
21
|
)
|
20
|
-
from classiq.interface.generator.expressions.qmod_sized_proxy import
|
22
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
23
|
+
QmodSizedProxy,
|
24
|
+
)
|
21
25
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
22
26
|
from classiq.interface.model.handle_binding import HandleBinding
|
23
27
|
|
@@ -213,6 +217,14 @@ class QuantumNumeric(QuantumScalar):
|
|
213
217
|
0 if self.fraction_digits is None else self.fraction_digits.to_int_value()
|
214
218
|
)
|
215
219
|
|
220
|
+
@property
|
221
|
+
def is_qbit(self) -> bool:
|
222
|
+
return (
|
223
|
+
self.size_in_bits == 1
|
224
|
+
and self.fraction_digits_value == 0
|
225
|
+
and not self.sign_value
|
226
|
+
)
|
227
|
+
|
216
228
|
def _update_size_in_bits_from_declaration(self) -> None:
|
217
229
|
if self.size is not None and self.size.is_evaluated():
|
218
230
|
self._size_in_bits = self.size.to_int_value()
|
@@ -7,9 +7,6 @@ PROVIDERS_PREFIX = "/providers"
|
|
7
7
|
|
8
8
|
IQCC_PREFIX = PROVIDERS_PREFIX + "/iqcc"
|
9
9
|
|
10
|
-
EXECUTION_NON_VERSIONED_PREFIX = "/execution/v1"
|
11
|
-
SYNTHESIS_NON_VERSIONED_PREFIX = "/synthesis/v1"
|
12
|
-
|
13
10
|
ANALYZER_CIRCUIT_PAGE = "circuit"
|
14
11
|
DEFAULT_IDE_FE_APP = "https://platform.classiq.io/"
|
15
12
|
|
@@ -58,9 +55,6 @@ TASKS_GENERATE_FULL_PATH = TASKS_GENERATE_SUFFIX
|
|
58
55
|
|
59
56
|
EXECUTION_JOBS_SUFFIX = "/jobs"
|
60
57
|
EXECUTION_JOBS_FULL_PATH = EXECUTION_PREFIX + EXECUTION_JOBS_SUFFIX
|
61
|
-
EXECUTION_JOBS_NON_VERSIONED_FULL_PATH = (
|
62
|
-
EXECUTION_NON_VERSIONED_PREFIX + EXECUTION_JOBS_SUFFIX
|
63
|
-
)
|
64
58
|
|
65
59
|
ANALYZER_FULL_PATH = ANALYZER_PREFIX + TASKS_SUFFIX
|
66
60
|
ANALYZER_RB_FULL_PATH = ANALYZER_PREFIX + TASK_RB_SUFFIX
|
@@ -12,9 +12,15 @@ from classiq.interface.generator.expressions.expression_types import (
|
|
12
12
|
ExpressionValue,
|
13
13
|
QmodStructInstance,
|
14
14
|
)
|
15
|
-
from classiq.interface.generator.expressions.qmod_qscalar_proxy import
|
16
|
-
|
17
|
-
|
15
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
16
|
+
QmodQNumProxy,
|
17
|
+
)
|
18
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
19
|
+
QmodQStructProxy,
|
20
|
+
)
|
21
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
22
|
+
QmodSizedProxy,
|
23
|
+
)
|
18
24
|
from classiq.interface.generator.expressions.type_proxy import TypeProxy
|
19
25
|
from classiq.interface.generator.functions.classical_function_declaration import (
|
20
26
|
ClassicalFunctionDeclaration,
|
@@ -3,10 +3,12 @@ from enum import Enum
|
|
3
3
|
from typing import Any
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqExpansionError
|
6
|
-
from classiq.interface.generator.expressions.
|
7
|
-
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
6
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
8
7
|
QmodStructInstance,
|
9
8
|
)
|
9
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
10
|
+
QmodSizedProxy,
|
11
|
+
)
|
10
12
|
from classiq.interface.generator.functions.classical_type import (
|
11
13
|
StructMetaType,
|
12
14
|
)
|
@@ -23,13 +23,13 @@ def evaluate_classical_expression(expr: Expression, scope: Scope) -> Evaluated:
|
|
23
23
|
)
|
24
24
|
for name, evaluated in all_symbols
|
25
25
|
if isinstance(evaluated.value, QuantumSymbol)
|
26
|
-
and evaluated.value.quantum_type.
|
26
|
+
and evaluated.value.quantum_type.is_evaluated
|
27
27
|
}
|
28
28
|
uninitialized_locals = {
|
29
29
|
name
|
30
30
|
for name, evaluated in all_symbols
|
31
31
|
if isinstance(evaluated.value, QuantumSymbol)
|
32
|
-
and not evaluated.value.quantum_type.
|
32
|
+
and not evaluated.value.quantum_type.is_evaluated
|
33
33
|
}
|
34
34
|
|
35
35
|
ret = evaluate(expr, locals_dict, uninitialized_locals)
|
@@ -8,7 +8,7 @@ from classiq.interface.generator.arith.argument_utils import (
|
|
8
8
|
unsigned_integer_interpretation,
|
9
9
|
)
|
10
10
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
11
|
-
from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
|
11
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qscalar_proxy import (
|
12
12
|
QmodQNumProxy,
|
13
13
|
QmodQScalarProxy,
|
14
14
|
QmodSizedProxy,
|
@@ -1,9 +1,10 @@
|
|
1
|
-
from typing import Union
|
1
|
+
from typing import TypeVar, Union
|
2
2
|
|
3
3
|
from classiq.interface.exceptions import (
|
4
4
|
ClassiqExpansionError,
|
5
5
|
ClassiqInternalExpansionError,
|
6
6
|
)
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
7
8
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
8
9
|
from classiq.interface.generator.functions.port_declaration import (
|
9
10
|
PortDeclarationDirection,
|
@@ -31,8 +32,6 @@ from classiq.model_expansions.evaluators.classical_expression import (
|
|
31
32
|
from classiq.model_expansions.evaluators.quantum_type_utils import (
|
32
33
|
copy_type_information,
|
33
34
|
set_element_type,
|
34
|
-
set_fraction_digits,
|
35
|
-
set_is_signed,
|
36
35
|
set_length,
|
37
36
|
set_size,
|
38
37
|
)
|
@@ -162,9 +161,14 @@ def _evaluate_qarray_in_quantum_symbol(
|
|
162
161
|
)
|
163
162
|
set_element_type(type_to_update, new_element_type)
|
164
163
|
if type_to_update.length is not None:
|
165
|
-
new_length =
|
166
|
-
type_to_update.length,
|
167
|
-
|
164
|
+
new_length = _eval_expr(
|
165
|
+
type_to_update.length,
|
166
|
+
scope,
|
167
|
+
int,
|
168
|
+
type_to_update.type_name,
|
169
|
+
"length",
|
170
|
+
param_name,
|
171
|
+
)
|
168
172
|
set_length(type_to_update, new_length)
|
169
173
|
return type_to_update
|
170
174
|
|
@@ -173,23 +177,61 @@ def _evaluate_qnum_in_quantum_symbol(
|
|
173
177
|
type_to_update: QuantumNumeric, scope: Scope, param_name: str
|
174
178
|
) -> QuantumNumeric:
|
175
179
|
if type_to_update.is_signed is not None:
|
176
|
-
new_is_sign =
|
177
|
-
type_to_update.is_signed,
|
178
|
-
|
179
|
-
|
180
|
+
new_is_sign = _eval_expr(
|
181
|
+
type_to_update.is_signed,
|
182
|
+
scope,
|
183
|
+
bool,
|
184
|
+
type_to_update.type_name,
|
185
|
+
"sign",
|
186
|
+
param_name,
|
187
|
+
)
|
188
|
+
type_to_update.is_signed = Expression(expr=str(new_is_sign))
|
180
189
|
if type_to_update.fraction_digits is not None:
|
181
|
-
new_fraction_digits =
|
182
|
-
type_to_update.fraction_digits,
|
183
|
-
|
184
|
-
|
190
|
+
new_fraction_digits = _eval_expr(
|
191
|
+
type_to_update.fraction_digits,
|
192
|
+
scope,
|
193
|
+
int,
|
194
|
+
type_to_update.type_name,
|
195
|
+
"fraction digits",
|
196
|
+
param_name,
|
197
|
+
)
|
198
|
+
type_to_update.fraction_digits = Expression(expr=str(new_fraction_digits))
|
185
199
|
if type_to_update.size is not None:
|
186
|
-
new_size =
|
187
|
-
|
200
|
+
new_size = _eval_expr(
|
201
|
+
type_to_update.size,
|
202
|
+
scope,
|
203
|
+
int,
|
204
|
+
type_to_update.type_name,
|
205
|
+
"size",
|
206
|
+
param_name,
|
188
207
|
)
|
189
208
|
set_size(type_to_update, new_size, param_name)
|
190
209
|
return type_to_update
|
191
210
|
|
192
211
|
|
212
|
+
_EXPR_TYPE = TypeVar("_EXPR_TYPE")
|
213
|
+
|
214
|
+
|
215
|
+
def _eval_expr(
|
216
|
+
expression: Expression,
|
217
|
+
scope: Scope,
|
218
|
+
expected_type: type[_EXPR_TYPE],
|
219
|
+
type_name: str,
|
220
|
+
attr_name: str,
|
221
|
+
param_name: str,
|
222
|
+
) -> _EXPR_TYPE:
|
223
|
+
val = evaluate_classical_expression(expression, scope).value
|
224
|
+
if expected_type is int and isinstance(val, float):
|
225
|
+
val = int(val)
|
226
|
+
if not isinstance(val, expected_type):
|
227
|
+
raise ClassiqExpansionError(
|
228
|
+
f"When inferring the type of parameter {param_name!r}: "
|
229
|
+
f"{type_name} {attr_name} must be {expected_type.__name__}, got "
|
230
|
+
f"{str(val)!r}"
|
231
|
+
)
|
232
|
+
return val
|
233
|
+
|
234
|
+
|
193
235
|
def _evaluate_qstruct_in_quantum_symbol(
|
194
236
|
type_to_update: TypeName, scope: Scope, param_name: str
|
195
237
|
) -> TypeName:
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from classiq.interface.exceptions import (
|
5
4
|
ClassiqExpansionError,
|
@@ -33,12 +32,11 @@ def copy_type_information(
|
|
33
32
|
if isinstance(to_type, QuantumBit):
|
34
33
|
set_size(to_type, from_type.size_in_bits, to_param_name)
|
35
34
|
elif isinstance(to_type, QuantumNumeric):
|
36
|
-
|
37
|
-
|
38
|
-
to_type
|
39
|
-
|
40
|
-
|
41
|
-
)
|
35
|
+
if to_type.size is None and isinstance(from_type, QuantumNumeric):
|
36
|
+
to_type.is_signed = Expression(expr=str(from_type.sign_value))
|
37
|
+
to_type.fraction_digits = Expression(
|
38
|
+
expr=str(from_type.fraction_digits_value)
|
39
|
+
)
|
42
40
|
set_size(to_type, from_type.size_in_bits, to_param_name)
|
43
41
|
elif isinstance(to_type, QuantumBitvector):
|
44
42
|
if isinstance(from_type, QuantumBitvector) and type( # noqa: E721
|
@@ -73,8 +71,8 @@ def set_size(quantum_type: QuantumType, size: int, param_name: str) -> None:
|
|
73
71
|
if isinstance(quantum_type, QuantumNumeric):
|
74
72
|
quantum_type.size = Expression(expr=str(size))
|
75
73
|
if not quantum_type.has_sign or not quantum_type.has_fraction_digits:
|
76
|
-
|
77
|
-
|
74
|
+
quantum_type.is_signed = Expression(expr="False")
|
75
|
+
quantum_type.fraction_digits = Expression(expr="0")
|
78
76
|
elif isinstance(quantum_type, QuantumBitvector):
|
79
77
|
if quantum_type.has_length:
|
80
78
|
if size % quantum_type.length_value != 0:
|
@@ -107,54 +105,6 @@ def set_size(quantum_type: QuantumType, size: int, param_name: str) -> None:
|
|
107
105
|
set_size(fields_without_size[0], size - predetermined_size_part, param_name)
|
108
106
|
|
109
107
|
|
110
|
-
def set_fraction_digits(
|
111
|
-
quantum_numeric: QuantumNumeric, fraction_digits: Optional[int], param_name: str
|
112
|
-
) -> None:
|
113
|
-
if fraction_digits is not None and fraction_digits < 0:
|
114
|
-
raise ClassiqExpansionError(
|
115
|
-
f"Number of fraction digits for {param_name!r} was deduced to be negative: "
|
116
|
-
f"{fraction_digits!r}"
|
117
|
-
)
|
118
|
-
|
119
|
-
if (
|
120
|
-
fraction_digits is not None
|
121
|
-
and quantum_numeric.fraction_digits is not None
|
122
|
-
and quantum_numeric.fraction_digits.is_evaluated()
|
123
|
-
and quantum_numeric.fraction_digits_value != fraction_digits
|
124
|
-
):
|
125
|
-
raise ClassiqExpansionError(
|
126
|
-
f"Fraction digits mismatch for variable {param_name!r} between declared "
|
127
|
-
f"fraction digits {quantum_numeric.fraction_digits_value!r} and assigned fraction "
|
128
|
-
f"digits {fraction_digits!r}"
|
129
|
-
)
|
130
|
-
|
131
|
-
if not (
|
132
|
-
quantum_numeric.fraction_digits is not None
|
133
|
-
and quantum_numeric.fraction_digits.is_evaluated()
|
134
|
-
):
|
135
|
-
quantum_numeric.fraction_digits = Expression(expr=str(fraction_digits or 0))
|
136
|
-
|
137
|
-
|
138
|
-
def set_is_signed(
|
139
|
-
quantum_numeric: QuantumNumeric, is_signed: Optional[bool], param_name: str
|
140
|
-
) -> None:
|
141
|
-
if (
|
142
|
-
is_signed is not None
|
143
|
-
and quantum_numeric.is_signed is not None
|
144
|
-
and quantum_numeric.is_signed.is_evaluated()
|
145
|
-
and quantum_numeric.sign_value != is_signed
|
146
|
-
):
|
147
|
-
raise ClassiqExpansionError(
|
148
|
-
f"Sign mismatch for variable {param_name!r} between declared sign {quantum_numeric.sign_value!r} and assigned sign {is_signed!r}"
|
149
|
-
)
|
150
|
-
|
151
|
-
if not (
|
152
|
-
quantum_numeric.is_signed is not None
|
153
|
-
and quantum_numeric.is_signed.is_evaluated()
|
154
|
-
):
|
155
|
-
quantum_numeric.is_signed = Expression(expr=str(is_signed or False))
|
156
|
-
|
157
|
-
|
158
108
|
def set_element_type(
|
159
109
|
quantum_array: QuantumBitvector, element_type: ConcreteQuantumType
|
160
110
|
) -> None:
|
@@ -17,7 +17,9 @@ from classiq.interface.generator.expressions.expression_constants import (
|
|
17
17
|
)
|
18
18
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
19
19
|
from classiq.interface.generator.expressions.non_symbolic_expr import NonSymbolicExpr
|
20
|
-
from classiq.interface.generator.expressions.qmod_sized_proxy import
|
20
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
21
|
+
QmodSizedProxy,
|
22
|
+
)
|
21
23
|
from classiq.interface.generator.expressions.sympy_supported_expressions import (
|
22
24
|
SYMPY_SUPPORTED_EXPRESSIONS,
|
23
25
|
)
|
@@ -1,10 +1,29 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
+
from sys import exc_info
|
3
|
+
from types import TracebackType
|
2
4
|
from typing import TYPE_CHECKING, Any
|
3
5
|
|
4
|
-
from classiq.interface.
|
6
|
+
from classiq.interface.exceptions import (
|
7
|
+
ClassiqExpansionError,
|
8
|
+
ClassiqInternalExpansionError,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
11
|
+
ClassicalArrayProxy,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
14
|
+
ClassicalProxy,
|
15
|
+
)
|
16
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_scalar_proxy import (
|
17
|
+
ClassicalScalarProxy,
|
18
|
+
)
|
19
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
20
|
+
ClassicalStructProxy,
|
21
|
+
)
|
22
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
5
23
|
QmodStructInstance,
|
6
24
|
)
|
7
|
-
from classiq.interface.generator.functions.
|
25
|
+
from classiq.interface.generator.functions.classical_type import ClassicalArray
|
26
|
+
from classiq.interface.generator.functions.type_name import Struct, TypeName
|
8
27
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
9
28
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
10
29
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -20,9 +39,10 @@ from classiq.model_expansions.closure import (
|
|
20
39
|
GenerativeClosure,
|
21
40
|
)
|
22
41
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
42
|
+
from classiq.qmod.cparam import CParam
|
23
43
|
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
24
44
|
from classiq.qmod.model_state_container import QMODULE
|
25
|
-
from classiq.qmod.qmod_parameter import CParamStruct
|
45
|
+
from classiq.qmod.qmod_parameter import CParamStruct, create_param
|
26
46
|
from classiq.qmod.qmod_variable import QNum, _create_qvar_for_qtype
|
27
47
|
from classiq.qmod.quantum_expandable import (
|
28
48
|
QTerminalCallable,
|
@@ -37,6 +57,23 @@ if TYPE_CHECKING:
|
|
37
57
|
)
|
38
58
|
|
39
59
|
|
60
|
+
def _unwrap_traceback_frame(e: Exception) -> Exception:
|
61
|
+
fallback_error = ClassiqExpansionError(str(e))
|
62
|
+
traceback = exc_info()[2]
|
63
|
+
if traceback is None:
|
64
|
+
return fallback_error
|
65
|
+
back_frame = traceback.tb_frame.f_back
|
66
|
+
if back_frame is None:
|
67
|
+
return fallback_error
|
68
|
+
back_tb = TracebackType(
|
69
|
+
tb_next=None,
|
70
|
+
tb_frame=back_frame,
|
71
|
+
tb_lasti=back_frame.f_lasti,
|
72
|
+
tb_lineno=back_frame.f_lineno,
|
73
|
+
)
|
74
|
+
return e.with_traceback(back_tb)
|
75
|
+
|
76
|
+
|
40
77
|
class LenList(list):
|
41
78
|
@property
|
42
79
|
def len(self) -> int:
|
@@ -45,7 +82,10 @@ class LenList(list):
|
|
45
82
|
def __getitem__(self, item: Any) -> Any:
|
46
83
|
if isinstance(item, QNum):
|
47
84
|
return SymbolicExpr(f"{self}[{item}]", True)
|
48
|
-
|
85
|
+
try:
|
86
|
+
return super().__getitem__(item)
|
87
|
+
except (IndexError, TypeError) as e:
|
88
|
+
raise _unwrap_traceback_frame(e) from None
|
49
89
|
|
50
90
|
@classmethod
|
51
91
|
def wrap(cls, obj: Any) -> Any:
|
@@ -54,6 +94,22 @@ class LenList(list):
|
|
54
94
|
return LenList([cls.wrap(item) for item in obj])
|
55
95
|
|
56
96
|
|
97
|
+
def _create_qmod_classical_var(proxy: ClassicalProxy) -> CParam:
|
98
|
+
if isinstance(proxy, ClassicalScalarProxy):
|
99
|
+
classical_type = proxy._classical_type
|
100
|
+
elif isinstance(proxy, ClassicalArrayProxy):
|
101
|
+
classical_type = ClassicalArray(
|
102
|
+
element_type=proxy._element_type, size=proxy._length
|
103
|
+
)
|
104
|
+
elif isinstance(proxy, ClassicalStructProxy):
|
105
|
+
classical_type = TypeName(name=proxy._decl.name)
|
106
|
+
else:
|
107
|
+
raise ClassiqInternalExpansionError(
|
108
|
+
f"Unrecognized classical proxy {type(proxy).__name__}"
|
109
|
+
)
|
110
|
+
return create_param(str(proxy.handle), classical_type, QMODULE)
|
111
|
+
|
112
|
+
|
57
113
|
def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated) -> Any:
|
58
114
|
if isinstance(param, PortDeclaration):
|
59
115
|
quantum_symbol = evaluated.as_type(QuantumSymbol)
|
@@ -90,6 +146,9 @@ def translate_ast_arg_to_python_qmod(param: PositionalArg, evaluated: Evaluated)
|
|
90
146
|
struct_type=Struct(name=classical_value.struct_declaration.name),
|
91
147
|
qmodule=QMODULE,
|
92
148
|
)
|
149
|
+
if isinstance(classical_value, ClassicalProxy):
|
150
|
+
return _create_qmod_classical_var(classical_value)
|
151
|
+
|
93
152
|
return LenList.wrap(classical_value)
|
94
153
|
|
95
154
|
|
@@ -148,7 +207,8 @@ def emit_generative_statements(
|
|
148
207
|
with _InterpreterExpandable(interpreter):
|
149
208
|
set_frontend_interpreter(interpreter)
|
150
209
|
for block_name, generative_function in operation.generative_blocks.items():
|
151
|
-
with
|
152
|
-
block_name
|
153
|
-
|
210
|
+
with (
|
211
|
+
interpreter._builder.block_context(block_name),
|
212
|
+
generative_mode_context(True),
|
213
|
+
):
|
154
214
|
generative_function._py_callable(*python_qmod_args)
|
File without changes
|
@@ -0,0 +1,60 @@
|
|
1
|
+
from classiq.interface.exceptions import ClassiqValueError
|
2
|
+
from classiq.interface.generator.arith.arithmetic import is_bool
|
3
|
+
from classiq.interface.generator.expressions.expression import Expression
|
4
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
5
|
+
ArithmeticOperation,
|
6
|
+
ArithmeticOperationKind,
|
7
|
+
)
|
8
|
+
from classiq.interface.model.quantum_type import QuantumBit, QuantumNumeric
|
9
|
+
|
10
|
+
from classiq.model_expansions.scope import QuantumSymbol
|
11
|
+
|
12
|
+
|
13
|
+
def validate_assignment_bool_expression(
|
14
|
+
result_symbol: QuantumSymbol, expr: str, op_kind: ArithmeticOperationKind
|
15
|
+
) -> None:
|
16
|
+
if not is_bool(expr):
|
17
|
+
return
|
18
|
+
_validate_target_type(result_symbol, expr, op_kind)
|
19
|
+
|
20
|
+
|
21
|
+
def _validate_target_type(
|
22
|
+
target_symbol: QuantumSymbol, expr: str, op_kind: ArithmeticOperationKind
|
23
|
+
) -> None:
|
24
|
+
supported_types = _supported_types()
|
25
|
+
if target_symbol.quantum_type.qmod_type_name not in supported_types:
|
26
|
+
raise ClassiqValueError(
|
27
|
+
f'The expression has been evaluated to "{expr}" which is a Boolean value. '
|
28
|
+
f"Cannot perform {op_kind.value} operation of Boolean expression to result variable '{target_symbol.handle}' of type {target_symbol.quantum_type.qmod_type_name}. "
|
29
|
+
f"Boolean expressions can only be applied on {' or '.join(supported_types)}."
|
30
|
+
)
|
31
|
+
|
32
|
+
|
33
|
+
def convert_assignment_bool_expression(op: ArithmeticOperation) -> None:
|
34
|
+
if not is_bool(op.expression.expr):
|
35
|
+
return
|
36
|
+
op.expression = op.expression.model_copy(
|
37
|
+
update=dict(expr="1" if op.expression.expr == "True" else "0")
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
def convert_inplace_op_bool_expression(
|
42
|
+
op: ArithmeticOperation, target: QuantumSymbol
|
43
|
+
) -> None:
|
44
|
+
if not is_bool(op.expression.expr):
|
45
|
+
return
|
46
|
+
_validate_target_type(target, op.expression.expr, op.operation_kind)
|
47
|
+
op.expression = op.expression.model_copy(
|
48
|
+
update=dict(expr="1" if op.expression.expr == "True" else "0")
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
def _supported_types() -> tuple[str, ...]:
|
53
|
+
return (
|
54
|
+
QuantumBit().qmod_type_name,
|
55
|
+
QuantumNumeric(
|
56
|
+
size=Expression(expr="1"),
|
57
|
+
is_signed=Expression(expr="False"),
|
58
|
+
fraction_digits=Expression(expr="0"),
|
59
|
+
).qmod_type_name,
|
60
|
+
)
|
@@ -11,6 +11,10 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
11
11
|
)
|
12
12
|
|
13
13
|
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
14
|
+
from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_expressions import (
|
15
|
+
convert_assignment_bool_expression,
|
16
|
+
validate_assignment_bool_expression,
|
17
|
+
)
|
14
18
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
15
19
|
from classiq.model_expansions.scope import QuantumSymbol
|
16
20
|
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
@@ -24,6 +28,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
24
28
|
):
|
25
29
|
direction = PortDeclarationDirection.Output
|
26
30
|
self._update_result_type(op)
|
31
|
+
convert_assignment_bool_expression(op)
|
27
32
|
else:
|
28
33
|
direction = PortDeclarationDirection.Inout
|
29
34
|
self._capture_handle(op.result_var, direction)
|
@@ -47,6 +52,10 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
47
52
|
self._machine_precision,
|
48
53
|
)
|
49
54
|
result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
55
|
+
|
56
|
+
validate_assignment_bool_expression(
|
57
|
+
result_symbol, op.expression.expr, op.operation_kind
|
58
|
+
) # must be here, otherwise copy_type_information will throw a non-indicative error
|
50
59
|
copy_type_information(
|
51
60
|
result_type, result_symbol.quantum_type, str(op.result_var)
|
52
61
|
)
|
@@ -13,9 +13,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
13
13
|
PortDeclarationDirection,
|
14
14
|
)
|
15
15
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
16
|
-
from classiq.interface.model.classical_parameter_declaration import (
|
17
|
-
ClassicalParameterDeclaration,
|
18
|
-
)
|
19
16
|
from classiq.interface.model.handle_binding import HandleBinding
|
20
17
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
21
18
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -162,11 +159,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
162
159
|
back_ref=self._get_back_ref(propagated_debug_info),
|
163
160
|
)
|
164
161
|
is_allocate_or_free = new_call.func_name == free.func_decl.name
|
165
|
-
parameters = {
|
166
|
-
arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
|
167
|
-
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
168
|
-
if isinstance(arg_decl, ClassicalParameterDeclaration)
|
169
|
-
}
|
170
162
|
|
171
163
|
port_to_passed_variable_map = {
|
172
164
|
arg_decl.name: str(evaluated_arg.value.handle)
|
@@ -176,11 +168,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
176
168
|
self._debug_info[new_call.uuid] = FunctionDebugInfo(
|
177
169
|
name=new_call.func_name,
|
178
170
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
179
|
-
parameters=(
|
180
|
-
parameters
|
181
|
-
if propagated_debug_info is None or propagated_debug_info.name == ""
|
182
|
-
else propagated_debug_info.parameters
|
183
|
-
),
|
184
171
|
is_allocate_or_free=is_allocate_or_free,
|
185
172
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
186
173
|
node=new_call._as_back_ref(),
|
@@ -1,9 +1,5 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
2
|
|
3
|
-
from classiq.interface.exceptions import ClassiqValueError
|
4
|
-
from classiq.interface.generator.expressions.expression import Expression
|
5
|
-
from classiq.interface.model.allocate import Allocate
|
6
|
-
from classiq.interface.model.handle_binding import HandleBinding
|
7
3
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
8
4
|
|
9
5
|
from classiq.model_expansions.closure import FunctionClosure
|
@@ -17,21 +13,12 @@ if TYPE_CHECKING:
|
|
17
13
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
18
14
|
|
19
15
|
|
20
|
-
ALLOCATE_COMPATIBILITY_ERROR_MESSAGE = (
|
21
|
-
"'allocate' expects two argument: The number of qubits to allocate (integer) and "
|
22
|
-
"the variable to be allocated (quantum variable)"
|
23
|
-
)
|
24
|
-
|
25
|
-
|
26
16
|
class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
27
17
|
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
28
18
|
super().__init__(interpreter)
|
29
19
|
self._model = self._interpreter._model
|
30
20
|
|
31
21
|
def emit(self, call: QuantumFunctionCall, /) -> bool:
|
32
|
-
if call.function == "allocate": # FIXME: Remove compatibility (CAD-25935)
|
33
|
-
self._allocate_compatibility(call)
|
34
|
-
return True
|
35
22
|
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
36
23
|
args = call.positional_args
|
37
24
|
with ErrorManager().call(function.name):
|
@@ -40,15 +27,6 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
|
|
40
27
|
)
|
41
28
|
return True
|
42
29
|
|
43
|
-
def _allocate_compatibility(self, call: QuantumFunctionCall) -> None:
|
44
|
-
if len(call.positional_args) != 2:
|
45
|
-
raise ClassiqValueError(ALLOCATE_COMPATIBILITY_ERROR_MESSAGE)
|
46
|
-
size, target = call.positional_args
|
47
|
-
if not isinstance(size, Expression) or not isinstance(target, HandleBinding):
|
48
|
-
raise ClassiqValueError(ALLOCATE_COMPATIBILITY_ERROR_MESSAGE)
|
49
|
-
allocate = Allocate(size=size, target=target, source_ref=call.source_ref)
|
50
|
-
self._interpreter.emit_statement(allocate)
|
51
|
-
|
52
30
|
|
53
31
|
class DeclarativeQuantumFunctionCallEmitter(
|
54
32
|
QuantumFunctionCallEmitter, DeclarativeCallEmitter
|
@@ -19,7 +19,7 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
19
19
|
from classiq.interface.generator.expressions.expression_constants import (
|
20
20
|
CPARAM_EXECUTION_SUFFIX_PATTERN,
|
21
21
|
)
|
22
|
-
from classiq.interface.generator.expressions.qmod_struct_instance import (
|
22
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
23
23
|
QmodStructInstance,
|
24
24
|
)
|
25
25
|
from classiq.interface.generator.functions.type_name import TypeName
|
@@ -72,9 +72,9 @@ class QuantumSymbol:
|
|
72
72
|
array_length = self.quantum_type.length_value
|
73
73
|
if start < 0 or end > array_length:
|
74
74
|
raise ClassiqExpansionError(
|
75
|
-
f"Slice [{start}:{end}] is out of bounds
|
76
|
-
f"{self.quantum_type.type_name} {str(self.handle)!r} of
|
77
|
-
f"{array_length}"
|
75
|
+
f"Slice [{start}:{end}] is out of bounds for "
|
76
|
+
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
77
|
+
f"length {array_length})"
|
78
78
|
)
|
79
79
|
return QuantumSymbol(
|
80
80
|
handle=SlicedHandleBinding(
|
@@ -96,8 +96,9 @@ class QuantumSymbol:
|
|
96
96
|
array_length = self.quantum_type.length_value
|
97
97
|
if index < 0 or index >= array_length:
|
98
98
|
raise ClassiqExpansionError(
|
99
|
-
f"
|
100
|
-
f"{str(self.handle)!r} of
|
99
|
+
f"Index {index} is out of bounds for "
|
100
|
+
f"{self.quantum_type.type_name.lower()} {str(self.handle)!r} (of "
|
101
|
+
f"length {array_length})"
|
101
102
|
)
|
102
103
|
return QuantumSymbol(
|
103
104
|
handle=SubscriptHandleBinding(
|