classiq 0.74.0__py3-none-any.whl → 0.76.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 +36 -0
- classiq/analyzer/show_interactive_hack.py +58 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +8 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -4
- classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
- classiq/applications/qnn/qlayer.py +23 -19
- classiq/applications/qnn/types.py +1 -4
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +3 -16
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +38 -0
- classiq/executor.py +7 -19
- classiq/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +18 -13
- classiq/interface/executor/user_budget.py +56 -0
- classiq/interface/generator/application_apis/finance_declarations.py +3 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +3 -0
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +30 -124
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +46 -22
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +14 -13
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +9 -2
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +4 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
- classiq/interface/generator/functions/classical_type.py +36 -1
- classiq/interface/generator/functions/type_name.py +32 -5
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/generated_circuit_data.py +11 -25
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +10 -13
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/helpers/versioned_model.py +12 -0
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/handle_binding.py +12 -0
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/model/statement_block.py +9 -1
- classiq/interface/model/within_apply_operation.py +12 -0
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +82 -23
- classiq/model_expansions/capturing/captured_vars.py +2 -0
- classiq/model_expansions/closure.py +18 -0
- classiq/model_expansions/evaluators/argument_types.py +6 -5
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +26 -13
- classiq/model_expansions/evaluators/type_type_match.py +2 -2
- classiq/model_expansions/expression_evaluator.py +1 -1
- classiq/model_expansions/generative_functions.py +66 -33
- classiq/model_expansions/interpreters/base_interpreter.py +27 -19
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +26 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +25 -1
- classiq/model_expansions/quantum_operations/allocate.py +27 -11
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +220 -19
- classiq/model_expansions/quantum_operations/bind.py +54 -30
- classiq/model_expansions/quantum_operations/block_evaluator.py +42 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +14 -12
- classiq/model_expansions/quantum_operations/composite_emitter.py +1 -1
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +23 -9
- classiq/model_expansions/quantum_operations/emitter.py +21 -8
- classiq/model_expansions/quantum_operations/expression_evaluator.py +1 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +1 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +10 -7
- classiq/model_expansions/sympy_conversion/arithmetics.py +18 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +2 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +10 -1
- classiq/model_expansions/transformers/model_renamer.py +48 -8
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +197 -0
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/qmod/builtins/functions/allocation.py +2 -2
- classiq/qmod/builtins/functions/arithmetic.py +14 -12
- classiq/qmod/builtins/functions/standard_gates.py +23 -23
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +8 -3
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +30 -2
- classiq/qmod/quantum_function.py +19 -6
- classiq/qmod/semantics/lambdas.py +6 -2
- classiq/qmod/semantics/validation/main_validation.py +17 -4
- classiq/qmod/symbolic.py +8 -19
- classiq/qmod/symbolic_expr.py +34 -2
- classiq/qmod/write_qmod.py +5 -1
- classiq/synthesis.py +17 -31
- classiq/visualization.py +35 -0
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/METADATA +1 -1
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/RECORD +96 -91
- {classiq-0.74.0.dist-info → classiq-0.76.0.dist-info}/WHEEL +1 -1
@@ -1,7 +1,22 @@
|
|
1
1
|
from classiq.interface.enum_utils import StrEnum
|
2
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
2
3
|
|
3
4
|
|
4
5
|
class TypeQualifier(StrEnum):
|
5
6
|
Const = "const"
|
6
7
|
QFree = "qfree"
|
7
8
|
Quantum = "quantum"
|
9
|
+
Inferred = "inferred"
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def and_(first: "TypeQualifier", second: "TypeQualifier") -> "TypeQualifier":
|
13
|
+
if second is TypeQualifier.Inferred:
|
14
|
+
raise ClassiqInternalExpansionError
|
15
|
+
if first is TypeQualifier.Quantum or second is TypeQualifier.Quantum:
|
16
|
+
return TypeQualifier.Quantum
|
17
|
+
elif first is TypeQualifier.QFree or second is TypeQualifier.QFree:
|
18
|
+
return TypeQualifier.QFree
|
19
|
+
else:
|
20
|
+
if first is not TypeQualifier.Const and second is not TypeQualifier.Const:
|
21
|
+
raise ClassiqInternalExpansionError("Unexpected type qualifiers")
|
22
|
+
return TypeQualifier.Const
|
@@ -40,6 +40,7 @@ IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
|
|
40
40
|
CLASSIQ_HIERARCHY_SEPARATOR: Literal["__"] = "__"
|
41
41
|
QASM_SEPARATOR = "_"
|
42
42
|
SPLIT_MARKER: str = "part"
|
43
|
+
ARITH_ENGINE_PREFIX = "arith_eng__"
|
43
44
|
PART_SUFFIX_REGEX = re.compile(
|
44
45
|
rf".+{QASM_SEPARATOR}{SPLIT_MARKER}{QASM_SEPARATOR}(\d+)$"
|
45
46
|
)
|
@@ -177,10 +178,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
177
178
|
absolute_qubits: Optional[tuple[int, ...]] = Field(default=None)
|
178
179
|
is_basis_gate: Optional[bool] = Field(default=None)
|
179
180
|
is_inverse: bool = Field(default=False)
|
180
|
-
is_allocate_or_free: bool = Field(default=False)
|
181
181
|
is_unitary: bool = Field(default=True, exclude=True)
|
182
182
|
uuid: Optional[UUID] = Field(default=None, exclude=True)
|
183
|
-
level: OperationLevel = Field(default=OperationLevel.UNKNOWN)
|
184
183
|
port_to_passed_variable_map: dict[str, str] = Field(default={})
|
185
184
|
release_by_inverse: bool = Field(default=False)
|
186
185
|
back_refs: StatementBlock = Field(default_factory=list)
|
@@ -190,16 +189,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
190
189
|
override_debug_info: Optional["FunctionDebugInfoInterface"] = None
|
191
190
|
|
192
191
|
@property
|
193
|
-
def
|
194
|
-
|
195
|
-
temporary measure to handle the fact that in the current release we do not have
|
196
|
-
the backref, and therefore fallback to the old field of is_allocate_or_free
|
197
|
-
"""
|
198
|
-
return (
|
199
|
-
is_allocate_or_free_by_backref(self.back_refs)
|
200
|
-
if bool(self.back_refs)
|
201
|
-
else self.is_allocate_or_free
|
202
|
-
)
|
192
|
+
def is_allocate_or_free(self) -> bool:
|
193
|
+
return is_allocate_or_free_by_backref(self.back_refs)
|
203
194
|
|
204
195
|
@property
|
205
196
|
def name(self) -> str:
|
@@ -215,10 +206,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
215
206
|
if isinstance(back_ref, QuantumFunctionCall):
|
216
207
|
name = generate_original_function_name(back_ref.func_name)
|
217
208
|
if part_match := PART_SUFFIX_REGEX.match(generated_name):
|
218
|
-
|
219
|
-
|
220
|
-
suffix = ""
|
221
|
-
return f"{name}{suffix}"
|
209
|
+
name += f" [{part_match.group(1)}]"
|
210
|
+
return name.removeprefix(ARITH_ENGINE_PREFIX)
|
222
211
|
|
223
212
|
statement_kind: str = back_ref.kind
|
224
213
|
if isinstance(back_ref, ArithmeticOperation):
|
@@ -230,19 +219,16 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
230
219
|
return self.back_refs[0] if self.back_refs else None
|
231
220
|
|
232
221
|
@property
|
233
|
-
def
|
222
|
+
def level(self) -> OperationLevel:
|
234
223
|
# Temp fix for currently "supported" statements
|
235
224
|
if self.name in {StatementType.CONTROL, StatementType.POWER}:
|
236
225
|
return OperationLevel.QMOD_STATEMENT
|
237
226
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
# return OperationLevel.ENGINE_FUNCTION_CALL
|
244
|
-
return self.level
|
245
|
-
if isinstance(back_ref, QuantumFunctionCall):
|
227
|
+
if self.first_back_ref is None:
|
228
|
+
# we use ENGINE_FUNCTION_CALL in case where there's not back ref
|
229
|
+
return OperationLevel.ENGINE_FUNCTION_CALL
|
230
|
+
|
231
|
+
if isinstance(self.first_back_ref, QuantumFunctionCall):
|
246
232
|
return OperationLevel.QMOD_FUNCTION_CALL
|
247
233
|
return OperationLevel.QMOD_STATEMENT
|
248
234
|
|
@@ -102,6 +102,13 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
|
|
102
102
|
debug_mode (bool): If `True`, debug information is added to the
|
103
103
|
synthesized result, potentially slowing down the synthesis. Useful for
|
104
104
|
executing interactive algorithms. Defaults to `True`.
|
105
|
+
optimization_level (OptimizationLevel) : The optimization level used during synthesis (0-3);
|
106
|
+
determines the trade-off between synthesis speed and the quality of the results. Defaults to 3.
|
107
|
+
OptimizationLevel Options:
|
108
|
+
- NONE = 0
|
109
|
+
- LIGHT = 1
|
110
|
+
- MEDIUM = 2
|
111
|
+
- HIGH = 3
|
105
112
|
output_format (List[QuantumFormat]): Lists the output format(s)
|
106
113
|
for the quantum circuit. Defaults to `[QuantumFormat.QASM]`.
|
107
114
|
`QuantumFormat` Options:
|
@@ -1,11 +1,9 @@
|
|
1
1
|
import uuid
|
2
2
|
from datetime import datetime, timezone
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import
|
4
|
+
from typing import Optional, Union
|
5
5
|
|
6
6
|
import pydantic
|
7
|
-
from pydantic import model_validator
|
8
|
-
from pydantic_core.core_schema import ValidationInfo
|
9
7
|
from typing_extensions import TypeAlias
|
10
8
|
|
11
9
|
from classiq.interface.compression_utils import decompress
|
@@ -39,8 +37,6 @@ from classiq.interface.ide.visual_model import CircuitMetrics
|
|
39
37
|
RegisterName: TypeAlias = str
|
40
38
|
InitialConditions: TypeAlias = dict[RegisterName, int]
|
41
39
|
|
42
|
-
OMIT_DEBUG_INFO_FLAG = "omit_debug_info"
|
43
|
-
|
44
40
|
|
45
41
|
class TranspiledCircuitData(CircuitCodeInterface):
|
46
42
|
depth: int
|
@@ -77,18 +73,8 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
77
73
|
program_id: str = pydantic.Field(default_factory=get_uuid_as_str)
|
78
74
|
execution_primitives_input: Optional[PrimitivesInput] = pydantic.Field(default=None)
|
79
75
|
|
80
|
-
|
81
|
-
|
82
|
-
def remove_debug_info(
|
83
|
-
cls, data: dict[str, Any], info: ValidationInfo
|
84
|
-
) -> dict[str, Any]:
|
85
|
-
if (
|
86
|
-
isinstance(data, dict)
|
87
|
-
and info.context is not None
|
88
|
-
and info.context.get(OMIT_DEBUG_INFO_FLAG, False)
|
89
|
-
):
|
90
|
-
data.pop("debug_info", None)
|
91
|
-
return data
|
76
|
+
def __str__(self) -> str:
|
77
|
+
return self.model_dump_json(indent=2)
|
92
78
|
|
93
79
|
def _hardware_agnostic_program_code(self) -> CodeAndSyntax:
|
94
80
|
circuit_code = self.program_circuit.get_code_by_priority()
|
@@ -177,7 +163,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
177
163
|
file.write(self.model_dump_json(indent=4))
|
178
164
|
|
179
165
|
@classmethod
|
180
|
-
def from_qprog(cls, qprog:
|
166
|
+
def from_qprog(cls, qprog: "QuantumProgram") -> "QuantumProgram":
|
181
167
|
"""
|
182
168
|
Creates a `QuantumProgram` instance from a raw quantum program string.
|
183
169
|
|
@@ -187,7 +173,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
187
173
|
Returns:
|
188
174
|
QuantumProgram: The `QuantumProgram` instance.
|
189
175
|
"""
|
190
|
-
return
|
176
|
+
return qprog
|
191
177
|
|
192
178
|
@property
|
193
179
|
def _can_use_transpiled_code(self) -> bool:
|
@@ -1,10 +1,10 @@
|
|
1
|
+
from itertools import chain
|
1
2
|
from typing import Optional
|
2
3
|
|
3
4
|
import pydantic
|
4
5
|
import sympy
|
5
6
|
|
6
7
|
from classiq.interface.backend.pydantic_backend import PydanticExecutionParameter
|
7
|
-
from classiq.interface.exceptions import ClassiqValueError
|
8
8
|
from classiq.interface.generator.parameters import ParameterType
|
9
9
|
|
10
10
|
|
@@ -12,15 +12,10 @@ class FunctionExecutionData(pydantic.BaseModel):
|
|
12
12
|
power_parameter: Optional[ParameterType] = pydantic.Field(default=None)
|
13
13
|
|
14
14
|
@property
|
15
|
-
def
|
15
|
+
def power_vars(self) -> Optional[list[str]]:
|
16
16
|
if self.power_parameter is None:
|
17
17
|
return None
|
18
|
-
|
19
|
-
if len(power_vars) != 1:
|
20
|
-
raise ClassiqValueError(
|
21
|
-
f"Power parameter expression: {self.power_parameter} must contain exactly one variable"
|
22
|
-
)
|
23
|
-
return str(list(power_vars)[0])
|
18
|
+
return list(map(str, sympy.sympify(self.power_parameter).free_symbols))
|
24
19
|
|
25
20
|
|
26
21
|
class ExecutionData(pydantic.BaseModel):
|
@@ -32,8 +27,10 @@ class ExecutionData(pydantic.BaseModel):
|
|
32
27
|
def execution_parameters(
|
33
28
|
self,
|
34
29
|
) -> set[PydanticExecutionParameter]:
|
35
|
-
return
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
return set(
|
31
|
+
chain.from_iterable(
|
32
|
+
function_execution_data.power_vars
|
33
|
+
for function_execution_data in self.function_execution.values()
|
34
|
+
if function_execution_data.power_vars is not None
|
35
|
+
)
|
36
|
+
)
|
@@ -17,6 +17,12 @@ class LenList(list):
|
|
17
17
|
def len(self) -> int:
|
18
18
|
return len(self)
|
19
19
|
|
20
|
+
def __getitem__(self, item: Any) -> Any:
|
21
|
+
res = super().__getitem__(item)
|
22
|
+
if isinstance(item, slice):
|
23
|
+
res = type(self)(res)
|
24
|
+
return res
|
25
|
+
|
20
26
|
|
21
27
|
def get_sdk_compatible_python_object(obj: Any) -> Any:
|
22
28
|
if isinstance(obj, list):
|
@@ -1,7 +1,19 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
1
3
|
import pydantic
|
2
4
|
|
3
5
|
from classiq.interface._version import VERSION
|
6
|
+
from classiq.interface.interface_version import INTERFACE_VERSION
|
4
7
|
|
5
8
|
|
6
9
|
class VersionedModel(pydantic.BaseModel):
|
7
10
|
version: str = pydantic.Field(default=VERSION)
|
11
|
+
interface_version: str = pydantic.Field(default="0")
|
12
|
+
|
13
|
+
@pydantic.model_validator(mode="before")
|
14
|
+
@classmethod
|
15
|
+
def set_interface_version(cls, values: dict[str, Any]) -> dict[str, Any]:
|
16
|
+
# We "override" the default value mechanism so that the schema does not depend on the version
|
17
|
+
if "interface_version" not in values:
|
18
|
+
values["interface_version"] = INTERFACE_VERSION
|
19
|
+
return values
|
@@ -1 +1 @@
|
|
1
|
-
INTERFACE_VERSION = "
|
1
|
+
INTERFACE_VERSION = "10"
|
@@ -67,6 +67,9 @@ class HandleBinding(ASTNode):
|
|
67
67
|
def is_constant(self) -> bool:
|
68
68
|
return True
|
69
69
|
|
70
|
+
def expressions(self) -> list[Expression]:
|
71
|
+
return []
|
72
|
+
|
70
73
|
|
71
74
|
class NestedHandleBinding(HandleBinding):
|
72
75
|
base_handle: "ConcreteHandleBinding"
|
@@ -111,6 +114,9 @@ class NestedHandleBinding(HandleBinding):
|
|
111
114
|
def is_constant(self) -> bool:
|
112
115
|
return self.base_handle.is_constant()
|
113
116
|
|
117
|
+
def expressions(self) -> list[Expression]:
|
118
|
+
return self.base_handle.expressions()
|
119
|
+
|
114
120
|
|
115
121
|
class SubscriptHandleBinding(NestedHandleBinding):
|
116
122
|
index: Expression
|
@@ -191,6 +197,9 @@ class SubscriptHandleBinding(NestedHandleBinding):
|
|
191
197
|
and self.index.is_constant()
|
192
198
|
)
|
193
199
|
|
200
|
+
def expressions(self) -> list[Expression]:
|
201
|
+
return super().expressions() + [self.index]
|
202
|
+
|
194
203
|
|
195
204
|
class SlicedHandleBinding(NestedHandleBinding):
|
196
205
|
start: Expression
|
@@ -305,6 +314,9 @@ class SlicedHandleBinding(NestedHandleBinding):
|
|
305
314
|
and self.end.is_constant()
|
306
315
|
)
|
307
316
|
|
317
|
+
def expressions(self) -> list[Expression]:
|
318
|
+
return super().expressions() + [self.start, self.end]
|
319
|
+
|
308
320
|
|
309
321
|
class FieldHandleBinding(NestedHandleBinding):
|
310
322
|
field: str
|
@@ -16,8 +16,7 @@ from classiq.interface.model.parameter import Parameter
|
|
16
16
|
class AnonPortDeclaration(Parameter):
|
17
17
|
quantum_type: ConcreteQuantumType
|
18
18
|
direction: PortDeclarationDirection
|
19
|
-
|
20
|
-
type_qualifier: TypeQualifier = pydantic.Field(default=TypeQualifier.Quantum)
|
19
|
+
type_qualifier: TypeQualifier
|
21
20
|
kind: Literal["PortDeclaration"]
|
22
21
|
|
23
22
|
@pydantic.model_validator(mode="before")
|
@@ -5,6 +5,7 @@ import pydantic
|
|
5
5
|
from classiq.interface.ast_node import ASTNode
|
6
6
|
from classiq.interface.exceptions import ClassiqError
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
8
9
|
from classiq.interface.model.quantum_function_declaration import (
|
9
10
|
AnonQuantumOperandDeclaration,
|
10
11
|
)
|
@@ -56,7 +57,7 @@ class QuantumLambdaFunction(ASTNode):
|
|
56
57
|
def named_func_decl(self) -> AnonQuantumOperandDeclaration:
|
57
58
|
named_params = [
|
58
59
|
param.rename(rename)
|
59
|
-
for param, rename in
|
60
|
+
for param, rename in zip_strict(
|
60
61
|
self.func_decl.positional_arg_declarations,
|
61
62
|
self.pos_rename_params,
|
62
63
|
strict=False, # strict=False enables lambda keyword args
|
@@ -24,7 +24,12 @@ from classiq.interface.model.repeat import Repeat
|
|
24
24
|
from classiq.interface.model.variable_declaration_statement import (
|
25
25
|
VariableDeclarationStatement,
|
26
26
|
)
|
27
|
-
from classiq.interface.model.within_apply_operation import
|
27
|
+
from classiq.interface.model.within_apply_operation import (
|
28
|
+
Action,
|
29
|
+
Compute,
|
30
|
+
Uncompute,
|
31
|
+
WithinApply,
|
32
|
+
)
|
28
33
|
|
29
34
|
ConcreteQuantumStatement = Annotated[
|
30
35
|
Union[
|
@@ -43,6 +48,9 @@ ConcreteQuantumStatement = Annotated[
|
|
43
48
|
WithinApply,
|
44
49
|
PhaseOperation,
|
45
50
|
Block,
|
51
|
+
Compute,
|
52
|
+
Action,
|
53
|
+
Uncompute,
|
46
54
|
],
|
47
55
|
Field(..., discriminator="kind"),
|
48
56
|
]
|
@@ -15,3 +15,15 @@ class WithinApply(QuantumOperation):
|
|
15
15
|
|
16
16
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
17
17
|
return reset_lists(self, ["compute", "action"])
|
18
|
+
|
19
|
+
|
20
|
+
class Compute(QuantumOperation):
|
21
|
+
kind: Literal["Compute"]
|
22
|
+
|
23
|
+
|
24
|
+
class Action(QuantumOperation):
|
25
|
+
kind: Literal["Action"]
|
26
|
+
|
27
|
+
|
28
|
+
class Uncompute(QuantumOperation):
|
29
|
+
kind: Literal["Uncompute"]
|
@@ -6,6 +6,8 @@ CONVERSION_PREFIX = "/conversion"
|
|
6
6
|
PROVIDERS_PREFIX = "/providers"
|
7
7
|
|
8
8
|
IQCC_PREFIX = PROVIDERS_PREFIX + "/iqcc"
|
9
|
+
USER_BUDGETS_PREFIX = "/user_budgets"
|
10
|
+
|
9
11
|
|
10
12
|
ANALYZER_CIRCUIT_PAGE = "circuit"
|
11
13
|
DEFAULT_IDE_FE_APP = "https://platform.classiq.io/"
|
@@ -50,6 +52,7 @@ TASK_TEST_SUFFIX = TASKS_SUFFIX + "/test"
|
|
50
52
|
TASK_PREDICT_SUFFIX = TASKS_SUFFIX + "/predict"
|
51
53
|
TASK_RB_SUFFIX = TASKS_SUFFIX + RB
|
52
54
|
TASKS_GENERATE_FULL_PATH = TASKS_GENERATE_SUFFIX
|
55
|
+
TASKS_VISUAL_MODEL_FULL_PATH = ANALYZER_PREFIX + TASKS_VISUAL_MODEL_SUFFIX
|
53
56
|
|
54
57
|
EXECUTION_JOBS_SUFFIX = "/jobs"
|
55
58
|
EXECUTION_JOBS_FULL_PATH = EXECUTION_PREFIX + EXECUTION_JOBS_SUFFIX
|
@@ -80,3 +83,6 @@ IQCC_LIST_AUTH_METHODS_SUFFIX = "/auth_methods"
|
|
80
83
|
IQCC_LIST_AUTH_METHODS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_METHODS_SUFFIX
|
81
84
|
IQCC_LIST_AUTH_TARGETS_SUFFIX = "/auth_targets"
|
82
85
|
IQCC_LIST_AUTH_TARGETS_FULL_PATH = IQCC_PREFIX + IQCC_LIST_AUTH_TARGETS_SUFFIX
|
86
|
+
|
87
|
+
USER_BUDGETS_SUFFIX = "/all"
|
88
|
+
USER_BUDGETS_FULL_PATH = USER_BUDGETS_PREFIX + USER_BUDGETS_SUFFIX
|
@@ -2,6 +2,7 @@ from collections.abc import Mapping
|
|
2
2
|
from enum import Enum
|
3
3
|
from typing import Any, Callable, Union, get_args
|
4
4
|
|
5
|
+
import sympy
|
5
6
|
from sympy import Eq, Expr, Piecewise, Symbol
|
6
7
|
|
7
8
|
from classiq.interface.exceptions import (
|
@@ -15,6 +16,9 @@ from classiq.interface.generator.expressions.expression_types import (
|
|
15
16
|
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
16
17
|
AnyClassicalValue,
|
17
18
|
)
|
19
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_array_proxy import (
|
20
|
+
ClassicalArrayProxy,
|
21
|
+
)
|
18
22
|
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
19
23
|
ClassicalProxy,
|
20
24
|
)
|
@@ -53,6 +57,8 @@ from classiq.model_expansions.sympy_conversion.arithmetics import (
|
|
53
57
|
BitwiseOr,
|
54
58
|
BitwiseXor,
|
55
59
|
LogicalXor,
|
60
|
+
LShift,
|
61
|
+
RShift,
|
56
62
|
)
|
57
63
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
58
64
|
MISSING_SLICE_VALUE_PLACEHOLDER,
|
@@ -60,11 +66,12 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
|
60
66
|
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
61
67
|
sympy_to_python,
|
62
68
|
)
|
63
|
-
from classiq.model_expansions.utils.sympy_utils import
|
64
|
-
|
65
|
-
|
69
|
+
from classiq.model_expansions.utils.sympy_utils import is_constant_subscript
|
70
|
+
from classiq.qmod.builtins.classical_functions import (
|
71
|
+
__all__ as qmod_classical_functions,
|
66
72
|
)
|
67
73
|
from classiq.qmod.model_state_container import QMODULE
|
74
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
68
75
|
|
69
76
|
|
70
77
|
def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
@@ -166,15 +173,14 @@ def get_field(
|
|
166
173
|
],
|
167
174
|
field: str,
|
168
175
|
) -> ExpressionValue:
|
169
|
-
if isinstance(proxy, AnyClassicalValue)
|
170
|
-
|
176
|
+
if isinstance(proxy, AnyClassicalValue) or (
|
177
|
+
isinstance(proxy, Symbol)
|
178
|
+
and not isinstance(proxy, QmodSizedProxy)
|
179
|
+
and not isinstance(proxy, ClassicalProxy)
|
180
|
+
):
|
181
|
+
return AnyClassicalValue(f"get_field({qmod_val_to_expr_str(proxy)}, '{field}')")
|
171
182
|
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
172
183
|
return getattr(proxy, field)
|
173
|
-
if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
|
174
|
-
raise ClassiqExpansionError(
|
175
|
-
f"Cannot evaluate '{proxy}.{field}': Variable {str(proxy)!r} is not "
|
176
|
-
f"initialized"
|
177
|
-
)
|
178
184
|
if isinstance(proxy, list):
|
179
185
|
if field != "len":
|
180
186
|
raise ClassiqExpansionError(
|
@@ -210,9 +216,10 @@ def get_type(struct_type: Symbol) -> TypeProxy:
|
|
210
216
|
|
211
217
|
|
212
218
|
def do_div(lhs: Any, rhs: Any) -> Any:
|
213
|
-
|
214
|
-
|
215
|
-
|
219
|
+
res = lhs / rhs
|
220
|
+
if isinstance(res, sympy.Expr):
|
221
|
+
res = res.evalf()
|
222
|
+
return res
|
216
223
|
|
217
224
|
|
218
225
|
_EXPRESSION_TYPES = get_args(ExpressionValue)
|
@@ -229,7 +236,9 @@ def _is_qmod_value(val: Any) -> bool:
|
|
229
236
|
|
230
237
|
|
231
238
|
def do_subscript(value: Any, index: Any) -> Any:
|
232
|
-
if not isinstance(value, list) or not isinstance(
|
239
|
+
if not isinstance(value, (list, ClassicalArrayProxy)) or not isinstance(
|
240
|
+
index, QmodQNumProxy
|
241
|
+
):
|
233
242
|
if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
|
234
243
|
raise ClassiqExpansionError(
|
235
244
|
f"Subscript {value}[{index}] is not supported. Supported subscripts "
|
@@ -244,22 +253,31 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
244
253
|
and not is_constant_subscript(index)
|
245
254
|
and _is_qmod_value(index)
|
246
255
|
):
|
247
|
-
return AnyClassicalValue(
|
256
|
+
return AnyClassicalValue(qmod_val_to_expr_str(value))[index]
|
248
257
|
return value[index]
|
249
258
|
if index.is_signed or index.fraction_digits > 0:
|
250
259
|
raise ClassiqExpansionError(
|
251
260
|
"Quantum numeric subscript must be an unsigned integer (is_signed=False, "
|
252
261
|
"fraction_digits=0)"
|
253
262
|
)
|
254
|
-
if
|
263
|
+
if isinstance(value, ClassicalArrayProxy):
|
264
|
+
length = value.length
|
265
|
+
else:
|
266
|
+
length = len(value)
|
267
|
+
if length != 2**index.size:
|
255
268
|
raise ClassiqExpansionError(
|
256
269
|
f"Quantum numeric subscript size mismatch: The quantum numeric has "
|
257
|
-
f"{index.size} qubits but the list size is {
|
270
|
+
f"{index.size} qubits but the list size is {length} != 2**{index.size}"
|
271
|
+
)
|
272
|
+
if isinstance(value, ClassicalArrayProxy):
|
273
|
+
return AnyClassicalValue(
|
274
|
+
f"do_subscript({qmod_val_to_expr_str(value)}, {qmod_val_to_expr_str(index)})"
|
275
|
+
)
|
276
|
+
else:
|
277
|
+
return Piecewise(
|
278
|
+
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
279
|
+
(value[-1], True),
|
258
280
|
)
|
259
|
-
return Piecewise(
|
260
|
-
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
261
|
-
(value[-1], True),
|
262
|
-
)
|
263
281
|
|
264
282
|
|
265
283
|
def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
@@ -270,9 +288,29 @@ def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
|
270
288
|
return do_subscript(value, slice(lower, upper))
|
271
289
|
|
272
290
|
|
291
|
+
def do_sum(val: Any) -> Any:
|
292
|
+
if isinstance(val, AnyClassicalValue):
|
293
|
+
return AnyClassicalValue(f"sum({val})")
|
294
|
+
return sum(val)
|
295
|
+
|
296
|
+
|
297
|
+
do_sum.__name__ = "sum"
|
298
|
+
|
299
|
+
|
300
|
+
def mod_inverse(a: Any, b: Any) -> Any:
|
301
|
+
if (
|
302
|
+
isinstance(a, AnyClassicalValue)
|
303
|
+
or (isinstance(a, sympy.Basic) and len(a.free_symbols) > 0)
|
304
|
+
or isinstance(b, AnyClassicalValue)
|
305
|
+
or (isinstance(b, sympy.Basic) and len(b.free_symbols) > 0)
|
306
|
+
):
|
307
|
+
return AnyClassicalValue(f"mod_inverse({a}, {b})")
|
308
|
+
return sympy.mod_inverse(a, b)
|
309
|
+
|
310
|
+
|
273
311
|
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
274
312
|
print,
|
275
|
-
|
313
|
+
do_sum,
|
276
314
|
struct_literal,
|
277
315
|
get_field,
|
278
316
|
get_type,
|
@@ -284,8 +322,29 @@ CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
|
284
322
|
BitwiseNot,
|
285
323
|
BitwiseOr,
|
286
324
|
LogicalXor,
|
325
|
+
RShift,
|
326
|
+
LShift,
|
327
|
+
mod_inverse,
|
328
|
+
]
|
329
|
+
|
330
|
+
|
331
|
+
def _symbolic_function(func: str) -> Callable:
|
332
|
+
def wrapper(*args: Any) -> AnyClassicalValue:
|
333
|
+
return AnyClassicalValue(
|
334
|
+
f"{func}({', '.join(map(qmod_val_to_expr_str, args))})"
|
335
|
+
)
|
336
|
+
|
337
|
+
wrapper.__name__ = func
|
338
|
+
return wrapper
|
339
|
+
|
340
|
+
|
341
|
+
QMOD_CLASSICAL_FUNCTIONS = [
|
342
|
+
_symbolic_function(func) for func in qmod_classical_functions
|
287
343
|
]
|
288
344
|
|
289
345
|
ATOMIC_EXPRESSION_FUNCTIONS = {
|
290
|
-
**{
|
346
|
+
**{
|
347
|
+
core_func.__name__: core_func
|
348
|
+
for core_func in CORE_LIB_FUNCTIONS_LIST + QMOD_CLASSICAL_FUNCTIONS
|
349
|
+
},
|
291
350
|
}
|
@@ -15,6 +15,7 @@ from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
15
15
|
from classiq.interface.generator.functions.port_declaration import (
|
16
16
|
PortDeclarationDirection,
|
17
17
|
)
|
18
|
+
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
18
19
|
from classiq.interface.model.classical_parameter_declaration import (
|
19
20
|
ClassicalParameterDeclaration,
|
20
21
|
)
|
@@ -132,6 +133,7 @@ class _CapturedHandle(_Captured):
|
|
132
133
|
name=self.mangled_name,
|
133
134
|
quantum_type=self.quantum_type,
|
134
135
|
direction=self.direction.dump(),
|
136
|
+
type_qualifier=TypeQualifier.Inferred, # TODO https://classiq.atlassian.net/browse/CLS-1830
|
135
137
|
)
|
136
138
|
|
137
139
|
def is_same_var(self, other: "_CapturedHandle") -> bool:
|
@@ -8,6 +8,16 @@ from typing import Any, Optional
|
|
8
8
|
from typing_extensions import Self
|
9
9
|
|
10
10
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
11
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
12
|
+
ClassicalProxy,
|
13
|
+
)
|
14
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_struct_proxy import (
|
15
|
+
ClassicalStructProxy,
|
16
|
+
)
|
17
|
+
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
18
|
+
get_proxy_type,
|
19
|
+
)
|
20
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
11
21
|
from classiq.interface.model.quantum_function_declaration import (
|
12
22
|
NamedParamsQuantumFunctionDeclaration,
|
13
23
|
PositionalArg,
|
@@ -34,6 +44,10 @@ class Closure:
|
|
34
44
|
positional_arg_declarations: Sequence[PositionalArg] = tuple()
|
35
45
|
captured_vars: CapturedVars = field(default_factory=CapturedVars)
|
36
46
|
|
47
|
+
@property
|
48
|
+
def parameters_dict(self) -> dict[str, PositionalArg]:
|
49
|
+
return nameables_to_dict(self.positional_arg_declarations)
|
50
|
+
|
37
51
|
|
38
52
|
@dataclass(frozen=True)
|
39
53
|
class GenerativeClosure(Closure):
|
@@ -139,6 +153,10 @@ def _evaluated_arg_to_str(arg: Any) -> str:
|
|
139
153
|
return _evaluated_one_operand_to_str(arg)
|
140
154
|
if isinstance(arg, list) and arg and isinstance(arg[0], FunctionClosure):
|
141
155
|
return _evaluated_operands_list_to_str(arg)
|
156
|
+
if isinstance(arg, ClassicalProxy):
|
157
|
+
if isinstance(arg, ClassicalStructProxy):
|
158
|
+
return repr(arg.struct_declaration)
|
159
|
+
return repr(get_proxy_type(arg))
|
142
160
|
return evaluated_classical_param_to_str(arg)
|
143
161
|
|
144
162
|
|
@@ -34,9 +34,10 @@ def add_information_from_output_arguments(
|
|
34
34
|
if parameter.direction != PortDeclarationDirection.Output:
|
35
35
|
continue
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
if parameter.quantum_type.is_evaluated:
|
38
|
+
copy_type_information(
|
39
|
+
parameter.quantum_type,
|
40
|
+
argument_as_quantum_symbol.quantum_type,
|
41
|
+
str(argument_as_quantum_symbol.handle),
|
42
|
+
)
|
42
43
|
return args
|