classiq 0.67.0__py3-none-any.whl → 0.69.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 +9 -9
- classiq/_internals/async_utils.py +1 -1
- classiq/_internals/authentication/password_manager.py +1 -1
- classiq/_internals/client.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/execution_session.py +7 -3
- classiq/execution/jobs.py +2 -5
- classiq/executor.py +7 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +2 -3
- classiq/interface/chemistry/operator.py +12 -8
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +26 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +96 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/functions/classical_type.py +12 -1
- classiq/interface/generator/generated_circuit_data.py +64 -23
- classiq/interface/generator/quantum_program.py +18 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +45 -3
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/classical_if.py +2 -2
- classiq/interface/model/control.py +2 -2
- classiq/interface/model/invert.py +2 -2
- classiq/interface/model/power.py +2 -2
- classiq/interface/model/quantum_function_call.py +4 -0
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/model/repeat.py +2 -2
- classiq/interface/model/statement_block.py +1 -1
- classiq/interface/model/within_apply_operation.py +2 -2
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/generative_functions.py +4 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +78 -18
- classiq/model_expansions/quantum_operations/allocate.py +3 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
- classiq/model_expansions/quantum_operations/bind.py +2 -1
- classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/quantum_operations/classicalif.py +5 -4
- classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
- classiq/model_expansions/quantum_operations/emitter.py +16 -2
- classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -1
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -1
- classiq/model_expansions/scope_initialization.py +5 -19
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
- classiq/open_library/functions/__init__.py +1 -2
- classiq/open_library/functions/amplitude_amplification.py +11 -12
- classiq/open_library/functions/discrete_sine_cosine_transform.py +17 -14
- classiq/open_library/functions/grover.py +7 -11
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/modular_exponentiation.py +17 -33
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/state_preparation.py +16 -17
- classiq/open_library/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +12 -4
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/chemistry.py +6 -38
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_expandable.py +30 -6
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/types_validation.py +1 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/utilities.py +31 -2
- classiq/qmod/write_qmod.py +10 -7
- classiq/synthesis.py +25 -9
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/METADATA +1 -1
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/RECORD +85 -81
- classiq/interface/execution/jobs.py +0 -31
- classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
- {classiq-0.67.0.dist-info → classiq-0.69.0.dist-info}/WHEEL +0 -0
@@ -2,15 +2,24 @@ import logging
|
|
2
2
|
from typing import Literal, Optional, Union
|
3
3
|
|
4
4
|
import pydantic
|
5
|
-
from pydantic import ConfigDict
|
5
|
+
from pydantic import ConfigDict, Field
|
6
6
|
from typing_extensions import TypeAlias
|
7
7
|
|
8
|
+
from classiq.interface.debug_info.back_ref_util import is_allocate_or_free_by_backref
|
8
9
|
from classiq.interface.enum_utils import StrEnum
|
9
10
|
from classiq.interface.generator.control_state import ControlState
|
10
11
|
from classiq.interface.generator.register_role import RegisterRole
|
11
12
|
from classiq.interface.generator.synthesis_metadata.synthesis_execution_data import (
|
12
13
|
ExecutionData,
|
13
14
|
)
|
15
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
16
|
+
QuantumExpressionOperation,
|
17
|
+
)
|
18
|
+
from classiq.interface.model.statement_block import (
|
19
|
+
ConcreteQuantumStatement,
|
20
|
+
QuantumFunctionCall,
|
21
|
+
StatementBlock,
|
22
|
+
)
|
14
23
|
|
15
24
|
from classiq.model_expansions.capturing.mangling_utils import (
|
16
25
|
demangle_capture_name,
|
@@ -22,7 +31,7 @@ _logger = logging.getLogger(__name__)
|
|
22
31
|
ParameterName = str
|
23
32
|
IOQubitMapping: TypeAlias = dict[str, tuple[int, ...]]
|
24
33
|
|
25
|
-
CLASSIQ_HIERARCHY_SEPARATOR: Literal["
|
34
|
+
CLASSIQ_HIERARCHY_SEPARATOR: Literal["__"] = "__"
|
26
35
|
|
27
36
|
VISUALIZATION_HIDE_LIST = [
|
28
37
|
"apply_to_all",
|
@@ -119,34 +128,75 @@ class OperationLevel(StrEnum):
|
|
119
128
|
UNKNOWN = "UNKNOWN"
|
120
129
|
|
121
130
|
|
122
|
-
class
|
123
|
-
|
124
|
-
|
131
|
+
class StatementType(StrEnum):
|
132
|
+
CONTROL = "control"
|
133
|
+
POWER = "power"
|
134
|
+
INVERT = "invert"
|
135
|
+
WITHIN_APPLY = "within_apply"
|
136
|
+
ASSIGNMENT = "assignment"
|
137
|
+
REPEAT = "repeat"
|
125
138
|
|
126
139
|
|
127
140
|
class FunctionDebugInfoInterface(pydantic.BaseModel):
|
128
|
-
generated_function: Optional[GeneratedFunction] =
|
141
|
+
generated_function: Optional[GeneratedFunction] = Field(default=None)
|
129
142
|
children: list["FunctionDebugInfoInterface"]
|
130
143
|
relative_qubits: tuple[int, ...]
|
131
|
-
absolute_qubits: Optional[tuple[int, ...]] =
|
132
|
-
is_basis_gate: Optional[bool] =
|
133
|
-
is_inverse: bool =
|
134
|
-
is_allocate_or_free: bool =
|
135
|
-
level: OperationLevel =
|
136
|
-
|
137
|
-
|
138
|
-
|
144
|
+
absolute_qubits: Optional[tuple[int, ...]] = Field(default=None)
|
145
|
+
is_basis_gate: Optional[bool] = Field(default=None)
|
146
|
+
is_inverse: bool = Field(default=False)
|
147
|
+
is_allocate_or_free: bool = Field(default=False)
|
148
|
+
level: OperationLevel = Field(default=OperationLevel.UNKNOWN)
|
149
|
+
port_to_passed_variable_map: dict[str, str] = Field(default={})
|
150
|
+
release_by_inverse: bool = Field(default=False)
|
151
|
+
back_refs: StatementBlock = Field(default_factory=list)
|
139
152
|
|
140
153
|
model_config = ConfigDict(extra="allow")
|
141
154
|
# Temporary field to store the override debug info for parallel old/new visualization
|
142
155
|
override_debug_info: Optional["FunctionDebugInfoInterface"] = None
|
143
156
|
|
157
|
+
@property
|
158
|
+
def is_allocate_or_free_(self) -> bool:
|
159
|
+
"""
|
160
|
+
temporary measure to handle the fact that in the current release we do not have
|
161
|
+
the backref, and therefore fallback to the old field of is_allocate_or_free
|
162
|
+
"""
|
163
|
+
return (
|
164
|
+
is_allocate_or_free_by_backref(self.back_refs)
|
165
|
+
if bool(self.back_refs)
|
166
|
+
else self.is_allocate_or_free
|
167
|
+
)
|
168
|
+
|
144
169
|
@property
|
145
170
|
def name(self) -> str:
|
146
171
|
if self.generated_function is None:
|
147
172
|
return ""
|
148
173
|
return self.generated_function.name
|
149
174
|
|
175
|
+
@property
|
176
|
+
def first_back_ref(self) -> Optional[ConcreteQuantumStatement]:
|
177
|
+
return self.back_refs[0] if self.back_refs else None
|
178
|
+
|
179
|
+
@property
|
180
|
+
def level_(self) -> OperationLevel:
|
181
|
+
# Temp fix for currently "supported" statements
|
182
|
+
if self.name in {StatementType.CONTROL, StatementType.POWER}:
|
183
|
+
return OperationLevel.QMOD_STATEMENT
|
184
|
+
|
185
|
+
back_ref = self.first_back_ref
|
186
|
+
if back_ref is None:
|
187
|
+
# This is the expected behavior for the case where there's not back ref.
|
188
|
+
# We will use it once we can rely on the existence of the back ref in
|
189
|
+
# all expected cases (non-engine calls)
|
190
|
+
# return OperationLevel.ENGINE_FUNCTION_CALL
|
191
|
+
return self.level
|
192
|
+
if isinstance(back_ref, QuantumFunctionCall):
|
193
|
+
return OperationLevel.QMOD_FUNCTION_CALL
|
194
|
+
# Temp "fix" for assignment statements until we have a way to fully
|
195
|
+
# distinguish them and to properly display them
|
196
|
+
if isinstance(back_ref, QuantumExpressionOperation):
|
197
|
+
return OperationLevel.ENGINE_FUNCTION_CALL
|
198
|
+
return OperationLevel.QMOD_STATEMENT
|
199
|
+
|
150
200
|
@property
|
151
201
|
def registers(self) -> list[GeneratedRegister]:
|
152
202
|
if self.generated_function is None:
|
@@ -165,15 +215,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
165
215
|
return list()
|
166
216
|
return self.generated_function.control_states
|
167
217
|
|
168
|
-
@staticmethod
|
169
|
-
def create_parameters_from_dict(
|
170
|
-
parameters: dict[str, str]
|
171
|
-
) -> list[OperationParameter]:
|
172
|
-
return [
|
173
|
-
OperationParameter(label=key, value=value)
|
174
|
-
for key, value in parameters.items()
|
175
|
-
]
|
176
|
-
|
177
218
|
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
178
219
|
if self.absolute_qubits is None:
|
179
220
|
return self
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import uuid
|
2
2
|
from datetime import datetime, timezone
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Optional, Union
|
4
|
+
from typing import Any, Optional, Union
|
5
5
|
|
6
6
|
import pydantic
|
7
|
+
from pydantic import model_validator
|
8
|
+
from pydantic_core.core_schema import ValidationInfo
|
7
9
|
from typing_extensions import TypeAlias
|
8
10
|
|
9
11
|
from classiq.interface.exceptions import (
|
@@ -36,6 +38,8 @@ from classiq.interface.ide.visual_model import CircuitMetrics
|
|
36
38
|
RegisterName: TypeAlias = str
|
37
39
|
InitialConditions: TypeAlias = dict[RegisterName, int]
|
38
40
|
|
41
|
+
OMIT_DEBUG_INFO_FLAG = "omit_debug_info"
|
42
|
+
|
39
43
|
|
40
44
|
class TranspiledCircuitData(CircuitCodeInterface):
|
41
45
|
depth: int
|
@@ -71,6 +75,19 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
|
|
71
75
|
program_id: str = pydantic.Field(default_factory=get_uuid_as_str)
|
72
76
|
execution_primitives_input: Optional[PrimitivesInput] = pydantic.Field(default=None)
|
73
77
|
|
78
|
+
@model_validator(mode="before")
|
79
|
+
@classmethod
|
80
|
+
def remove_debug_info(
|
81
|
+
cls, data: dict[str, Any], info: ValidationInfo
|
82
|
+
) -> dict[str, Any]:
|
83
|
+
if (
|
84
|
+
isinstance(data, dict)
|
85
|
+
and info.context is not None
|
86
|
+
and info.context.get(OMIT_DEBUG_INFO_FLAG, False)
|
87
|
+
):
|
88
|
+
data.pop("debug_info", None)
|
89
|
+
return data
|
90
|
+
|
74
91
|
def _hardware_agnostic_program_code(self) -> CodeAndSyntax:
|
75
92
|
circuit_code = self.program_circuit.get_code_by_priority()
|
76
93
|
if circuit_code is not None:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from collections import Counter
|
2
2
|
from enum import Enum, EnumMeta, IntEnum
|
3
|
+
from typing import Any, Callable
|
3
4
|
|
4
5
|
import pydantic
|
5
6
|
|
@@ -7,6 +8,33 @@ from classiq.interface.ast_node import HashableASTNode
|
|
7
8
|
from classiq.interface.exceptions import ClassiqValueError
|
8
9
|
|
9
10
|
|
11
|
+
def rebuild_dynamic_enum(name: str, members: dict[str, int]) -> type[IntEnum]:
|
12
|
+
"""
|
13
|
+
Rebuilds the dynamic enum from its name and members.
|
14
|
+
Returns a new enum type.
|
15
|
+
"""
|
16
|
+
new_enum = IntEnum(name, members) # type: ignore[misc]
|
17
|
+
setattr(new_enum, "__members_data__", members) # noqa: B010
|
18
|
+
setattr(new_enum, "__reduce_ex__", dynamic_enum_reduce_ex) # noqa: B010
|
19
|
+
return new_enum
|
20
|
+
|
21
|
+
|
22
|
+
def dynamic_enum_reduce_ex(
|
23
|
+
obj: Any, protocol: int
|
24
|
+
) -> tuple[Callable[..., type[IntEnum]], tuple[str, dict[str, int]]]:
|
25
|
+
"""
|
26
|
+
Custom __reduce_ex__ for dynamic enums.
|
27
|
+
This function will be used when pickling an enum type or one of its members.
|
28
|
+
"""
|
29
|
+
# Get the enum type and its member data.
|
30
|
+
enum_type = type(obj)
|
31
|
+
members = getattr(enum_type, "__members_data__", None)
|
32
|
+
if members is None:
|
33
|
+
raise ValueError("Dynamic enum is missing __members_data__ attribute")
|
34
|
+
# Return the callable and arguments needed to rebuild the enum type.
|
35
|
+
return rebuild_dynamic_enum, (enum_type.__name__, members)
|
36
|
+
|
37
|
+
|
10
38
|
class EnumDeclaration(HashableASTNode):
|
11
39
|
name: str
|
12
40
|
|
@@ -39,12 +67,15 @@ class EnumDeclaration(HashableASTNode):
|
|
39
67
|
|
40
68
|
return members
|
41
69
|
|
42
|
-
def create_enum(self) -> IntEnum:
|
43
|
-
|
70
|
+
def create_enum(self) -> type[IntEnum]:
|
71
|
+
dynamic_enum = IntEnum(self.name, self.members) # type: ignore[misc]
|
72
|
+
setattr(dynamic_enum, "__members_data__", self.members) # noqa: B010
|
73
|
+
setattr(dynamic_enum, "__reduce_ex__", dynamic_enum_reduce_ex) # noqa: B010
|
74
|
+
return dynamic_enum
|
44
75
|
|
45
76
|
|
46
77
|
def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
47
|
-
members
|
78
|
+
members = _get_members(enum_type)
|
48
79
|
return EnumDeclaration(
|
49
80
|
name=enum_type.__name__,
|
50
81
|
members={
|
@@ -52,3 +83,14 @@ def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
|
52
83
|
for member in sorted(members, key=lambda member: member.value)
|
53
84
|
},
|
54
85
|
)
|
86
|
+
|
87
|
+
|
88
|
+
def _get_members(enum_type: EnumMeta) -> list[Enum]:
|
89
|
+
members: list[Enum] = list(enum_type)
|
90
|
+
for member in members:
|
91
|
+
if not isinstance(member.value, int):
|
92
|
+
raise ClassiqValueError(
|
93
|
+
f"Member {member.name!r} of enum {enum_type.__name__!r} has a "
|
94
|
+
f"non-integer value {member.value!r}"
|
95
|
+
)
|
96
|
+
return members
|
@@ -7,7 +7,6 @@ from pydantic import ConfigDict
|
|
7
7
|
from classiq.interface.enum_utils import StrEnum
|
8
8
|
from classiq.interface.generator.generated_circuit_data import (
|
9
9
|
OperationLevel,
|
10
|
-
OperationParameter,
|
11
10
|
)
|
12
11
|
from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
|
13
12
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
@@ -114,7 +113,6 @@ class Operation(pydantic.BaseModel):
|
|
114
113
|
control_qubits: tuple[int, ...] = pydantic.Field(default_factory=tuple)
|
115
114
|
auxiliary_qubits: tuple[int, ...]
|
116
115
|
target_qubits: tuple[int, ...]
|
117
|
-
parameters: list[OperationParameter] = pydantic.Field(default_factory=list)
|
118
116
|
operation_level: OperationLevel
|
119
117
|
operation_type: OperationType = pydantic.Field(
|
120
118
|
description="Identifies unique operations that are visualized differently"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Literal
|
2
2
|
|
3
|
-
from classiq.interface.ast_node import ASTNodeType,
|
3
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
4
4
|
from classiq.interface.generator.expressions.expression import Expression
|
5
5
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
6
6
|
|
@@ -16,4 +16,4 @@ class ClassicalIf(QuantumOperation):
|
|
16
16
|
else_: "StatementBlock"
|
17
17
|
|
18
18
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
19
|
-
return
|
19
|
+
return reset_lists(self, ["then", "else_"])
|
@@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Literal, Optional
|
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
-
from classiq.interface.ast_node import ASTNodeType,
|
5
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
6
6
|
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
7
7
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
8
8
|
QuantumExpressionOperation,
|
@@ -46,4 +46,4 @@ class Control(QuantumExpressionOperation):
|
|
46
46
|
)
|
47
47
|
|
48
48
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
49
|
-
return
|
49
|
+
return reset_lists(self, ["body", "else_block"])
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Literal
|
2
2
|
|
3
|
-
from classiq.interface.ast_node import ASTNodeType,
|
3
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
4
4
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
5
5
|
|
6
6
|
if TYPE_CHECKING:
|
@@ -13,4 +13,4 @@ class Invert(QuantumOperation):
|
|
13
13
|
body: "StatementBlock"
|
14
14
|
|
15
15
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
16
|
-
return
|
16
|
+
return reset_lists(self, ["body"])
|
classiq/interface/model/power.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Literal
|
2
2
|
|
3
|
-
from classiq.interface.ast_node import ASTNodeType,
|
3
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
4
4
|
from classiq.interface.generator.expressions.expression import Expression
|
5
5
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
6
6
|
|
@@ -15,4 +15,4 @@ class Power(QuantumOperation):
|
|
15
15
|
body: "StatementBlock"
|
16
16
|
|
17
17
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
18
|
-
return
|
18
|
+
return reset_lists(self, ["body"])
|
@@ -7,6 +7,7 @@ from typing import (
|
|
7
7
|
|
8
8
|
import pydantic
|
9
9
|
|
10
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
10
11
|
from classiq.interface.exceptions import ClassiqError, ClassiqValueError
|
11
12
|
from classiq.interface.generator.expressions.expression import Expression
|
12
13
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -45,6 +46,9 @@ class QuantumFunctionCall(QuantumOperation):
|
|
45
46
|
default=None
|
46
47
|
)
|
47
48
|
|
49
|
+
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
50
|
+
return reset_lists(self, ["positional_args"])
|
51
|
+
|
48
52
|
@property
|
49
53
|
def func_decl(self) -> QuantumFunctionDeclaration:
|
50
54
|
if self._func_decl is None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Literal
|
2
2
|
|
3
|
-
from classiq.interface.ast_node import ASTNodeType,
|
3
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
4
4
|
from classiq.interface.generator.expressions.expression import Expression
|
5
5
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
6
6
|
|
@@ -16,4 +16,4 @@ class Repeat(QuantumOperation):
|
|
16
16
|
body: "StatementBlock"
|
17
17
|
|
18
18
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
19
|
-
return
|
19
|
+
return reset_lists(self, ["body"])
|
@@ -27,8 +27,8 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
27
27
|
|
28
28
|
ConcreteQuantumStatement = Annotated[
|
29
29
|
Union[
|
30
|
-
Allocate,
|
31
30
|
QuantumFunctionCall,
|
31
|
+
Allocate,
|
32
32
|
ArithmeticOperation,
|
33
33
|
AmplitudeLoadingOperation,
|
34
34
|
VariableDeclarationStatement,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Literal
|
2
2
|
|
3
|
-
from classiq.interface.ast_node import ASTNodeType,
|
3
|
+
from classiq.interface.ast_node import ASTNodeType, reset_lists
|
4
4
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
5
5
|
|
6
6
|
if TYPE_CHECKING:
|
@@ -14,4 +14,4 @@ class WithinApply(QuantumOperation):
|
|
14
14
|
action: "StatementBlock"
|
15
15
|
|
16
16
|
def _as_back_ref(self: ASTNodeType) -> ASTNodeType:
|
17
|
-
return
|
17
|
+
return reset_lists(self, ["compute", "action"])
|
@@ -7,9 +7,6 @@ PROVIDERS_PREFIX = "/providers"
|
|
7
7
|
|
8
8
|
IQCC_PREFIX = PROVIDERS_PREFIX + "/iqcc"
|
9
9
|
|
10
|
-
EXECUTION_NON_VERSIONED_PREFIX = "/execution/v1"
|
11
|
-
SYNTHESIS_NON_VERSIONED_PREFIX = "/synthesis/v1"
|
12
|
-
|
13
10
|
ANALYZER_CIRCUIT_PAGE = "circuit"
|
14
11
|
DEFAULT_IDE_FE_APP = "https://platform.classiq.io/"
|
15
12
|
|
@@ -58,9 +55,6 @@ TASKS_GENERATE_FULL_PATH = TASKS_GENERATE_SUFFIX
|
|
58
55
|
|
59
56
|
EXECUTION_JOBS_SUFFIX = "/jobs"
|
60
57
|
EXECUTION_JOBS_FULL_PATH = EXECUTION_PREFIX + EXECUTION_JOBS_SUFFIX
|
61
|
-
EXECUTION_JOBS_NON_VERSIONED_FULL_PATH = (
|
62
|
-
EXECUTION_NON_VERSIONED_PREFIX + EXECUTION_JOBS_SUFFIX
|
63
|
-
)
|
64
58
|
|
65
59
|
ANALYZER_FULL_PATH = ANALYZER_PREFIX + TASKS_SUFFIX
|
66
60
|
ANALYZER_RB_FULL_PATH = ANALYZER_PREFIX + TASK_RB_SUFFIX
|
@@ -148,7 +148,8 @@ def emit_generative_statements(
|
|
148
148
|
with _InterpreterExpandable(interpreter):
|
149
149
|
set_frontend_interpreter(interpreter)
|
150
150
|
for block_name, generative_function in operation.generative_blocks.items():
|
151
|
-
with
|
152
|
-
block_name
|
153
|
-
|
151
|
+
with (
|
152
|
+
interpreter._builder.block_context(block_name),
|
153
|
+
generative_mode_context(True),
|
154
|
+
):
|
154
155
|
generative_function._py_callable(*python_qmod_args)
|
@@ -21,8 +21,11 @@ from classiq.interface.model.model import Model
|
|
21
21
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
22
22
|
from classiq.interface.model.phase_operation import PhaseOperation
|
23
23
|
from classiq.interface.model.power import Power
|
24
|
-
from classiq.interface.model.quantum_expressions.
|
25
|
-
|
24
|
+
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
25
|
+
AmplitudeLoadingOperation,
|
26
|
+
)
|
27
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
28
|
+
ArithmeticOperation,
|
26
29
|
)
|
27
30
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
28
31
|
from classiq.interface.model.quantum_function_declaration import (
|
@@ -55,7 +58,17 @@ from classiq.model_expansions.quantum_operations import (
|
|
55
58
|
VariableDeclarationStatementEmitter,
|
56
59
|
)
|
57
60
|
from classiq.model_expansions.quantum_operations.allocate import AllocateEmitter
|
58
|
-
from classiq.model_expansions.quantum_operations.
|
61
|
+
from classiq.model_expansions.quantum_operations.assignment_result_processor import (
|
62
|
+
AssignmentResultProcessor,
|
63
|
+
)
|
64
|
+
from classiq.model_expansions.quantum_operations.block_evaluator import BlockEvaluator
|
65
|
+
from classiq.model_expansions.quantum_operations.composite_emitter import (
|
66
|
+
CompositeEmitter,
|
67
|
+
)
|
68
|
+
from classiq.model_expansions.quantum_operations.expression_evaluator import (
|
69
|
+
ExpressionEvaluator,
|
70
|
+
)
|
71
|
+
from classiq.model_expansions.quantum_operations.handle_evaluator import HandleEvaluator
|
59
72
|
from classiq.model_expansions.scope import Evaluated, Scope
|
60
73
|
from classiq.model_expansions.scope_initialization import (
|
61
74
|
add_constants_to_scope,
|
@@ -134,15 +147,39 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
134
147
|
BindEmitter(self).emit(bind)
|
135
148
|
|
136
149
|
@emit.register
|
137
|
-
def
|
138
|
-
|
139
|
-
self,
|
150
|
+
def emit_amplitude_loading_operation(self, op: AmplitudeLoadingOperation) -> None:
|
151
|
+
CompositeEmitter[AmplitudeLoadingOperation](
|
152
|
+
self,
|
153
|
+
[
|
154
|
+
HandleEvaluator(self, "result_var"),
|
155
|
+
ExpressionEvaluator(self, "expression"),
|
156
|
+
AssignmentResultProcessor(self),
|
157
|
+
],
|
158
|
+
).emit(op)
|
159
|
+
|
160
|
+
@emit.register
|
161
|
+
def _emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
162
|
+
self.emit_arithmetic_operation(op)
|
163
|
+
|
164
|
+
def emit_arithmetic_operation(self, op: ArithmeticOperation) -> None:
|
165
|
+
CompositeEmitter[ArithmeticOperation](
|
166
|
+
self,
|
167
|
+
[
|
168
|
+
HandleEvaluator(self, "result_var"),
|
169
|
+
ExpressionEvaluator(self, "expression"),
|
170
|
+
AssignmentResultProcessor(self),
|
171
|
+
],
|
140
172
|
).emit(op)
|
141
173
|
|
142
174
|
@emit.register
|
143
175
|
def emit_inplace_binary_operation(self, op: InplaceBinaryOperation) -> None:
|
144
|
-
|
145
|
-
self,
|
176
|
+
CompositeEmitter[InplaceBinaryOperation](
|
177
|
+
self,
|
178
|
+
[
|
179
|
+
HandleEvaluator(self, "target"),
|
180
|
+
HandleEvaluator(self, "value"),
|
181
|
+
ExpressionEvaluator(self, "value"),
|
182
|
+
],
|
146
183
|
).emit(op)
|
147
184
|
|
148
185
|
@emit.register
|
@@ -157,37 +194,60 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
157
194
|
|
158
195
|
@emit.register
|
159
196
|
def emit_within_apply(self, within_apply: WithinApply) -> None:
|
160
|
-
|
197
|
+
BlockEvaluator(
|
161
198
|
self,
|
162
199
|
WITHIN_APPLY_NAME,
|
163
|
-
|
200
|
+
"within",
|
201
|
+
"apply",
|
202
|
+
"compute",
|
203
|
+
"action",
|
164
204
|
).emit(within_apply)
|
165
205
|
|
166
206
|
@emit.register
|
167
207
|
def emit_invert(self, invert: Invert) -> None:
|
168
|
-
|
208
|
+
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
169
209
|
|
170
210
|
@emit.register
|
171
211
|
def emit_repeat(self, repeat: Repeat) -> None:
|
172
212
|
RepeatEmitter(self).emit(repeat)
|
173
213
|
|
174
214
|
@emit.register
|
215
|
+
def _emit_control(self, control: Control) -> None:
|
216
|
+
self.emit_control(control)
|
217
|
+
|
175
218
|
def emit_control(self, control: Control) -> None:
|
176
|
-
|
219
|
+
CompositeEmitter[Control](
|
177
220
|
self,
|
178
|
-
|
179
|
-
|
221
|
+
[
|
222
|
+
ExpressionEvaluator(self, "expression"),
|
223
|
+
BlockEvaluator(
|
224
|
+
self,
|
225
|
+
CONTROL_OPERATOR_NAME,
|
226
|
+
"body",
|
227
|
+
"else_block",
|
228
|
+
),
|
229
|
+
],
|
180
230
|
).emit(control)
|
181
231
|
|
182
232
|
@emit.register
|
183
233
|
def emit_power(self, power: Power) -> None:
|
184
|
-
|
185
|
-
|
186
|
-
|
234
|
+
CompositeEmitter[Power](
|
235
|
+
self,
|
236
|
+
[
|
237
|
+
ExpressionEvaluator(self, "power"),
|
238
|
+
BlockEvaluator(self, CONTROL_OPERATOR_NAME, "body"),
|
239
|
+
],
|
240
|
+
).emit(power)
|
187
241
|
|
188
242
|
@emit.register
|
189
243
|
def emit_phase(self, phase: PhaseOperation) -> None:
|
190
|
-
|
244
|
+
CompositeEmitter[PhaseOperation](
|
245
|
+
self,
|
246
|
+
[
|
247
|
+
ExpressionEvaluator(self, "expression"),
|
248
|
+
ExpressionEvaluator(self, "theta"),
|
249
|
+
],
|
250
|
+
).emit(phase)
|
191
251
|
|
192
252
|
def _expand_body(self, operation: Closure) -> None:
|
193
253
|
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
@@ -12,7 +12,7 @@ from classiq.model_expansions.scope import QuantumSymbol
|
|
12
12
|
|
13
13
|
|
14
14
|
class AllocateEmitter(Emitter[Allocate]):
|
15
|
-
def emit(self, allocate: Allocate, /) ->
|
15
|
+
def emit(self, allocate: Allocate, /) -> bool:
|
16
16
|
target: QuantumSymbol = self._interpreter.evaluate(allocate.target).as_type(
|
17
17
|
QuantumSymbol
|
18
18
|
)
|
@@ -32,6 +32,7 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
32
32
|
)
|
33
33
|
self._register_debug_info(allocate)
|
34
34
|
self.emit_statement(allocate)
|
35
|
+
return True
|
35
36
|
|
36
37
|
def _get_var_size(self, target: QuantumSymbol, size: Expression | None) -> int:
|
37
38
|
if size is None:
|
@@ -70,4 +71,5 @@ class AllocateEmitter(Emitter[Allocate]):
|
|
70
71
|
level=OperationLevel.QMOD_STATEMENT,
|
71
72
|
is_allocate_or_free=True,
|
72
73
|
port_to_passed_variable_map={"ARG": str(allocate.target)},
|
74
|
+
node=allocate._as_back_ref(),
|
73
75
|
)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
2
|
+
from classiq.interface.generator.functions.port_declaration import (
|
3
|
+
PortDeclarationDirection,
|
4
|
+
)
|
5
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
6
|
+
ArithmeticOperation,
|
7
|
+
ArithmeticOperationKind,
|
8
|
+
)
|
9
|
+
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
10
|
+
QuantumAssignmentOperation,
|
11
|
+
)
|
12
|
+
|
13
|
+
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
14
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
15
|
+
from classiq.model_expansions.scope import QuantumSymbol
|
16
|
+
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
17
|
+
|
18
|
+
|
19
|
+
class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
20
|
+
def emit(self, op: QuantumAssignmentOperation, /) -> bool:
|
21
|
+
if (
|
22
|
+
isinstance(op, ArithmeticOperation)
|
23
|
+
and op.operation_kind == ArithmeticOperationKind.Assignment
|
24
|
+
):
|
25
|
+
direction = PortDeclarationDirection.Output
|
26
|
+
self._update_result_type(op)
|
27
|
+
else:
|
28
|
+
direction = PortDeclarationDirection.Inout
|
29
|
+
self._capture_handle(op.result_var, direction)
|
30
|
+
return False
|
31
|
+
|
32
|
+
def _update_result_type(self, op: ArithmeticOperation) -> None:
|
33
|
+
expr = self._evaluate_expression(op.expression)
|
34
|
+
symbols = self._get_symbols_in_expression(expr)
|
35
|
+
expr_str = rename_variables(
|
36
|
+
expr.expr,
|
37
|
+
{str(symbol.handle): symbol.handle.identifier for symbol in symbols}
|
38
|
+
| {symbol.handle.qmod_expr: symbol.handle.identifier for symbol in symbols},
|
39
|
+
)
|
40
|
+
for symbol in symbols:
|
41
|
+
expr_str = expr_str.replace(
|
42
|
+
symbol.handle.qmod_expr, symbol.handle.identifier
|
43
|
+
)
|
44
|
+
result_type = compute_arithmetic_result_type(
|
45
|
+
expr_str,
|
46
|
+
{symbol.handle.identifier: symbol.quantum_type for symbol in symbols},
|
47
|
+
self._machine_precision,
|
48
|
+
)
|
49
|
+
result_symbol = self._interpreter.evaluate(op.result_var).as_type(QuantumSymbol)
|
50
|
+
copy_type_information(
|
51
|
+
result_type, result_symbol.quantum_type, str(op.result_var)
|
52
|
+
)
|