classiq 0.47.0__py3-none-any.whl → 0.48.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/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +2 -7
- classiq/applications/grover/grover_model_constructor.py +2 -1
- classiq/execution/execution_session.py +40 -9
- classiq/execution/jobs.py +18 -6
- classiq/interface/_version.py +1 -1
- classiq/interface/execution/primitives.py +9 -1
- classiq/interface/executor/iqae_result.py +3 -3
- classiq/interface/executor/result.py +3 -1
- classiq/interface/generator/expressions/expression.py +8 -0
- classiq/interface/generator/functions/type_name.py +1 -3
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +17 -3
- classiq/interface/ide/visual_model.py +3 -4
- classiq/interface/model/bind_operation.py +0 -3
- classiq/interface/model/port_declaration.py +1 -12
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +34 -6
- classiq/interface/model/quantum_lambda_function.py +4 -1
- classiq/interface/model/quantum_statement.py +16 -1
- classiq/interface/model/quantum_variable_declaration.py +0 -22
- classiq/interface/server/global_versions.py +4 -4
- classiq/model_expansions/capturing/propagated_var_stack.py +5 -2
- classiq/model_expansions/closure.py +7 -2
- classiq/model_expansions/evaluators/quantum_type_utils.py +0 -7
- classiq/model_expansions/generative_functions.py +146 -28
- classiq/model_expansions/interpreter.py +11 -5
- classiq/model_expansions/quantum_operations/classicalif.py +27 -10
- classiq/model_expansions/quantum_operations/control.py +22 -15
- classiq/model_expansions/quantum_operations/emitter.py +60 -5
- classiq/model_expansions/quantum_operations/expression_operation.py +25 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +167 -95
- classiq/model_expansions/quantum_operations/invert.py +12 -6
- classiq/model_expansions/quantum_operations/phase.py +15 -3
- classiq/model_expansions/quantum_operations/power.py +9 -8
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +20 -5
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +32 -13
- classiq/model_expansions/quantum_operations/within_apply.py +19 -6
- classiq/model_expansions/scope.py +16 -5
- classiq/model_expansions/scope_initialization.py +11 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +23 -1
- classiq/model_expansions/visitors/variable_references.py +11 -7
- classiq/qmod/builtins/__init__.py +10 -0
- classiq/qmod/builtins/constants.py +10 -0
- classiq/qmod/builtins/functions/state_preparation.py +4 -1
- classiq/qmod/builtins/operations.py +43 -163
- classiq/qmod/create_model_function.py +1 -1
- classiq/qmod/generative.py +14 -5
- classiq/qmod/native/pretty_printer.py +9 -5
- classiq/qmod/pretty_print/pretty_printer.py +8 -4
- classiq/qmod/qmod_constant.py +28 -18
- classiq/qmod/qmod_variable.py +43 -23
- classiq/qmod/quantum_expandable.py +14 -1
- classiq/qmod/semantics/static_semantics_visitor.py +10 -0
- classiq/qmod/semantics/validation/constants_validation.py +16 -0
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/METADATA +3 -1
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/RECORD +56 -54
- {classiq-0.47.0.dist-info → classiq-0.48.0.dist-info}/WHEEL +0 -0
@@ -44,10 +44,5 @@ def _pauli_terms_to_qmod(hamiltonian: List[PauliTerm]) -> str:
|
|
44
44
|
return ", ".join(qmod_strings)
|
45
45
|
|
46
46
|
|
47
|
-
def
|
48
|
-
|
49
|
-
for struct in hamiltonian:
|
50
|
-
pauli_str = ", ".join([pauli_enum_to_str(p) for p in struct["pauli"]])
|
51
|
-
res.append(f'"pauli": [{pauli_str}], "coefficient": {struct["coefficient"]}')
|
52
|
-
|
53
|
-
return f"{{{', '.join(res)}}}"
|
47
|
+
def _pauli_dict_to_pauli_terms(hamiltonian: List[QmodPyStruct]) -> List[PauliTerm]:
|
48
|
+
return [PauliTerm(**struct) for struct in hamiltonian]
|
@@ -11,6 +11,7 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
|
|
11
11
|
from classiq.interface.model.port_declaration import PortDeclaration
|
12
12
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
13
13
|
ArithmeticOperation,
|
14
|
+
ArithmeticOperationKind,
|
14
15
|
)
|
15
16
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
16
17
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
@@ -110,7 +111,7 @@ def construct_grover_model(
|
|
110
111
|
ArithmeticOperation(
|
111
112
|
expression=Expression(expr=expression),
|
112
113
|
result_var=HandleBinding(name="res"),
|
113
|
-
|
114
|
+
operation_kind=ArithmeticOperationKind.InplaceXor,
|
114
115
|
),
|
115
116
|
],
|
116
117
|
),
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import json
|
2
2
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
|
3
3
|
|
4
|
+
from classiq.interface.chemistry.operator import PauliOperator, pauli_integers_to_str
|
4
5
|
from classiq.interface.exceptions import ClassiqValueError
|
5
|
-
from classiq.interface.execution.primitives import PrimitivesInput
|
6
|
+
from classiq.interface.execution.primitives import EstimateInput, PrimitivesInput
|
6
7
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
7
8
|
from classiq.interface.executor.result import (
|
8
9
|
EstimationResult,
|
@@ -12,7 +13,7 @@ from classiq.interface.generator.functions.qmod_python_interface import QmodPySt
|
|
12
13
|
from classiq.interface.generator.quantum_program import QuantumProgram
|
13
14
|
|
14
15
|
from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
|
15
|
-
|
16
|
+
_pauli_dict_to_pauli_terms,
|
16
17
|
_pauli_terms_to_qmod,
|
17
18
|
)
|
18
19
|
from classiq.execution.jobs import ExecutionJob
|
@@ -51,12 +52,26 @@ def _deserialize_program(program: Program) -> QuantumProgram:
|
|
51
52
|
)
|
52
53
|
|
53
54
|
|
55
|
+
def hamiltonian_to_pauli_terms(hamiltonian: Hamiltonian) -> List[PauliTerm]:
|
56
|
+
if isinstance(hamiltonian[0], PauliTerm):
|
57
|
+
return cast(List[PauliTerm], hamiltonian)
|
58
|
+
else:
|
59
|
+
return _pauli_dict_to_pauli_terms(cast(List[QmodPyStruct], hamiltonian))
|
60
|
+
|
61
|
+
|
54
62
|
def to_hamiltonian_str(hamiltonian: Hamiltonian) -> str:
|
55
|
-
return (
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
63
|
+
return _pauli_terms_to_qmod(hamiltonian_to_pauli_terms(hamiltonian))
|
64
|
+
|
65
|
+
|
66
|
+
def _hamiltonian_to_pauli_operator(hamiltonian: Hamiltonian) -> PauliOperator:
|
67
|
+
pauli_list = [
|
68
|
+
(
|
69
|
+
pauli_integers_to_str(elem.pauli), # type: ignore[arg-type]
|
70
|
+
elem.coefficient,
|
71
|
+
)
|
72
|
+
for elem in hamiltonian_to_pauli_terms(hamiltonian)
|
73
|
+
]
|
74
|
+
return PauliOperator(pauli_list=pauli_list)
|
60
75
|
|
61
76
|
|
62
77
|
def serialize(
|
@@ -196,7 +211,7 @@ class ExecutionSession:
|
|
196
211
|
SupportedPrimitives.SAMPLE, parameters=format_parameters(parameters)
|
197
212
|
)
|
198
213
|
self.program.execution_primitives_input = PrimitivesInput(
|
199
|
-
sample=[parameters] if parameters is not None else [{}]
|
214
|
+
sample=[parse_params(parameters)] if parameters is not None else [{}]
|
200
215
|
)
|
201
216
|
return execute(SerializedQuantumProgram(self.qprog))
|
202
217
|
|
@@ -229,7 +244,9 @@ class ExecutionSession:
|
|
229
244
|
self.program.model.classical_execution_code = generate_code_snippet(
|
230
245
|
SupportedPrimitives.BATCH_SAMPLE, parameters=format_parameters(parameters)
|
231
246
|
)
|
232
|
-
self.program.execution_primitives_input = PrimitivesInput(
|
247
|
+
self.program.execution_primitives_input = PrimitivesInput(
|
248
|
+
sample=[parse_params(params) for params in parameters]
|
249
|
+
)
|
233
250
|
return execute(SerializedQuantumProgram(self.qprog))
|
234
251
|
|
235
252
|
def estimate(
|
@@ -269,6 +286,14 @@ class ExecutionSession:
|
|
269
286
|
parameters=format_parameters(parameters),
|
270
287
|
hamiltonian=to_hamiltonian_str(hamiltonian),
|
271
288
|
)
|
289
|
+
self.program.execution_primitives_input = PrimitivesInput(
|
290
|
+
estimate=EstimateInput(
|
291
|
+
hamiltonian=_hamiltonian_to_pauli_operator(hamiltonian),
|
292
|
+
parameters=(
|
293
|
+
[parse_params(parameters)] if parameters is not None else [{}]
|
294
|
+
),
|
295
|
+
)
|
296
|
+
)
|
272
297
|
return execute(SerializedQuantumProgram(self.qprog))
|
273
298
|
|
274
299
|
def batch_estimate(
|
@@ -308,4 +333,10 @@ class ExecutionSession:
|
|
308
333
|
parameters=format_parameters(parameters),
|
309
334
|
hamiltonian=to_hamiltonian_str(hamiltonian),
|
310
335
|
)
|
336
|
+
self.program.execution_primitives_input = PrimitivesInput(
|
337
|
+
estimate=EstimateInput(
|
338
|
+
hamiltonian=_hamiltonian_to_pauli_operator(hamiltonian),
|
339
|
+
parameters=[parse_params(params) for params in parameters],
|
340
|
+
)
|
341
|
+
)
|
311
342
|
return execute(SerializedQuantumProgram(self.qprog))
|
classiq/execution/jobs.py
CHANGED
@@ -162,11 +162,16 @@ class ExecutionJob:
|
|
162
162
|
ClassiqAPIError: In case the job has failed.
|
163
163
|
"""
|
164
164
|
results = self.result()
|
165
|
-
if len(results) != 1
|
166
|
-
results[0].value, MultipleExecutionDetails
|
167
|
-
):
|
165
|
+
if len(results) != 1:
|
168
166
|
raise ClassiqExecutionResultError("batch_sample")
|
169
|
-
|
167
|
+
|
168
|
+
result = results[0].value
|
169
|
+
if isinstance(result, ExecutionDetails):
|
170
|
+
return [result]
|
171
|
+
if isinstance(result, MultipleExecutionDetails):
|
172
|
+
return result.details
|
173
|
+
|
174
|
+
raise ClassiqExecutionResultError("batch_sample")
|
170
175
|
|
171
176
|
def get_estimate_result(self) -> EstimationResult:
|
172
177
|
"""
|
@@ -202,9 +207,16 @@ class ExecutionJob:
|
|
202
207
|
ClassiqAPIError: In case the job has failed.
|
203
208
|
"""
|
204
209
|
results = self.result()
|
205
|
-
if len(results) != 1
|
210
|
+
if len(results) != 1:
|
206
211
|
raise ClassiqExecutionResultError("batch_estimate")
|
207
|
-
|
212
|
+
|
213
|
+
result = results[0].value
|
214
|
+
if isinstance(result, EstimationResult):
|
215
|
+
return [result]
|
216
|
+
if isinstance(result, EstimationResults):
|
217
|
+
return result.results
|
218
|
+
|
219
|
+
raise ClassiqExecutionResultError("batch_estimate")
|
208
220
|
|
209
221
|
async def poll_async(self, timeout_sec: Optional[float] = None) -> None:
|
210
222
|
if not self.status.is_final():
|
classiq/interface/_version.py
CHANGED
@@ -2,8 +2,16 @@ from typing import List, Optional
|
|
2
2
|
|
3
3
|
from pydantic import BaseModel, Field
|
4
4
|
|
5
|
+
from classiq.interface.chemistry.operator import PauliOperator
|
5
6
|
from classiq.interface.executor.quantum_code import Arguments
|
7
|
+
from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
|
6
8
|
|
7
9
|
|
8
|
-
class
|
10
|
+
class EstimateInput(BaseModel, json_encoders=CUSTOM_ENCODERS):
|
11
|
+
hamiltonian: PauliOperator
|
12
|
+
parameters: List[Arguments]
|
13
|
+
|
14
|
+
|
15
|
+
class PrimitivesInput(BaseModel, json_encoders=CUSTOM_ENCODERS):
|
9
16
|
sample: Optional[List[Arguments]] = Field(default=None)
|
17
|
+
estimate: Optional[EstimateInput] = Field(default=None)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
from typing import List
|
1
|
+
from typing import List
|
2
2
|
|
3
|
-
from pydantic import BaseModel
|
3
|
+
from pydantic import BaseModel, Field
|
4
4
|
|
5
5
|
from classiq.interface.executor.result import ExecutionDetails
|
6
6
|
from classiq.interface.generator.functions.classical_type import QmodPyObject
|
@@ -14,6 +14,6 @@ class IQAEIterationData(BaseModel):
|
|
14
14
|
|
15
15
|
class IQAEResult(VersionedModel, QmodPyObject):
|
16
16
|
estimation: float
|
17
|
-
confidence_interval:
|
17
|
+
confidence_interval: List[float] = Field(min_items=2, max_items=2)
|
18
18
|
iterations_data: List[IQAEIterationData]
|
19
19
|
warnings: List[str]
|
@@ -305,7 +305,9 @@ class EstimationMetadata(BaseModel, extra=pydantic.Extra.allow):
|
|
305
305
|
|
306
306
|
class EstimationResult(BaseModel, QmodPyObject):
|
307
307
|
value: Complex = pydantic.Field(..., description="Estimation for the operator")
|
308
|
-
variance: Complex = pydantic.Field(
|
308
|
+
variance: Optional[Complex] = pydantic.Field(
|
309
|
+
description="Variance of the estimation", default=None
|
310
|
+
)
|
309
311
|
metadata: EstimationMetadata = pydantic.Field(
|
310
312
|
..., description="Metadata for the estimation"
|
311
313
|
)
|
@@ -69,6 +69,14 @@ class Expression(HashableASTNode):
|
|
69
69
|
return self.as_constant(list)
|
70
70
|
|
71
71
|
def _try_to_immediate_evaluate(self) -> None:
|
72
|
+
# FIXME remove special treatment (CAD-22999)
|
73
|
+
if self.expr == "SIGNED":
|
74
|
+
self._evaluated_expr = EvaluatedExpression(value=True)
|
75
|
+
return
|
76
|
+
if self.expr == "UNSIGNED":
|
77
|
+
self._evaluated_expr = EvaluatedExpression(value=False)
|
78
|
+
return
|
79
|
+
|
72
80
|
try:
|
73
81
|
result = ast.literal_eval(self.expr)
|
74
82
|
if isinstance(result, (int, float, bool)):
|
@@ -67,9 +67,7 @@ class TypeName(ClassicalType, QuantumType): # type:ignore[misc]
|
|
67
67
|
return self._assigned_fields
|
68
68
|
|
69
69
|
def _set_fields(self, fields: Mapping[str, "ConcreteQuantumType"]) -> None:
|
70
|
-
|
71
|
-
|
72
|
-
QMODULE.qstruct_decls[self.name].fields = fields
|
70
|
+
self._assigned_fields = fields
|
73
71
|
|
74
72
|
|
75
73
|
class Enum(TypeName):
|
@@ -1,12 +1,26 @@
|
|
1
1
|
from typing import Dict, Optional, Set
|
2
2
|
|
3
3
|
import pydantic
|
4
|
+
import sympy
|
4
5
|
|
5
6
|
from classiq.interface.backend.pydantic_backend import PydanticExecutionParameter
|
7
|
+
from classiq.interface.exceptions import ClassiqValueError
|
8
|
+
from classiq.interface.generator.parameters import ParameterType
|
6
9
|
|
7
10
|
|
8
11
|
class FunctionExecutionData(pydantic.BaseModel):
|
9
|
-
power_parameter: Optional[
|
12
|
+
power_parameter: Optional[ParameterType] = pydantic.Field(default=None)
|
13
|
+
|
14
|
+
@property
|
15
|
+
def power_var(self) -> Optional[str]:
|
16
|
+
if self.power_parameter is None:
|
17
|
+
return None
|
18
|
+
power_vars = sympy.sympify(self.power_parameter).free_symbols
|
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])
|
10
24
|
|
11
25
|
|
12
26
|
class ExecutionData(pydantic.BaseModel):
|
@@ -19,7 +33,7 @@ class ExecutionData(pydantic.BaseModel):
|
|
19
33
|
self,
|
20
34
|
) -> Set[PydanticExecutionParameter]:
|
21
35
|
return {
|
22
|
-
function_execution_data.
|
36
|
+
function_execution_data.power_var
|
23
37
|
for function_execution_data in self.function_execution.values()
|
24
|
-
if function_execution_data.
|
38
|
+
if function_execution_data.power_var is not None
|
25
39
|
}
|
@@ -69,10 +69,9 @@ class Operation(pydantic.BaseModel):
|
|
69
69
|
target_qubits: Tuple[int, ...]
|
70
70
|
parameters: List[OperationParameter] = pydantic.Field(default_factory=list)
|
71
71
|
operation_level: OperationLevel
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
operation_type: OperationType = pydantic.Field(default=OperationType.REGULAR)
|
72
|
+
operation_type: OperationType = pydantic.Field(
|
73
|
+
description="Identifies unique operations that are visualized differently"
|
74
|
+
)
|
76
75
|
|
77
76
|
|
78
77
|
class ProgramVisualModel(VersionedModel):
|
@@ -1,25 +1,20 @@
|
|
1
|
-
from typing import Any, Dict, Literal, Mapping
|
1
|
+
from typing import Any, Dict, Literal, Mapping
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
|
6
|
-
from classiq.interface.generator.expressions.expression import Expression
|
7
6
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
8
7
|
from classiq.interface.generator.functions.port_declaration import (
|
9
8
|
PortDeclarationDirection,
|
10
9
|
)
|
11
10
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
12
11
|
from classiq.interface.model.parameter import Parameter
|
13
|
-
from classiq.interface.model.quantum_variable_declaration import (
|
14
|
-
QuantumVariableDeclaration,
|
15
|
-
)
|
16
12
|
|
17
13
|
|
18
14
|
class AnonPortDeclaration(Parameter):
|
19
15
|
kind: Literal["PortDeclaration"]
|
20
16
|
|
21
17
|
quantum_type: ConcreteQuantumType
|
22
|
-
size: Optional[Expression] = pydantic.Field(default=None, exclude=True)
|
23
18
|
direction: PortDeclarationDirection
|
24
19
|
|
25
20
|
@pydantic.root_validator(pre=True)
|
@@ -37,12 +32,6 @@ class AnonPortDeclaration(Parameter):
|
|
37
32
|
|
38
33
|
return direction
|
39
34
|
|
40
|
-
@pydantic.validator("size")
|
41
|
-
def _propagate_size_to_type(
|
42
|
-
cls, size: Optional[Expression], values: Mapping[str, Any]
|
43
|
-
) -> Optional[Expression]:
|
44
|
-
return QuantumVariableDeclaration._propagate_size_to_type(size, values)
|
45
|
-
|
46
35
|
def rename(self, new_name: str) -> "PortDeclaration":
|
47
36
|
if type(self) not in (AnonPortDeclaration, PortDeclaration):
|
48
37
|
raise ClassiqInternalError
|
@@ -1,7 +1,8 @@
|
|
1
|
-
from typing import Dict, Literal, Mapping, Sequence
|
1
|
+
from typing import Dict, Literal, Mapping, Optional, Sequence
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
5
|
+
from classiq.interface.enum_utils import StrEnum
|
5
6
|
from classiq.interface.generator.arith.arithmetic import (
|
6
7
|
ARITHMETIC_EXPRESSION_RESULT_NAME,
|
7
8
|
compute_arithmetic_result_type,
|
@@ -17,13 +18,40 @@ from classiq.interface.model.quantum_statement import HandleMetadata
|
|
17
18
|
from classiq.interface.model.quantum_type import QuantumType
|
18
19
|
|
19
20
|
|
21
|
+
class ArithmeticOperationKind(StrEnum):
|
22
|
+
InplaceAdd = "inplace_add"
|
23
|
+
Assignment = "assignment"
|
24
|
+
InplaceXor = "inplace_xor"
|
25
|
+
|
26
|
+
|
20
27
|
class ArithmeticOperation(QuantumAssignmentOperation):
|
21
28
|
kind: Literal["ArithmeticOperation"]
|
22
29
|
|
23
|
-
inplace_result: bool = pydantic.Field(
|
30
|
+
inplace_result: Optional[bool] = pydantic.Field(
|
24
31
|
description="Determines whether the result variable is initialized",
|
32
|
+
default=None,
|
33
|
+
exclude=True,
|
34
|
+
)
|
35
|
+
|
36
|
+
operation_kind: ArithmeticOperationKind = pydantic.Field(
|
37
|
+
default=ArithmeticOperationKind.InplaceXor,
|
25
38
|
)
|
26
39
|
|
40
|
+
@property
|
41
|
+
def is_inplace(self) -> bool:
|
42
|
+
return self.get_operation_kind() in (
|
43
|
+
ArithmeticOperationKind.InplaceXor,
|
44
|
+
ArithmeticOperationKind.InplaceAdd,
|
45
|
+
)
|
46
|
+
|
47
|
+
def get_operation_kind(self) -> ArithmeticOperationKind:
|
48
|
+
if hasattr(self, "inplace_result"):
|
49
|
+
if self.inplace_result is False:
|
50
|
+
return ArithmeticOperationKind.Assignment
|
51
|
+
if self.inplace_result is True:
|
52
|
+
return ArithmeticOperationKind.InplaceXor
|
53
|
+
return self.operation_kind
|
54
|
+
|
27
55
|
def initialize_var_types(
|
28
56
|
self,
|
29
57
|
var_types: Dict[str, QuantumType],
|
@@ -39,7 +67,7 @@ class ArithmeticOperation(QuantumAssignmentOperation):
|
|
39
67
|
self,
|
40
68
|
) -> Mapping[str, ConcreteHandleBinding]:
|
41
69
|
inouts = dict(super().wiring_inouts)
|
42
|
-
if self.
|
70
|
+
if self.is_inplace:
|
43
71
|
inouts[self.result_name()] = self.result_var
|
44
72
|
return inouts
|
45
73
|
|
@@ -49,7 +77,7 @@ class ArithmeticOperation(QuantumAssignmentOperation):
|
|
49
77
|
HandleMetadata(handle=handle, readable_location="in an expression")
|
50
78
|
for handle in self.var_handles
|
51
79
|
]
|
52
|
-
if self.
|
80
|
+
if self.is_inplace:
|
53
81
|
inouts.append(
|
54
82
|
HandleMetadata(
|
55
83
|
handle=self.result_var,
|
@@ -60,13 +88,13 @@ class ArithmeticOperation(QuantumAssignmentOperation):
|
|
60
88
|
|
61
89
|
@property
|
62
90
|
def wiring_outputs(self) -> Mapping[str, HandleBinding]:
|
63
|
-
if self.
|
91
|
+
if self.is_inplace:
|
64
92
|
return {}
|
65
93
|
return super().wiring_outputs
|
66
94
|
|
67
95
|
@property
|
68
96
|
def readable_outputs(self) -> Sequence[HandleMetadata]:
|
69
|
-
if self.
|
97
|
+
if self.is_inplace:
|
70
98
|
return []
|
71
99
|
return [
|
72
100
|
HandleMetadata(
|
@@ -19,7 +19,7 @@ class QuantumLambdaFunction(ASTNode):
|
|
19
19
|
|
20
20
|
rename_params: Dict[str, str] = pydantic.Field(
|
21
21
|
default_factory=dict,
|
22
|
-
exclude=
|
22
|
+
exclude=True,
|
23
23
|
)
|
24
24
|
|
25
25
|
pos_rename_params: List[str] = pydantic.Field(
|
@@ -41,6 +41,9 @@ class QuantumLambdaFunction(ASTNode):
|
|
41
41
|
def py_callable(self) -> Callable:
|
42
42
|
return self._py_callable
|
43
43
|
|
44
|
+
def is_generative(self) -> bool:
|
45
|
+
return self.py_callable is not None
|
46
|
+
|
44
47
|
def set_py_callable(self, py_callable: Callable) -> None:
|
45
48
|
self._py_callable = py_callable
|
46
49
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Any, Dict, Mapping, Optional, Sequence
|
2
|
+
from typing import Any, Callable, Dict, Mapping, Optional, Sequence
|
3
3
|
|
4
|
+
import pydantic
|
4
5
|
from pydantic import Extra, root_validator
|
5
6
|
|
6
7
|
from classiq.interface.ast_node import ASTNode
|
@@ -29,6 +30,8 @@ class HandleMetadata:
|
|
29
30
|
|
30
31
|
|
31
32
|
class QuantumOperation(QuantumStatement):
|
33
|
+
_generative_blocks: Dict[str, Callable] = pydantic.PrivateAttr(default_factory=dict)
|
34
|
+
|
32
35
|
@property
|
33
36
|
def wiring_inputs(self) -> Mapping[str, HandleBinding]:
|
34
37
|
return dict()
|
@@ -64,3 +67,15 @@ class QuantumOperation(QuantumStatement):
|
|
64
67
|
@property
|
65
68
|
def readable_outputs(self) -> Sequence[HandleMetadata]:
|
66
69
|
return [HandleMetadata(handle=handle) for handle in self.outputs]
|
70
|
+
|
71
|
+
def set_generative_block(self, block_name: str, py_callable: Callable) -> None:
|
72
|
+
self._generative_blocks[block_name] = py_callable
|
73
|
+
|
74
|
+
def get_generative_block(self, block_name: str) -> Callable:
|
75
|
+
return self._generative_blocks[block_name]
|
76
|
+
|
77
|
+
def has_generative_block(self, block_name: str) -> bool:
|
78
|
+
return block_name in self._generative_blocks
|
79
|
+
|
80
|
+
def is_generative(self) -> bool:
|
81
|
+
return len(self._generative_blocks) > 0
|
@@ -1,29 +1,7 @@
|
|
1
|
-
from typing import Any, Mapping, Optional
|
2
|
-
|
3
|
-
import pydantic
|
4
|
-
|
5
1
|
from classiq.interface.ast_node import ASTNode
|
6
|
-
from classiq.interface.generator.expressions.expression import Expression
|
7
2
|
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
8
|
-
from classiq.interface.model.quantum_type import (
|
9
|
-
QuantumBitvector,
|
10
|
-
QuantumNumeric,
|
11
|
-
)
|
12
3
|
|
13
4
|
|
14
5
|
class QuantumVariableDeclaration(ASTNode):
|
15
6
|
name: str
|
16
7
|
quantum_type: ConcreteQuantumType
|
17
|
-
size: Optional[Expression] = pydantic.Field(default=None, exclude=True)
|
18
|
-
|
19
|
-
@pydantic.validator("size")
|
20
|
-
def _propagate_size_to_type(
|
21
|
-
cls, size: Optional[Expression], values: Mapping[str, Any]
|
22
|
-
) -> Optional[Expression]:
|
23
|
-
if size is not None:
|
24
|
-
quantum_type = values.get("quantum_type")
|
25
|
-
if isinstance(quantum_type, QuantumBitvector):
|
26
|
-
quantum_type.length = size
|
27
|
-
elif isinstance(quantum_type, QuantumNumeric):
|
28
|
-
quantum_type.size = size
|
29
|
-
return size
|
@@ -1,13 +1,13 @@
|
|
1
|
-
from datetime import date
|
2
|
-
from typing import Any, Dict
|
1
|
+
from datetime import date
|
2
|
+
from typing import Any, Dict
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
from pydantic import BaseModel
|
6
6
|
|
7
7
|
|
8
8
|
class DeprecationInfo(BaseModel):
|
9
|
-
deprecation_date:
|
10
|
-
removal_date:
|
9
|
+
deprecation_date: date = pydantic.Field()
|
10
|
+
removal_date: date = pydantic.Field()
|
11
11
|
|
12
12
|
|
13
13
|
class GlobalVersions(BaseModel):
|
@@ -15,7 +15,7 @@ from classiq.interface.model.quantum_function_call import ArgValue
|
|
15
15
|
from classiq.interface.model.quantum_statement import QuantumOperation
|
16
16
|
|
17
17
|
from classiq.model_expansions.capturing.mangling_utils import mangle_captured_var_name
|
18
|
-
from classiq.model_expansions.closure import FunctionClosure
|
18
|
+
from classiq.model_expansions.closure import FunctionClosure, GenerativeFunctionClosure
|
19
19
|
from classiq.model_expansions.function_builder import OperationBuilder
|
20
20
|
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
21
21
|
|
@@ -144,7 +144,10 @@ class PropagatedVarStack:
|
|
144
144
|
def _get_propagated_var_name(self, var: PropagatedVariable) -> str:
|
145
145
|
if (
|
146
146
|
var.defining_function == self._builder.current_function.name
|
147
|
-
or
|
147
|
+
or not isinstance(
|
148
|
+
self._builder.current_function, GenerativeFunctionClosure
|
149
|
+
) # FIXME doesn't work for all cases (CAD-22663)
|
150
|
+
and self._no_name_conflict(var)
|
148
151
|
):
|
149
152
|
handle_name = var.name
|
150
153
|
if var in self._to_mangle:
|
@@ -40,6 +40,11 @@ class Closure:
|
|
40
40
|
}
|
41
41
|
|
42
42
|
|
43
|
+
@dataclass(frozen=True)
|
44
|
+
class GenerativeClosure(Closure):
|
45
|
+
generative_blocks: Dict[str, GenerativeQFunc] = None # type:ignore[assignment]
|
46
|
+
|
47
|
+
|
43
48
|
@dataclass(frozen=True)
|
44
49
|
class FunctionClosure(Closure):
|
45
50
|
is_lambda: bool = False
|
@@ -101,8 +106,8 @@ class FunctionClosure(Closure):
|
|
101
106
|
|
102
107
|
|
103
108
|
@dataclass(frozen=True)
|
104
|
-
class GenerativeFunctionClosure(FunctionClosure):
|
105
|
-
|
109
|
+
class GenerativeFunctionClosure(GenerativeClosure, FunctionClosure):
|
110
|
+
pass
|
106
111
|
|
107
112
|
|
108
113
|
NestedFunctionClosureT = Union[FunctionClosure, List["NestedFunctionClosureT"]]
|
@@ -10,7 +10,6 @@ from classiq.interface.generator.functions.type_name import (
|
|
10
10
|
TypeName,
|
11
11
|
)
|
12
12
|
from classiq.interface.model.bind_operation import BindOperation
|
13
|
-
from classiq.interface.model.inplace_binary_operation import BinaryOperation
|
14
13
|
from classiq.interface.model.quantum_type import (
|
15
14
|
QuantumBit,
|
16
15
|
QuantumBitvector,
|
@@ -227,9 +226,3 @@ def validate_inplace_binary_op_vars(
|
|
227
226
|
raise ClassiqExpansionError(
|
228
227
|
f"Cannot perform `{operation_name}` operation with non numeric target {target_var.handle}"
|
229
228
|
)
|
230
|
-
if operation_name != BinaryOperation.Xor.value and (
|
231
|
-
value_var.quantum_type.sign_value or target_var.quantum_type.sign_value
|
232
|
-
):
|
233
|
-
raise ClassiqExpansionError(
|
234
|
-
f"Cannot perform `{operation_name}` operation with signed variables"
|
235
|
-
)
|