classiq 0.61.0__py3-none-any.whl → 0.63.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/__init__.py +3 -0
- classiq/_internals/api_wrapper.py +6 -26
- classiq/_internals/client.py +1 -9
- classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -8
- classiq/applications/combinatorial_helpers/optimization_model.py +13 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +143 -13
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +58 -23
- classiq/applications/grover/grover_model_constructor.py +1 -1
- classiq/applications/libraries/qmci_library.py +2 -1
- classiq/execution/execution_session.py +66 -96
- classiq/execution/jobs.py +12 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +26 -5
- classiq/interface/backend/pydantic_backend.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +3 -1
- classiq/interface/chemistry/operator.py +0 -204
- classiq/interface/execution/primitives.py +1 -0
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/generated_circuit_data.py +22 -7
- classiq/interface/generator/model/model.py +3 -0
- classiq/interface/generator/model/preferences/preferences.py +14 -1
- classiq/interface/generator/quantum_function_call.py +4 -2
- classiq/interface/generator/types/compilation_metadata.py +2 -1
- classiq/interface/model/handle_binding.py +50 -5
- classiq/interface/model/quantum_type.py +16 -0
- classiq/interface/server/routes.py +1 -3
- classiq/model_expansions/capturing/captured_vars.py +114 -28
- classiq/model_expansions/closure.py +25 -65
- classiq/model_expansions/function_builder.py +19 -9
- classiq/model_expansions/generative_functions.py +16 -2
- classiq/model_expansions/interpreter.py +110 -66
- classiq/model_expansions/model_tables.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +83 -20
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +3 -10
- classiq/model_expansions/quantum_operations/emitter.py +3 -4
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +1 -2
- classiq/model_expansions/quantum_operations/quantum_function_call.py +1 -1
- classiq/model_expansions/quantum_operations/repeat.py +4 -3
- classiq/model_expansions/quantum_operations/shallow_emitter.py +9 -3
- classiq/model_expansions/scope.py +9 -13
- classiq/model_expansions/scope_initialization.py +34 -25
- classiq/model_expansions/transformers/var_splitter.py +57 -7
- classiq/open_library/__init__.py +4 -0
- classiq/open_library/functions/__init__.py +130 -0
- classiq/{qmod/builtins → open_library}/functions/amplitude_estimation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/discrete_sine_cosine_transform.py +6 -4
- classiq/{qmod/builtins → open_library}/functions/grover.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/linear_pauli_rotation.py +1 -1
- classiq/{qmod/builtins → open_library}/functions/modular_exponentiation.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/qpe.py +2 -2
- classiq/{qmod/builtins → open_library}/functions/state_preparation.py +6 -149
- classiq/{qmod/builtins → open_library}/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +81 -0
- classiq/{qmod/builtins → open_library}/functions/variational.py +1 -1
- classiq/qmod/builtins/functions/__init__.py +4 -130
- classiq/qmod/builtins/functions/allocation.py +150 -0
- classiq/qmod/builtins/functions/arithmetic.py +0 -34
- classiq/qmod/builtins/functions/operators.py +0 -6
- classiq/qmod/builtins/operations.py +19 -80
- classiq/qmod/create_model_function.py +8 -162
- classiq/qmod/generative.py +0 -16
- classiq/qmod/model_state_container.py +7 -0
- classiq/qmod/native/pretty_printer.py +10 -11
- classiq/qmod/pretty_print/pretty_printer.py +1 -1
- classiq/qmod/python_classical_type.py +1 -5
- classiq/qmod/qfunc.py +11 -12
- classiq/qmod/qmod_variable.py +1 -3
- classiq/qmod/quantum_expandable.py +23 -1
- classiq/qmod/quantum_function.py +69 -7
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/METADATA +2 -1
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/RECORD +82 -78
- classiq/qmod/builtins/functions/utility_functions.py +0 -43
- /classiq/{qmod/builtins → open_library}/functions/hea.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qaoa_penalty.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qft_functions.py +0 -0
- /classiq/{qmod/builtins → open_library}/functions/qsvt.py +0 -0
- {classiq-0.61.0.dist-info → classiq-0.63.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
from typing import Literal
|
2
|
+
|
3
|
+
from classiq.qmod.qfunc import qfunc
|
4
|
+
from classiq.qmod.qmod_parameter import CArray, CInt, CReal
|
5
|
+
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit
|
6
|
+
|
7
|
+
|
8
|
+
@qfunc(external=True)
|
9
|
+
def allocate(
|
10
|
+
num_qubits: CInt, out: Output[QArray[QBit, Literal["num_qubits"]]]
|
11
|
+
) -> None:
|
12
|
+
"""
|
13
|
+
[Qmod core-library function]
|
14
|
+
|
15
|
+
Allocates the specified number of qubits to a given quantum variable and initializes
|
16
|
+
them in the zero state:
|
17
|
+
|
18
|
+
$$
|
19
|
+
\\left|\\text{out}\\right\\rangle = \\left|0\\right\\rangle^{\\otimes \\text{num_qubits}}
|
20
|
+
$$
|
21
|
+
|
22
|
+
Args:
|
23
|
+
num_qubits: The number of qubits to allocate. Must be a positive integer.
|
24
|
+
out: The quantum variable that will receive the allocated qubits. Must be uninitialized before allocation.
|
25
|
+
|
26
|
+
Notes:
|
27
|
+
1. If the output variable has been declared with a specific number of qubits, the number of qubits allocated must match the declared number.
|
28
|
+
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
29
|
+
"""
|
30
|
+
pass
|
31
|
+
|
32
|
+
|
33
|
+
@qfunc(external=True)
|
34
|
+
def free(in_: Input[QArray[QBit]]) -> None:
|
35
|
+
"""
|
36
|
+
[Qmod core-library function]
|
37
|
+
|
38
|
+
Releases the qubits allocated to a quantum variable, allowing them to be reused.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
in_: The quantum variable that will be freed. Must be initialized before.
|
42
|
+
|
43
|
+
Note:
|
44
|
+
This operation does not uncompute the qubits. It is the responsibility of the user to ensure that the qubits are at the zero state before freeing them.
|
45
|
+
"""
|
46
|
+
pass
|
47
|
+
|
48
|
+
|
49
|
+
@qfunc(external=True)
|
50
|
+
def prepare_state(
|
51
|
+
probabilities: CArray[CReal],
|
52
|
+
bound: CReal,
|
53
|
+
out: Output[QArray[QBit, Literal["log(get_field(probabilities, 'len'), 2)"]]],
|
54
|
+
) -> None:
|
55
|
+
"""
|
56
|
+
[Qmod core-library function]
|
57
|
+
|
58
|
+
Initializes a quantum variable in a state corresponding to a given probability distribution:
|
59
|
+
|
60
|
+
$$
|
61
|
+
\\left|\\text{out}\\right\\rangle = \\sum_{i=0}^{\\text{len(probabilities)}-1} \\sqrt{\\text{probabilities}[i]} \\left|i\\right\\rangle
|
62
|
+
$$
|
63
|
+
|
64
|
+
with $i = 0, 1, 2, ..., \\text{len(amplitudes)}-1$ corresponding to computational basis states.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
probabilities: The probability distribution to initialize the quantum variable. Must be a valid probability distribution, i.e., a list of non-negative real numbers that sum to 1. Must have a valid length (a power of 2).
|
68
|
+
bound: An error bound, expressed as the $L^{2}$ norm between the expected and actual distributions. A larger bound can reduce the circuit size at the expense of accuracy. Must be a positive real number.
|
69
|
+
out: The quantum variable that will receive the initialized state. Must be uninitialized.
|
70
|
+
|
71
|
+
Notes:
|
72
|
+
1. If the output variable has been declared with a specific number of qubits, the number of qubits formed by the distribution must match the declared number.
|
73
|
+
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
74
|
+
"""
|
75
|
+
pass
|
76
|
+
|
77
|
+
|
78
|
+
@qfunc(external=True)
|
79
|
+
def prepare_amplitudes(
|
80
|
+
amplitudes: CArray[CReal],
|
81
|
+
bound: CReal,
|
82
|
+
out: Output[QArray[QBit, Literal["log(get_field(amplitudes, 'len'), 2)"]]],
|
83
|
+
) -> None:
|
84
|
+
"""
|
85
|
+
[Qmod core-library function]
|
86
|
+
|
87
|
+
Initializes a quantum variable in a state corresponding to the given amplitudes:
|
88
|
+
|
89
|
+
$$
|
90
|
+
\\left|\\text{out}\\right\\rangle = \\sum_{i=0}^{\\text{len(amplitudes)}-1} \\text{amplitudes}[i] \\left|i\\right\\rangle
|
91
|
+
$$
|
92
|
+
|
93
|
+
with $i = 0, 1, 2, ..., \\text{len(amplitudes)}-1$ corresponding to computational basis states.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
amplitudes: The amplitudes to initialize the quantum variable. Must be a valid real quantum state vector, i.e., the sum of squares should be 1. Must have a valid length (a power of 2).
|
97
|
+
bound: An error bound, expressed as the $L^{2}$ norm between the expected and actual distributions. A larger bound can reduce the circuit size at the expense of accuracy. Must be a positive real number.
|
98
|
+
out: The quantum variable that will receive the initialized state. Must be uninitialized.
|
99
|
+
|
100
|
+
Notes:
|
101
|
+
1. If the output variable has been declared with a specific number of qubits, the number of qubits formed by the distribution must match the declared number.
|
102
|
+
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
103
|
+
"""
|
104
|
+
pass
|
105
|
+
|
106
|
+
|
107
|
+
@qfunc(external=True)
|
108
|
+
def inplace_prepare_state(
|
109
|
+
probabilities: CArray[CReal],
|
110
|
+
bound: CReal,
|
111
|
+
target: QArray[QBit, Literal["log(get_field(probabilities, 'len'), 2)"]],
|
112
|
+
) -> None:
|
113
|
+
"""
|
114
|
+
[Qmod core-library function]
|
115
|
+
|
116
|
+
Transforms a given quantum variable in the state |0> to the state per the specified probability distribution
|
117
|
+
(similar to `prepare_state` but preformed on an initialized variable).
|
118
|
+
|
119
|
+
Args:
|
120
|
+
probabilities: The probability distribution corresponding to the quantum variable state. Must be a valid probability distribution, i.e., a list of non-negative real numbers that sum to 1. Must have a valid length (a power of 2).
|
121
|
+
bound: An error bound, expressed as the $L^{2}$ norm between the expected and actual distributions. A larger bound can reduce the circuit size at the expense of accuracy. Must be a positive real number.
|
122
|
+
target: The quantum variable to act upon.
|
123
|
+
|
124
|
+
This is useful as part of quantum building blocks like the Grover diffuser operator, $\\left|\\psi\\right\\rangle\\left\\langle\\psi\\right| \\left( 2\\left|0\\right\\rangle\\left\\langle0\\right| - \\mathcal{I} \\right)$, where the output state of the oracle is reflected about this state.
|
125
|
+
|
126
|
+
"""
|
127
|
+
pass
|
128
|
+
|
129
|
+
|
130
|
+
@qfunc(external=True)
|
131
|
+
def inplace_prepare_amplitudes(
|
132
|
+
amplitudes: CArray[CReal],
|
133
|
+
bound: CReal,
|
134
|
+
target: QArray[QBit, Literal["log(get_field(amplitudes, 'len'), 2)"]],
|
135
|
+
) -> None:
|
136
|
+
"""
|
137
|
+
[Qmod core-library function]
|
138
|
+
|
139
|
+
Transforms a given quantum variable in the state |0> to the state per the specified amplitudes
|
140
|
+
(similar to `prepare_amplitudes` but preformed on an initialized variable).
|
141
|
+
|
142
|
+
Args:
|
143
|
+
amplitudes: The amplitudes to initialize the quantum variable. Must be a valid real quantum state vector, i.e., the sum of squares should be 1. Must have a valid length (a power of 2).
|
144
|
+
bound: An error bound, expressed as the $L^{2}$ norm between the expected and actual distributions. A larger bound can reduce the circuit size at the expense of accuracy. Must be a positive real number.
|
145
|
+
target: The quantum variable to act upon.
|
146
|
+
|
147
|
+
This is useful as part of quantum building blocks like the Grover diffuser operator, $\\left|\\psi\\right\\rangle\\left\\langle\\psi\\right| \\left( 2\\left|0\\right\\rangle\\left\\langle0\\right| - \\mathcal{I} \\right)$, where the output state of the oracle is reflected about this state.
|
148
|
+
|
149
|
+
"""
|
150
|
+
pass
|
@@ -1,13 +1,8 @@
|
|
1
1
|
from typing import Literal
|
2
2
|
|
3
|
-
from classiq.qmod.builtins.functions.qft_functions import qft
|
4
|
-
from classiq.qmod.builtins.functions.standard_gates import PHASE
|
5
|
-
from classiq.qmod.builtins.operations import bind, repeat, within_apply
|
6
|
-
from classiq.qmod.cparam import CInt
|
7
3
|
from classiq.qmod.qfunc import qfunc
|
8
4
|
from classiq.qmod.qmod_parameter import CArray, CReal
|
9
5
|
from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
|
10
|
-
from classiq.qmod.symbolic import pi
|
11
6
|
|
12
7
|
|
13
8
|
@qfunc(external=True)
|
@@ -58,32 +53,3 @@ def integer_xor(left: QArray[QBit], right: QArray[QBit]) -> None:
|
|
58
53
|
@qfunc(external=True)
|
59
54
|
def real_xor_constant(left: CReal, right: QNum) -> None:
|
60
55
|
pass
|
61
|
-
|
62
|
-
|
63
|
-
@qfunc
|
64
|
-
def modular_increment(a: CInt, x: QNum) -> None:
|
65
|
-
"""
|
66
|
-
[Qmod Classiq-library function]
|
67
|
-
|
68
|
-
Adds $a$ to $x$ modulo the range of $x$, assumed that $x$ is a non-negative integer and $a$ is an integer.
|
69
|
-
Mathematically it is described as:
|
70
|
-
|
71
|
-
$$
|
72
|
-
x = (x+a)\\ \\mod \\ 2^{x.size}-1
|
73
|
-
$$
|
74
|
-
|
75
|
-
Args:
|
76
|
-
a: A classical integer to be added to x.
|
77
|
-
x: A quantum number that is assumed to be non-negative integer.
|
78
|
-
|
79
|
-
"""
|
80
|
-
array_cast: QArray = QArray("array_cast")
|
81
|
-
within_apply(
|
82
|
-
lambda: ( # type:ignore[arg-type]
|
83
|
-
bind(x, array_cast), # type:ignore[func-returns-value]
|
84
|
-
qft(array_cast),
|
85
|
-
),
|
86
|
-
lambda: repeat(
|
87
|
-
x.size, lambda i: PHASE(a * 2 * pi * 2**i / (2**x.size), array_cast[i])
|
88
|
-
),
|
89
|
-
)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from classiq.qmod.cparam import CInt
|
2
1
|
from classiq.qmod.qfunc import qfunc
|
3
2
|
from classiq.qmod.quantum_callable import QCallable, QCallableList
|
4
3
|
|
@@ -15,8 +14,3 @@ def apply(
|
|
15
14
|
operand: QCallable,
|
16
15
|
) -> None:
|
17
16
|
pass
|
18
|
-
|
19
|
-
|
20
|
-
@qfunc
|
21
|
-
def switch(selector: CInt, cases: QCallableList) -> None:
|
22
|
-
cases[selector]()
|
@@ -1,16 +1,12 @@
|
|
1
1
|
import inspect
|
2
2
|
import sys
|
3
|
-
import warnings
|
4
3
|
from collections.abc import Mapping
|
5
4
|
from types import FrameType
|
6
5
|
from typing import (
|
7
|
-
TYPE_CHECKING,
|
8
6
|
Any,
|
9
7
|
Callable,
|
10
8
|
Final,
|
11
|
-
Optional,
|
12
9
|
Union,
|
13
|
-
overload,
|
14
10
|
)
|
15
11
|
|
16
12
|
from classiq.interface.exceptions import ClassiqValueError
|
@@ -44,7 +40,8 @@ from classiq.interface.model.repeat import Repeat
|
|
44
40
|
from classiq.interface.model.statement_block import StatementBlock
|
45
41
|
from classiq.interface.model.within_apply_operation import WithinApply
|
46
42
|
|
47
|
-
from classiq.qmod.
|
43
|
+
from classiq.qmod.generative import is_generative_mode
|
44
|
+
from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVar
|
48
45
|
from classiq.qmod.quantum_callable import QCallable
|
49
46
|
from classiq.qmod.quantum_expandable import prepare_arg
|
50
47
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
@@ -89,9 +86,10 @@ def if_(
|
|
89
86
|
else_=_operand_to_body(else_, "else") if else_ != _MISSING_VALUE else [], # type: ignore[arg-type]
|
90
87
|
source_ref=source_ref,
|
91
88
|
)
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
if is_generative_mode():
|
90
|
+
if_stmt.set_generative_block("then", then)
|
91
|
+
if callable(else_):
|
92
|
+
if_stmt.set_generative_block("else", else_)
|
95
93
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(if_stmt)
|
96
94
|
|
97
95
|
|
@@ -109,9 +107,10 @@ def control(
|
|
109
107
|
else_block=_operand_to_body(else_block, "else_block") if else_block else None,
|
110
108
|
source_ref=source_ref,
|
111
109
|
)
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
if is_generative_mode():
|
111
|
+
control_stmt.set_generative_block("body", stmt_block)
|
112
|
+
if else_block is not None:
|
113
|
+
control_stmt.set_generative_block("else_block", else_block)
|
115
114
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
|
116
115
|
|
117
116
|
|
@@ -161,22 +160,7 @@ def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
161
160
|
)
|
162
161
|
|
163
162
|
|
164
|
-
@overload
|
165
163
|
def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
|
166
|
-
pass
|
167
|
-
|
168
|
-
|
169
|
-
@overload
|
170
|
-
def inplace_add(*, value: QNum, target: QNum) -> None:
|
171
|
-
pass
|
172
|
-
|
173
|
-
|
174
|
-
def inplace_add(
|
175
|
-
expression: Optional[SymbolicExpr] = None,
|
176
|
-
target_var: Optional[QScalar] = None,
|
177
|
-
value: Optional[QNum] = None,
|
178
|
-
target: Optional[QNum] = None,
|
179
|
-
) -> None:
|
180
164
|
"""
|
181
165
|
Add an arithmetic expression to a quantum variable.
|
182
166
|
|
@@ -187,23 +171,6 @@ def inplace_add(
|
|
187
171
|
target_var: A scalar quantum variable
|
188
172
|
"""
|
189
173
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
190
|
-
if value is not None or target is not None:
|
191
|
-
warnings.warn(
|
192
|
-
"Parameters 'value' and 'target of function 'inplace_add' have "
|
193
|
-
"been renamed to 'expression' and 'target_var' respectively. Parameters "
|
194
|
-
"'value' and 'target' will no longer be supported starting on 02/12/24 at "
|
195
|
-
"the earliest.\nHint: Change `inplace_add(value=..., target=...)` to "
|
196
|
-
"`inplace_add(expression=..., target_var=...)` or `inplace_add(..., ...)`.",
|
197
|
-
category=DeprecationWarning,
|
198
|
-
stacklevel=2,
|
199
|
-
)
|
200
|
-
if value is not None:
|
201
|
-
expression = value
|
202
|
-
if target is not None:
|
203
|
-
target_var = target
|
204
|
-
if TYPE_CHECKING:
|
205
|
-
assert expression is not None
|
206
|
-
assert target_var is not None
|
207
174
|
source_ref = get_source_ref(sys._getframe(1))
|
208
175
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
209
176
|
ArithmeticOperation(
|
@@ -215,22 +182,7 @@ def inplace_add(
|
|
215
182
|
)
|
216
183
|
|
217
184
|
|
218
|
-
@overload
|
219
185
|
def inplace_xor(expression: SymbolicExpr, target_var: QScalar) -> None:
|
220
|
-
pass
|
221
|
-
|
222
|
-
|
223
|
-
@overload
|
224
|
-
def inplace_xor(*, value: QNum, target: QNum) -> None:
|
225
|
-
pass
|
226
|
-
|
227
|
-
|
228
|
-
def inplace_xor(
|
229
|
-
expression: Optional[SymbolicExpr] = None,
|
230
|
-
target_var: Optional[QScalar] = None,
|
231
|
-
value: Optional[QNum] = None,
|
232
|
-
target: Optional[QNum] = None,
|
233
|
-
) -> None:
|
234
186
|
"""
|
235
187
|
Bitwise-XOR a quantum variable with an arithmetic expression.
|
236
188
|
|
@@ -241,23 +193,6 @@ def inplace_xor(
|
|
241
193
|
target_var: A scalar quantum variable
|
242
194
|
"""
|
243
195
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
244
|
-
if value is not None or target is not None:
|
245
|
-
warnings.warn(
|
246
|
-
"Parameters 'value' and 'target of function 'inplace_xor' have "
|
247
|
-
"been renamed to 'expression' and 'target_var' respectively. Parameters "
|
248
|
-
"'value' and 'target' will no longer be supported starting on 02/12/24 at "
|
249
|
-
"the earliest.\nHint: Change `inplace_xor(value=..., target=...)` to "
|
250
|
-
"`inplace_xor(expression=..., target_var=...)` or `inplace_xor(..., ...)`.",
|
251
|
-
category=DeprecationWarning,
|
252
|
-
stacklevel=2,
|
253
|
-
)
|
254
|
-
if value is not None:
|
255
|
-
expression = value
|
256
|
-
if target is not None:
|
257
|
-
target_var = target
|
258
|
-
if TYPE_CHECKING:
|
259
|
-
assert expression is not None
|
260
|
-
assert target_var is not None
|
261
196
|
source_ref = get_source_ref(sys._getframe(1))
|
262
197
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
263
198
|
ArithmeticOperation(
|
@@ -282,8 +217,9 @@ def within_apply(
|
|
282
217
|
action=_operand_to_body(apply, "apply"),
|
283
218
|
source_ref=source_ref,
|
284
219
|
)
|
285
|
-
|
286
|
-
|
220
|
+
if is_generative_mode():
|
221
|
+
within_apply_stmt.set_generative_block("within", within)
|
222
|
+
within_apply_stmt.set_generative_block("apply", apply)
|
287
223
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(within_apply_stmt)
|
288
224
|
|
289
225
|
|
@@ -313,7 +249,8 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
|
|
313
249
|
body=iteration_operand.body,
|
314
250
|
source_ref=source_ref,
|
315
251
|
)
|
316
|
-
|
252
|
+
if is_generative_mode():
|
253
|
+
repeat_stmt.set_generative_block("body", iteration)
|
317
254
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(repeat_stmt)
|
318
255
|
|
319
256
|
|
@@ -329,7 +266,8 @@ def power(
|
|
329
266
|
body=_operand_to_body(stmt_block, "stmt_block"),
|
330
267
|
source_ref=source_ref,
|
331
268
|
)
|
332
|
-
|
269
|
+
if is_generative_mode():
|
270
|
+
power_stmt.set_generative_block("body", stmt_block)
|
333
271
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(power_stmt)
|
334
272
|
|
335
273
|
|
@@ -340,7 +278,8 @@ def invert(stmt_block: Union[QCallable, Callable[[], None]]) -> None:
|
|
340
278
|
invert_stmt = Invert(
|
341
279
|
body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref
|
342
280
|
)
|
343
|
-
|
281
|
+
if is_generative_mode():
|
282
|
+
invert_stmt.set_generative_block("body", stmt_block)
|
344
283
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(invert_stmt)
|
345
284
|
|
346
285
|
|
@@ -1,30 +1,15 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Optional, Union
|
2
2
|
|
3
3
|
from classiq.interface.exceptions import ClassiqError
|
4
4
|
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
5
5
|
from classiq.interface.generator.model.constraints import Constraints
|
6
6
|
from classiq.interface.generator.model.preferences.preferences import Preferences
|
7
|
-
from classiq.interface.
|
8
|
-
from classiq.interface.model.model import MAIN_FUNCTION_NAME, Model, SerializedModel
|
9
|
-
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
10
|
-
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
7
|
+
from classiq.interface.model.model import MAIN_FUNCTION_NAME, SerializedModel
|
11
8
|
|
12
|
-
from classiq.model_expansions.interpreter import Interpreter
|
13
|
-
from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
|
14
9
|
from classiq.qmod.classical_function import CFunc
|
15
|
-
from classiq.qmod.generative import (
|
16
|
-
is_generative_expansion_enabled,
|
17
|
-
set_frontend_interpreter,
|
18
|
-
)
|
19
|
-
from classiq.qmod.model_state_container import QMODULE
|
20
|
-
from classiq.qmod.qfunc import DEC_QFUNCS, GEN_QFUNCS
|
21
|
-
from classiq.qmod.quantum_expandable import _prepare_args
|
22
10
|
from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
|
23
|
-
from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
|
24
11
|
from classiq.qmod.write_qmod import write_qmod
|
25
12
|
|
26
|
-
GEN_MAIN_NAME = "_gen_main"
|
27
|
-
|
28
13
|
|
29
14
|
def create_model(
|
30
15
|
entry_point: Union[QFunc, GenerativeQFunc],
|
@@ -57,154 +42,15 @@ def create_model(
|
|
57
42
|
f"The entry point function must be named 'main', got '{entry_point.func_decl.name}'"
|
58
43
|
)
|
59
44
|
|
60
|
-
|
61
|
-
gen_func._py_callable.__name__ for gen_func in GEN_QFUNCS
|
62
|
-
} - set(BUILTIN_FUNCTION_DECLARATIONS.keys())
|
63
|
-
|
64
|
-
if len(user_gen_functions) > 0 and is_generative_expansion_enabled():
|
65
|
-
model = _expand_generative_model(
|
66
|
-
(
|
67
|
-
entry_point
|
68
|
-
if isinstance(entry_point, QFunc)
|
69
|
-
else QFunc(entry_point._py_callable)
|
70
|
-
),
|
71
|
-
constraints,
|
72
|
-
execution_preferences,
|
73
|
-
preferences,
|
74
|
-
)
|
75
|
-
else:
|
76
|
-
if TYPE_CHECKING:
|
77
|
-
assert isinstance(entry_point, QFunc)
|
78
|
-
model = entry_point.create_model(
|
79
|
-
constraints,
|
80
|
-
execution_preferences,
|
81
|
-
preferences,
|
82
|
-
classical_execution_function,
|
83
|
-
)
|
84
|
-
result = model.get_model()
|
85
|
-
|
86
|
-
if out_file is not None:
|
87
|
-
write_qmod(result, out_file)
|
88
|
-
|
89
|
-
return result
|
90
|
-
|
91
|
-
|
92
|
-
def _expand_generative_model(
|
93
|
-
gen_main: QFunc,
|
94
|
-
constraints: Optional[Constraints] = None,
|
95
|
-
execution_preferences: Optional[ExecutionPreferences] = None,
|
96
|
-
preferences: Optional[Preferences] = None,
|
97
|
-
) -> Model:
|
98
|
-
@QFunc
|
99
|
-
def _dummy() -> None:
|
100
|
-
pass
|
101
|
-
|
102
|
-
model = _dummy.create_model(
|
45
|
+
model = entry_point.create_model(
|
103
46
|
constraints,
|
104
47
|
execution_preferences,
|
105
48
|
preferences,
|
49
|
+
classical_execution_function,
|
106
50
|
)
|
107
|
-
|
108
|
-
model.functions = gen_expand_model.functions
|
109
|
-
model.functions_compilation_metadata = (
|
110
|
-
gen_expand_model.functions_compilation_metadata
|
111
|
-
)
|
112
|
-
model.types = list(QMODULE.type_decls.values())
|
113
|
-
model.enums = list(QMODULE.enum_decls.values())
|
114
|
-
model.qstructs = list(QMODULE.qstruct_decls.values())
|
115
|
-
return model
|
116
|
-
|
117
|
-
|
118
|
-
def _get_generative_functions(
|
119
|
-
gen_main: QFunc,
|
120
|
-
preferences: Optional[Preferences],
|
121
|
-
) -> Model:
|
122
|
-
# The Interpreter accepts a model and a list of generative functions.
|
123
|
-
# Since the main function is generative, it can only be expanded using the
|
124
|
-
# Interpreter.
|
125
|
-
# To solve this deadlock, we create a wrapper model
|
126
|
-
# `qfunc main(...) { _gen_main(...); }` and rename `main` to `_gen_main` before
|
127
|
-
# passing them to the Interpreter.
|
128
|
-
gen_model = _get_wrapper_main(gen_main, preferences)
|
129
|
-
gen_functions = _get_all_model_functions_as_generative_functions()
|
130
|
-
return _interpret_generative_model(gen_model, gen_functions)
|
131
|
-
|
132
|
-
|
133
|
-
def _get_wrapper_main(
|
134
|
-
gen_main: QFunc,
|
135
|
-
preferences: Optional[Preferences],
|
136
|
-
) -> Model:
|
137
|
-
extra_args = {}
|
138
|
-
if preferences is not None:
|
139
|
-
extra_args["preferences"] = preferences
|
140
|
-
functions_compilation_metadata = {
|
141
|
-
qfunc._py_callable.__name__: qfunc.compilation_metadata
|
142
|
-
for qfunc in DEC_QFUNCS + GEN_QFUNCS
|
143
|
-
if qfunc.compilation_metadata is not None
|
144
|
-
}
|
145
|
-
return Model(
|
146
|
-
functions=[
|
147
|
-
NativeFunctionDefinition(
|
148
|
-
name=MAIN_FUNCTION_NAME,
|
149
|
-
positional_arg_declarations=gen_main.func_decl.positional_arg_declarations,
|
150
|
-
body=[
|
151
|
-
QuantumFunctionCall(
|
152
|
-
function=GEN_MAIN_NAME,
|
153
|
-
positional_args=_prepare_args(
|
154
|
-
gen_main.func_decl,
|
155
|
-
gen_main._get_positional_args(),
|
156
|
-
{},
|
157
|
-
),
|
158
|
-
),
|
159
|
-
],
|
160
|
-
),
|
161
|
-
],
|
162
|
-
functions_compilation_metadata=functions_compilation_metadata,
|
163
|
-
**extra_args,
|
164
|
-
)
|
165
|
-
|
166
|
-
|
167
|
-
def _get_all_model_functions_as_generative_functions() -> list[GenerativeQFunc]:
|
168
|
-
|
169
|
-
gen_functions = list(GEN_QFUNCS) + [
|
170
|
-
GenerativeQFunc(
|
171
|
-
dec_func._py_callable, dec_func.func_decl, dec_func.compilation_metadata
|
172
|
-
)
|
173
|
-
for dec_func in DEC_QFUNCS
|
174
|
-
]
|
175
|
-
return [
|
176
|
-
(
|
177
|
-
gen_func
|
178
|
-
if gen_func.func_decl.name != MAIN_FUNCTION_NAME
|
179
|
-
else GenerativeQFunc(
|
180
|
-
gen_func._py_callable,
|
181
|
-
gen_func.func_decl.model_copy(update={"name": GEN_MAIN_NAME}),
|
182
|
-
gen_func.compilation_metadata,
|
183
|
-
)
|
184
|
-
)
|
185
|
-
for gen_func in gen_functions
|
186
|
-
if gen_func.func_decl.name not in BUILTIN_FUNCTION_DECLARATIONS
|
187
|
-
]
|
188
|
-
|
51
|
+
result = model.get_model()
|
189
52
|
|
190
|
-
|
191
|
-
|
192
|
-
) -> Model:
|
193
|
-
resolve_function_calls(
|
194
|
-
gen_model,
|
195
|
-
{gen_func.func_decl.name: gen_func.func_decl for gen_func in gen_functions},
|
196
|
-
)
|
197
|
-
interpreter = Interpreter(gen_model, gen_functions, is_frontend=True)
|
198
|
-
set_frontend_interpreter(interpreter)
|
199
|
-
expand_model = interpreter.expand()
|
200
|
-
functions_dict = nameables_to_dict(expand_model.functions)
|
53
|
+
if out_file is not None:
|
54
|
+
write_qmod(result, out_file)
|
201
55
|
|
202
|
-
|
203
|
-
expanded_gen_main_name = cast(
|
204
|
-
QuantumFunctionCall, functions_dict[MAIN_FUNCTION_NAME].body[0]
|
205
|
-
).func_name
|
206
|
-
functions_dict[MAIN_FUNCTION_NAME] = functions_dict[
|
207
|
-
expanded_gen_main_name
|
208
|
-
].model_copy(update={"name": MAIN_FUNCTION_NAME})
|
209
|
-
functions_dict.pop(expanded_gen_main_name)
|
210
|
-
return expand_model.model_copy(update={"functions": list(functions_dict.values())})
|
56
|
+
return result
|
classiq/qmod/generative.py
CHANGED
@@ -8,7 +8,6 @@ from classiq.interface.generator.expressions.expression import Expression
|
|
8
8
|
if TYPE_CHECKING:
|
9
9
|
from classiq.model_expansions.interpreter import Interpreter
|
10
10
|
|
11
|
-
_GENERATIVE_ENABLED_SWITCH: bool = True
|
12
11
|
_GENERATIVE_MODE: bool = False
|
13
12
|
_FRONTEND_INTERPRETER: Optional["Interpreter"] = None
|
14
13
|
|
@@ -28,21 +27,6 @@ def generative_mode_context(generative: bool) -> Iterator[None]:
|
|
28
27
|
_GENERATIVE_MODE = previous
|
29
28
|
|
30
29
|
|
31
|
-
@contextmanager
|
32
|
-
def enable_generative_expansion(enabled: bool) -> Iterator[None]:
|
33
|
-
global _GENERATIVE_ENABLED_SWITCH
|
34
|
-
previous = _GENERATIVE_ENABLED_SWITCH
|
35
|
-
_GENERATIVE_ENABLED_SWITCH = enabled
|
36
|
-
try:
|
37
|
-
yield
|
38
|
-
finally:
|
39
|
-
_GENERATIVE_ENABLED_SWITCH = previous
|
40
|
-
|
41
|
-
|
42
|
-
def is_generative_expansion_enabled() -> bool:
|
43
|
-
return _GENERATIVE_ENABLED_SWITCH
|
44
|
-
|
45
|
-
|
46
30
|
def set_frontend_interpreter(interpreter: "Interpreter") -> None:
|
47
31
|
global _FRONTEND_INTERPRETER
|
48
32
|
_FRONTEND_INTERPRETER = interpreter
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
1
3
|
from classiq.interface.generator.constant import Constant
|
2
4
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
3
5
|
from classiq.interface.generator.types.enum_declaration import EnumDeclaration
|
@@ -7,6 +9,9 @@ from classiq.interface.model.native_function_definition import (
|
|
7
9
|
NativeFunctionDefinition,
|
8
10
|
)
|
9
11
|
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from classiq.qmod.quantum_function import GenerativeQFunc
|
14
|
+
|
10
15
|
|
11
16
|
class ModelStateContainer:
|
12
17
|
enum_decls: dict[str, EnumDeclaration]
|
@@ -15,6 +20,8 @@ class ModelStateContainer:
|
|
15
20
|
native_defs: dict[str, NativeFunctionDefinition]
|
16
21
|
constants: dict[str, Constant]
|
17
22
|
functions_compilation_metadata: dict[str, CompilationMetadata]
|
23
|
+
generative_functions: dict[str, "GenerativeQFunc"]
|
24
|
+
function_dependencies: dict[str, list[str]]
|
18
25
|
|
19
26
|
|
20
27
|
QMODULE = ModelStateContainer()
|
@@ -78,7 +78,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
78
78
|
)
|
79
79
|
from classiq.interface.model.within_apply_operation import WithinApply
|
80
80
|
|
81
|
-
from classiq.
|
81
|
+
from classiq.open_library.functions import OPEN_LIBRARY_FUNCTIONS
|
82
82
|
from classiq.qmod.native.expression_to_qmod import transform_expression
|
83
83
|
from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
|
84
84
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
@@ -114,16 +114,15 @@ class DSLPrettyPrinter(Visitor):
|
|
114
114
|
else []
|
115
115
|
)
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
)
|
117
|
+
items = [
|
118
|
+
*constants,
|
119
|
+
*enum_decls,
|
120
|
+
*struct_decls,
|
121
|
+
*qstruct_decls,
|
122
|
+
*func_defs,
|
123
|
+
*classical_code,
|
124
|
+
]
|
125
|
+
return "\n".join([item for item in items if item != ""])
|
127
126
|
|
128
127
|
def visit_Constant(self, constant: Constant) -> str:
|
129
128
|
return f"{self._indent}{self.visit(constant.name)}: {self.visit(constant.const_type)} = {self.visit(constant.value)};\n"
|