classiq 0.83.0__py3-none-any.whl → 0.85.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 +27 -0
- classiq/applications/chemistry/chemistry_model_constructor.py +0 -2
- classiq/applications/chemistry/hartree_fock.py +68 -0
- classiq/applications/chemistry/mapping.py +85 -0
- classiq/applications/chemistry/op_utils.py +79 -0
- classiq/applications/chemistry/problems.py +195 -0
- classiq/applications/chemistry/ucc.py +109 -0
- classiq/applications/chemistry/z2_symmetries.py +368 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +20 -42
- classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
- classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
- classiq/evaluators/classical_expression.py +53 -0
- classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
- classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
- classiq/execution/__init__.py +12 -1
- classiq/execution/execution_session.py +238 -49
- classiq/execution/jobs.py +26 -1
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +39 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/constants.py +1 -0
- classiq/interface/debug_info/debug_info.py +0 -4
- classiq/interface/execution/primitives.py +29 -1
- classiq/interface/executor/estimate_cost.py +35 -0
- classiq/interface/executor/execution_result.py +13 -0
- classiq/interface/executor/result.py +116 -1
- classiq/interface/executor/user_budget.py +26 -33
- classiq/interface/generator/expressions/atomic_expression_functions.py +10 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
- classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
- classiq/interface/generator/functions/classical_type.py +2 -35
- classiq/interface/generator/functions/concrete_types.py +20 -3
- classiq/interface/generator/functions/type_modifier.py +0 -19
- classiq/interface/generator/generated_circuit_data.py +5 -18
- classiq/interface/generator/types/compilation_metadata.py +0 -3
- classiq/interface/ide/operation_registry.py +45 -0
- classiq/interface/ide/visual_model.py +68 -3
- classiq/interface/model/bounds.py +12 -2
- classiq/interface/model/model.py +12 -7
- classiq/interface/model/port_declaration.py +2 -24
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
- classiq/interface/model/variable_declaration_statement.py +33 -6
- classiq/interface/pretty_print/__init__.py +0 -0
- classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
- classiq/interface/server/routes.py +4 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +47 -6
- classiq/model_expansions/function_builder.py +4 -1
- classiq/model_expansions/interpreters/base_interpreter.py +3 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +16 -1
- classiq/model_expansions/quantum_operations/allocate.py +1 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +64 -22
- classiq/model_expansions/quantum_operations/bind.py +2 -2
- classiq/model_expansions/quantum_operations/bounds.py +7 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +31 -11
- classiq/model_expansions/scope.py +7 -0
- classiq/model_expansions/scope_initialization.py +3 -3
- classiq/model_expansions/transformers/model_renamer.py +6 -4
- classiq/model_expansions/transformers/type_modifier_inference.py +81 -43
- classiq/model_expansions/transformers/var_splitter.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +2 -3
- classiq/open_library/functions/__init__.py +3 -2
- classiq/open_library/functions/amplitude_amplification.py +10 -18
- classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
- classiq/open_library/functions/grover.py +14 -6
- classiq/open_library/functions/modular_exponentiation.py +22 -20
- classiq/open_library/functions/qaoa_penalty.py +8 -1
- classiq/open_library/functions/state_preparation.py +18 -32
- classiq/qmod/__init__.py +2 -0
- classiq/qmod/builtins/enums.py +23 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -4
- classiq/qmod/builtins/operations.py +65 -1
- classiq/qmod/builtins/structs.py +55 -3
- classiq/qmod/classical_variable.py +74 -0
- classiq/qmod/declaration_inferrer.py +3 -2
- classiq/qmod/native/pretty_printer.py +20 -20
- classiq/qmod/pretty_print/expression_to_python.py +2 -1
- classiq/qmod/pretty_print/pretty_printer.py +35 -21
- classiq/qmod/python_classical_type.py +12 -5
- classiq/qmod/qfunc.py +2 -19
- classiq/qmod/qmod_constant.py +2 -5
- classiq/qmod/qmod_parameter.py +2 -5
- classiq/qmod/qmod_variable.py +61 -23
- classiq/qmod/quantum_expandable.py +5 -3
- classiq/qmod/quantum_function.py +49 -4
- classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -9
- classiq/qmod/symbolic_type.py +2 -1
- classiq/qmod/utilities.py +0 -2
- classiq/qmod/write_qmod.py +1 -1
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/METADATA +4 -1
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/RECORD +101 -90
- classiq/interface/model/quantum_variable_declaration.py +0 -7
- classiq/model_expansions/evaluators/classical_expression.py +0 -36
- /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
- /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/WHEEL +0 -0
classiq/qmod/builtins/enums.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
from enum import IntEnum
|
2
|
+
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
4
5
|
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from classiq.qmod.builtins.structs import SparsePauliOp
|
8
|
+
|
5
9
|
|
6
10
|
class Element(IntEnum):
|
7
11
|
H = 0
|
@@ -176,6 +180,25 @@ class Pauli(IntEnum):
|
|
176
180
|
"""Z (int): Pauli-Z matrix, represented by the integer 3. \n
|
177
181
|
$Z = \\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\end{bmatrix}$"""
|
178
182
|
|
183
|
+
def __call__(self, index: int) -> "SparsePauliOp":
|
184
|
+
from classiq.qmod.builtins.structs import (
|
185
|
+
IndexedPauli,
|
186
|
+
SparsePauliOp,
|
187
|
+
SparsePauliTerm,
|
188
|
+
)
|
189
|
+
|
190
|
+
return SparsePauliOp(
|
191
|
+
terms=[ # type:ignore[arg-type]
|
192
|
+
SparsePauliTerm(
|
193
|
+
paulis=[ # type:ignore[arg-type]
|
194
|
+
IndexedPauli(pauli=self, index=index) # type:ignore[arg-type]
|
195
|
+
],
|
196
|
+
coefficient=1.0, # type:ignore[arg-type]
|
197
|
+
)
|
198
|
+
],
|
199
|
+
num_qubits=index + 1, # type:ignore[arg-type]
|
200
|
+
)
|
201
|
+
|
179
202
|
|
180
203
|
class QSVMFeatureMapEntanglement(IntEnum):
|
181
204
|
FULL = 0
|
@@ -71,6 +71,7 @@ CORE_LIB_DECLS = [
|
|
71
71
|
single_pauli_exponent,
|
72
72
|
commuting_paulis_exponent,
|
73
73
|
suzuki_trotter,
|
74
|
+
multi_suzuki_trotter,
|
74
75
|
parametric_suzuki_trotter,
|
75
76
|
sparse_suzuki_trotter,
|
76
77
|
qdrift,
|
@@ -132,6 +133,7 @@ __all__ = [ # noqa: RUF022
|
|
132
133
|
"molecule_hartree_fock",
|
133
134
|
"molecule_hva",
|
134
135
|
"molecule_ucc",
|
136
|
+
"multi_suzuki_trotter",
|
135
137
|
"parametric_suzuki_trotter",
|
136
138
|
"pauli_feature_map",
|
137
139
|
"permute",
|
@@ -55,13 +55,11 @@ def commuting_paulis_exponent(
|
|
55
55
|
|
56
56
|
@qfunc(external=True)
|
57
57
|
def suzuki_trotter(
|
58
|
-
pauli_operator:
|
58
|
+
pauli_operator: SparsePauliOp, # FIXME: Rename to hamiltonian (CLS-2912)
|
59
59
|
evolution_coefficient: CReal,
|
60
60
|
order: CInt,
|
61
61
|
repetitions: CInt,
|
62
|
-
qbv: QArray[
|
63
|
-
QBit, Literal["get_field(get_field(pauli_operator[0], 'pauli'), 'len')"]
|
64
|
-
],
|
62
|
+
qbv: QArray[QBit], # FIXME: Add length expr (CLS-2912)
|
65
63
|
) -> None:
|
66
64
|
"""
|
67
65
|
[Qmod core-library function]
|
@@ -82,6 +80,36 @@ def suzuki_trotter(
|
|
82
80
|
pass
|
83
81
|
|
84
82
|
|
83
|
+
@qfunc(external=True)
|
84
|
+
def multi_suzuki_trotter(
|
85
|
+
hamiltonians: CArray[SparsePauliOp],
|
86
|
+
evolution_coefficients: CArray[CReal],
|
87
|
+
order: CInt,
|
88
|
+
repetitions: CInt,
|
89
|
+
qbv: QArray,
|
90
|
+
) -> None:
|
91
|
+
"""
|
92
|
+
[Qmod core-library function]
|
93
|
+
|
94
|
+
Applies the Suzuki-Trotter decomposition jointly to a sum of Hamiltonians
|
95
|
+
(represented as Pauli operators), each with its separate evolution coefficient,
|
96
|
+
approximating $\\exp{-iH_1t_1+H_2t_2+\\dots}$ with a specified order and number of
|
97
|
+
repetitions.
|
98
|
+
|
99
|
+
The Suzuki-Trotter decomposition is a method for approximating the exponential of a sum of operators by a product of exponentials of each operator.
|
100
|
+
The Suzuki-Trotter decomposition of a given order nullifies the error of the Taylor series expansion of the product of exponentials up to that order.
|
101
|
+
The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
hamiltonians: The hamitonians to be exponentiated, in sparse representation.
|
105
|
+
evolution_coefficients: The hamiltonian coefficients (can be link-time).
|
106
|
+
order: The order of the Suzuki-Trotter decomposition.
|
107
|
+
repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
|
108
|
+
qbv: The target quantum variable of the exponentiation.
|
109
|
+
"""
|
110
|
+
pass
|
111
|
+
|
112
|
+
|
85
113
|
@qfunc(external=True)
|
86
114
|
def parametric_suzuki_trotter(
|
87
115
|
paulis: CArray[CArray[Pauli]],
|
@@ -7,6 +7,7 @@ from typing import (
|
|
7
7
|
Callable,
|
8
8
|
Final,
|
9
9
|
NoReturn,
|
10
|
+
Optional,
|
10
11
|
Union,
|
11
12
|
overload,
|
12
13
|
)
|
@@ -20,6 +21,8 @@ from classiq.interface.generator.functions.classical_type import Integer
|
|
20
21
|
from classiq.interface.helpers.text_utils import s
|
21
22
|
from classiq.interface.model.allocate import Allocate
|
22
23
|
from classiq.interface.model.bind_operation import BindOperation
|
24
|
+
from classiq.interface.model.block import Block
|
25
|
+
from classiq.interface.model.bounds import SetBoundsStatement
|
23
26
|
from classiq.interface.model.classical_if import ClassicalIf
|
24
27
|
from classiq.interface.model.classical_parameter_declaration import (
|
25
28
|
ClassicalParameterDeclaration,
|
@@ -46,7 +49,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
46
49
|
|
47
50
|
from classiq.qmod.generative import is_generative_mode
|
48
51
|
from classiq.qmod.qmod_constant import QConstant
|
49
|
-
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVar
|
52
|
+
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QNum, QScalar, QVar
|
50
53
|
from classiq.qmod.quantum_callable import QCallable
|
51
54
|
from classiq.qmod.quantum_expandable import prepare_arg
|
52
55
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
@@ -398,6 +401,65 @@ def phase(expr: SymbolicExpr, theta: float = 1.0) -> None:
|
|
398
401
|
)
|
399
402
|
|
400
403
|
|
404
|
+
@suppress_return_value
|
405
|
+
def block(
|
406
|
+
statements: Union[QCallable, Callable[[], Statements]],
|
407
|
+
) -> None:
|
408
|
+
_validate_operand(statements)
|
409
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
410
|
+
source_ref = get_source_ref(sys._getframe(1))
|
411
|
+
|
412
|
+
block_stmt = Block(
|
413
|
+
statements=_operand_to_body(statements, "statements"),
|
414
|
+
source_ref=source_ref,
|
415
|
+
)
|
416
|
+
if is_generative_mode():
|
417
|
+
block_stmt.set_generative_block("statements", statements)
|
418
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(block_stmt)
|
419
|
+
|
420
|
+
|
421
|
+
@overload
|
422
|
+
def reset_bounds(
|
423
|
+
target_var: QNum,
|
424
|
+
) -> None:
|
425
|
+
pass
|
426
|
+
|
427
|
+
|
428
|
+
@overload
|
429
|
+
def reset_bounds(
|
430
|
+
target_var: QNum,
|
431
|
+
lower_bound: Union[float, SymbolicExpr],
|
432
|
+
upper_bound: Union[float, SymbolicExpr],
|
433
|
+
) -> None:
|
434
|
+
pass
|
435
|
+
|
436
|
+
|
437
|
+
@suppress_return_value
|
438
|
+
def reset_bounds(
|
439
|
+
target_var: QNum,
|
440
|
+
lower_bound: Optional[Union[float, SymbolicExpr]] = None,
|
441
|
+
upper_bound: Optional[Union[float, SymbolicExpr]] = None,
|
442
|
+
) -> None:
|
443
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
444
|
+
source_ref = get_source_ref(sys._getframe(1))
|
445
|
+
|
446
|
+
lower_bound_expr = (
|
447
|
+
None if lower_bound is None else Expression(expr=str(lower_bound))
|
448
|
+
)
|
449
|
+
upper_bound_expr = (
|
450
|
+
None if upper_bound is None else Expression(expr=str(upper_bound))
|
451
|
+
)
|
452
|
+
|
453
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
454
|
+
SetBoundsStatement(
|
455
|
+
target=target_var.get_handle_binding(),
|
456
|
+
lower_bound=lower_bound_expr,
|
457
|
+
upper_bound=upper_bound_expr,
|
458
|
+
source_ref=source_ref,
|
459
|
+
)
|
460
|
+
)
|
461
|
+
|
462
|
+
|
401
463
|
def _validate_operand(stmt_block: Any, num_params: int = 0) -> None:
|
402
464
|
if stmt_block is None:
|
403
465
|
_raise_operand_error(
|
@@ -502,6 +564,7 @@ __all__ = [
|
|
502
564
|
"assign",
|
503
565
|
"assign_amplitude",
|
504
566
|
"bind",
|
567
|
+
"block",
|
505
568
|
"control",
|
506
569
|
"if_",
|
507
570
|
"inplace_add",
|
@@ -510,6 +573,7 @@ __all__ = [
|
|
510
573
|
"phase",
|
511
574
|
"power",
|
512
575
|
"repeat",
|
576
|
+
"reset_bounds",
|
513
577
|
"within_apply",
|
514
578
|
]
|
515
579
|
|
classiq/qmod/builtins/structs.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
from dataclasses import dataclass, fields, is_dataclass
|
2
|
+
from typing import Union
|
2
3
|
|
4
|
+
from classiq.interface.exceptions import ClassiqValueError
|
3
5
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
6
|
+
from classiq.interface.helpers.text_utils import are, readable_list, s
|
4
7
|
|
5
8
|
from classiq.qmod.builtins.enums import LadderOperator, Pauli
|
6
9
|
from classiq.qmod.cparam import CArray, CBool, CInt, CReal
|
@@ -56,13 +59,62 @@ class SparsePauliOp:
|
|
56
59
|
Represents a collection of sparse Pauli operators.
|
57
60
|
|
58
61
|
Attributes:
|
59
|
-
|
62
|
+
terms (CArray[SparsePauliTerm]): The list of chosen sparse Pauli terms, corresponds to a product of them. (See: SparsePauliTerm)
|
60
63
|
num_qubits (CInt): The number of qubits in the Hamiltonian.
|
61
64
|
"""
|
62
65
|
|
63
|
-
|
66
|
+
terms: CArray[SparsePauliTerm]
|
64
67
|
num_qubits: CInt
|
65
68
|
|
69
|
+
def __mul__(self, obj: Union[float, "SparsePauliOp"]) -> "SparsePauliOp":
|
70
|
+
if isinstance(obj, (int, float, complex)):
|
71
|
+
return SparsePauliOp(
|
72
|
+
terms=[ # type:ignore[arg-type]
|
73
|
+
SparsePauliTerm(
|
74
|
+
paulis=term.paulis,
|
75
|
+
coefficient=obj * term.coefficient,
|
76
|
+
)
|
77
|
+
for term in self.terms # type:ignore[attr-defined]
|
78
|
+
],
|
79
|
+
num_qubits=self.num_qubits,
|
80
|
+
)
|
81
|
+
if len(self.terms) != 1 or len(obj.terms) != 1: # type:ignore[arg-type]
|
82
|
+
raise ClassiqValueError("Cannot attach a pauli to multiple pauli terms")
|
83
|
+
existing_indices = {
|
84
|
+
indexed_pauli.index for indexed_pauli in self.terms[0].paulis
|
85
|
+
}
|
86
|
+
added_indices = {indexed_pauli.index for indexed_pauli in obj.terms[0].paulis}
|
87
|
+
overlapping_indices = sorted(existing_indices.intersection(added_indices))
|
88
|
+
if len(overlapping_indices):
|
89
|
+
raise ClassiqValueError(
|
90
|
+
f"Pauli{s(overlapping_indices)} at "
|
91
|
+
f"{'indices' if len(overlapping_indices) > 1 else 'index'} "
|
92
|
+
f"{readable_list(overlapping_indices)} {are(overlapping_indices)} "
|
93
|
+
f"already assigned"
|
94
|
+
)
|
95
|
+
return SparsePauliOp(
|
96
|
+
terms=[ # type:ignore[arg-type]
|
97
|
+
SparsePauliTerm(
|
98
|
+
paulis=self.terms[0].paulis + obj.terms[0].paulis,
|
99
|
+
coefficient=self.terms[0].coefficient * obj.terms[0].coefficient,
|
100
|
+
)
|
101
|
+
],
|
102
|
+
num_qubits=max(
|
103
|
+
self.num_qubits, obj.num_qubits # type:ignore[call-overload]
|
104
|
+
),
|
105
|
+
)
|
106
|
+
|
107
|
+
def __rmul__(self, obj: Union[float, "SparsePauliOp"]) -> "SparsePauliOp":
|
108
|
+
return self.__mul__(obj)
|
109
|
+
|
110
|
+
def __add__(self, other: "SparsePauliOp") -> "SparsePauliOp":
|
111
|
+
return SparsePauliOp(
|
112
|
+
terms=self.terms + other.terms, # type:ignore[arg-type]
|
113
|
+
num_qubits=max(
|
114
|
+
self.num_qubits, other.num_qubits # type:ignore[call-overload]
|
115
|
+
),
|
116
|
+
)
|
117
|
+
|
66
118
|
|
67
119
|
@dataclass
|
68
120
|
class Position:
|
@@ -167,7 +219,7 @@ BUILTIN_STRUCT_DECLARATIONS = {
|
|
167
219
|
struct_decl.__name__: StructDeclaration(
|
168
220
|
name=struct_decl.__name__,
|
169
221
|
variables={
|
170
|
-
field.name: PythonClassicalType().convert(field.type)
|
222
|
+
field.name: PythonClassicalType().convert(field.type, nested=True)
|
171
223
|
for field in fields(struct_decl)
|
172
224
|
},
|
173
225
|
)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import sys
|
2
|
+
from typing import TYPE_CHECKING, Any
|
3
|
+
|
4
|
+
from classiq.interface.exceptions import ClassiqInternalError
|
5
|
+
from classiq.interface.generator.expressions.expression import Expression
|
6
|
+
from classiq.interface.generator.functions.classical_type import Bool, ClassicalType
|
7
|
+
from classiq.interface.model.handle_binding import HandleBinding
|
8
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
9
|
+
ArithmeticOperation,
|
10
|
+
ArithmeticOperationKind,
|
11
|
+
)
|
12
|
+
from classiq.interface.model.variable_declaration_statement import (
|
13
|
+
VariableDeclarationStatement,
|
14
|
+
)
|
15
|
+
|
16
|
+
from classiq.qmod.cparam import CBool, CParam, CParamScalar
|
17
|
+
from classiq.qmod.qmod_variable import QBit, _infer_variable_name
|
18
|
+
from classiq.qmod.quantum_callable import QCallable
|
19
|
+
from classiq.qmod.symbolic import symbolic_function
|
20
|
+
from classiq.qmod.symbolic_type import SYMBOLIC_TYPES
|
21
|
+
from classiq.qmod.utilities import get_source_ref
|
22
|
+
|
23
|
+
|
24
|
+
def declare_classical_variable(
|
25
|
+
name: str, classical_type: ClassicalType, frame_depth: int
|
26
|
+
) -> None:
|
27
|
+
if TYPE_CHECKING:
|
28
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
29
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
30
|
+
VariableDeclarationStatement(
|
31
|
+
name=name,
|
32
|
+
qmod_type=classical_type,
|
33
|
+
source_ref=get_source_ref(sys._getframe(frame_depth)),
|
34
|
+
)
|
35
|
+
)
|
36
|
+
|
37
|
+
|
38
|
+
def assign_classical_variable(target: CParam, value: Any, frame_depth: int) -> None:
|
39
|
+
if not isinstance(value, SYMBOLIC_TYPES):
|
40
|
+
raise TypeError(f"Invalid argument {value!r} for classical variable assignment")
|
41
|
+
|
42
|
+
if TYPE_CHECKING:
|
43
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
44
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
45
|
+
ArithmeticOperation(
|
46
|
+
expression=Expression(expr=str(value)),
|
47
|
+
result_var=HandleBinding(name=str(target)),
|
48
|
+
operation_kind=ArithmeticOperationKind.Assignment,
|
49
|
+
source_ref=get_source_ref(sys._getframe(frame_depth)),
|
50
|
+
)
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
def measure(var: QBit) -> CParamScalar:
|
55
|
+
"""
|
56
|
+
Measures the given qubit. `measure` is a non-unitary operation.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
var: a qubit variable
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
the measurement result (a symbolic boolean variable)
|
63
|
+
"""
|
64
|
+
name = _infer_variable_name(None, 2)
|
65
|
+
if name is None:
|
66
|
+
raise ClassiqInternalError("Could not infer measure var name")
|
67
|
+
declare_classical_variable(name, Bool(), 2)
|
68
|
+
res_var = CParamScalar(name)
|
69
|
+
res_val = symbolic_function(
|
70
|
+
var,
|
71
|
+
return_type=CBool, # type:ignore[type-abstract]
|
72
|
+
)
|
73
|
+
assign_classical_variable(res_var, res_val, 2)
|
74
|
+
return res_var
|
@@ -75,14 +75,15 @@ class _PythonClassicalType(PythonClassicalType):
|
|
75
75
|
all_decls = BUILTIN_STRUCT_DECLARATIONS | self.qmodule.type_decls
|
76
76
|
if py_type.__name__ in all_decls:
|
77
77
|
classical_type.set_classical_struct_decl(
|
78
|
-
all_decls[py_type.__name__].model_copy()
|
78
|
+
all_decls[py_type.__name__].model_copy(deep=True)
|
79
79
|
)
|
80
80
|
return classical_type
|
81
81
|
|
82
82
|
struct_decl = StructDeclaration(
|
83
83
|
name=py_type.__name__,
|
84
84
|
variables={
|
85
|
-
f.name: self.convert(f.type
|
85
|
+
f.name: self.convert(f.type, nested=True)
|
86
|
+
for f in dataclasses.fields(py_type)
|
86
87
|
},
|
87
88
|
)
|
88
89
|
check_duplicate_types([struct_decl, *self.qmodule.user_types()])
|
@@ -1,13 +1,13 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import Optional, Union
|
3
3
|
|
4
|
+
from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
|
4
5
|
from classiq.interface.exceptions import ClassiqInternalError
|
5
6
|
from classiq.interface.generator.constant import Constant
|
6
7
|
from classiq.interface.generator.expressions.expression import Expression
|
7
8
|
from classiq.interface.generator.functions.classical_type import (
|
8
9
|
Bool,
|
9
10
|
ClassicalArray,
|
10
|
-
ClassicalList,
|
11
11
|
ClassicalTuple,
|
12
12
|
Integer,
|
13
13
|
Real,
|
@@ -29,6 +29,7 @@ from classiq.interface.generator.visitor import NodeType
|
|
29
29
|
from classiq.interface.model.allocate import Allocate
|
30
30
|
from classiq.interface.model.bind_operation import BindOperation
|
31
31
|
from classiq.interface.model.block import Block
|
32
|
+
from classiq.interface.model.bounds import SetBoundsStatement
|
32
33
|
from classiq.interface.model.classical_if import ClassicalIf
|
33
34
|
from classiq.interface.model.classical_parameter_declaration import (
|
34
35
|
AnonClassicalParameterDeclaration,
|
@@ -76,20 +77,16 @@ from classiq.interface.model.quantum_type import (
|
|
76
77
|
QuantumBitvector,
|
77
78
|
QuantumNumeric,
|
78
79
|
)
|
79
|
-
from classiq.interface.model.quantum_variable_declaration import (
|
80
|
-
QuantumVariableDeclaration,
|
81
|
-
)
|
82
80
|
from classiq.interface.model.repeat import Repeat
|
83
81
|
from classiq.interface.model.statement_block import StatementBlock
|
84
82
|
from classiq.interface.model.variable_declaration_statement import (
|
85
83
|
VariableDeclarationStatement,
|
86
84
|
)
|
87
85
|
from classiq.interface.model.within_apply_operation import WithinApply
|
86
|
+
from classiq.interface.pretty_print.expression_to_qmod import transform_expression
|
88
87
|
|
89
88
|
from classiq.open_library.functions import OPEN_LIBRARY_FUNCTIONS
|
90
|
-
from classiq.qmod.native.expression_to_qmod import transform_expression
|
91
89
|
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
92
|
-
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
93
90
|
|
94
91
|
|
95
92
|
class DSLPrettyPrinter(ModelVisitor):
|
@@ -190,11 +187,6 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
190
187
|
self._level -= 1
|
191
188
|
return variables_str
|
192
189
|
|
193
|
-
def visit_QuantumVariableDeclaration(
|
194
|
-
self, var_decl: QuantumVariableDeclaration
|
195
|
-
) -> str:
|
196
|
-
return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
|
197
|
-
|
198
190
|
def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
|
199
191
|
modifier_str = (
|
200
192
|
f"{port_decl.type_modifier} "
|
@@ -248,9 +240,6 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
248
240
|
def visit_Bool(self, ctbool: Bool) -> str:
|
249
241
|
return "bool"
|
250
242
|
|
251
|
-
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
252
|
-
return f"{self.visit(ctlist.element_type)}[]"
|
253
|
-
|
254
243
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
255
244
|
element_type = self.visit(ctarray.element_type)
|
256
245
|
if ctarray.length is not None:
|
@@ -267,9 +256,9 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
267
256
|
return type_.name
|
268
257
|
|
269
258
|
def visit_VariableDeclarationStatement(
|
270
|
-
self,
|
259
|
+
self, var_decl: VariableDeclarationStatement
|
271
260
|
) -> str:
|
272
|
-
return f"{self._indent}{self.
|
261
|
+
return f"{self._indent}{var_decl.name}: {self.visit(var_decl.qmod_type)};\n"
|
273
262
|
|
274
263
|
def visit_AnonQuantumOperandDeclaration(
|
275
264
|
self, op_decl: AnonQuantumOperandDeclaration
|
@@ -365,10 +354,10 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
365
354
|
return invert_code
|
366
355
|
|
367
356
|
def visit_Block(self, block: Block) -> str:
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
return
|
357
|
+
block_code = f"{self._indent}{{\n"
|
358
|
+
block_code += self._visit_body(block.statements)
|
359
|
+
block_code += f"{self._indent}}}\n"
|
360
|
+
return block_code
|
372
361
|
|
373
362
|
def _visit_body(self, body: StatementBlock) -> str:
|
374
363
|
code = ""
|
@@ -447,6 +436,17 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
447
436
|
def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
|
448
437
|
return str(op)
|
449
438
|
|
439
|
+
def visit_SetBoundsStatement(self, op: SetBoundsStatement) -> str:
|
440
|
+
target = self.visit(op.target)
|
441
|
+
if op.lower_bound is None or op.upper_bound is None:
|
442
|
+
return f"{self._indent}reset_bounds({target});\n"
|
443
|
+
else:
|
444
|
+
lower_bound = self.visit(op.lower_bound)
|
445
|
+
upper_bound = self.visit(op.upper_bound)
|
446
|
+
return (
|
447
|
+
f"{self._indent}reset_bounds({target}, {lower_bound}, {upper_bound});\n"
|
448
|
+
)
|
449
|
+
|
450
450
|
@property
|
451
451
|
def _indent(self) -> str:
|
452
452
|
return " " * self._level
|
@@ -6,8 +6,9 @@ from typing import Callable
|
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
|
+
from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
|
10
|
+
|
9
11
|
import classiq
|
10
|
-
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
11
12
|
|
12
13
|
IDENTIFIER = re.compile(r"[a-zA-Z_]\w*")
|
13
14
|
BINARY_OPS: Mapping[type[ast.operator], str] = {
|
@@ -3,13 +3,13 @@ from typing import Optional, Union, cast
|
|
3
3
|
|
4
4
|
import black
|
5
5
|
|
6
|
+
from classiq.interface.constants import DEFAULT_DECIMAL_PRECISION
|
6
7
|
from classiq.interface.exceptions import ClassiqInternalError
|
7
8
|
from classiq.interface.generator.constant import Constant
|
8
9
|
from classiq.interface.generator.expressions.expression import Expression
|
9
10
|
from classiq.interface.generator.functions.classical_type import (
|
10
11
|
Bool,
|
11
12
|
ClassicalArray,
|
12
|
-
ClassicalList,
|
13
13
|
ClassicalTuple,
|
14
14
|
Integer,
|
15
15
|
Real,
|
@@ -30,6 +30,8 @@ from classiq.interface.generator.types.struct_declaration import StructDeclarati
|
|
30
30
|
from classiq.interface.generator.visitor import NodeType, Visitor
|
31
31
|
from classiq.interface.model.allocate import Allocate
|
32
32
|
from classiq.interface.model.bind_operation import BindOperation
|
33
|
+
from classiq.interface.model.block import Block
|
34
|
+
from classiq.interface.model.bounds import SetBoundsStatement
|
33
35
|
from classiq.interface.model.classical_if import ClassicalIf
|
34
36
|
from classiq.interface.model.classical_parameter_declaration import (
|
35
37
|
AnonClassicalParameterDeclaration,
|
@@ -75,9 +77,6 @@ from classiq.interface.model.quantum_type import (
|
|
75
77
|
QuantumBitvector,
|
76
78
|
QuantumNumeric,
|
77
79
|
)
|
78
|
-
from classiq.interface.model.quantum_variable_declaration import (
|
79
|
-
QuantumVariableDeclaration,
|
80
|
-
)
|
81
80
|
from classiq.interface.model.repeat import Repeat
|
82
81
|
from classiq.interface.model.statement_block import StatementBlock
|
83
82
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -88,10 +87,11 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
88
87
|
import classiq
|
89
88
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
90
89
|
from classiq.qmod.pretty_print.expression_to_python import transform_expression
|
91
|
-
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
92
90
|
|
93
91
|
|
94
92
|
class VariableDeclarationAssignment(Visitor):
|
93
|
+
# FIXME: Support classical variable types
|
94
|
+
|
95
95
|
def __init__(self, pretty_printer: "PythonPrettyPrinter") -> None:
|
96
96
|
self.pretty_printer = pretty_printer
|
97
97
|
|
@@ -252,11 +252,6 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
252
252
|
self._level -= 1
|
253
253
|
return variables_str
|
254
254
|
|
255
|
-
def visit_QuantumVariableDeclaration(
|
256
|
-
self, var_decl: QuantumVariableDeclaration
|
257
|
-
) -> str:
|
258
|
-
return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
|
259
|
-
|
260
255
|
def visit_AnonPortDeclaration(self, port_decl: AnonPortDeclaration) -> str:
|
261
256
|
var_type = self._extract_port_type(port_decl)
|
262
257
|
return f"{port_decl.name}: {var_type}"
|
@@ -338,10 +333,6 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
338
333
|
self._imports["CBool"] = 1
|
339
334
|
return "CBool"
|
340
335
|
|
341
|
-
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
342
|
-
self._imports["CArray"] = 1
|
343
|
-
return f"CArray[{self.visit(ctlist.element_type)}]"
|
344
|
-
|
345
336
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
346
337
|
self._imports["CArray"] = 1
|
347
338
|
element_type = self.visit(ctarray.element_type)
|
@@ -366,14 +357,23 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
366
357
|
self._imports[type_.name] = 1
|
367
358
|
|
368
359
|
def visit_VariableDeclarationStatement(
|
369
|
-
self,
|
360
|
+
self,
|
361
|
+
local_decl: VariableDeclarationStatement,
|
362
|
+
walrus: bool = False,
|
370
363
|
) -> str:
|
371
364
|
type_name, params = VariableDeclarationAssignment(self).visit(
|
372
|
-
local_decl.
|
365
|
+
local_decl.qmod_type
|
373
366
|
)
|
374
367
|
params = [f'"{local_decl.name}"'] + params
|
375
368
|
param_args = ", ".join(params)
|
376
|
-
|
369
|
+
|
370
|
+
res = f"{self._indent}{local_decl.name}"
|
371
|
+
if walrus:
|
372
|
+
res += " := "
|
373
|
+
else:
|
374
|
+
res += f": {self.visit(local_decl.qmod_type)} = "
|
375
|
+
res += f"{type_name}({param_args})\n"
|
376
|
+
return res
|
377
377
|
|
378
378
|
def _visit_operand_arg_decl(self, arg_decl: AnonPositionalArg) -> str:
|
379
379
|
if isinstance(arg_decl, AnonPortDeclaration):
|
@@ -481,6 +481,10 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
481
481
|
self._imports["invert"] = 1
|
482
482
|
return f"{self._indent}invert({self._visit_body(invert.body)})\n"
|
483
483
|
|
484
|
+
def visit_Block(self, block: Block) -> str:
|
485
|
+
self._imports["block"] = 1
|
486
|
+
return f"{self._indent}block({self._visit_body(block.statements)})\n"
|
487
|
+
|
484
488
|
def _visit_body(
|
485
489
|
self, body: StatementBlock, operand_arguments: Optional[list[str]] = None
|
486
490
|
) -> str:
|
@@ -493,10 +497,8 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
493
497
|
self._level += 1
|
494
498
|
for i, statement in enumerate(body):
|
495
499
|
if isinstance(statement, VariableDeclarationStatement):
|
496
|
-
|
497
|
-
|
498
|
-
)
|
499
|
-
if isinstance(statement, AmplitudeLoadingOperation):
|
500
|
+
code += self.visit_VariableDeclarationStatement(statement, walrus=True)
|
501
|
+
elif isinstance(statement, AmplitudeLoadingOperation):
|
500
502
|
code += self.visit_AmplitudeLoadingOperation(statement, in_lambda=True)
|
501
503
|
elif isinstance(statement, ArithmeticOperation):
|
502
504
|
code += self.visit_ArithmeticOperation(statement, in_lambda=True)
|
@@ -579,6 +581,18 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
579
581
|
def visit_OperandIdentifier(self, op: OperandIdentifier) -> str:
|
580
582
|
return str(op)
|
581
583
|
|
584
|
+
def visit_SetBoundsStatement(self, op: SetBoundsStatement) -> str:
|
585
|
+
self._imports["reset_bounds"] = 1
|
586
|
+
target = self.visit(op.target)
|
587
|
+
if op.lower_bound is None or op.upper_bound is None:
|
588
|
+
return f"{self._indent}reset_bounds({target})\n"
|
589
|
+
else:
|
590
|
+
lower_bound = self.visit(op.lower_bound)
|
591
|
+
upper_bound = self.visit(op.upper_bound)
|
592
|
+
return (
|
593
|
+
f"{self._indent}reset_bounds({target}, {lower_bound}, {upper_bound})\n"
|
594
|
+
)
|
595
|
+
|
582
596
|
@property
|
583
597
|
def _indent(self) -> str:
|
584
598
|
return " " * self._level
|