classiq 0.69.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/analyzer/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +6 -0
- classiq/interface/chemistry/operator.py +1 -21
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- 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 +23 -29
- classiq/interface/generator/functions/type_name.py +26 -2
- classiq/interface/generator/generated_circuit_data.py +21 -3
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/model/native_function_definition.py +0 -10
- classiq/interface/model/quantum_type.py +15 -3
- 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 +63 -4
- 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/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -6
- classiq/model_expansions/scope_initialization.py +17 -16
- 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/lookup_table.py +58 -0
- classiq/qmod/declaration_inferrer.py +3 -1
- classiq/qmod/qmod_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +11 -14
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +29 -0
- classiq/qmod/utilities.py +38 -1
- {classiq-0.69.0.dist-info → classiq-0.70.0.dist-info}/METADATA +10 -12
- {classiq-0.69.0.dist-info → classiq-0.70.0.dist-info}/RECORD +60 -49
- {classiq-0.69.0.dist-info → classiq-0.70.0.dist-info}/WHEEL +1 -1
- /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
@@ -4,7 +4,15 @@ from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
4
4
|
import pydantic
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import ClassiqExpansionError
|
7
|
-
from classiq.interface.generator.expressions.
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
8
|
+
ClassicalProxy,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
11
|
+
ClassicalStructProxy,
|
12
|
+
)
|
13
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
14
|
+
QmodQStructProxy,
|
15
|
+
)
|
8
16
|
from classiq.interface.generator.functions.classical_type import (
|
9
17
|
ClassicalType,
|
10
18
|
)
|
@@ -16,6 +24,7 @@ from classiq.interface.model.quantum_type import (
|
|
16
24
|
|
17
25
|
if TYPE_CHECKING:
|
18
26
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
27
|
+
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
19
28
|
|
20
29
|
|
21
30
|
class TypeName(ClassicalType, QuantumType):
|
@@ -24,6 +33,9 @@ class TypeName(ClassicalType, QuantumType):
|
|
24
33
|
_assigned_fields: Optional[Mapping[str, "ConcreteQuantumType"]] = (
|
25
34
|
pydantic.PrivateAttr(default=None)
|
26
35
|
)
|
36
|
+
_classical_struct_decl: Optional["StructDeclaration"] = pydantic.PrivateAttr(
|
37
|
+
default=None
|
38
|
+
)
|
27
39
|
|
28
40
|
@pydantic.model_validator(mode="before")
|
29
41
|
@classmethod
|
@@ -40,7 +52,7 @@ class TypeName(ClassicalType, QuantumType):
|
|
40
52
|
)
|
41
53
|
|
42
54
|
def get_proxy(self, handle: "HandleBinding") -> "QmodQStructProxy":
|
43
|
-
from classiq.interface.generator.expressions.qmod_qstruct_proxy import (
|
55
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_qstruct_proxy import (
|
44
56
|
QmodQStructProxy,
|
45
57
|
)
|
46
58
|
|
@@ -81,6 +93,18 @@ class TypeName(ClassicalType, QuantumType):
|
|
81
93
|
field_type.is_evaluated for field_type in self.fields.values()
|
82
94
|
)
|
83
95
|
|
96
|
+
@property
|
97
|
+
def has_classical_struct_decl(self) -> bool:
|
98
|
+
return self._classical_struct_decl is not None
|
99
|
+
|
100
|
+
def set_classical_struct_decl(self, decl: "StructDeclaration") -> None:
|
101
|
+
self._classical_struct_decl = decl
|
102
|
+
|
103
|
+
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
104
|
+
if self._classical_struct_decl is None:
|
105
|
+
raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
|
106
|
+
return ClassicalStructProxy(handle, self._classical_struct_decl)
|
107
|
+
|
84
108
|
|
85
109
|
class Enum(TypeName):
|
86
110
|
pass
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import logging
|
2
|
+
import re
|
2
3
|
from typing import Literal, Optional, Union
|
3
4
|
|
4
5
|
import pydantic
|
@@ -7,6 +8,9 @@ from typing_extensions import TypeAlias
|
|
7
8
|
|
8
9
|
from classiq.interface.debug_info.back_ref_util import is_allocate_or_free_by_backref
|
9
10
|
from classiq.interface.enum_utils import StrEnum
|
11
|
+
from classiq.interface.generator.compiler_keywords import (
|
12
|
+
generate_original_function_name,
|
13
|
+
)
|
10
14
|
from classiq.interface.generator.control_state import ControlState
|
11
15
|
from classiq.interface.generator.register_role import RegisterRole
|
12
16
|
from classiq.interface.generator.synthesis_metadata.synthesis_execution_data import (
|
@@ -32,6 +36,11 @@ ParameterName = str
|
|
32
36
|
IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
|
33
37
|
|
34
38
|
CLASSIQ_HIERARCHY_SEPARATOR: Literal["__"] = "__"
|
39
|
+
QASM_SEPARATOR = "_"
|
40
|
+
SPLIT_MARKER: str = "part"
|
41
|
+
PART_SUFFIX_REGEX = re.compile(
|
42
|
+
rf".+{QASM_SEPARATOR}{SPLIT_MARKER}{QASM_SEPARATOR}(\d+)$"
|
43
|
+
)
|
35
44
|
|
36
45
|
VISUALIZATION_HIDE_LIST = [
|
37
46
|
"apply_to_all",
|
@@ -168,9 +177,18 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
168
177
|
|
169
178
|
@property
|
170
179
|
def name(self) -> str:
|
171
|
-
if self.generated_function
|
172
|
-
|
173
|
-
|
180
|
+
generated_name = self.generated_function.name if self.generated_function else ""
|
181
|
+
# Temp fix for currently "supported" statements (same as for level_ property)
|
182
|
+
if generated_name in {StatementType.CONTROL, StatementType.POWER}:
|
183
|
+
return generated_name
|
184
|
+
if self.first_back_ref and isinstance(self.first_back_ref, QuantumFunctionCall):
|
185
|
+
name = generate_original_function_name(self.first_back_ref.func_name)
|
186
|
+
if part_match := PART_SUFFIX_REGEX.match(generated_name):
|
187
|
+
suffix = f" [{part_match.group(1)}]"
|
188
|
+
else:
|
189
|
+
suffix = ""
|
190
|
+
return f"{name}{suffix}"
|
191
|
+
return generated_name
|
174
192
|
|
175
193
|
@property
|
176
194
|
def first_back_ref(self) -> Optional[ConcreteQuantumStatement]:
|
@@ -117,7 +117,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
117
117
|
instruction_set: Optional[QuantumInstructionSet] = None,
|
118
118
|
) -> quantum_code.QuantumCode:
|
119
119
|
initial_values = initial_values or self.initial_values
|
120
|
-
|
121
120
|
if instruction_set is not None:
|
122
121
|
code, syntax = (
|
123
122
|
self.program_circuit.get_code(instruction_set),
|
@@ -10,13 +10,6 @@ if TYPE_CHECKING:
|
|
10
10
|
from classiq.interface.model.statement_block import StatementBlock
|
11
11
|
|
12
12
|
|
13
|
-
class FunctionSynthesisData(pydantic.BaseModel):
|
14
|
-
should_synthesize_separately: bool = pydantic.Field(
|
15
|
-
default=False,
|
16
|
-
description="Whether the function should be synthesized separately.",
|
17
|
-
)
|
18
|
-
|
19
|
-
|
20
13
|
class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
|
21
14
|
"""
|
22
15
|
Facilitates the creation of a user-defined composite function
|
@@ -28,6 +21,3 @@ class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
|
|
28
21
|
body: "StatementBlock" = pydantic.Field(
|
29
22
|
default_factory=list, description="List of function calls to perform."
|
30
23
|
)
|
31
|
-
synthesis_data: FunctionSynthesisData = pydantic.Field(
|
32
|
-
default_factory=FunctionSynthesisData, deprecated=True, exclude=True
|
33
|
-
)
|
@@ -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()
|
@@ -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
|
|
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
|
)
|