classiq 0.86.1__py3-none-any.whl → 0.88.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.
Potentially problematic release.
This version of classiq might be problematic. Click here for more details.
- classiq/__init__.py +2 -0
- classiq/applications/__init__.py +1 -2
- classiq/applications/chemistry/hartree_fock.py +5 -1
- classiq/applications/chemistry/op_utils.py +2 -2
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +1 -1
- classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
- classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
- classiq/applications/combinatorial_helpers/memory.py +4 -4
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
- classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
- classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +34 -2
- classiq/evaluators/argument_types.py +15 -6
- classiq/evaluators/parameter_types.py +43 -39
- classiq/evaluators/qmod_annotated_expression.py +117 -17
- classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -5
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +66 -16
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +48 -26
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +65 -72
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +13 -6
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +36 -19
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +17 -5
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +24 -2
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
- classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +3 -4
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +51 -24
- classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
- classiq/evaluators/qmod_node_evaluators/utils.py +28 -6
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +330 -0
- classiq/evaluators/quantum_type_utils.py +0 -131
- classiq/evaluators/type_type_match.py +1 -1
- classiq/execution/execution_session.py +18 -3
- classiq/execution/qnn.py +4 -1
- classiq/execution/user_budgets.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +10 -30
- classiq/interface/backend/quantum_backend_providers.py +63 -52
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/application_apis/__init__.py +0 -1
- classiq/interface/generator/arith/binary_ops.py +107 -115
- classiq/interface/generator/arith/extremum_operations.py +33 -45
- classiq/interface/generator/arith/number_utils.py +4 -1
- classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
- classiq/interface/generator/compiler_keywords.py +2 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +0 -2
- classiq/interface/generator/function_param_list.py +129 -5
- classiq/interface/generator/functions/classical_type.py +67 -2
- classiq/interface/generator/functions/qmod_python_interface.py +15 -0
- classiq/interface/generator/functions/type_name.py +12 -0
- classiq/interface/generator/model/preferences/preferences.py +1 -17
- classiq/interface/generator/quantum_program.py +1 -13
- classiq/interface/generator/transpiler_basis_gates.py +5 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -8
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/helpers/text_utils.py +7 -2
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/classical_if.py +48 -0
- classiq/interface/model/classical_parameter_declaration.py +4 -0
- classiq/interface/model/handle_binding.py +28 -16
- classiq/interface/model/port_declaration.py +12 -0
- classiq/interface/model/quantum_function_declaration.py +12 -0
- classiq/interface/model/quantum_type.py +117 -2
- classiq/interface/pretty_print/expression_to_qmod.py +7 -8
- classiq/interface/pyomo_extension/__init__.py +0 -4
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
- classiq/model_expansions/arithmetic.py +43 -1
- classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
- classiq/model_expansions/capturing/captured_vars.py +2 -5
- classiq/model_expansions/quantum_operations/allocate.py +23 -16
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
- classiq/model_expansions/quantum_operations/bind.py +15 -7
- classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +2 -8
- classiq/open_library/functions/__init__.py +4 -0
- classiq/open_library/functions/lcu.py +117 -0
- classiq/open_library/functions/state_preparation.py +47 -5
- classiq/qmod/builtins/__init__.py +0 -3
- classiq/qmod/builtins/classical_functions.py +0 -28
- classiq/qmod/builtins/enums.py +26 -20
- classiq/qmod/builtins/functions/__init__.py +0 -5
- classiq/qmod/builtins/operations.py +142 -0
- classiq/qmod/builtins/structs.py +33 -29
- classiq/qmod/native/pretty_printer.py +1 -1
- classiq/qmod/pretty_print/expression_to_python.py +1 -6
- classiq/qmod/pretty_print/pretty_printer.py +4 -1
- classiq/qmod/qmod_variable.py +94 -2
- classiq/qmod/semantics/annotation/call_annotation.py +4 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +20 -5
- {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/METADATA +5 -5
- {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/RECORD +106 -124
- classiq/applications/finance/__init__.py +0 -15
- classiq/interface/finance/finance_modelling_params.py +0 -11
- classiq/interface/finance/function_input.py +0 -102
- classiq/interface/finance/gaussian_model_input.py +0 -50
- classiq/interface/finance/log_normal_model_input.py +0 -40
- classiq/interface/finance/model_input.py +0 -22
- classiq/interface/generator/amplitude_estimation.py +0 -34
- classiq/interface/generator/application_apis/finance_declarations.py +0 -108
- classiq/interface/generator/expressions/enums/__init__.py +0 -0
- classiq/interface/generator/expressions/enums/finance_functions.py +0 -12
- classiq/interface/generator/finance.py +0 -107
- classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
- classiq/interface/generator/grover_diffuser.py +0 -93
- classiq/interface/generator/grover_operator.py +0 -106
- classiq/interface/generator/oracles/__init__.py +0 -3
- classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
- classiq/interface/generator/oracles/custom_oracle.py +0 -65
- classiq/interface/generator/oracles/oracle_abc.py +0 -76
- classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
- classiq/interface/generator/qpe.py +0 -169
- classiq/interface/grover/__init__.py +0 -0
- classiq/interface/grover/grover_modelling_params.py +0 -13
- classiq/model_expansions/transformers/var_splitter.py +0 -224
- classiq/qmod/builtins/functions/finance.py +0 -34
- /classiq/{interface/finance → evaluators/qmod_type_inference}/__init__.py +0 -0
- {classiq-0.86.1.dist-info → classiq-0.88.0.dist-info}/WHEEL +0 -0
|
@@ -58,6 +58,14 @@ class ClassicalType(HashableASTNode):
|
|
|
58
58
|
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
|
59
59
|
return ClassicalScalarProxy(handle, self)
|
|
60
60
|
|
|
61
|
+
@property
|
|
62
|
+
def qmod_type_name(self) -> str:
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def raw_qmod_type_name(self) -> str:
|
|
67
|
+
return self.qmod_type_name
|
|
68
|
+
|
|
61
69
|
@property
|
|
62
70
|
def expressions(self) -> list[Expression]:
|
|
63
71
|
return []
|
|
@@ -79,6 +87,10 @@ class Integer(ClassicalType):
|
|
|
79
87
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
|
80
88
|
return values_with_discriminator(values, "kind", "int")
|
|
81
89
|
|
|
90
|
+
@property
|
|
91
|
+
def qmod_type_name(self) -> str:
|
|
92
|
+
return "CInt"
|
|
93
|
+
|
|
82
94
|
|
|
83
95
|
class Real(ClassicalType):
|
|
84
96
|
kind: Literal["real"]
|
|
@@ -88,6 +100,10 @@ class Real(ClassicalType):
|
|
|
88
100
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
|
89
101
|
return values_with_discriminator(values, "kind", "real")
|
|
90
102
|
|
|
103
|
+
@property
|
|
104
|
+
def qmod_type_name(self) -> str:
|
|
105
|
+
return "CReal"
|
|
106
|
+
|
|
91
107
|
|
|
92
108
|
class Bool(ClassicalType):
|
|
93
109
|
kind: Literal["bool"]
|
|
@@ -97,6 +113,10 @@ class Bool(ClassicalType):
|
|
|
97
113
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
|
98
114
|
return values_with_discriminator(values, "kind", "bool")
|
|
99
115
|
|
|
116
|
+
@property
|
|
117
|
+
def qmod_type_name(self) -> str:
|
|
118
|
+
return "CBool"
|
|
119
|
+
|
|
100
120
|
|
|
101
121
|
class StructMetaType(ClassicalType):
|
|
102
122
|
kind: Literal["type_proxy"]
|
|
@@ -124,6 +144,14 @@ class ClassicalArray(ClassicalType):
|
|
|
124
144
|
def has_length(self) -> bool:
|
|
125
145
|
return self.length is not None and self.length.is_evaluated()
|
|
126
146
|
|
|
147
|
+
@property
|
|
148
|
+
def has_constant_length(self) -> bool:
|
|
149
|
+
return (
|
|
150
|
+
self.length is not None
|
|
151
|
+
and self.length.is_evaluated()
|
|
152
|
+
and self.length.is_constant()
|
|
153
|
+
)
|
|
154
|
+
|
|
127
155
|
@property
|
|
128
156
|
def length_value(self) -> int:
|
|
129
157
|
if not self.has_length:
|
|
@@ -163,6 +191,18 @@ class ClassicalArray(ClassicalType):
|
|
|
163
191
|
raw_type.set_generative()
|
|
164
192
|
return raw_type
|
|
165
193
|
|
|
194
|
+
@property
|
|
195
|
+
def qmod_type_name(self) -> str:
|
|
196
|
+
if self.length is None:
|
|
197
|
+
length = ""
|
|
198
|
+
else:
|
|
199
|
+
length = f", {self.length.expr}"
|
|
200
|
+
return f"CArray[{self.element_type.qmod_type_name}{length}]"
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def raw_qmod_type_name(self) -> str:
|
|
204
|
+
return "CArray"
|
|
205
|
+
|
|
166
206
|
|
|
167
207
|
class ClassicalTuple(ClassicalType):
|
|
168
208
|
kind: Literal["tuple"]
|
|
@@ -196,10 +236,24 @@ class ClassicalTuple(ClassicalType):
|
|
|
196
236
|
element_type.is_purely_generative for element_type in self.element_types
|
|
197
237
|
)
|
|
198
238
|
|
|
199
|
-
def get_raw_type(self) -> "ConcreteClassicalType":
|
|
239
|
+
def get_raw_type(self, *, preserve_length: bool = False) -> "ConcreteClassicalType":
|
|
200
240
|
if len(self.element_types) == 0:
|
|
201
241
|
return self
|
|
202
|
-
|
|
242
|
+
chosen_element = self.element_types[0]
|
|
243
|
+
for element in self.element_types:
|
|
244
|
+
if (
|
|
245
|
+
not isinstance(element, ClassicalTuple)
|
|
246
|
+
or len(element.element_types) > 0
|
|
247
|
+
):
|
|
248
|
+
chosen_element = element
|
|
249
|
+
break
|
|
250
|
+
if preserve_length:
|
|
251
|
+
length = Expression(expr=str(len(self.element_types)))
|
|
252
|
+
else:
|
|
253
|
+
length = None
|
|
254
|
+
raw_type = ClassicalArray(
|
|
255
|
+
element_type=chosen_element.get_raw_type(), length=length
|
|
256
|
+
)
|
|
203
257
|
if self._is_generative:
|
|
204
258
|
raw_type.set_generative()
|
|
205
259
|
return raw_type
|
|
@@ -208,6 +262,17 @@ class ClassicalTuple(ClassicalType):
|
|
|
208
262
|
def length(self) -> int:
|
|
209
263
|
return len(self.element_types)
|
|
210
264
|
|
|
265
|
+
@property
|
|
266
|
+
def qmod_type_name(self) -> str:
|
|
267
|
+
raw_type = self.get_raw_type(preserve_length=True)
|
|
268
|
+
if isinstance(raw_type, ClassicalTuple):
|
|
269
|
+
return "CArray[0]"
|
|
270
|
+
return raw_type.qmod_type_name
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
def raw_qmod_type_name(self) -> str:
|
|
274
|
+
return "CArray"
|
|
275
|
+
|
|
211
276
|
|
|
212
277
|
class OpaqueHandle(ClassicalType):
|
|
213
278
|
pass
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
from collections.abc import Mapping
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
|
5
|
+
QmodStructInstance,
|
|
6
|
+
)
|
|
7
|
+
|
|
4
8
|
QmodPyStruct = Mapping[str, Any]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def qmod_value_to_dict(qmod_value: Any) -> Any:
|
|
12
|
+
if isinstance(qmod_value, QmodStructInstance):
|
|
13
|
+
return {
|
|
14
|
+
field_name: qmod_value_to_dict(field_value)
|
|
15
|
+
for field_name, field_value in qmod_value.fields.items()
|
|
16
|
+
}
|
|
17
|
+
if isinstance(qmod_value, list):
|
|
18
|
+
return [qmod_value_to_dict(item) for item in qmod_value]
|
|
19
|
+
return qmod_value
|
|
@@ -101,6 +101,12 @@ class TypeName(ClassicalType, QuantumType):
|
|
|
101
101
|
field_type.is_evaluated for field_type in self.fields.values()
|
|
102
102
|
)
|
|
103
103
|
|
|
104
|
+
@property
|
|
105
|
+
def is_constant(self) -> bool:
|
|
106
|
+
return self.has_fields and all(
|
|
107
|
+
field_type.is_constant for field_type in self.fields.values()
|
|
108
|
+
)
|
|
109
|
+
|
|
104
110
|
@property
|
|
105
111
|
def has_classical_struct_decl(self) -> bool:
|
|
106
112
|
return self._classical_struct_decl is not None
|
|
@@ -177,6 +183,12 @@ class TypeName(ClassicalType, QuantumType):
|
|
|
177
183
|
raw_type.set_classical_struct_decl(raw_decl)
|
|
178
184
|
return raw_type
|
|
179
185
|
|
|
186
|
+
@property
|
|
187
|
+
def minimal_size_in_bits(self) -> int:
|
|
188
|
+
return sum(
|
|
189
|
+
field_type.minimal_size_in_bits for field_type in self.fields.values()
|
|
190
|
+
)
|
|
191
|
+
|
|
180
192
|
|
|
181
193
|
class Enum(TypeName):
|
|
182
194
|
pass
|
|
@@ -50,14 +50,6 @@ class QuantumFormat(StrEnum):
|
|
|
50
50
|
EXECUTION_SERIALIZATION = "_execution_serialization"
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
_SERVICE_PROVIDER_TO_FORMAT: dict[Provider, QuantumFormat] = {
|
|
54
|
-
Provider.CLASSIQ: QuantumFormat.QASM,
|
|
55
|
-
Provider.IONQ: QuantumFormat.IONQ,
|
|
56
|
-
Provider.AZURE_QUANTUM: QuantumFormat.QSHARP,
|
|
57
|
-
Provider.IBM_QUANTUM: QuantumFormat.QASM,
|
|
58
|
-
Provider.AMAZON_BRAKET: QuantumFormat.QASM,
|
|
59
|
-
}
|
|
60
|
-
|
|
61
53
|
if TYPE_CHECKING:
|
|
62
54
|
PydanticConstrainedQuantumFormatList = list[QuantumFormat]
|
|
63
55
|
else:
|
|
@@ -176,7 +168,7 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
|
|
|
176
168
|
deprecated=True,
|
|
177
169
|
)
|
|
178
170
|
optimization_level: OptimizationLevel = pydantic.Field(
|
|
179
|
-
default=OptimizationLevel.
|
|
171
|
+
default=OptimizationLevel.LIGHT,
|
|
180
172
|
description="The optimization level used during synthesis; determines the trade-off between synthesis speed and the quality of the results",
|
|
181
173
|
)
|
|
182
174
|
output_format: PydanticConstrainedQuantumFormatList = pydantic.Field(
|
|
@@ -260,14 +252,6 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
|
|
|
260
252
|
"has at least one format that appears twice or more"
|
|
261
253
|
)
|
|
262
254
|
|
|
263
|
-
service_provider = info.data.get("backend_service_provider")
|
|
264
|
-
if service_provider is None:
|
|
265
|
-
return output_format
|
|
266
|
-
|
|
267
|
-
provider_format = _SERVICE_PROVIDER_TO_FORMAT.get(service_provider)
|
|
268
|
-
if provider_format is not None and provider_format not in output_format:
|
|
269
|
-
output_format.append(provider_format)
|
|
270
|
-
|
|
271
255
|
return output_format
|
|
272
256
|
|
|
273
257
|
@pydantic.field_validator("backend_name")
|
|
@@ -19,9 +19,7 @@ from classiq.interface.executor.quantum_instruction_set import QuantumInstructio
|
|
|
19
19
|
from classiq.interface.executor.register_initialization import RegisterInitialization
|
|
20
20
|
from classiq.interface.generator.circuit_code.circuit_code import CircuitCodeInterface
|
|
21
21
|
from classiq.interface.generator.circuit_code.types_and_constants import (
|
|
22
|
-
DEFAULT_INSTRUCTION_SET,
|
|
23
22
|
INSTRUCTION_SET_TO_FORMAT,
|
|
24
|
-
VENDOR_TO_INSTRUCTION_SET,
|
|
25
23
|
CodeAndSyntax,
|
|
26
24
|
)
|
|
27
25
|
from classiq.interface.generator.generated_circuit_data import (
|
|
@@ -82,7 +80,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
|
82
80
|
def __str__(self) -> str:
|
|
83
81
|
return self.model_dump_json(indent=2)
|
|
84
82
|
|
|
85
|
-
def
|
|
83
|
+
def _default_program_code(self) -> CodeAndSyntax:
|
|
86
84
|
circuit_code = self.program_circuit.get_code_by_priority()
|
|
87
85
|
if circuit_code is not None:
|
|
88
86
|
return circuit_code
|
|
@@ -91,16 +89,6 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
|
91
89
|
missing_formats=list(INSTRUCTION_SET_TO_FORMAT.values())
|
|
92
90
|
)
|
|
93
91
|
|
|
94
|
-
def _default_program_code(self) -> CodeAndSyntax:
|
|
95
|
-
if self.hardware_data.backend_data is None:
|
|
96
|
-
return self._hardware_agnostic_program_code()
|
|
97
|
-
|
|
98
|
-
backend_provider = self.hardware_data.backend_data.hw_provider
|
|
99
|
-
instruction_set: QuantumInstructionSet = VENDOR_TO_INSTRUCTION_SET.get(
|
|
100
|
-
backend_provider, DEFAULT_INSTRUCTION_SET
|
|
101
|
-
)
|
|
102
|
-
return self.program_circuit.get_code(instruction_set), instruction_set
|
|
103
|
-
|
|
104
92
|
def to_base_program(self) -> quantum_code.QuantumBaseCode:
|
|
105
93
|
code, syntax = self._default_program_code()
|
|
106
94
|
return quantum_code.QuantumBaseCode(code=code, syntax=syntax)
|
|
@@ -57,11 +57,15 @@ EXTRA_TWO_QUBIT_GATES: BasisGates = frozenset(
|
|
|
57
57
|
)
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
+
NON_UNITARY_GATES: BasisGates = frozenset(("if_else",))
|
|
61
|
+
|
|
60
62
|
TWO_QUBIT_GATES = BASIC_TWO_QUBIT_GATES | EXTRA_TWO_QUBIT_GATES
|
|
61
63
|
|
|
62
64
|
THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap"))
|
|
63
65
|
DEFAULT_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | BASIC_TWO_QUBIT_GATES
|
|
64
|
-
ALL_GATES: BasisGates =
|
|
66
|
+
ALL_GATES: BasisGates = (
|
|
67
|
+
SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES | NON_UNITARY_GATES
|
|
68
|
+
)
|
|
65
69
|
|
|
66
70
|
ROUTING_TWO_QUBIT_BASIS_GATES: BasisGates = frozenset(
|
|
67
71
|
("cx", "ecr", "rzx", "ryy", "rxx", "rzz", "cy", "cz", "cp", "swap")
|
|
@@ -132,13 +132,6 @@ class FermionMapping(IntEnum):
|
|
|
132
132
|
FAST_BRAVYI_KITAEV = 3
|
|
133
133
|
|
|
134
134
|
|
|
135
|
-
class FinanceFunctionType(IntEnum):
|
|
136
|
-
VAR = 0
|
|
137
|
-
SHORTFALL = 1
|
|
138
|
-
X_SQUARE = 2
|
|
139
|
-
EUROPEAN_CALL_OPTION = 3
|
|
140
|
-
|
|
141
|
-
|
|
142
135
|
class LadderOperator(IntEnum):
|
|
143
136
|
PLUS = 0
|
|
144
137
|
MINUS = 1
|
|
@@ -171,7 +164,6 @@ class QSVMFeatureMapEntanglement(IntEnum):
|
|
|
171
164
|
__all__ = [
|
|
172
165
|
"Element",
|
|
173
166
|
"FermionMapping",
|
|
174
|
-
"FinanceFunctionType",
|
|
175
167
|
"LadderOperator",
|
|
176
168
|
"Optimizer",
|
|
177
169
|
"Pauli",
|
|
@@ -37,8 +37,8 @@ class ModelNormalizer(Visitor):
|
|
|
37
37
|
|
|
38
38
|
class ClearModelInternals(Transformer):
|
|
39
39
|
def visit_Expression(self, expr: Expression) -> Expression:
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
expr._evaluated_expr = None
|
|
41
|
+
expr._try_to_immediate_evaluate()
|
|
42
42
|
return expr
|
|
43
43
|
|
|
44
44
|
def visit_ClassicalType(self, classical_type: ClassicalType) -> ClassicalType:
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def s(items: Union[list, int]) -> str:
|
|
5
|
+
if isinstance(items, list):
|
|
6
|
+
items = len(items)
|
|
7
|
+
return "" if items == 1 else "s"
|
|
3
8
|
|
|
4
9
|
|
|
5
10
|
def are(items: list) -> str:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
INTERFACE_VERSION = "
|
|
1
|
+
INTERFACE_VERSION = "12"
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import operator
|
|
3
|
+
from collections.abc import Mapping
|
|
1
4
|
from typing import TYPE_CHECKING, Literal
|
|
2
5
|
|
|
6
|
+
import pydantic
|
|
7
|
+
|
|
3
8
|
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
|
4
9
|
from classiq.interface.generator.expressions.expression import Expression
|
|
10
|
+
from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
|
|
5
11
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
|
6
12
|
|
|
7
13
|
if TYPE_CHECKING:
|
|
@@ -14,6 +20,9 @@ class ClassicalIf(QuantumOperation):
|
|
|
14
20
|
condition: Expression
|
|
15
21
|
then: "StatementBlock"
|
|
16
22
|
else_: "StatementBlock"
|
|
23
|
+
_condition_wiring_inouts: dict[str, HandleBinding] = pydantic.PrivateAttr(
|
|
24
|
+
default_factory=dict
|
|
25
|
+
)
|
|
17
26
|
|
|
18
27
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
|
19
28
|
return reset_lists(self, ["then", "else_"])
|
|
@@ -21,3 +30,42 @@ class ClassicalIf(QuantumOperation):
|
|
|
21
30
|
@property
|
|
22
31
|
def expressions(self) -> list[Expression]:
|
|
23
32
|
return [self.condition]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def wiring_inputs(self) -> Mapping[str, HandleBinding]:
|
|
36
|
+
return functools.reduce(
|
|
37
|
+
operator.ior,
|
|
38
|
+
(
|
|
39
|
+
op.wiring_inputs
|
|
40
|
+
for op in (*self.then, *self.else_)
|
|
41
|
+
if isinstance(op, QuantumOperation)
|
|
42
|
+
),
|
|
43
|
+
dict(),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def wiring_inouts(self) -> Mapping[str, ConcreteHandleBinding]:
|
|
48
|
+
return (
|
|
49
|
+
functools.reduce(
|
|
50
|
+
operator.ior,
|
|
51
|
+
(
|
|
52
|
+
op.wiring_inouts
|
|
53
|
+
for op in (*self.then, *self.else_)
|
|
54
|
+
if isinstance(op, QuantumOperation)
|
|
55
|
+
),
|
|
56
|
+
dict(),
|
|
57
|
+
)
|
|
58
|
+
| self._condition_wiring_inouts
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def wiring_outputs(self) -> Mapping[str, HandleBinding]:
|
|
63
|
+
return functools.reduce(
|
|
64
|
+
operator.ior,
|
|
65
|
+
(
|
|
66
|
+
op.wiring_outputs
|
|
67
|
+
for op in (*self.then, *self.else_)
|
|
68
|
+
if isinstance(op, QuantumOperation)
|
|
69
|
+
),
|
|
70
|
+
dict(),
|
|
71
|
+
)
|
|
@@ -156,7 +156,12 @@ class SubscriptHandleBinding(NestedHandleBinding):
|
|
|
156
156
|
def _get_collapsed_index(self) -> Expression:
|
|
157
157
|
if TYPE_CHECKING:
|
|
158
158
|
assert isinstance(self.base_handle, SlicedHandleBinding)
|
|
159
|
-
if
|
|
159
|
+
if (
|
|
160
|
+
self.index.is_evaluated()
|
|
161
|
+
and self.index.is_constant()
|
|
162
|
+
and self.base_handle.start.is_evaluated()
|
|
163
|
+
and self.base_handle.start.is_constant()
|
|
164
|
+
):
|
|
160
165
|
return Expression(
|
|
161
166
|
expr=str(
|
|
162
167
|
self.base_handle.start.to_int_value() + self.index.to_int_value()
|
|
@@ -170,7 +175,8 @@ class SubscriptHandleBinding(NestedHandleBinding):
|
|
|
170
175
|
if (
|
|
171
176
|
isinstance(other_handle, SlicedHandleBinding)
|
|
172
177
|
and self.index.is_evaluated()
|
|
173
|
-
and
|
|
178
|
+
and self.index.is_constant()
|
|
179
|
+
and other_handle.is_constant()
|
|
174
180
|
):
|
|
175
181
|
return (
|
|
176
182
|
other_handle.start.to_int_value()
|
|
@@ -186,7 +192,8 @@ class SubscriptHandleBinding(NestedHandleBinding):
|
|
|
186
192
|
isinstance(prefix, SlicedHandleBinding)
|
|
187
193
|
and self.base_handle == prefix.base_handle
|
|
188
194
|
and self.index.is_evaluated()
|
|
189
|
-
and
|
|
195
|
+
and self.index.is_constant()
|
|
196
|
+
and prefix.is_constant()
|
|
190
197
|
and prefix.start.to_int_value()
|
|
191
198
|
<= self.index.to_int_value()
|
|
192
199
|
< prefix.end.to_int_value()
|
|
@@ -243,19 +250,17 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
|
243
250
|
)
|
|
244
251
|
|
|
245
252
|
def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
|
|
246
|
-
if not self.
|
|
253
|
+
if not self.is_constant():
|
|
247
254
|
return False
|
|
248
255
|
start = self.start.to_int_value()
|
|
249
256
|
end = self.end.to_int_value()
|
|
250
257
|
if (
|
|
251
258
|
isinstance(other_handle, SubscriptHandleBinding)
|
|
252
259
|
and other_handle.index.is_evaluated()
|
|
260
|
+
and other_handle.index.is_constant()
|
|
253
261
|
):
|
|
254
262
|
return start <= other_handle.index.to_int_value() < end
|
|
255
|
-
if (
|
|
256
|
-
isinstance(other_handle, SlicedHandleBinding)
|
|
257
|
-
and other_handle._is_evaluated()
|
|
258
|
-
):
|
|
263
|
+
if isinstance(other_handle, SlicedHandleBinding) and other_handle.is_constant():
|
|
259
264
|
other_start = other_handle.start.to_int_value()
|
|
260
265
|
other_end = other_handle.end.to_int_value()
|
|
261
266
|
return start <= other_start < end or other_start <= start < other_end
|
|
@@ -264,7 +269,12 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
|
264
269
|
def _get_collapsed_start(self) -> Expression:
|
|
265
270
|
if TYPE_CHECKING:
|
|
266
271
|
assert isinstance(self.base_handle, SlicedHandleBinding)
|
|
267
|
-
if
|
|
272
|
+
if (
|
|
273
|
+
self.start.is_evaluated()
|
|
274
|
+
and self.start.is_constant()
|
|
275
|
+
and self.base_handle.start.is_evaluated()
|
|
276
|
+
and self.base_handle.start.is_constant()
|
|
277
|
+
):
|
|
268
278
|
return Expression(
|
|
269
279
|
expr=str(
|
|
270
280
|
self.base_handle.start.to_int_value() + self.start.to_int_value()
|
|
@@ -275,7 +285,11 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
|
275
285
|
def _get_collapsed_stop(self) -> Expression:
|
|
276
286
|
if TYPE_CHECKING:
|
|
277
287
|
assert isinstance(self.base_handle, SlicedHandleBinding)
|
|
278
|
-
if
|
|
288
|
+
if (
|
|
289
|
+
self.is_constant()
|
|
290
|
+
and self.base_handle.start.is_evaluated()
|
|
291
|
+
and self.base_handle.start.is_constant()
|
|
292
|
+
):
|
|
279
293
|
return Expression(
|
|
280
294
|
expr=str(
|
|
281
295
|
self.end.to_int_value()
|
|
@@ -295,8 +309,8 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
|
295
309
|
if (
|
|
296
310
|
isinstance(prefix, SlicedHandleBinding)
|
|
297
311
|
and self.base_handle == prefix.base_handle
|
|
298
|
-
and self.
|
|
299
|
-
and prefix.
|
|
312
|
+
and self.is_constant()
|
|
313
|
+
and prefix.is_constant()
|
|
300
314
|
):
|
|
301
315
|
prefix_start = prefix.start.to_int_value()
|
|
302
316
|
prefix_end = prefix.end.to_int_value()
|
|
@@ -313,14 +327,12 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
|
313
327
|
)
|
|
314
328
|
return super().replace_prefix(prefix, replacement)
|
|
315
329
|
|
|
316
|
-
def _is_evaluated(self) -> bool:
|
|
317
|
-
return self.start.is_evaluated() and self.end.is_evaluated()
|
|
318
|
-
|
|
319
330
|
def is_constant(self) -> bool:
|
|
320
331
|
return (
|
|
321
332
|
super().is_constant()
|
|
322
|
-
and self.
|
|
333
|
+
and self.start.is_evaluated()
|
|
323
334
|
and self.start.is_constant()
|
|
335
|
+
and self.end.is_evaluated()
|
|
324
336
|
and self.end.is_constant()
|
|
325
337
|
)
|
|
326
338
|
|
|
@@ -44,6 +44,18 @@ class AnonPortDeclaration(Parameter):
|
|
|
44
44
|
raise ClassiqInternalError
|
|
45
45
|
return PortDeclaration(**{**self.__dict__, "name": new_name})
|
|
46
46
|
|
|
47
|
+
@property
|
|
48
|
+
def qmod_type_name(self) -> str:
|
|
49
|
+
prefix = ""
|
|
50
|
+
suffix = ""
|
|
51
|
+
if self.type_modifier in (TypeModifier.Const, TypeModifier.Permutable):
|
|
52
|
+
prefix += f"{self.type_modifier.name}["
|
|
53
|
+
suffix += "]"
|
|
54
|
+
if self.direction != PortDeclarationDirection.Inout:
|
|
55
|
+
prefix += f"{self.direction.name}["
|
|
56
|
+
suffix += "]"
|
|
57
|
+
return f"{prefix}{self.quantum_type.qmod_type_name}{suffix}"
|
|
58
|
+
|
|
47
59
|
|
|
48
60
|
class PortDeclaration(AnonPortDeclaration):
|
|
49
61
|
name: str
|
|
@@ -190,6 +190,18 @@ class AnonQuantumOperandDeclaration(AnonQuantumFunctionDeclaration):
|
|
|
190
190
|
def is_generative(self) -> bool:
|
|
191
191
|
return self._is_generative
|
|
192
192
|
|
|
193
|
+
@property
|
|
194
|
+
def qmod_type_name(self) -> str:
|
|
195
|
+
if self.is_list:
|
|
196
|
+
type_name = "QCallableList"
|
|
197
|
+
else:
|
|
198
|
+
type_name = "QCallable"
|
|
199
|
+
if len(self.positional_arg_declarations) == 0:
|
|
200
|
+
params = ""
|
|
201
|
+
else:
|
|
202
|
+
params = f"[{', '.join(param.qmod_type_name for param in self.positional_arg_declarations)}]"
|
|
203
|
+
return f"{type_name}{params}"
|
|
204
|
+
|
|
193
205
|
|
|
194
206
|
AnonQuantumFunctionDeclaration.model_rebuild()
|
|
195
207
|
|