classiq 0.75.0__py3-none-any.whl → 0.77.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 +15 -7
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +11 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -7
- classiq/applications/qnn/gradients/quantum_gradient.py +3 -5
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -2
- classiq/applications/qnn/qlayer.py +14 -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 +16 -2
- 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 +45 -21
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +12 -11
- classiq/interface/generator/expressions/proxies/quantum/qmod_qarray_proxy.py +6 -15
- classiq/interface/generator/expressions/proxies/quantum/qmod_qscalar_proxy.py +22 -6
- classiq/interface/generator/expressions/proxies/quantum/qmod_sized_proxy.py +9 -4
- classiq/interface/generator/expressions/sympy_supported_expressions.py +1 -0
- classiq/interface/generator/functions/classical_type.py +6 -1
- classiq/interface/generator/functions/type_name.py +7 -2
- classiq/interface/generator/functions/type_qualifier.py +15 -0
- classiq/interface/generator/model/preferences/preferences.py +7 -0
- classiq/interface/generator/quantum_program.py +5 -19
- classiq/interface/helpers/backward_compatibility.py +9 -0
- classiq/interface/helpers/datastructures.py +6 -0
- classiq/interface/model/handle_binding.py +8 -0
- classiq/interface/model/model.py +3 -6
- classiq/interface/model/port_declaration.py +1 -2
- classiq/interface/model/quantum_function_call.py +31 -1
- classiq/interface/model/quantum_lambda_function.py +2 -1
- classiq/interface/model/quantum_statement.py +14 -1
- classiq/interface/server/routes.py +6 -0
- classiq/interface/source_reference.py +7 -2
- classiq/model_expansions/atomic_expression_functions_defs.py +62 -19
- classiq/model_expansions/capturing/captured_vars.py +18 -6
- classiq/model_expansions/closure.py +5 -0
- classiq/model_expansions/evaluators/arg_type_match.py +2 -2
- classiq/model_expansions/evaluators/argument_types.py +3 -3
- classiq/model_expansions/evaluators/classical_expression.py +9 -9
- classiq/model_expansions/evaluators/classical_type_inference.py +17 -6
- classiq/model_expansions/evaluators/parameter_types.py +45 -24
- classiq/model_expansions/expression_evaluator.py +21 -12
- classiq/model_expansions/function_builder.py +45 -0
- classiq/model_expansions/generative_functions.py +62 -35
- classiq/model_expansions/interpreters/base_interpreter.py +32 -7
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +9 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +17 -5
- classiq/model_expansions/quantum_operations/allocate.py +8 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +221 -20
- 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 +35 -18
- 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 -9
- classiq/model_expansions/quantum_operations/quantum_function_call.py +4 -3
- classiq/model_expansions/scope.py +63 -10
- 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 +45 -7
- classiq/model_expansions/utils/handles_collector.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +3 -3
- classiq/model_expansions/visitors/variable_references.py +45 -9
- classiq/open_library/functions/lookup_table.py +1 -1
- classiq/open_library/functions/state_preparation.py +1 -1
- 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/create_model_function.py +21 -3
- classiq/qmod/declaration_inferrer.py +19 -7
- classiq/qmod/generative.py +9 -1
- classiq/qmod/global_declarative_switch.py +19 -0
- classiq/qmod/native/expression_to_qmod.py +4 -0
- classiq/qmod/native/pretty_printer.py +12 -3
- classiq/qmod/pretty_print/pretty_printer.py +5 -1
- classiq/qmod/python_classical_type.py +4 -5
- classiq/qmod/qfunc.py +31 -23
- classiq/qmod/qmod_constant.py +15 -7
- classiq/qmod/qmod_variable.py +7 -1
- classiq/qmod/quantum_expandable.py +29 -1
- classiq/qmod/quantum_function.py +45 -25
- 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 +26 -0
- classiq/qmod/write_qmod.py +36 -10
- classiq/synthesis.py +24 -37
- classiq/visualization.py +35 -0
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/METADATA +1 -1
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/RECORD +101 -96
- {classiq-0.75.0.dist-info → classiq-0.77.0.dist-info}/WHEEL +0 -0
@@ -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
|
@@ -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:
|
@@ -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):
|
@@ -355,3 +355,11 @@ ConcreteHandleBinding = Union[
|
|
355
355
|
SubscriptHandleBinding.model_rebuild()
|
356
356
|
SlicedHandleBinding.model_rebuild()
|
357
357
|
FieldHandleBinding.model_rebuild()
|
358
|
+
|
359
|
+
|
360
|
+
class HandlesList(ASTNode):
|
361
|
+
handles: list["GeneralHandle"]
|
362
|
+
|
363
|
+
|
364
|
+
GeneralHandle = Union[ConcreteHandleBinding, HandlesList]
|
365
|
+
HandlesList.model_rebuild()
|
classiq/interface/model/model.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from collections import Counter
|
2
2
|
from collections.abc import Mapping
|
3
|
-
from typing import Any, Literal, NewType
|
3
|
+
from typing import Any, Literal, NewType
|
4
4
|
|
5
5
|
import pydantic
|
6
6
|
|
@@ -9,7 +9,6 @@ from classiq.interface.debug_info.debug_info import DebugInfoCollection
|
|
9
9
|
from classiq.interface.exceptions import ClassiqValueError
|
10
10
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
11
11
|
from classiq.interface.generator.constant import Constant
|
12
|
-
from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
|
13
12
|
from classiq.interface.generator.functions.port_declaration import (
|
14
13
|
PortDeclarationDirection,
|
15
14
|
)
|
@@ -103,9 +102,6 @@ class Model(VersionedModel, ASTNode):
|
|
103
102
|
functions_compilation_metadata: dict[str, CompilationMetadata] = pydantic.Field(
|
104
103
|
default_factory=dict
|
105
104
|
)
|
106
|
-
execution_parameters: Optional[dict[str, ConcreteClassicalType]] = pydantic.Field(
|
107
|
-
default=None, exclude=True
|
108
|
-
)
|
109
105
|
|
110
106
|
@property
|
111
107
|
def main_func(self) -> NativeFunctionDefinition:
|
@@ -184,11 +180,12 @@ class Model(VersionedModel, ASTNode):
|
|
184
180
|
)
|
185
181
|
return constants
|
186
182
|
|
187
|
-
def
|
183
|
+
def dump_no_metadata(self) -> dict[str, Any]:
|
188
184
|
return self.model_dump(
|
189
185
|
exclude={
|
190
186
|
"constraints",
|
191
187
|
"execution_preferences",
|
192
188
|
"preferences",
|
189
|
+
"functions_compilation_metadata",
|
193
190
|
},
|
194
191
|
)
|
@@ -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")
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections.abc import Iterable, Mapping, Sequence
|
2
|
+
from itertools import chain
|
2
3
|
from typing import (
|
3
4
|
Literal,
|
4
5
|
Optional,
|
@@ -15,7 +16,9 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
15
16
|
)
|
16
17
|
from classiq.interface.model.handle_binding import (
|
17
18
|
ConcreteHandleBinding,
|
19
|
+
GeneralHandle,
|
18
20
|
HandleBinding,
|
21
|
+
HandlesList,
|
19
22
|
)
|
20
23
|
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
21
24
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -31,6 +34,7 @@ ArgValue = Union[
|
|
31
34
|
Expression,
|
32
35
|
QuantumOperand,
|
33
36
|
ConcreteHandleBinding,
|
37
|
+
HandlesList,
|
34
38
|
]
|
35
39
|
|
36
40
|
|
@@ -146,6 +150,26 @@ class QuantumFunctionCall(QuantumOperation):
|
|
146
150
|
)
|
147
151
|
]
|
148
152
|
|
153
|
+
@property
|
154
|
+
def handles_with_directions(
|
155
|
+
self,
|
156
|
+
) -> Iterable[tuple[HandleBinding, PortDeclarationDirection]]:
|
157
|
+
return [(handle, param.direction) for handle, param in self.handles_with_params]
|
158
|
+
|
159
|
+
@property
|
160
|
+
def handles_with_params(
|
161
|
+
self,
|
162
|
+
) -> Iterable[tuple[HandleBinding, AnonPortDeclaration]]:
|
163
|
+
return [
|
164
|
+
(handle, param)
|
165
|
+
for arg, param in zip(
|
166
|
+
self.positional_args, self.func_decl.positional_arg_declarations
|
167
|
+
)
|
168
|
+
if isinstance(param, AnonPortDeclaration)
|
169
|
+
and isinstance(arg, (HandleBinding, HandlesList))
|
170
|
+
for handle in _get_handles(arg)
|
171
|
+
]
|
172
|
+
|
149
173
|
@property
|
150
174
|
def params(self) -> list[Expression]:
|
151
175
|
return [
|
@@ -161,7 +185,7 @@ class QuantumFunctionCall(QuantumOperation):
|
|
161
185
|
return [
|
162
186
|
param
|
163
187
|
for param in self.positional_args
|
164
|
-
if not isinstance(param, (Expression, HandleBinding))
|
188
|
+
if not isinstance(param, (Expression, HandleBinding, HandlesList))
|
165
189
|
]
|
166
190
|
|
167
191
|
@property
|
@@ -224,3 +248,9 @@ class QuantumFunctionCall(QuantumOperation):
|
|
224
248
|
f" for parameter {param_name}" if len(self.positional_args) > 1 else ""
|
225
249
|
)
|
226
250
|
return f"as an argument{param_text} of function {self.func_name!r}"
|
251
|
+
|
252
|
+
|
253
|
+
def _get_handles(var: GeneralHandle) -> Iterable[HandleBinding]:
|
254
|
+
if isinstance(var, HandleBinding):
|
255
|
+
return [var]
|
256
|
+
return chain.from_iterable(_get_handles(item) for item in var.handles)
|
@@ -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
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from collections.abc import Mapping, Sequence
|
1
|
+
from collections.abc import Iterable, Mapping, Sequence
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from typing import Any, Callable, Optional
|
4
4
|
from uuid import UUID, uuid4
|
@@ -9,6 +9,9 @@ from typing_extensions import Self
|
|
9
9
|
|
10
10
|
from classiq.interface.ast_node import ASTNode
|
11
11
|
from classiq.interface.generator.expressions.expression import Expression
|
12
|
+
from classiq.interface.generator.functions.port_declaration import (
|
13
|
+
PortDeclarationDirection,
|
14
|
+
)
|
12
15
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
13
16
|
from classiq.interface.model.handle_binding import (
|
14
17
|
ConcreteHandleBinding,
|
@@ -90,6 +93,16 @@ class QuantumOperation(QuantumStatement):
|
|
90
93
|
def readable_outputs(self) -> Sequence[HandleMetadata]:
|
91
94
|
return [HandleMetadata(handle=handle) for handle in self.outputs]
|
92
95
|
|
96
|
+
@property
|
97
|
+
def handles_with_directions(
|
98
|
+
self,
|
99
|
+
) -> Iterable[tuple[HandleBinding, PortDeclarationDirection]]:
|
100
|
+
return (
|
101
|
+
[(handle, PortDeclarationDirection.Input) for handle in self.inputs]
|
102
|
+
+ [(handle, PortDeclarationDirection.Output) for handle in self.outputs]
|
103
|
+
+ [(handle, PortDeclarationDirection.Inout) for handle in self.inouts]
|
104
|
+
)
|
105
|
+
|
93
106
|
def set_generative_block(self, block_name: str, py_callable: Callable) -> None:
|
94
107
|
self._generative_blocks[block_name] = py_callable
|
95
108
|
|
@@ -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
|
@@ -33,11 +33,16 @@ class SourceReference(HashablePydanticBaseModel):
|
|
33
33
|
file_name: Optional[str] = pydantic.Field(default=None)
|
34
34
|
|
35
35
|
def __str__(self) -> str:
|
36
|
-
|
36
|
+
return f"{self.file_string()}{self.ref_inside_file()}"
|
37
|
+
|
38
|
+
def file_string(self) -> str:
|
39
|
+
return _prepare_file_string(self.file_name) if self.file_name else ""
|
40
|
+
|
41
|
+
def ref_inside_file(self) -> str:
|
37
42
|
start_character_string = (
|
38
43
|
f" character {self.start_column + 1}" if self.start_column > 0 else ""
|
39
44
|
)
|
40
|
-
return f"
|
45
|
+
return f"line {self.start_line + 1}{start_character_string}"
|
41
46
|
|
42
47
|
|
43
48
|
class SourceReferencedError(pydantic.BaseModel):
|
@@ -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 (
|
@@ -56,6 +57,8 @@ from classiq.model_expansions.sympy_conversion.arithmetics import (
|
|
56
57
|
BitwiseOr,
|
57
58
|
BitwiseXor,
|
58
59
|
LogicalXor,
|
60
|
+
LShift,
|
61
|
+
RShift,
|
59
62
|
)
|
60
63
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
61
64
|
MISSING_SLICE_VALUE_PLACEHOLDER,
|
@@ -63,11 +66,12 @@ from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
|
63
66
|
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
64
67
|
sympy_to_python,
|
65
68
|
)
|
66
|
-
from classiq.model_expansions.utils.sympy_utils import
|
67
|
-
|
68
|
-
|
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,
|
69
72
|
)
|
70
73
|
from classiq.qmod.model_state_container import QMODULE
|
74
|
+
from classiq.qmod.utilities import qmod_val_to_expr_str
|
71
75
|
|
72
76
|
|
73
77
|
def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
@@ -169,19 +173,14 @@ def get_field(
|
|
169
173
|
],
|
170
174
|
field: str,
|
171
175
|
) -> ExpressionValue:
|
172
|
-
if isinstance(proxy, AnyClassicalValue)
|
173
|
-
return AnyClassicalValue(f"({proxy}).{field}")
|
174
|
-
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
175
|
-
return getattr(proxy, field)
|
176
|
-
if (
|
176
|
+
if isinstance(proxy, AnyClassicalValue) or (
|
177
177
|
isinstance(proxy, Symbol)
|
178
178
|
and not isinstance(proxy, QmodSizedProxy)
|
179
179
|
and not isinstance(proxy, ClassicalProxy)
|
180
180
|
):
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
)
|
181
|
+
return AnyClassicalValue(f"get_field({qmod_val_to_expr_str(proxy)}, '{field}')")
|
182
|
+
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
183
|
+
return getattr(proxy, field)
|
185
184
|
if isinstance(proxy, list):
|
186
185
|
if field != "len":
|
187
186
|
raise ClassiqExpansionError(
|
@@ -217,9 +216,10 @@ def get_type(struct_type: Symbol) -> TypeProxy:
|
|
217
216
|
|
218
217
|
|
219
218
|
def do_div(lhs: Any, rhs: Any) -> Any:
|
220
|
-
|
221
|
-
|
222
|
-
|
219
|
+
res = lhs / rhs
|
220
|
+
if isinstance(res, sympy.Expr):
|
221
|
+
res = res.evalf()
|
222
|
+
return res
|
223
223
|
|
224
224
|
|
225
225
|
_EXPRESSION_TYPES = get_args(ExpressionValue)
|
@@ -253,7 +253,7 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
253
253
|
and not is_constant_subscript(index)
|
254
254
|
and _is_qmod_value(index)
|
255
255
|
):
|
256
|
-
return AnyClassicalValue(
|
256
|
+
return AnyClassicalValue(qmod_val_to_expr_str(value))[index]
|
257
257
|
return value[index]
|
258
258
|
if index.is_signed or index.fraction_digits > 0:
|
259
259
|
raise ClassiqExpansionError(
|
@@ -270,7 +270,9 @@ def do_subscript(value: Any, index: Any) -> Any:
|
|
270
270
|
f"{index.size} qubits but the list size is {length} != 2**{index.size}"
|
271
271
|
)
|
272
272
|
if isinstance(value, ClassicalArrayProxy):
|
273
|
-
return AnyClassicalValue(
|
273
|
+
return AnyClassicalValue(
|
274
|
+
f"do_subscript({qmod_val_to_expr_str(value)}, {qmod_val_to_expr_str(index)})"
|
275
|
+
)
|
274
276
|
else:
|
275
277
|
return Piecewise(
|
276
278
|
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
@@ -286,9 +288,29 @@ def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
|
286
288
|
return do_subscript(value, slice(lower, upper))
|
287
289
|
|
288
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
|
+
|
289
311
|
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
290
312
|
print,
|
291
|
-
|
313
|
+
do_sum,
|
292
314
|
struct_literal,
|
293
315
|
get_field,
|
294
316
|
get_type,
|
@@ -300,8 +322,29 @@ CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
|
300
322
|
BitwiseNot,
|
301
323
|
BitwiseOr,
|
302
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
|
303
343
|
]
|
304
344
|
|
305
345
|
ATOMIC_EXPRESSION_FUNCTIONS = {
|
306
|
-
**{
|
346
|
+
**{
|
347
|
+
core_func.__name__: core_func
|
348
|
+
for core_func in CORE_LIB_FUNCTIONS_LIST + QMOD_CLASSICAL_FUNCTIONS
|
349
|
+
},
|
307
350
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import dataclasses
|
2
2
|
from collections.abc import Sequence
|
3
3
|
from dataclasses import dataclass, field
|
4
|
-
from typing import TYPE_CHECKING, Callable
|
4
|
+
from typing import TYPE_CHECKING, Callable, Union, cast
|
5
5
|
|
6
6
|
from typing_extensions import Self
|
7
7
|
|
@@ -15,11 +15,13 @@ 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
|
)
|
21
22
|
from classiq.interface.model.handle_binding import (
|
22
23
|
HandleBinding,
|
24
|
+
HandlesList,
|
23
25
|
NestedHandleBinding,
|
24
26
|
SlicedHandleBinding,
|
25
27
|
)
|
@@ -132,6 +134,7 @@ class _CapturedHandle(_Captured):
|
|
132
134
|
name=self.mangled_name,
|
133
135
|
quantum_type=self.quantum_type,
|
134
136
|
direction=self.direction.dump(),
|
137
|
+
type_qualifier=TypeQualifier.Inferred, # TODO https://classiq.atlassian.net/browse/CLS-1830
|
135
138
|
)
|
136
139
|
|
137
140
|
def is_same_var(self, other: "_CapturedHandle") -> bool:
|
@@ -252,7 +255,7 @@ class CapturedVars:
|
|
252
255
|
|
253
256
|
def _conjugate_direction(
|
254
257
|
self,
|
255
|
-
source_direction: PortDirection
|
258
|
+
source_direction: Union[PortDirection, bool],
|
256
259
|
target_direction: PortDirection,
|
257
260
|
var_name: str,
|
258
261
|
) -> PortDirection:
|
@@ -651,12 +654,9 @@ def validate_args_are_not_propagated(
|
|
651
654
|
for handle in captured_vars
|
652
655
|
if isinstance(handle, HandleBinding)
|
653
656
|
}
|
654
|
-
arg_handles = {
|
655
|
-
demangle_handle(arg) for arg in args if isinstance(arg, HandleBinding)
|
656
|
-
}
|
657
657
|
violating_handles = [
|
658
658
|
f"{str(arg_handle)!r}"
|
659
|
-
for arg_handle in
|
659
|
+
for arg_handle in _get_all_handles(args)
|
660
660
|
if any(
|
661
661
|
arg_handle.overlaps(captured_handle) for captured_handle in captured_handles
|
662
662
|
)
|
@@ -667,6 +667,18 @@ def validate_args_are_not_propagated(
|
|
667
667
|
)
|
668
668
|
|
669
669
|
|
670
|
+
def _get_all_handles(args: Sequence[ArgValue]) -> set[HandleBinding]:
|
671
|
+
arg_handles: set[HandleBinding] = set()
|
672
|
+
for arg in args:
|
673
|
+
if isinstance(arg, HandleBinding):
|
674
|
+
arg_handles.add(demangle_handle(arg))
|
675
|
+
elif isinstance(arg, HandlesList):
|
676
|
+
arg_handles |= set(
|
677
|
+
map(demangle_handle, cast(list[HandleBinding], arg.handles))
|
678
|
+
)
|
679
|
+
return arg_handles
|
680
|
+
|
681
|
+
|
670
682
|
def validate_captured_directions(
|
671
683
|
captured_vars: CapturedVars, report_outin: bool = True
|
672
684
|
) -> None:
|
@@ -17,6 +17,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_struct_
|
|
17
17
|
from classiq.interface.generator.expressions.proxies.classical.utils import (
|
18
18
|
get_proxy_type,
|
19
19
|
)
|
20
|
+
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
20
21
|
from classiq.interface.model.quantum_function_declaration import (
|
21
22
|
NamedParamsQuantumFunctionDeclaration,
|
22
23
|
PositionalArg,
|
@@ -43,6 +44,10 @@ class Closure:
|
|
43
44
|
positional_arg_declarations: Sequence[PositionalArg] = tuple()
|
44
45
|
captured_vars: CapturedVars = field(default_factory=CapturedVars)
|
45
46
|
|
47
|
+
@property
|
48
|
+
def parameters_dict(self) -> dict[str, PositionalArg]:
|
49
|
+
return nameables_to_dict(self.positional_arg_declarations)
|
50
|
+
|
46
51
|
|
47
52
|
@dataclass(frozen=True)
|
48
53
|
class GenerativeClosure(Closure):
|
@@ -27,7 +27,7 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
27
27
|
|
28
28
|
from classiq.model_expansions.closure import FunctionClosure
|
29
29
|
from classiq.model_expansions.evaluators.type_type_match import check_signature_match
|
30
|
-
from classiq.model_expansions.scope import Evaluated,
|
30
|
+
from classiq.model_expansions.scope import Evaluated, QuantumVariable
|
31
31
|
from classiq.qmod.model_state_container import QMODULE
|
32
32
|
from classiq.qmod.qmod_parameter import CInt, get_qmod_type
|
33
33
|
|
@@ -77,7 +77,7 @@ def check_arg_type_match(
|
|
77
77
|
|
78
78
|
|
79
79
|
def _check_qvar_type_match(argument: Any, error_message: str) -> None:
|
80
|
-
if not isinstance(argument,
|
80
|
+
if not isinstance(argument, QuantumVariable):
|
81
81
|
raise ClassiqExpansionError(error_message)
|
82
82
|
|
83
83
|
|
@@ -7,7 +7,7 @@ from classiq.interface.model.port_declaration import AnonPortDeclaration
|
|
7
7
|
from classiq.interface.model.quantum_function_declaration import AnonPositionalArg
|
8
8
|
|
9
9
|
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
10
|
-
from classiq.model_expansions.scope import Evaluated,
|
10
|
+
from classiq.model_expansions.scope import Evaluated, QuantumVariable
|
11
11
|
|
12
12
|
|
13
13
|
def add_information_from_output_arguments(
|
@@ -29,7 +29,7 @@ def add_information_from_output_arguments(
|
|
29
29
|
if not isinstance(parameter, AnonPortDeclaration):
|
30
30
|
continue
|
31
31
|
|
32
|
-
argument_as_quantum_symbol = argument.as_type(
|
32
|
+
argument_as_quantum_symbol = argument.as_type(QuantumVariable)
|
33
33
|
|
34
34
|
if parameter.direction != PortDeclarationDirection.Output:
|
35
35
|
continue
|
@@ -38,6 +38,6 @@ def add_information_from_output_arguments(
|
|
38
38
|
copy_type_information(
|
39
39
|
parameter.quantum_type,
|
40
40
|
argument_as_quantum_symbol.quantum_type,
|
41
|
-
str(argument_as_quantum_symbol
|
41
|
+
str(argument_as_quantum_symbol),
|
42
42
|
)
|
43
43
|
return args
|
@@ -5,6 +5,9 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
5
5
|
)
|
6
6
|
from classiq.interface.generator.expressions.expression import Expression
|
7
7
|
from classiq.interface.generator.expressions.expression_types import ExpressionValue
|
8
|
+
from classiq.interface.generator.expressions.proxies.classical.any_classical_value import (
|
9
|
+
AnyClassicalValue,
|
10
|
+
)
|
8
11
|
from classiq.interface.model.handle_binding import HandleBinding
|
9
12
|
|
10
13
|
from classiq.model_expansions.expression_evaluator import evaluate
|
@@ -19,18 +22,15 @@ def evaluate_classical_expression(expr: Expression, scope: Scope) -> Evaluated:
|
|
19
22
|
if isinstance(evaluated.value, get_args(ExpressionValue))
|
20
23
|
} | {
|
21
24
|
name: EvaluatedExpression(
|
22
|
-
value=
|
25
|
+
value=(
|
26
|
+
evaluated.value.quantum_type.get_proxy(HandleBinding(name=name))
|
27
|
+
if evaluated.value.quantum_type.is_evaluated
|
28
|
+
else AnyClassicalValue(name)
|
29
|
+
)
|
23
30
|
)
|
24
31
|
for name, evaluated in all_symbols
|
25
32
|
if isinstance(evaluated.value, QuantumSymbol)
|
26
|
-
and evaluated.value.quantum_type.is_evaluated
|
27
|
-
}
|
28
|
-
uninitialized_locals = {
|
29
|
-
name
|
30
|
-
for name, evaluated in all_symbols
|
31
|
-
if isinstance(evaluated.value, QuantumSymbol)
|
32
|
-
and not evaluated.value.quantum_type.is_evaluated
|
33
33
|
}
|
34
34
|
|
35
|
-
ret = evaluate(expr, locals_dict
|
35
|
+
ret = evaluate(expr, locals_dict)
|
36
36
|
return Evaluated(value=ret.value)
|