classiq 0.82.1__py3-none-any.whl → 0.84.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 +27 -0
- classiq/applications/chemistry/chemistry_model_constructor.py +2 -4
- classiq/applications/chemistry/hartree_fock.py +68 -0
- classiq/applications/chemistry/mapping.py +85 -0
- classiq/applications/chemistry/op_utils.py +79 -0
- classiq/applications/chemistry/problems.py +195 -0
- classiq/applications/chemistry/ucc.py +109 -0
- classiq/applications/chemistry/z2_symmetries.py +368 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -2
- classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
- classiq/{model_expansions/evaluators → evaluators}/argument_types.py +3 -3
- classiq/{model_expansions/evaluators → evaluators}/classical_expression.py +1 -1
- classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
- classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
- classiq/execution/__init__.py +12 -1
- classiq/execution/execution_session.py +189 -43
- classiq/execution/jobs.py +26 -1
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +39 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/constants.py +1 -0
- classiq/interface/execution/primitives.py +29 -1
- classiq/interface/executor/estimate_cost.py +35 -0
- classiq/interface/executor/execution_result.py +13 -0
- classiq/interface/executor/result.py +116 -1
- classiq/interface/executor/user_budget.py +26 -33
- classiq/interface/generator/application_apis/finance_declarations.py +3 -3
- classiq/interface/generator/expressions/atomic_expression_functions.py +11 -3
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
- classiq/interface/generator/functions/classical_type.py +2 -35
- classiq/interface/generator/functions/concrete_types.py +0 -3
- classiq/interface/generator/functions/type_modifier.py +22 -0
- classiq/interface/generator/generated_circuit_data.py +5 -16
- classiq/interface/generator/model/model.py +8 -0
- classiq/interface/generator/quantum_program.py +0 -13
- classiq/interface/generator/types/compilation_metadata.py +0 -3
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/ide/visual_model.py +6 -2
- classiq/interface/model/model.py +12 -7
- classiq/interface/model/port_declaration.py +4 -2
- classiq/interface/pretty_print/__init__.py +0 -0
- classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
- classiq/interface/server/routes.py +4 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +42 -5
- classiq/model_expansions/capturing/captured_vars.py +21 -8
- classiq/model_expansions/interpreters/base_interpreter.py +3 -3
- classiq/model_expansions/quantum_operations/allocate.py +1 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +1 -1
- classiq/model_expansions/quantum_operations/bind.py +2 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +42 -36
- classiq/model_expansions/quantum_operations/variable_decleration.py +1 -1
- classiq/model_expansions/scope_initialization.py +3 -3
- classiq/model_expansions/transformers/model_renamer.py +16 -5
- classiq/model_expansions/transformers/{type_qualifier_inference.py → type_modifier_inference.py} +134 -100
- classiq/model_expansions/visitors/symbolic_param_inference.py +10 -7
- classiq/open_library/functions/__init__.py +3 -0
- classiq/open_library/functions/amplitude_amplification.py +10 -18
- classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
- classiq/open_library/functions/grover.py +14 -6
- classiq/open_library/functions/modular_exponentiation.py +22 -20
- classiq/open_library/functions/state_preparation.py +18 -1
- classiq/qmod/__init__.py +2 -2
- classiq/qmod/builtins/enums.py +23 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +16 -8
- classiq/qmod/builtins/functions/exponentiation.py +32 -4
- classiq/qmod/builtins/functions/standard_gates.py +7 -7
- classiq/qmod/builtins/structs.py +55 -3
- classiq/qmod/declaration_inferrer.py +8 -7
- classiq/qmod/native/pretty_printer.py +7 -11
- classiq/qmod/pretty_print/expression_to_python.py +2 -1
- classiq/qmod/pretty_print/pretty_printer.py +7 -12
- classiq/qmod/python_classical_type.py +12 -5
- classiq/qmod/qfunc.py +1 -1
- classiq/qmod/qmod_constant.py +2 -5
- classiq/qmod/qmod_parameter.py +2 -5
- classiq/qmod/qmod_variable.py +66 -25
- classiq/qmod/quantum_expandable.py +4 -2
- classiq/qmod/quantum_function.py +7 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -9
- classiq/qmod/semantics/validation/type_hints.py +9 -9
- classiq/qmod/utilities.py +0 -2
- classiq/qmod/write_qmod.py +1 -1
- classiq/synthesis.py +0 -2
- {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/METADATA +4 -1
- {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/RECORD +95 -86
- classiq/interface/generator/functions/type_qualifier.py +0 -22
- /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
- /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
- {classiq-0.82.1.dist-info → classiq-0.84.0.dist-info}/WHEEL +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
import datetime
|
2
|
-
from collections import defaultdict
|
3
2
|
from typing import Optional
|
4
3
|
|
5
4
|
import pydantic
|
6
5
|
from pydantic import ConfigDict, Field
|
6
|
+
from tabulate import tabulate
|
7
7
|
|
8
8
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
9
9
|
|
@@ -15,6 +15,7 @@ class UserBudget(VersionedModel):
|
|
15
15
|
available_budget: float
|
16
16
|
used_budget: float
|
17
17
|
last_allocation_date: datetime.datetime
|
18
|
+
budget_limit: Optional[float] = Field(default=None)
|
18
19
|
|
19
20
|
model_config = ConfigDict(extra="ignore")
|
20
21
|
|
@@ -22,35 +23,27 @@ class UserBudget(VersionedModel):
|
|
22
23
|
class UserBudgets(VersionedModel):
|
23
24
|
budgets: list[UserBudget] = pydantic.Field(default=[])
|
24
25
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
for provider, values in table_data.items():
|
50
|
-
print( # noqa: T201
|
51
|
-
format_row(
|
52
|
-
provider, values["available"], values["used"], values["currency"]
|
53
|
-
)
|
54
|
-
)
|
55
|
-
|
56
|
-
print(line) # noqa: T201
|
26
|
+
def __str__(self) -> str:
|
27
|
+
rows = [
|
28
|
+
[
|
29
|
+
budget.provider,
|
30
|
+
f"{budget.used_budget:.3f}",
|
31
|
+
f"{budget.available_budget:.3f}",
|
32
|
+
(
|
33
|
+
f"{budget.budget_limit:.3f}"
|
34
|
+
if budget.budget_limit is not None
|
35
|
+
else "NOT SET"
|
36
|
+
),
|
37
|
+
budget.currency_code,
|
38
|
+
]
|
39
|
+
for budget in self.budgets
|
40
|
+
]
|
41
|
+
|
42
|
+
headers = [
|
43
|
+
"Provider",
|
44
|
+
"Used Budget",
|
45
|
+
"Remaining Budget",
|
46
|
+
"Budget Limit",
|
47
|
+
"Currency",
|
48
|
+
]
|
49
|
+
return tabulate(rows, headers=headers, tablefmt="grid")
|
@@ -9,8 +9,8 @@ from classiq.interface.generator.functions.classical_type import Real
|
|
9
9
|
from classiq.interface.generator.functions.port_declaration import (
|
10
10
|
PortDeclarationDirection,
|
11
11
|
)
|
12
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
12
13
|
from classiq.interface.generator.functions.type_name import Struct
|
13
|
-
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
14
14
|
from classiq.interface.model.classical_parameter_declaration import (
|
15
15
|
ClassicalParameterDeclaration,
|
16
16
|
)
|
@@ -56,13 +56,13 @@ def _generate_finance_function(
|
|
56
56
|
)
|
57
57
|
),
|
58
58
|
direction=PortDeclarationDirection.Inout,
|
59
|
-
|
59
|
+
type_modifier=TypeModifier.Mutable,
|
60
60
|
),
|
61
61
|
PortDeclaration(
|
62
62
|
name=OBJECTIVE_PORT_NAME,
|
63
63
|
quantum_type=QuantumBit(),
|
64
64
|
direction=PortDeclarationDirection.Inout,
|
65
|
-
|
65
|
+
type_modifier=TypeModifier.Mutable,
|
66
66
|
),
|
67
67
|
],
|
68
68
|
)
|
@@ -11,15 +11,18 @@ CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS = {
|
|
11
11
|
"molecule_ground_state_solution_post_process",
|
12
12
|
}
|
13
13
|
|
14
|
-
|
15
|
-
*CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS,
|
14
|
+
CLASSIQ_EXPR_FUNCTIONS = {
|
16
15
|
"do_div",
|
17
16
|
"do_slice",
|
18
17
|
"do_subscript",
|
19
18
|
"get_type",
|
20
19
|
"struct_literal",
|
21
20
|
"get_field",
|
22
|
-
|
21
|
+
}
|
22
|
+
|
23
|
+
SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
|
24
|
+
*CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS,
|
25
|
+
*CLASSIQ_EXPR_FUNCTIONS,
|
23
26
|
}
|
24
27
|
|
25
28
|
SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
@@ -30,6 +33,11 @@ SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
|
30
33
|
"LogicalXor",
|
31
34
|
"RShift",
|
32
35
|
"LShift",
|
36
|
+
"mod_inverse",
|
37
|
+
"min",
|
38
|
+
"Min",
|
39
|
+
"max",
|
40
|
+
"Max",
|
33
41
|
}
|
34
42
|
|
35
43
|
SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
|
@@ -21,12 +21,6 @@ def subscript_to_str(index: Any) -> str:
|
|
21
21
|
|
22
22
|
|
23
23
|
class AnyClassicalValue(sympy.Symbol):
|
24
|
-
|
25
|
-
is_commutative = None
|
26
|
-
is_infinite = None
|
27
|
-
is_finite = None
|
28
|
-
is_extended_real = None
|
29
|
-
|
30
24
|
def __getitem__(self, item: Any) -> "AnyClassicalValue":
|
31
25
|
if isinstance(item, slice):
|
32
26
|
return AnyClassicalValue(f"{self}[{subscript_to_str(item)}]")
|
@@ -98,39 +98,6 @@ class Bool(ClassicalType):
|
|
98
98
|
return values_with_discriminator(values, "kind", "bool")
|
99
99
|
|
100
100
|
|
101
|
-
class ClassicalList(ClassicalType):
|
102
|
-
kind: Literal["list"]
|
103
|
-
element_type: "ConcreteClassicalType"
|
104
|
-
|
105
|
-
@pydantic.model_validator(mode="before")
|
106
|
-
@classmethod
|
107
|
-
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
108
|
-
return values_with_discriminator(values, "kind", "list")
|
109
|
-
|
110
|
-
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
111
|
-
return ClassicalArrayProxy(
|
112
|
-
handle, self.element_type, AnyClassicalValue(f"get_field({handle}, 'len')")
|
113
|
-
)
|
114
|
-
|
115
|
-
@property
|
116
|
-
def expressions(self) -> list[Expression]:
|
117
|
-
return self.element_type.expressions
|
118
|
-
|
119
|
-
@property
|
120
|
-
def is_purely_declarative(self) -> bool:
|
121
|
-
return super().is_purely_declarative and self.element_type.is_purely_declarative
|
122
|
-
|
123
|
-
@property
|
124
|
-
def is_purely_generative(self) -> bool:
|
125
|
-
return super().is_purely_generative and self.element_type.is_purely_generative
|
126
|
-
|
127
|
-
def get_raw_type(self) -> "ConcreteClassicalType":
|
128
|
-
raw_type = ClassicalArray(element_type=self.element_type.get_raw_type())
|
129
|
-
if self._is_generative:
|
130
|
-
raw_type.set_generative()
|
131
|
-
return raw_type
|
132
|
-
|
133
|
-
|
134
101
|
class StructMetaType(ClassicalType):
|
135
102
|
kind: Literal["type_proxy"]
|
136
103
|
|
@@ -146,8 +113,8 @@ class StructMetaType(ClassicalType):
|
|
146
113
|
class ClassicalArray(ClassicalType):
|
147
114
|
kind: Literal["array"]
|
148
115
|
element_type: "ConcreteClassicalType"
|
149
|
-
size: Optional[int] = None
|
150
|
-
length: Optional[Expression] =
|
116
|
+
size: Optional[int] = pydantic.Field(exclude=True, default=None)
|
117
|
+
length: Optional[Expression] = None
|
151
118
|
|
152
119
|
@pydantic.model_validator(mode="before")
|
153
120
|
@classmethod
|
@@ -5,7 +5,6 @@ from pydantic import Field
|
|
5
5
|
from classiq.interface.generator.functions.classical_type import (
|
6
6
|
Bool,
|
7
7
|
ClassicalArray,
|
8
|
-
ClassicalList,
|
9
8
|
ClassicalTuple,
|
10
9
|
Estimation,
|
11
10
|
Histogram,
|
@@ -29,7 +28,6 @@ ConcreteClassicalType = Annotated[
|
|
29
28
|
Integer,
|
30
29
|
Real,
|
31
30
|
Bool,
|
32
|
-
ClassicalList,
|
33
31
|
StructMetaType,
|
34
32
|
TypeName,
|
35
33
|
ClassicalArray,
|
@@ -41,7 +39,6 @@ ConcreteClassicalType = Annotated[
|
|
41
39
|
],
|
42
40
|
Field(discriminator="kind"),
|
43
41
|
]
|
44
|
-
ClassicalList.model_rebuild()
|
45
42
|
ClassicalArray.model_rebuild()
|
46
43
|
ClassicalTuple.model_rebuild()
|
47
44
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from classiq.interface.enum_utils import StrEnum
|
2
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
3
|
+
|
4
|
+
|
5
|
+
class TypeModifier(StrEnum):
|
6
|
+
Const = "const"
|
7
|
+
Permutable = "permutable"
|
8
|
+
Mutable = "mutable"
|
9
|
+
Inferred = "inferred"
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def and_(first: "TypeModifier", second: "TypeModifier") -> "TypeModifier":
|
13
|
+
if second is TypeModifier.Inferred:
|
14
|
+
raise ClassiqInternalExpansionError
|
15
|
+
if first is TypeModifier.Mutable or second is TypeModifier.Mutable:
|
16
|
+
return TypeModifier.Mutable
|
17
|
+
elif first is TypeModifier.Permutable or second is TypeModifier.Permutable:
|
18
|
+
return TypeModifier.Permutable
|
19
|
+
else:
|
20
|
+
if first is not TypeModifier.Const and second is not TypeModifier.Const:
|
21
|
+
raise ClassiqInternalExpansionError("Unexpected type modifiers")
|
22
|
+
return TypeModifier.Const
|
@@ -28,8 +28,6 @@ from classiq.interface.model.statement_block import (
|
|
28
28
|
)
|
29
29
|
|
30
30
|
from classiq.model_expansions.capturing.mangling_utils import (
|
31
|
-
demangle_capture_name,
|
32
|
-
demangle_name,
|
33
31
|
is_captured_var_name,
|
34
32
|
)
|
35
33
|
|
@@ -85,12 +83,6 @@ class GeneratedRegister(pydantic.BaseModel):
|
|
85
83
|
def is_captured(self) -> bool:
|
86
84
|
return is_captured_var_name(self.name)
|
87
85
|
|
88
|
-
@staticmethod
|
89
|
-
def demangle_name(name: str) -> str:
|
90
|
-
if is_captured_var_name(name):
|
91
|
-
name = demangle_capture_name(name)
|
92
|
-
return demangle_name(name)
|
93
|
-
|
94
86
|
|
95
87
|
class GeneratedFunction(pydantic.BaseModel):
|
96
88
|
name: str
|
@@ -202,8 +194,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
202
194
|
@property
|
203
195
|
def name(self) -> str:
|
204
196
|
generated_name = self.generated_function.name if self.generated_function else ""
|
205
|
-
# Temp fix for
|
206
|
-
if generated_name
|
197
|
+
# Temp fix for remaining old "supported" statements - power
|
198
|
+
if generated_name == StatementType.POWER:
|
207
199
|
return generated_name
|
208
200
|
|
209
201
|
back_ref = self.first_back_ref
|
@@ -243,8 +235,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
243
235
|
|
244
236
|
@property
|
245
237
|
def level(self) -> OperationLevel:
|
246
|
-
# Temp fix for
|
247
|
-
if self.name
|
238
|
+
# Temp fix for remaining old "supported" statements - power
|
239
|
+
if self.name == StatementType.POWER:
|
248
240
|
return OperationLevel.QMOD_STATEMENT
|
249
241
|
|
250
242
|
if self.first_back_ref is None:
|
@@ -275,15 +267,12 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
275
267
|
|
276
268
|
@property
|
277
269
|
def control_qubits(self) -> tuple[int, ...]:
|
278
|
-
control_states_names = {
|
279
|
-
control_state.name for control_state in self.control_states
|
280
|
-
}
|
281
270
|
return tuple(
|
282
271
|
qubit
|
283
272
|
for register in self.registers
|
284
273
|
for qubit in register.qubit_indexes_absolute
|
285
274
|
if register.role is RegisterRole.INPUT
|
286
|
-
and register.name
|
275
|
+
and register.name == self.control_variable
|
287
276
|
)
|
288
277
|
|
289
278
|
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
@@ -11,6 +11,9 @@ from classiq.interface.generator.types.qstruct_declaration import QStructDeclara
|
|
11
11
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
12
12
|
from classiq.interface.helpers.validation_helpers import is_list_unique
|
13
13
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
14
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
15
|
+
ClassicalParameterDeclaration,
|
16
|
+
)
|
14
17
|
from classiq.interface.model.quantum_type import RegisterQuantumTypeDict
|
15
18
|
|
16
19
|
TYPE_LIBRARY_DUPLICATED_TYPE_NAMES = (
|
@@ -71,3 +74,8 @@ class ExecutionModel(ClassiqBaseModel):
|
|
71
74
|
register_filter_bitstrings: dict[str, list[str]] = pydantic.Field(
|
72
75
|
default_factory=dict,
|
73
76
|
)
|
77
|
+
|
78
|
+
circuit_execution_params: dict[str, ClassicalParameterDeclaration] = pydantic.Field(
|
79
|
+
default_factory=dict,
|
80
|
+
description="Mapping between a execution parameter name and its declaration",
|
81
|
+
)
|
@@ -166,19 +166,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
166
166
|
with open(filename, "w") as file:
|
167
167
|
file.write(self.model_dump_json(indent=4))
|
168
168
|
|
169
|
-
@classmethod
|
170
|
-
def from_qprog(cls, qprog: "QuantumProgram") -> "QuantumProgram":
|
171
|
-
"""
|
172
|
-
Creates a `QuantumProgram` instance from a raw quantum program string.
|
173
|
-
|
174
|
-
Args:
|
175
|
-
qprog: The raw quantum program in string format.
|
176
|
-
|
177
|
-
Returns:
|
178
|
-
QuantumProgram: The `QuantumProgram` instance.
|
179
|
-
"""
|
180
|
-
return qprog
|
181
|
-
|
182
169
|
@property
|
183
170
|
def _can_use_transpiled_code(self) -> bool:
|
184
171
|
return self.data.execution_data is None
|
@@ -6,9 +6,6 @@ class CompilationMetadata(BaseModel):
|
|
6
6
|
occurrences_number: NonNegativeInt = Field(default=1)
|
7
7
|
_occupation_number: NonNegativeInt = PrivateAttr(default=0)
|
8
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
9
|
|
13
10
|
@property
|
14
11
|
def occupation_number(self) -> NonNegativeInt:
|
@@ -5,7 +5,7 @@ from classiq.interface.ast_node import ASTNode
|
|
5
5
|
from classiq.interface.debug_info.debug_info import DebugInfoCollection
|
6
6
|
from classiq.interface.generator.expressions.expression import Expression
|
7
7
|
from classiq.interface.generator.functions.classical_type import ClassicalType
|
8
|
-
from classiq.interface.generator.functions.
|
8
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
9
9
|
from classiq.interface.generator.visitor import Transformer, Visitor
|
10
10
|
from classiq.interface.model.model import Model
|
11
11
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
@@ -32,7 +32,7 @@ class ModelNormalizer(Visitor):
|
|
32
32
|
expr.expr = ast.unparse(ExprNormalizer().visit(ast.parse(expr.expr)))
|
33
33
|
|
34
34
|
def visit_AnonPortDeclaration(self, decl: AnonPortDeclaration) -> None:
|
35
|
-
decl.
|
35
|
+
decl.type_modifier = TypeModifier.Mutable
|
36
36
|
|
37
37
|
|
38
38
|
class ClearModelInternals(Transformer):
|
@@ -110,7 +110,9 @@ class Operation(pydantic.BaseModel):
|
|
110
110
|
name: str
|
111
111
|
qasm_name: str = pydantic.Field(default="")
|
112
112
|
details: str = pydantic.Field(default="")
|
113
|
-
children: list["Operation"]
|
113
|
+
children: list["Operation"] = pydantic.Field(default_factory=list)
|
114
|
+
# children_ids is optional in order to support backwards compatibility.
|
115
|
+
children_ids: list[int] = pydantic.Field(default_factory=list)
|
114
116
|
operation_data: Optional[OperationData] = None
|
115
117
|
operation_links: OperationLinks
|
116
118
|
control_qubits: tuple[int, ...] = pydantic.Field(default_factory=tuple)
|
@@ -129,5 +131,7 @@ class Operation(pydantic.BaseModel):
|
|
129
131
|
|
130
132
|
|
131
133
|
class ProgramVisualModel(VersionedModel):
|
132
|
-
main_operation: Operation
|
134
|
+
main_operation: Operation = pydantic.Field(default=None)
|
135
|
+
id_to_operations: dict[int, Operation] = pydantic.Field(default_factory=dict)
|
136
|
+
main_operation_id: int = pydantic.Field(default=None)
|
133
137
|
program_data: ProgramData
|
classiq/interface/model/model.py
CHANGED
@@ -185,11 +185,16 @@ class Model(VersionedModel, ASTNode):
|
|
185
185
|
return constants
|
186
186
|
|
187
187
|
def dump_no_metadata(self) -> dict[str, Any]:
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
188
|
+
compilation_metadata_with_unchecked = {
|
189
|
+
name: CompilationMetadata(unchecked=comp_metadata.unchecked)
|
190
|
+
for name, comp_metadata in self.functions_compilation_metadata.items()
|
191
|
+
if len(comp_metadata.unchecked) > 0
|
192
|
+
}
|
193
|
+
model = self.model_copy(
|
194
|
+
update={
|
195
|
+
"functions_compilation_metadata": compilation_metadata_with_unchecked,
|
196
|
+
}
|
197
|
+
)
|
198
|
+
return model.model_dump(
|
199
|
+
exclude={"constraints", "execution_preferences", "preferences"},
|
195
200
|
)
|
@@ -8,7 +8,9 @@ from classiq.interface.generator.functions.concrete_types import ConcreteQuantum
|
|
8
8
|
from classiq.interface.generator.functions.port_declaration import (
|
9
9
|
PortDeclarationDirection,
|
10
10
|
)
|
11
|
-
from classiq.interface.generator.functions.
|
11
|
+
from classiq.interface.generator.functions.type_modifier import (
|
12
|
+
TypeModifier,
|
13
|
+
)
|
12
14
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
13
15
|
from classiq.interface.model.parameter import Parameter
|
14
16
|
|
@@ -16,8 +18,8 @@ from classiq.interface.model.parameter import Parameter
|
|
16
18
|
class AnonPortDeclaration(Parameter):
|
17
19
|
quantum_type: ConcreteQuantumType
|
18
20
|
direction: PortDeclarationDirection
|
19
|
-
type_qualifier: TypeQualifier
|
20
21
|
kind: Literal["PortDeclaration"]
|
22
|
+
type_modifier: TypeModifier
|
21
23
|
|
22
24
|
@pydantic.model_validator(mode="before")
|
23
25
|
@classmethod
|
File without changes
|
@@ -6,7 +6,7 @@ from typing import Callable, Optional
|
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
|
-
from classiq.
|
9
|
+
from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
|
10
10
|
|
11
11
|
IDENTIFIER = re.compile(r"[a-zA-Z_]\w*")
|
12
12
|
BINARY_OPS: Mapping[type[ast.operator], str] = {
|
@@ -40,6 +40,10 @@ COMPARE_OPS: Mapping[type[ast.cmpop], str] = {
|
|
40
40
|
LIST_FORMAT_CHAR_LIMIT = 20
|
41
41
|
|
42
42
|
|
43
|
+
class PrettyPrinterError(AssertionError):
|
44
|
+
pass
|
45
|
+
|
46
|
+
|
43
47
|
@dataclass
|
44
48
|
class ASTToQMODCode:
|
45
49
|
level: int
|
@@ -59,10 +63,13 @@ class ASTToQMODCode:
|
|
59
63
|
elif isinstance(node, ast.Attribute):
|
60
64
|
# Enum attribute access
|
61
65
|
if not isinstance(node.value, ast.Name) or not isinstance(node.attr, str):
|
62
|
-
raise
|
66
|
+
raise PrettyPrinterError("Error parsing enum attribute access")
|
63
67
|
if not (IDENTIFIER.match(node.value.id) and IDENTIFIER.match(node.attr)):
|
64
|
-
raise
|
65
|
-
|
68
|
+
raise PrettyPrinterError("Error parsing enum attribute access")
|
69
|
+
# FIXME: identify enum member accesses by type name (CLS-2858)
|
70
|
+
if len(node.value.id) > 0 and node.value.id[0].isupper():
|
71
|
+
return f"{node.value.id!s}::{node.attr!s}"
|
72
|
+
return f"{node.value.id!s}.{node.attr!s}"
|
66
73
|
elif isinstance(node, ast.Name):
|
67
74
|
return node.id
|
68
75
|
elif isinstance(node, ast.Num):
|
@@ -91,7 +98,7 @@ class ASTToQMODCode:
|
|
91
98
|
)
|
92
99
|
elif isinstance(node, ast.Compare):
|
93
100
|
if len(node.ops) != 1 or len(node.comparators) != 1:
|
94
|
-
raise
|
101
|
+
raise PrettyPrinterError("Error parsing comparison expression.")
|
95
102
|
return "({} {} {})".format(
|
96
103
|
self.ast_to_code(node.left),
|
97
104
|
COMPARE_OPS[type(node.ops[0])],
|
@@ -108,20 +115,20 @@ class ASTToQMODCode:
|
|
108
115
|
elif isinstance(node, ast.Slice):
|
109
116
|
# A QMOD expression does not support slice step
|
110
117
|
if node.lower is None or node.upper is None or node.step is not None:
|
111
|
-
raise
|
118
|
+
raise PrettyPrinterError("Error parsing slice expression.")
|
112
119
|
return f"{self.ast_to_code(node.lower)}:{self.ast_to_code(node.upper)}"
|
113
120
|
elif isinstance(node, ast.Call):
|
114
121
|
func = self.ast_to_code(node.func)
|
115
122
|
if func == "get_field":
|
116
123
|
if len(node.args) != 2:
|
117
|
-
raise
|
124
|
+
raise PrettyPrinterError("Error parsing struct field access.")
|
118
125
|
field = str(self.ast_to_code(node.args[1])).replace("'", "")
|
119
126
|
if not IDENTIFIER.match(field):
|
120
|
-
raise
|
127
|
+
raise PrettyPrinterError("Error parsing struct field access.")
|
121
128
|
return f"{self.ast_to_code(node.args[0])}.{field}"
|
122
129
|
elif func == "struct_literal":
|
123
130
|
if len(node.args) != 1 or not isinstance(node.args[0], ast.Name):
|
124
|
-
raise
|
131
|
+
raise PrettyPrinterError("Error parsing struct literal.")
|
125
132
|
keywords = node.keywords
|
126
133
|
initializer_list = self.indent_items(
|
127
134
|
lambda: [
|
@@ -133,7 +140,7 @@ class ASTToQMODCode:
|
|
133
140
|
return f"{self.ast_to_code(node.args[0])} {{{initializer_list}}}"
|
134
141
|
elif func == "do_subscript":
|
135
142
|
if len(node.args) != 2:
|
136
|
-
raise
|
143
|
+
raise PrettyPrinterError("Error parsing array access.")
|
137
144
|
return f"{self.ast_to_code(node.args[0])}[{self.ast_to_code(node.args[1])}]"
|
138
145
|
else:
|
139
146
|
return "{}({})".format(
|
@@ -142,7 +149,7 @@ class ASTToQMODCode:
|
|
142
149
|
elif isinstance(node, ast.Expr):
|
143
150
|
return self._cleaned_ast_to_code(node.value)
|
144
151
|
else:
|
145
|
-
raise
|
152
|
+
raise PrettyPrinterError("Error parsing expression: unsupported AST node.")
|
146
153
|
|
147
154
|
def indent_items(self, items: Callable[[], list[str]]) -> str:
|
148
155
|
should_indent = (
|
@@ -91,3 +91,7 @@ IQCC_LIST_AUTH_TARGETS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_TARGETS_SUFFIX
|
|
91
91
|
|
92
92
|
USER_BUDGETS_SUFFIX = "/all"
|
93
93
|
USER_BUDGETS_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGETS_SUFFIX
|
94
|
+
USER_BUDGET_SET_LIMIT_SUFFIX = "/set_limit"
|
95
|
+
USER_BUDGET_SET_LIMIT_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGET_SET_LIMIT_SUFFIX
|
96
|
+
USER_BUDGET_CLEAR_LIMIT_SUFFIX = "/clear_limit"
|
97
|
+
USER_BUDGET_CLEAR_LIMIT_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGET_CLEAR_LIMIT_SUFFIX
|
@@ -39,7 +39,6 @@ from classiq.interface.generator.functions.classical_function_declaration import
|
|
39
39
|
from classiq.interface.generator.functions.classical_type import (
|
40
40
|
Bool,
|
41
41
|
ClassicalArray,
|
42
|
-
ClassicalList,
|
43
42
|
ClassicalTuple,
|
44
43
|
ClassicalType,
|
45
44
|
OpaqueHandle,
|
@@ -91,7 +90,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
91
90
|
if isinstance(val, (Enum, int)):
|
92
91
|
return val
|
93
92
|
|
94
|
-
elif isinstance(qmod_type,
|
93
|
+
elif isinstance(qmod_type, ClassicalArray):
|
95
94
|
if isinstance(val, list):
|
96
95
|
return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
|
97
96
|
|
@@ -145,9 +144,9 @@ def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
|
|
145
144
|
field_name: python_val_to_qmod(val[field_name], field_type)
|
146
145
|
for field_name, field_type in struct_decl.variables.items()
|
147
146
|
}
|
148
|
-
return QmodStructInstance(struct_decl.model_copy(), qmod_dict)
|
147
|
+
return QmodStructInstance(struct_decl.model_copy(deep=True), qmod_dict)
|
149
148
|
|
150
|
-
if isinstance(qmod_type,
|
149
|
+
if isinstance(qmod_type, ClassicalArray):
|
151
150
|
if not isinstance(val, list):
|
152
151
|
raise ClassiqInternalExpansionError("Bad value for list")
|
153
152
|
return [python_val_to_qmod(elem, qmod_type.element_type) for elem in val]
|
@@ -182,7 +181,7 @@ def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
|
|
182
181
|
|
183
182
|
def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
|
184
183
|
return QmodStructInstance(
|
185
|
-
QMODULE.type_decls[struct_type_symbol.name].model_copy(),
|
184
|
+
QMODULE.type_decls[struct_type_symbol.name].model_copy(deep=True),
|
186
185
|
{field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
|
187
186
|
)
|
188
187
|
|
@@ -330,6 +329,40 @@ def mod_inverse(a: Any, b: Any) -> Any:
|
|
330
329
|
return sympy.mod_inverse(a, b)
|
331
330
|
|
332
331
|
|
332
|
+
def min_wrapper(*vals: Any) -> Any:
|
333
|
+
try:
|
334
|
+
return sympy.Min(*vals)
|
335
|
+
except ValueError:
|
336
|
+
return AnyClassicalValue(f"Min({', '.join(map(str, vals))})")
|
337
|
+
|
338
|
+
|
339
|
+
min_wrapper.__name__ = "min"
|
340
|
+
|
341
|
+
|
342
|
+
def Min_wrapper(*vals: Any) -> Any: # noqa: N802
|
343
|
+
return min_wrapper(*vals)
|
344
|
+
|
345
|
+
|
346
|
+
Min_wrapper.__name__ = "Min"
|
347
|
+
|
348
|
+
|
349
|
+
def max_wrapper(*vals: Any) -> Any:
|
350
|
+
try:
|
351
|
+
return sympy.Max(*vals)
|
352
|
+
except ValueError:
|
353
|
+
return AnyClassicalValue(f"Max({', '.join(map(str, vals))})")
|
354
|
+
|
355
|
+
|
356
|
+
max_wrapper.__name__ = "max"
|
357
|
+
|
358
|
+
|
359
|
+
def Max_wrapper(*vals: Any) -> Any: # noqa: N802
|
360
|
+
return max_wrapper(*vals)
|
361
|
+
|
362
|
+
|
363
|
+
Max_wrapper.__name__ = "Max"
|
364
|
+
|
365
|
+
|
333
366
|
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
334
367
|
print,
|
335
368
|
do_sum,
|
@@ -347,6 +380,10 @@ CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
|
347
380
|
RShift,
|
348
381
|
LShift,
|
349
382
|
mod_inverse,
|
383
|
+
min_wrapper,
|
384
|
+
Min_wrapper,
|
385
|
+
max_wrapper,
|
386
|
+
Max_wrapper,
|
350
387
|
]
|
351
388
|
|
352
389
|
|