classiq 0.83.0__py3-none-any.whl → 0.84.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/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
- classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
- classiq/{model_expansions/evaluators → evaluators}/classical_expression.py +1 -1
- 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 +189 -43
- 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/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 +5 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
- classiq/interface/generator/functions/classical_type.py +2 -35
- classiq/interface/generator/functions/concrete_types.py +0 -3
- classiq/interface/generator/functions/type_modifier.py +0 -19
- classiq/interface/generator/generated_circuit_data.py +0 -8
- classiq/interface/generator/types/compilation_metadata.py +0 -3
- classiq/interface/ide/visual_model.py +6 -2
- classiq/interface/model/model.py +12 -7
- classiq/interface/model/port_declaration.py +2 -24
- 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 +42 -5
- classiq/model_expansions/interpreters/base_interpreter.py +3 -3
- classiq/model_expansions/quantum_operations/allocate.py +1 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +1 -1
- classiq/model_expansions/quantum_operations/bind.py +2 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
- classiq/model_expansions/quantum_operations/variable_decleration.py +1 -1
- 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/visitors/symbolic_param_inference.py +2 -3
- classiq/open_library/functions/__init__.py +3 -0
- 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/state_preparation.py +17 -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/structs.py +55 -3
- classiq/qmod/declaration_inferrer.py +3 -2
- classiq/qmod/native/pretty_printer.py +2 -6
- classiq/qmod/pretty_print/expression_to_python.py +2 -1
- classiq/qmod/pretty_print/pretty_printer.py +1 -6
- classiq/qmod/python_classical_type.py +12 -5
- classiq/qmod/qmod_constant.py +2 -5
- classiq/qmod/qmod_parameter.py +2 -5
- classiq/qmod/qmod_variable.py +56 -15
- classiq/qmod/quantum_expandable.py +4 -2
- classiq/qmod/quantum_function.py +7 -2
- classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -9
- classiq/qmod/utilities.py +0 -2
- classiq/qmod/write_qmod.py +1 -1
- {classiq-0.83.0.dist-info → classiq-0.84.0.dist-info}/METADATA +4 -1
- {classiq-0.83.0.dist-info → classiq-0.84.0.dist-info}/RECORD +82 -73
- /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.84.0.dist-info}/WHEEL +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
from classiq.open_library.functions.qft_functions import qft, qft_no_swap
|
2
2
|
from classiq.qmod.builtins.classical_functions import qft_const_adder_phase
|
3
|
+
from classiq.qmod.builtins.functions.allocation import free
|
3
4
|
from classiq.qmod.builtins.functions.standard_gates import PHASE, SWAP, X
|
4
5
|
from classiq.qmod.builtins.operations import (
|
5
6
|
allocate,
|
@@ -11,7 +12,7 @@ from classiq.qmod.builtins.operations import (
|
|
11
12
|
)
|
12
13
|
from classiq.qmod.cparam import CInt
|
13
14
|
from classiq.qmod.qfunc import qfunc
|
14
|
-
from classiq.qmod.qmod_variable import QArray, QBit
|
15
|
+
from classiq.qmod.qmod_variable import Const, Permutable, QArray, QBit
|
15
16
|
from classiq.qmod.symbolic import min, mod_inverse
|
16
17
|
|
17
18
|
|
@@ -50,8 +51,10 @@ def qft_space_add_const(value: CInt, phi_b: QArray[QBit]) -> None:
|
|
50
51
|
)
|
51
52
|
|
52
53
|
|
53
|
-
@qfunc
|
54
|
-
def cc_modular_add(
|
54
|
+
@qfunc(unchecked=["phi_b"])
|
55
|
+
def cc_modular_add(
|
56
|
+
n: CInt, a: CInt, phi_b: Permutable[QArray[QBit]], c1: Const[QBit], c2: Const[QBit]
|
57
|
+
) -> None:
|
55
58
|
"""
|
56
59
|
[Qmod Classiq-library function]
|
57
60
|
|
@@ -69,11 +72,9 @@ def cc_modular_add(n: CInt, a: CInt, phi_b: QArray[QBit], c1: QBit, c2: QBit) ->
|
|
69
72
|
ctrl: QArray[QBit] = QArray()
|
70
73
|
aux = QBit()
|
71
74
|
|
75
|
+
allocate(aux)
|
72
76
|
within_apply(
|
73
|
-
lambda: (
|
74
|
-
allocate(aux),
|
75
|
-
bind([c1, c2], ctrl),
|
76
|
-
),
|
77
|
+
lambda: bind([c1, c2], ctrl),
|
77
78
|
lambda: (
|
78
79
|
control(ctrl, lambda: qft_space_add_const(a, phi_b)),
|
79
80
|
invert(lambda: qft_space_add_const(n, phi_b)),
|
@@ -87,11 +88,16 @@ def cc_modular_add(n: CInt, a: CInt, phi_b: QArray[QBit], c1: QBit, c2: QBit) ->
|
|
87
88
|
),
|
88
89
|
),
|
89
90
|
)
|
91
|
+
free(aux)
|
90
92
|
|
91
93
|
|
92
|
-
@qfunc
|
94
|
+
@qfunc(unchecked=["b"])
|
93
95
|
def c_modular_multiply(
|
94
|
-
n: CInt,
|
96
|
+
n: CInt,
|
97
|
+
a: CInt,
|
98
|
+
b: Permutable[QArray[QBit]],
|
99
|
+
x: Const[QArray[QBit]],
|
100
|
+
ctrl: Const[QBit],
|
95
101
|
) -> None:
|
96
102
|
"""
|
97
103
|
[Qmod Classiq-library function]
|
@@ -118,7 +124,7 @@ def c_modular_multiply(
|
|
118
124
|
|
119
125
|
|
120
126
|
@qfunc
|
121
|
-
def multiswap(x: QArray[QBit], y: QArray[QBit]) -> None:
|
127
|
+
def multiswap(x: Permutable[QArray[QBit]], y: Permutable[QArray[QBit]]) -> None:
|
122
128
|
"""
|
123
129
|
[Qmod Classiq-library function]
|
124
130
|
|
@@ -150,16 +156,12 @@ def inplace_c_modular_multiply(n: CInt, a: CInt, x: QArray[QBit], ctrl: QBit) ->
|
|
150
156
|
x: The quantum factor.
|
151
157
|
ctrl: The control bit.
|
152
158
|
"""
|
153
|
-
b: QArray[QBit] = QArray()
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
control(ctrl, lambda: multiswap(x, b)),
|
160
|
-
invert(lambda: c_modular_multiply(n, mod_inverse(a, n), b, x, ctrl)),
|
161
|
-
),
|
162
|
-
)
|
159
|
+
b: QArray[QBit] = QArray(length=x.len + 1)
|
160
|
+
allocate(b)
|
161
|
+
c_modular_multiply(n, a, b, x, ctrl)
|
162
|
+
control(ctrl, lambda: multiswap(x, b))
|
163
|
+
invert(lambda: c_modular_multiply(n, mod_inverse(a, n), b, x, ctrl))
|
164
|
+
free(b)
|
163
165
|
|
164
166
|
|
165
167
|
@qfunc
|
@@ -483,3 +483,20 @@ def prepare_dicke_state(k: int, qvar: QArray[QBit]) -> None:
|
|
483
483
|
if k > 0:
|
484
484
|
apply_to_all(X, qvar[0:k])
|
485
485
|
prepare_dicke_state_unary_input(k, qvar)
|
486
|
+
|
487
|
+
|
488
|
+
@qfunc
|
489
|
+
def prepare_basis_state(state: list[bool], arr: Output[QArray]) -> None:
|
490
|
+
"""
|
491
|
+
[Qmod Classiq-library function]
|
492
|
+
|
493
|
+
Initializes a quantum array in the specified basis state.
|
494
|
+
|
495
|
+
Args:
|
496
|
+
values: The desired basis state, given as a list of boolean values for each qubit.
|
497
|
+
arr: The quantum array to prepare.
|
498
|
+
"""
|
499
|
+
allocate(len(state), arr)
|
500
|
+
for idx, value in enumerate(state):
|
501
|
+
if value:
|
502
|
+
X(arr[idx])
|
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]],
|
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
|
)
|
@@ -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,
|
@@ -85,11 +85,10 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
85
85
|
VariableDeclarationStatement,
|
86
86
|
)
|
87
87
|
from classiq.interface.model.within_apply_operation import WithinApply
|
88
|
+
from classiq.interface.pretty_print.expression_to_qmod import transform_expression
|
88
89
|
|
89
90
|
from classiq.open_library.functions import OPEN_LIBRARY_FUNCTIONS
|
90
|
-
from classiq.qmod.native.expression_to_qmod import transform_expression
|
91
91
|
from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
|
92
|
-
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
93
92
|
|
94
93
|
|
95
94
|
class DSLPrettyPrinter(ModelVisitor):
|
@@ -248,9 +247,6 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
248
247
|
def visit_Bool(self, ctbool: Bool) -> str:
|
249
248
|
return "bool"
|
250
249
|
|
251
|
-
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
252
|
-
return f"{self.visit(ctlist.element_type)}[]"
|
253
|
-
|
254
250
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
255
251
|
element_type = self.visit(ctarray.element_type)
|
256
252
|
if ctarray.length is not None:
|
@@ -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,
|
@@ -88,7 +88,6 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
88
88
|
import classiq
|
89
89
|
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
90
90
|
from classiq.qmod.pretty_print.expression_to_python import transform_expression
|
91
|
-
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
92
91
|
|
93
92
|
|
94
93
|
class VariableDeclarationAssignment(Visitor):
|
@@ -338,10 +337,6 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
338
337
|
self._imports["CBool"] = 1
|
339
338
|
return "CBool"
|
340
339
|
|
341
|
-
def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
|
342
|
-
self._imports["CArray"] = 1
|
343
|
-
return f"CArray[{self.visit(ctlist.element_type)}]"
|
344
|
-
|
345
340
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
346
341
|
self._imports["CArray"] = 1
|
347
342
|
element_type = self.visit(ctarray.element_type)
|
@@ -31,7 +31,9 @@ CARRAY_ERROR_MESSAGE = (
|
|
31
31
|
|
32
32
|
|
33
33
|
class PythonClassicalType:
|
34
|
-
def convert(
|
34
|
+
def convert(
|
35
|
+
self, py_type: type, nested: bool = False
|
36
|
+
) -> Optional[ConcreteClassicalType]:
|
35
37
|
if py_type is int:
|
36
38
|
return Integer().set_generative()
|
37
39
|
elif py_type is CInt:
|
@@ -45,16 +47,18 @@ class PythonClassicalType:
|
|
45
47
|
elif py_type is CBool:
|
46
48
|
return Bool()
|
47
49
|
elif get_origin(py_type) is list:
|
48
|
-
element_type = self.convert(get_args(py_type)[0])
|
50
|
+
element_type = self.convert(get_args(py_type)[0], nested=True)
|
49
51
|
if element_type is not None:
|
50
52
|
return ClassicalArray(element_type=element_type).set_generative()
|
51
53
|
elif get_origin(py_type) is CArray:
|
52
54
|
array_args = version_portable_get_args(py_type)
|
53
55
|
if len(array_args) == 1:
|
54
|
-
return ClassicalArray(
|
56
|
+
return ClassicalArray(
|
57
|
+
element_type=self.convert(array_args[0], nested=True)
|
58
|
+
)
|
55
59
|
elif len(array_args) == 2:
|
56
60
|
return ClassicalArray(
|
57
|
-
element_type=self.convert(array_args[0]),
|
61
|
+
element_type=self.convert(array_args[0], nested=True),
|
58
62
|
length=Expression(expr=get_type_hint_expr(array_args[1])),
|
59
63
|
)
|
60
64
|
raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
|
@@ -62,7 +66,10 @@ class PythonClassicalType:
|
|
62
66
|
return self.register_struct(py_type)
|
63
67
|
elif inspect.isclass(py_type) and isinstance(py_type, EnumMeta):
|
64
68
|
self.register_enum(py_type)
|
65
|
-
|
69
|
+
enum_type = Enum(name=py_type.__name__)
|
70
|
+
if not nested:
|
71
|
+
enum_type.set_generative()
|
72
|
+
return enum_type
|
66
73
|
elif py_type in (CArray, list):
|
67
74
|
raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
|
68
75
|
return None
|
classiq/qmod/qmod_constant.py
CHANGED
@@ -5,10 +5,7 @@ from typing import TYPE_CHECKING, Any, Optional, cast, get_origin
|
|
5
5
|
from classiq.interface.exceptions import ClassiqError, ClassiqValueError
|
6
6
|
from classiq.interface.generator.constant import Constant
|
7
7
|
from classiq.interface.generator.expressions.expression import Expression
|
8
|
-
from classiq.interface.generator.functions.classical_type import
|
9
|
-
ClassicalArray,
|
10
|
-
ClassicalList,
|
11
|
-
)
|
8
|
+
from classiq.interface.generator.functions.classical_type import ClassicalArray
|
12
9
|
|
13
10
|
from classiq.qmod.cparam import CArray, CParamScalar
|
14
11
|
from classiq.qmod.declaration_inferrer import python_type_to_qmod
|
@@ -118,7 +115,7 @@ class QConstant(SymbolicExpr):
|
|
118
115
|
if qmod_type is None:
|
119
116
|
raise ClassiqError("Invalid QMOD type")
|
120
117
|
|
121
|
-
if not isinstance(qmod_type,
|
118
|
+
if not isinstance(qmod_type, ClassicalArray):
|
122
119
|
raise ClassiqError("Invalid subscript to non-list constant")
|
123
120
|
|
124
121
|
return CParamList(
|
classiq/qmod/qmod_parameter.py
CHANGED
@@ -4,7 +4,6 @@ from classiq.interface.exceptions import ClassiqInternalError, ClassiqValueError
|
|
4
4
|
from classiq.interface.generator.functions.classical_type import (
|
5
5
|
Bool,
|
6
6
|
ClassicalArray,
|
7
|
-
ClassicalList,
|
8
7
|
ClassicalTuple,
|
9
8
|
ClassicalType,
|
10
9
|
Integer,
|
@@ -42,7 +41,7 @@ class CParamList(CParam):
|
|
42
41
|
def __init__(
|
43
42
|
self,
|
44
43
|
expr: str,
|
45
|
-
list_type: Union[
|
44
|
+
list_type: Union[ClassicalArray, ClassicalTuple],
|
46
45
|
qmodule: ModelStateContainer,
|
47
46
|
) -> None:
|
48
47
|
super().__init__(expr)
|
@@ -149,7 +148,7 @@ def create_param(
|
|
149
148
|
decl = ctype.classical_struct_decl
|
150
149
|
ctype = Struct(name=ctype.name)
|
151
150
|
ctype.set_classical_struct_decl(decl)
|
152
|
-
if isinstance(ctype, (
|
151
|
+
if isinstance(ctype, (ClassicalArray, ClassicalTuple)):
|
153
152
|
return CParamList(expr_str, ctype, qmodule=qmodule)
|
154
153
|
elif isinstance(ctype, Struct):
|
155
154
|
return CParamStruct(expr_str, ctype, qmodule=qmodule)
|
@@ -164,8 +163,6 @@ def get_qmod_type(ctype: ClassicalType) -> type:
|
|
164
163
|
return CReal
|
165
164
|
elif isinstance(ctype, Bool):
|
166
165
|
return CBool
|
167
|
-
elif isinstance(ctype, ClassicalList):
|
168
|
-
return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
|
169
166
|
elif isinstance(ctype, ClassicalArray):
|
170
167
|
if ctype.length is None:
|
171
168
|
return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
|
classiq/qmod/qmod_variable.py
CHANGED
@@ -34,19 +34,20 @@ from classiq.interface.generator.expressions.proxies.quantum.qmod_qarray_proxy i
|
|
34
34
|
ILLEGAL_SLICE_MSG,
|
35
35
|
ILLEGAL_SLICING_STEP_MSG,
|
36
36
|
)
|
37
|
+
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
37
38
|
from classiq.interface.generator.functions.port_declaration import (
|
38
39
|
PortDeclarationDirection,
|
39
40
|
)
|
40
41
|
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
41
|
-
from classiq.interface.generator.functions.type_name import TypeName
|
42
|
+
from classiq.interface.generator.functions.type_name import Struct, TypeName
|
42
43
|
from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
|
44
|
+
from classiq.interface.helpers.classproperty import classproperty
|
43
45
|
from classiq.interface.model.handle_binding import (
|
44
46
|
FieldHandleBinding,
|
45
47
|
HandleBinding,
|
46
48
|
SlicedHandleBinding,
|
47
49
|
SubscriptHandleBinding,
|
48
50
|
)
|
49
|
-
from classiq.interface.model.port_declaration import AnonPortDeclaration
|
50
51
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
51
52
|
AmplitudeLoadingOperation,
|
52
53
|
)
|
@@ -136,7 +137,7 @@ class QVar(Symbolic):
|
|
136
137
|
return self._base_handle
|
137
138
|
|
138
139
|
@abc.abstractmethod
|
139
|
-
def get_qmod_type(self) ->
|
140
|
+
def get_qmod_type(self) -> ConcreteQuantumType:
|
140
141
|
raise NotImplementedError()
|
141
142
|
|
142
143
|
@classmethod
|
@@ -164,6 +165,14 @@ class QVar(Symbolic):
|
|
164
165
|
return self.get_qmod_type().type_name
|
165
166
|
|
166
167
|
|
168
|
+
class QmodExpressionCreator(Protocol):
|
169
|
+
"""
|
170
|
+
A callable that creates a Qmod expression from the provided QVars.
|
171
|
+
"""
|
172
|
+
|
173
|
+
def __call__(self, **kwargs: QVar) -> SymbolicExpr: ...
|
174
|
+
|
175
|
+
|
167
176
|
_Q = TypeVar("_Q", bound=QVar)
|
168
177
|
Output = Annotated[_Q, PortDeclarationDirection.Output]
|
169
178
|
Input = Annotated[_Q, PortDeclarationDirection.Input]
|
@@ -273,7 +282,7 @@ class QBit(QScalar):
|
|
273
282
|
) -> "QBit":
|
274
283
|
return QBit(origin, _expr_str=expr_str)
|
275
284
|
|
276
|
-
def get_qmod_type(self) ->
|
285
|
+
def get_qmod_type(self) -> ConcreteQuantumType:
|
277
286
|
return QuantumBit()
|
278
287
|
|
279
288
|
|
@@ -329,7 +338,7 @@ class QNum(Generic[_P], QScalar):
|
|
329
338
|
) -> "QNum":
|
330
339
|
return QNum(origin, *_get_qnum_attributes(type_hint), _expr_str=expr_str)
|
331
340
|
|
332
|
-
def get_qmod_type(self) ->
|
341
|
+
def get_qmod_type(self) -> ConcreteQuantumType:
|
333
342
|
return QuantumNumeric(
|
334
343
|
size=self._size,
|
335
344
|
is_signed=self._is_signed,
|
@@ -498,8 +507,15 @@ class QStruct(QVar):
|
|
498
507
|
setattr(self, field_name, var)
|
499
508
|
super().__init__(name, expr_str=_expr_str)
|
500
509
|
|
501
|
-
def get_qmod_type(self) ->
|
502
|
-
|
510
|
+
def get_qmod_type(self) -> ConcreteQuantumType:
|
511
|
+
classical_type = Struct(name=self._struct_name)
|
512
|
+
classical_type.set_fields(
|
513
|
+
{
|
514
|
+
field_name: field_var.get_qmod_type()
|
515
|
+
for field_name, field_var in self._fields.items()
|
516
|
+
}
|
517
|
+
)
|
518
|
+
return classical_type
|
503
519
|
|
504
520
|
@classmethod
|
505
521
|
def to_qvar(
|
@@ -529,9 +545,23 @@ class QStruct(QVar):
|
|
529
545
|
_expr_str=expr_str,
|
530
546
|
)
|
531
547
|
|
548
|
+
@classproperty
|
549
|
+
def num_qubits(cls) -> int: # noqa: N805
|
550
|
+
"""
|
551
|
+
The total number of qubits in this quantum struct.
|
552
|
+
Raises an error if the struct doesn't have a fixed size.
|
553
|
+
"""
|
554
|
+
qvar = cls.to_qvar(HandleBinding(name="dummy"), type_hint=cls, expr_str=None)
|
555
|
+
quantum_type = qvar.get_qmod_type()
|
556
|
+
if not quantum_type.has_size_in_bits:
|
557
|
+
raise ClassiqValueError(
|
558
|
+
f"Could not infer the size of struct {qvar._struct_name!r}"
|
559
|
+
)
|
560
|
+
return quantum_type.size_in_bits
|
561
|
+
|
532
562
|
|
533
|
-
def
|
534
|
-
return _create_qvar_for_qtype(
|
563
|
+
def create_qvar_from_quantum_type(quantum_type: ConcreteQuantumType, name: str) -> QVar:
|
564
|
+
return _create_qvar_for_qtype(quantum_type, HandleBinding(name=name))
|
535
565
|
|
536
566
|
|
537
567
|
def _create_qvar_for_qtype(
|
@@ -689,17 +719,27 @@ def _get_quantum_bit_vector(type_hint: type[QArray]) -> QuantumBitvector:
|
|
689
719
|
return QuantumBitvector(element_type=element_type, length=length_expr)
|
690
720
|
|
691
721
|
|
692
|
-
def _get_quantum_struct(type_hint: type[QStruct]) ->
|
693
|
-
_register_qstruct(type_hint, qmodule=QMODULE)
|
694
|
-
|
722
|
+
def _get_quantum_struct(type_hint: type[QStruct]) -> Struct:
|
723
|
+
decl = _register_qstruct(type_hint, qmodule=QMODULE)
|
724
|
+
classical_type = Struct(name=type_hint.__name__)
|
725
|
+
if decl is not None:
|
726
|
+
classical_type.set_fields(
|
727
|
+
{
|
728
|
+
field_name: field_type.model_copy(deep=True)
|
729
|
+
for field_name, field_type in decl.fields.items()
|
730
|
+
}
|
731
|
+
)
|
732
|
+
return classical_type
|
695
733
|
|
696
734
|
|
697
735
|
def _register_qstruct(
|
698
736
|
type_hint: type[QStruct], *, qmodule: ModelStateContainer
|
699
|
-
) ->
|
737
|
+
) -> Optional[QStructDeclaration]:
|
700
738
|
struct_name = type_hint.__name__
|
701
|
-
if type_hint is QStruct
|
702
|
-
return
|
739
|
+
if type_hint is QStruct:
|
740
|
+
return None
|
741
|
+
if struct_name in qmodule.qstruct_decls:
|
742
|
+
return qmodule.qstruct_decls[struct_name]
|
703
743
|
|
704
744
|
# temp assignment for recursive qstruct definitions
|
705
745
|
qmodule.qstruct_decls[struct_name] = QStructDeclaration(name=struct_name)
|
@@ -714,6 +754,7 @@ def _register_qstruct(
|
|
714
754
|
qmodule.qstruct_decls[struct_name] = struct_decl
|
715
755
|
QStructAnnotator().visit(struct_decl)
|
716
756
|
validate_qstruct(struct_decl)
|
757
|
+
return struct_decl
|
717
758
|
|
718
759
|
|
719
760
|
def _validate_fields(type_hint: type[QStruct]) -> None:
|
@@ -68,7 +68,7 @@ from classiq.qmod.qmod_parameter import (
|
|
68
68
|
)
|
69
69
|
from classiq.qmod.qmod_variable import (
|
70
70
|
QVar,
|
71
|
-
|
71
|
+
create_qvar_from_quantum_type,
|
72
72
|
)
|
73
73
|
from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
|
74
74
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
@@ -163,7 +163,9 @@ class QExpandable(QCallable, QExpandableInterface, ABC):
|
|
163
163
|
create_param(actual_name, arg.classical_type, self._qmodule)
|
164
164
|
)
|
165
165
|
elif isinstance(arg, AnonPortDeclaration):
|
166
|
-
result.append(
|
166
|
+
result.append(
|
167
|
+
create_qvar_from_quantum_type(arg.quantum_type, actual_name)
|
168
|
+
)
|
167
169
|
else:
|
168
170
|
assert isinstance(arg, AnonQuantumOperandDeclaration)
|
169
171
|
result.append(QTerminalCallable(arg, idx))
|