classiq 0.68.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 +4 -8
- 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/jobs.py +2 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +2 -3
- classiq/interface/chemistry/operator.py +11 -7
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +11 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- 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 +63 -24
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +12 -1
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/generative_functions.py +4 -3
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/scope_initialization.py +5 -19
- classiq/open_library/functions/amplitude_amplification.py +3 -7
- classiq/open_library/functions/discrete_sine_cosine_transform.py +4 -4
- classiq/open_library/functions/grover.py +2 -2
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/modular_exponentiation.py +10 -20
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/utility_functions.py +2 -2
- 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/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_function.py +3 -2
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/utilities.py +29 -1
- classiq/synthesis.py +9 -6
- {classiq-0.68.0.dist-info → classiq-0.69.0.dist-info}/METADATA +1 -1
- {classiq-0.68.0.dist-info → classiq-0.69.0.dist-info}/RECORD +46 -46
- classiq/interface/execution/jobs.py +0 -31
- {classiq-0.68.0.dist-info → classiq-0.69.0.dist-info}/WHEEL +0 -0
@@ -22,10 +22,6 @@ from classiq.interface.execution.iqcc import (
|
|
22
22
|
IQCCProbeAuthData,
|
23
23
|
IQCCProbeAuthResponse,
|
24
24
|
)
|
25
|
-
from classiq.interface.execution.jobs import (
|
26
|
-
ExecutionJobDetailsV1,
|
27
|
-
ExecutionJobsQueryResultsV1,
|
28
|
-
)
|
29
25
|
from classiq.interface.execution.primitives import PrimitivesInput
|
30
26
|
from classiq.interface.executor import execution_request
|
31
27
|
from classiq.interface.generator import quantum_program as generator_result
|
@@ -218,7 +214,7 @@ class ApiWrapper:
|
|
218
214
|
job_id: JobID,
|
219
215
|
name: str,
|
220
216
|
http_client: Optional[httpx.AsyncClient] = None,
|
221
|
-
) ->
|
217
|
+
) -> execution_request.ExecutionJobDetails:
|
222
218
|
data = await cls._call_task(
|
223
219
|
http_method=HTTPMethod.PATCH,
|
224
220
|
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}",
|
@@ -227,7 +223,7 @@ class ApiWrapper:
|
|
227
223
|
},
|
228
224
|
http_client=http_client,
|
229
225
|
)
|
230
|
-
return
|
226
|
+
return execution_request.ExecutionJobDetails.model_validate(data)
|
231
227
|
|
232
228
|
@classmethod
|
233
229
|
async def call_cancel_execution_job(
|
@@ -248,7 +244,7 @@ class ApiWrapper:
|
|
248
244
|
offset: int,
|
249
245
|
limit: int,
|
250
246
|
http_client: Optional[httpx.AsyncClient] = None,
|
251
|
-
) ->
|
247
|
+
) -> execution_request.ExecutionJobsQueryResults:
|
252
248
|
data = await cls._call_task(
|
253
249
|
http_method=HTTPMethod.GET,
|
254
250
|
url=f"{routes.EXECUTION_JOBS_FULL_PATH}",
|
@@ -258,7 +254,7 @@ class ApiWrapper:
|
|
258
254
|
},
|
259
255
|
http_client=http_client,
|
260
256
|
)
|
261
|
-
return
|
257
|
+
return execution_request.ExecutionJobsQueryResults.model_validate(data)
|
262
258
|
|
263
259
|
@classmethod
|
264
260
|
async def call_analysis_task(
|
@@ -24,7 +24,6 @@ from classiq.open_library.functions.utility_functions import (
|
|
24
24
|
from classiq.qmod.builtins.functions import RX
|
25
25
|
from classiq.qmod.builtins.operations import allocate, phase, repeat
|
26
26
|
from classiq.qmod.cparam import CReal
|
27
|
-
from classiq.qmod.create_model_function import create_model
|
28
27
|
from classiq.qmod.qfunc import qfunc
|
29
28
|
from classiq.qmod.qmod_parameter import CArray
|
30
29
|
from classiq.qmod.qmod_variable import Output, QVar
|
@@ -75,17 +74,15 @@ class CombinatorialProblem:
|
|
75
74
|
hadamard_transform(v)
|
76
75
|
repeat(
|
77
76
|
self.num_layers_,
|
78
|
-
lambda i: [
|
79
|
-
phase(
|
80
|
-
-self.cost_func(v), params[i]
|
81
|
-
), # type:ignore[func-returns-value]
|
77
|
+
lambda i: [
|
78
|
+
phase(-self.cost_func(v), params[i]),
|
82
79
|
apply_to_all(lambda q: RX(params[self.num_layers_ + i], q), v),
|
83
80
|
],
|
84
81
|
)
|
85
82
|
|
86
|
-
self.model_ = create_model(
|
87
|
-
|
88
|
-
) # type:ignore[assignment]
|
83
|
+
self.model_ = main.create_model(
|
84
|
+
constraints=constraints, preferences=preferences
|
85
|
+
).get_model() # type:ignore[assignment]
|
89
86
|
return self.model_ # type:ignore[return-value]
|
90
87
|
|
91
88
|
def get_qprog(self) -> SerializedQuantumProgram:
|
@@ -199,13 +196,13 @@ def execute_qaoa(
|
|
199
196
|
hadamard_transform(v)
|
200
197
|
repeat(
|
201
198
|
num_layers,
|
202
|
-
lambda i: [
|
203
|
-
phase(-cost_func(v), params[i]),
|
199
|
+
lambda i: [
|
200
|
+
phase(-cost_func(v), params[i]),
|
204
201
|
apply_to_all(lambda q: RX(params[num_layers + i], q), v),
|
205
202
|
],
|
206
203
|
)
|
207
204
|
|
208
|
-
model = create_model(
|
205
|
+
model = main.create_model().get_model()
|
209
206
|
qprog = synthesize(model)
|
210
207
|
|
211
208
|
with ExecutionSession(qprog, execution_preferences) as es:
|
@@ -71,7 +71,7 @@ class SimpleQuantumGradient(QuantumGradient):
|
|
71
71
|
post_process: PostProcessFunction,
|
72
72
|
epsilon: float = EPSILON,
|
73
73
|
*args: Any,
|
74
|
-
**kwargs: Any
|
74
|
+
**kwargs: Any,
|
75
75
|
) -> None:
|
76
76
|
super().__init__(quantum_program, execute, post_process)
|
77
77
|
self._epsilon = epsilon
|
@@ -94,7 +94,7 @@ def iter_inputs_weights(
|
|
94
94
|
post_process: PostProcessFunction,
|
95
95
|
*,
|
96
96
|
expected_shape: Shape = (),
|
97
|
-
requires_grad: Optional[bool] = None
|
97
|
+
requires_grad: Optional[bool] = None,
|
98
98
|
) -> Tensor:
|
99
99
|
if is_single_layer_circuit(weights):
|
100
100
|
iter_weights = torch.reshape(weights, (1, weights.shape[0]))
|
classiq/execution/jobs.py
CHANGED
@@ -9,7 +9,6 @@ from classiq.interface.exceptions import (
|
|
9
9
|
ClassiqAPIError,
|
10
10
|
ClassiqError,
|
11
11
|
)
|
12
|
-
from classiq.interface.execution.jobs import ExecutionJobDetailsV1
|
13
12
|
from classiq.interface.executor.execution_request import ExecutionJobDetails, JobCost
|
14
13
|
from classiq.interface.executor.execution_result import ResultsCollection
|
15
14
|
from classiq.interface.executor.result import (
|
@@ -26,8 +25,6 @@ from classiq._internals.async_utils import syncify_function
|
|
26
25
|
from classiq._internals.client import client
|
27
26
|
from classiq._internals.jobs import JobID, JobPoller
|
28
27
|
|
29
|
-
_JobDetails = Union[ExecutionJobDetails, ExecutionJobDetailsV1]
|
30
|
-
|
31
28
|
|
32
29
|
class ClassiqExecutionResultError(ClassiqError):
|
33
30
|
def __init__(self, primitive: str) -> None:
|
@@ -37,10 +34,10 @@ class ClassiqExecutionResultError(ClassiqError):
|
|
37
34
|
|
38
35
|
|
39
36
|
class ExecutionJob:
|
40
|
-
_details:
|
37
|
+
_details: ExecutionJobDetails
|
41
38
|
_result: Optional[ResultsCollection]
|
42
39
|
|
43
|
-
def __init__(self, details:
|
40
|
+
def __init__(self, details: ExecutionJobDetails) -> None:
|
44
41
|
self._details = details
|
45
42
|
self._result = None
|
46
43
|
|
classiq/interface/_version.py
CHANGED
@@ -172,15 +172,14 @@ class ClassiqNvidiaBackendNames(StrEnum):
|
|
172
172
|
|
173
173
|
SIMULATOR = "nvidia_simulator"
|
174
174
|
SIMULATOR_STATEVECTOR = "nvidia_simulator_statevector"
|
175
|
+
BRAKET_NVIDIA_SIMULATOR = "braket_nvidia_simulator"
|
176
|
+
BRAKET_NVIDIA_SIMULATOR_STATEVECTOR = "braket_nvidia_simulator_statevector"
|
175
177
|
|
176
178
|
|
177
179
|
class IntelBackendNames(StrEnum):
|
178
180
|
SIMULATOR = "intel_qsdk_simulator"
|
179
181
|
|
180
182
|
|
181
|
-
AllClassiqBackendNames = Union[ClassiqSimulatorBackendNames, ClassiqNvidiaBackendNames]
|
182
|
-
|
183
|
-
|
184
183
|
class GoogleNvidiaBackendNames(StrEnum):
|
185
184
|
"""
|
186
185
|
Google backend names which Classiq Supports running on.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from collections.abc import Collection
|
2
2
|
from functools import reduce
|
3
|
+
from itertools import combinations
|
3
4
|
from typing import (
|
4
5
|
Any,
|
5
6
|
Optional,
|
@@ -144,16 +145,19 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
144
145
|
@property
|
145
146
|
def is_commutative(self) -> bool:
|
146
147
|
return all(
|
147
|
-
self.
|
148
|
-
|
149
|
-
)
|
150
|
-
for qubit_num in range(self.num_qubits)
|
148
|
+
self._do_paulis_commute(first[0], second[0])
|
149
|
+
for first, second in combinations(self.pauli_list, 2)
|
151
150
|
)
|
152
151
|
|
153
152
|
@staticmethod
|
154
|
-
def
|
155
|
-
|
156
|
-
|
153
|
+
def _do_paulis_commute(
|
154
|
+
first: PydanticPauliMonomialStr, second: PydanticPauliMonomialStr
|
155
|
+
) -> bool:
|
156
|
+
commute = True
|
157
|
+
for c1, c2 in zip(first, second):
|
158
|
+
if (c1 != "I") and (c2 != "I") and (c1 != c2):
|
159
|
+
commute = not commute
|
160
|
+
return commute
|
157
161
|
|
158
162
|
@property
|
159
163
|
def num_qubits(self) -> int:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from classiq.interface.model.allocate import Allocate
|
2
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
3
|
+
from classiq.interface.model.statement_block import (
|
4
|
+
ConcreteQuantumStatement,
|
5
|
+
StatementBlock,
|
6
|
+
)
|
7
|
+
|
8
|
+
"""
|
9
|
+
This module contains helper functions to determine if a given quantum statement
|
10
|
+
is an allocation or free statement.
|
11
|
+
"""
|
12
|
+
|
13
|
+
|
14
|
+
def is_allocate_or_free(concrete_quantum_statement: ConcreteQuantumStatement) -> bool:
|
15
|
+
return isinstance(concrete_quantum_statement, Allocate) or (
|
16
|
+
isinstance(concrete_quantum_statement, QuantumFunctionCall)
|
17
|
+
and concrete_quantum_statement.function == "free"
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
def is_allocate_or_free_by_backref(back_refs: StatementBlock) -> bool:
|
22
|
+
return len(back_refs) > 0 and is_allocate_or_free(back_refs[0])
|
@@ -1,34 +1,23 @@
|
|
1
|
-
import json
|
2
1
|
from collections.abc import Mapping
|
3
|
-
from typing import
|
2
|
+
from typing import Optional, Union
|
4
3
|
from uuid import UUID
|
5
4
|
|
6
5
|
from pydantic import BaseModel, Field
|
7
6
|
|
8
|
-
from classiq.interface.
|
7
|
+
from classiq.interface.debug_info import back_ref_util
|
9
8
|
from classiq.interface.generator.generated_circuit_data import (
|
10
9
|
FunctionDebugInfoInterface,
|
11
10
|
OperationLevel,
|
11
|
+
StatementType,
|
12
12
|
)
|
13
13
|
from classiq.interface.model.statement_block import ConcreteQuantumStatement
|
14
14
|
|
15
15
|
ParameterValue = Union[float, int, str, None]
|
16
16
|
|
17
17
|
|
18
|
-
class StatementType(StrEnum):
|
19
|
-
CONTROL = "control"
|
20
|
-
POWER = "power"
|
21
|
-
INVERT = "invert"
|
22
|
-
WITHIN_APPLY = "within_apply"
|
23
|
-
ASSIGNMENT = "assignment"
|
24
|
-
REPEAT = "repeat"
|
25
|
-
|
26
|
-
|
27
18
|
class FunctionDebugInfo(BaseModel):
|
28
19
|
name: str
|
29
|
-
|
30
|
-
parameters: dict[str, str]
|
31
|
-
level: OperationLevel
|
20
|
+
level: OperationLevel = Field(default=OperationLevel.UNKNOWN)
|
32
21
|
statement_type: Union[StatementType, None] = None
|
33
22
|
is_allocate_or_free: bool = Field(default=False)
|
34
23
|
is_inverse: bool = Field(default=False)
|
@@ -36,12 +25,13 @@ class FunctionDebugInfo(BaseModel):
|
|
36
25
|
port_to_passed_variable_map: dict[str, str] = Field(default_factory=dict)
|
37
26
|
node: Optional[ConcreteQuantumStatement] = None
|
38
27
|
|
39
|
-
@
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
@property
|
29
|
+
def is_allocate_or_free_(self) -> bool:
|
30
|
+
return (
|
31
|
+
back_ref_util.is_allocate_or_free(self.node)
|
32
|
+
if self.node is not None
|
33
|
+
else self.is_allocate_or_free
|
34
|
+
)
|
45
35
|
|
46
36
|
def update_map_from_port_mapping(self, port_mapping: Mapping[str, str]) -> None:
|
47
37
|
new_port_to_passed_variable_map = self.port_to_passed_variable_map.copy()
|
@@ -59,7 +59,7 @@ def get_params(
|
|
59
59
|
machine_precision: int,
|
60
60
|
output_size: Optional[int] = None,
|
61
61
|
inplace_arg: Optional[str] = None,
|
62
|
-
target: Optional[RegisterArithmeticInfo] = None
|
62
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
63
63
|
) -> ArithmeticOperationParams:
|
64
64
|
operation = id2op(node_id)
|
65
65
|
if target and not operation_allows_target(operation):
|
@@ -334,7 +334,7 @@ def logical_and_params_getter(
|
|
334
334
|
machine_precision: int,
|
335
335
|
output_size: Optional[int] = None,
|
336
336
|
inplace_arg: Optional[str] = None,
|
337
|
-
target: Optional[RegisterArithmeticInfo] = None
|
337
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
338
338
|
) -> ArithmeticOperationParams:
|
339
339
|
return LogicalAnd(args=arg, target=target, machine_precision=machine_precision)
|
340
340
|
|
@@ -344,7 +344,7 @@ def logical_or_params_getter(
|
|
344
344
|
machine_precision: int,
|
345
345
|
output_size: Optional[int] = None,
|
346
346
|
inplace_arg: Optional[str] = None,
|
347
|
-
target: Optional[RegisterArithmeticInfo] = None
|
347
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
348
348
|
) -> ArithmeticOperationParams:
|
349
349
|
return LogicalOr(args=arg, target=target, machine_precision=machine_precision)
|
350
350
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Any, Literal, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
|
-
from pydantic import ConfigDict
|
4
|
+
from pydantic import ConfigDict, PrivateAttr
|
5
5
|
from sympy import IndexedBase, Symbol
|
6
|
+
from typing_extensions import Self
|
6
7
|
|
7
8
|
from classiq.interface.ast_node import HashableASTNode
|
8
9
|
from classiq.interface.generator.expressions.expression_types import RuntimeExpression
|
@@ -19,6 +20,8 @@ NamedSymbol = Union[IndexedBase, Symbol]
|
|
19
20
|
|
20
21
|
|
21
22
|
class ClassicalType(HashableASTNode):
|
23
|
+
_is_generative: bool = PrivateAttr(default=False)
|
24
|
+
|
22
25
|
def as_symbolic(self, name: str) -> Union[NamedSymbol, list[NamedSymbol]]:
|
23
26
|
return Symbol(name)
|
24
27
|
|
@@ -27,6 +30,14 @@ class ClassicalType(HashableASTNode):
|
|
27
30
|
def __str__(self) -> str:
|
28
31
|
return str(type(self).__name__)
|
29
32
|
|
33
|
+
def set_generative(self) -> Self:
|
34
|
+
self._is_generative = True
|
35
|
+
return self
|
36
|
+
|
37
|
+
@property
|
38
|
+
def is_generative(self) -> bool:
|
39
|
+
return self._is_generative
|
40
|
+
|
30
41
|
|
31
42
|
class Integer(ClassicalType):
|
32
43
|
kind: Literal["int"]
|
@@ -2,16 +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
|
)
|
14
|
-
from classiq.interface.model.
|
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
|
+
)
|
15
23
|
|
16
24
|
from classiq.model_expansions.capturing.mangling_utils import (
|
17
25
|
demangle_capture_name,
|
@@ -120,35 +128,75 @@ class OperationLevel(StrEnum):
|
|
120
128
|
UNKNOWN = "UNKNOWN"
|
121
129
|
|
122
130
|
|
123
|
-
class
|
124
|
-
|
125
|
-
|
131
|
+
class StatementType(StrEnum):
|
132
|
+
CONTROL = "control"
|
133
|
+
POWER = "power"
|
134
|
+
INVERT = "invert"
|
135
|
+
WITHIN_APPLY = "within_apply"
|
136
|
+
ASSIGNMENT = "assignment"
|
137
|
+
REPEAT = "repeat"
|
126
138
|
|
127
139
|
|
128
140
|
class FunctionDebugInfoInterface(pydantic.BaseModel):
|
129
|
-
generated_function: Optional[GeneratedFunction] =
|
141
|
+
generated_function: Optional[GeneratedFunction] = Field(default=None)
|
130
142
|
children: list["FunctionDebugInfoInterface"]
|
131
143
|
relative_qubits: tuple[int, ...]
|
132
|
-
absolute_qubits: Optional[tuple[int, ...]] =
|
133
|
-
is_basis_gate: Optional[bool] =
|
134
|
-
is_inverse: bool =
|
135
|
-
is_allocate_or_free: bool =
|
136
|
-
level: OperationLevel =
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
back_refs: StatementBlock = pydantic.Field(default_factory=list)
|
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)
|
141
152
|
|
142
153
|
model_config = ConfigDict(extra="allow")
|
143
154
|
# Temporary field to store the override debug info for parallel old/new visualization
|
144
155
|
override_debug_info: Optional["FunctionDebugInfoInterface"] = None
|
145
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
|
+
|
146
169
|
@property
|
147
170
|
def name(self) -> str:
|
148
171
|
if self.generated_function is None:
|
149
172
|
return ""
|
150
173
|
return self.generated_function.name
|
151
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
|
+
|
152
200
|
@property
|
153
201
|
def registers(self) -> list[GeneratedRegister]:
|
154
202
|
if self.generated_function is None:
|
@@ -167,15 +215,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
167
215
|
return list()
|
168
216
|
return self.generated_function.control_states
|
169
217
|
|
170
|
-
@staticmethod
|
171
|
-
def create_parameters_from_dict(
|
172
|
-
parameters: dict[str, str],
|
173
|
-
) -> list[OperationParameter]:
|
174
|
-
return [
|
175
|
-
OperationParameter(label=key, value=value)
|
176
|
-
for key, value in parameters.items()
|
177
|
-
]
|
178
|
-
|
179
218
|
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
180
219
|
if self.absolute_qubits is None:
|
181
220
|
return self
|
@@ -75,7 +75,7 @@ class EnumDeclaration(HashableASTNode):
|
|
75
75
|
|
76
76
|
|
77
77
|
def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
78
|
-
members
|
78
|
+
members = _get_members(enum_type)
|
79
79
|
return EnumDeclaration(
|
80
80
|
name=enum_type.__name__,
|
81
81
|
members={
|
@@ -83,3 +83,14 @@ def declaration_from_enum(enum_type: EnumMeta) -> EnumDeclaration:
|
|
83
83
|
for member in sorted(members, key=lambda member: member.value)
|
84
84
|
},
|
85
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"
|
@@ -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)
|
@@ -13,9 +13,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
13
13
|
PortDeclarationDirection,
|
14
14
|
)
|
15
15
|
from classiq.interface.generator.generated_circuit_data import OperationLevel
|
16
|
-
from classiq.interface.model.classical_parameter_declaration import (
|
17
|
-
ClassicalParameterDeclaration,
|
18
|
-
)
|
19
16
|
from classiq.interface.model.handle_binding import HandleBinding
|
20
17
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
21
18
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -162,11 +159,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
162
159
|
back_ref=self._get_back_ref(propagated_debug_info),
|
163
160
|
)
|
164
161
|
is_allocate_or_free = new_call.func_name == free.func_decl.name
|
165
|
-
parameters = {
|
166
|
-
arg_decl.name: FunctionDebugInfo.param_controller(value=evaluated_arg.value)
|
167
|
-
for arg_decl, evaluated_arg in zip(new_positional_arg_decls, evaluated_args)
|
168
|
-
if isinstance(arg_decl, ClassicalParameterDeclaration)
|
169
|
-
}
|
170
162
|
|
171
163
|
port_to_passed_variable_map = {
|
172
164
|
arg_decl.name: str(evaluated_arg.value.handle)
|
@@ -176,11 +168,6 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
176
168
|
self._debug_info[new_call.uuid] = FunctionDebugInfo(
|
177
169
|
name=new_call.func_name,
|
178
170
|
level=OperationLevel.QMOD_FUNCTION_CALL,
|
179
|
-
parameters=(
|
180
|
-
parameters
|
181
|
-
if propagated_debug_info is None or propagated_debug_info.name == ""
|
182
|
-
else propagated_debug_info.parameters
|
183
|
-
),
|
184
171
|
is_allocate_or_free=is_allocate_or_free,
|
185
172
|
port_to_passed_variable_map=port_to_passed_variable_map,
|
186
173
|
node=new_call._as_back_ref(),
|