classiq 0.67.0__py3-none-any.whl → 0.68.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 +5 -1
- classiq/_internals/async_utils.py +1 -1
- classiq/_internals/authentication/password_manager.py +1 -1
- classiq/_internals/client.py +1 -1
- classiq/execution/execution_session.py +7 -3
- classiq/executor.py +7 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -1
- classiq/interface/chemistry/operator.py +1 -1
- classiq/interface/debug_info/debug_info.py +15 -0
- classiq/interface/generator/arith/arithmetic.py +96 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
- classiq/interface/generator/generated_circuit_data.py +4 -2
- classiq/interface/generator/quantum_program.py +18 -1
- classiq/interface/generator/types/enum_declaration.py +33 -2
- classiq/interface/model/classical_if.py +2 -2
- classiq/interface/model/control.py +2 -2
- classiq/interface/model/invert.py +2 -2
- classiq/interface/model/power.py +2 -2
- classiq/interface/model/quantum_function_call.py +4 -0
- classiq/interface/model/repeat.py +2 -2
- classiq/interface/model/statement_block.py +1 -1
- classiq/interface/model/within_apply_operation.py +2 -2
- classiq/model_expansions/interpreters/generative_interpreter.py +78 -18
- classiq/model_expansions/quantum_operations/allocate.py +3 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
- classiq/model_expansions/quantum_operations/bind.py +2 -1
- classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
- classiq/model_expansions/quantum_operations/classicalif.py +5 -4
- classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
- classiq/model_expansions/quantum_operations/emitter.py +16 -2
- classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
- classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
- classiq/model_expansions/quantum_operations/repeat.py +2 -1
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -1
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
- classiq/open_library/functions/__init__.py +1 -2
- classiq/open_library/functions/amplitude_amplification.py +8 -5
- classiq/open_library/functions/discrete_sine_cosine_transform.py +16 -13
- classiq/open_library/functions/grover.py +6 -10
- classiq/open_library/functions/modular_exponentiation.py +7 -13
- classiq/open_library/functions/state_preparation.py +16 -17
- classiq/open_library/functions/swap_test.py +1 -1
- classiq/open_library/functions/utility_functions.py +10 -2
- classiq/qmod/builtins/functions/chemistry.py +6 -38
- classiq/qmod/quantum_expandable.py +30 -6
- classiq/qmod/semantics/validation/types_validation.py +1 -1
- classiq/qmod/symbolic.py +2 -1
- classiq/qmod/utilities.py +2 -1
- classiq/qmod/write_qmod.py +10 -7
- classiq/synthesis.py +20 -7
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/METADATA +1 -1
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/RECORD +55 -51
- classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
- {classiq-0.67.0.dist-info → classiq-0.68.0.dist-info}/WHEEL +0 -0
@@ -1,13 +1,11 @@
|
|
1
1
|
from classiq.open_library.functions.qft_functions import qft
|
2
|
-
from classiq.open_library.functions.utility_functions import
|
3
|
-
apply_to_all,
|
4
|
-
modular_increment,
|
5
|
-
)
|
2
|
+
from classiq.open_library.functions.utility_functions import apply_to_all
|
6
3
|
from classiq.qmod.builtins.functions.standard_gates import PHASE, H, S, X, Z
|
7
4
|
from classiq.qmod.builtins.operations import (
|
8
5
|
allocate,
|
9
6
|
bind,
|
10
7
|
control,
|
8
|
+
inplace_add,
|
11
9
|
invert,
|
12
10
|
repeat,
|
13
11
|
within_apply,
|
@@ -30,8 +28,13 @@ def _qct_d_operator(x: QNum, q: QBit) -> None:
|
|
30
28
|
|
31
29
|
@qfunc
|
32
30
|
def _qct_pi_operator(x: QArray[QBit], q: QBit) -> None:
|
33
|
-
control(
|
34
|
-
|
31
|
+
control(
|
32
|
+
q == 1,
|
33
|
+
lambda: [ # type:ignore[arg-type]
|
34
|
+
apply_to_all(X, x),
|
35
|
+
inplace_add(1, x), # type:ignore[arg-type, func-returns-value]
|
36
|
+
],
|
37
|
+
)
|
35
38
|
|
36
39
|
|
37
40
|
def _t_operator(x: QArray) -> None:
|
@@ -63,7 +66,7 @@ def _d1_operator(x: QArray[QBit], q: QBit) -> None:
|
|
63
66
|
|
64
67
|
|
65
68
|
def _pi2_operator(x: QArray[QBit], q: QBit) -> None:
|
66
|
-
control(q == 1, lambda:
|
69
|
+
control(q == 1, lambda: inplace_add(1, x)) # type:ignore[arg-type]
|
67
70
|
|
68
71
|
|
69
72
|
def _j_operator(q: QBit) -> None:
|
@@ -76,7 +79,7 @@ def _b_t_operator(q: QBit) -> None:
|
|
76
79
|
|
77
80
|
|
78
81
|
def _d0dt_operator(x: QArray, q: QBit) -> None:
|
79
|
-
x_num: QNum = QNum(
|
82
|
+
x_num: QNum = QNum(size=x.len)
|
80
83
|
bind(x, x_num)
|
81
84
|
_b_t_operator(q)
|
82
85
|
control(x_num == 0, lambda: _j_operator(q))
|
@@ -140,7 +143,7 @@ def qct_qst_type2(x: QArray[QBit], q: QBit) -> None:
|
|
140
143
|
x: The LSB part of the qubit array to apply the transform to.
|
141
144
|
q: The MSB of the qubit array to apply the transform to.
|
142
145
|
"""
|
143
|
-
extended_state: QArray = QArray(
|
146
|
+
extended_state: QArray = QArray()
|
144
147
|
_vn_operator(x, q)
|
145
148
|
bind([x, q], extended_state)
|
146
149
|
qft(extended_state)
|
@@ -159,8 +162,8 @@ def qct_type2(x: QArray[QBit]) -> None:
|
|
159
162
|
Args:
|
160
163
|
x: The qubit array to apply the transform to.
|
161
164
|
"""
|
162
|
-
q = QBit(
|
163
|
-
within_apply(lambda: allocate(
|
165
|
+
q = QBit()
|
166
|
+
within_apply(lambda: allocate(q), lambda: qct_qst_type2(x, q))
|
164
167
|
|
165
168
|
|
166
169
|
@qfunc
|
@@ -174,8 +177,8 @@ def qst_type2(x: QArray[QBit]) -> None:
|
|
174
177
|
Args:
|
175
178
|
x: The qubit array to apply the transform to.
|
176
179
|
"""
|
177
|
-
q = QBit(
|
180
|
+
q = QBit()
|
178
181
|
within_apply(
|
179
|
-
lambda: (allocate(
|
182
|
+
lambda: (allocate(q), X(q)), # type:ignore[arg-type]
|
180
183
|
lambda: qct_qst_type2(x, q),
|
181
184
|
)
|
@@ -40,9 +40,9 @@ def phase_oracle(
|
|
40
40
|
predicate: A predicate function that takes a QArray of QBits and sets a single QBit |1> if the predicate is true, and |0> otherwise.
|
41
41
|
target: The target QArray of QBits to apply the phase oracle to.
|
42
42
|
"""
|
43
|
-
aux = QBit(
|
43
|
+
aux = QBit()
|
44
44
|
within_apply(
|
45
|
-
within=lambda: (allocate(
|
45
|
+
within=lambda: (allocate(aux), X(aux), H(aux)), # type:ignore[arg-type]
|
46
46
|
apply=lambda: predicate(target, aux),
|
47
47
|
)
|
48
48
|
|
@@ -64,8 +64,8 @@ def reflect_about_zero(packed_vars: QArray[QBit]) -> None:
|
|
64
64
|
Args:
|
65
65
|
packed_vars: The quantum state to reflect.
|
66
66
|
"""
|
67
|
-
msbs: QNum = QNum(
|
68
|
-
lsb = QBit(
|
67
|
+
msbs: QNum = QNum(size=packed_vars.len - 1)
|
68
|
+
lsb = QBit()
|
69
69
|
bind(packed_vars, [msbs, lsb])
|
70
70
|
within_apply(
|
71
71
|
lambda: (X(lsb), H(lsb)), # type:ignore[arg-type]
|
@@ -126,7 +126,7 @@ def grover_operator(
|
|
126
126
|
packed_vars: The state to which to apply the grover operator.
|
127
127
|
"""
|
128
128
|
oracle(packed_vars)
|
129
|
-
grover_diffuser(
|
129
|
+
grover_diffuser(space_transform, packed_vars)
|
130
130
|
U(0, 0, 0, pi, packed_vars[0])
|
131
131
|
|
132
132
|
|
@@ -149,9 +149,5 @@ def grover_search(
|
|
149
149
|
hadamard_transform(packed_vars)
|
150
150
|
power(
|
151
151
|
reps,
|
152
|
-
lambda: grover_operator(
|
153
|
-
lambda qba: oracle(qba),
|
154
|
-
lambda qba: hadamard_transform(qba),
|
155
|
-
packed_vars,
|
156
|
-
),
|
152
|
+
lambda: grover_operator(oracle, hadamard_transform, packed_vars),
|
157
153
|
)
|
@@ -11,24 +11,18 @@ from classiq.qmod.builtins.operations import (
|
|
11
11
|
)
|
12
12
|
from classiq.qmod.cparam import CInt
|
13
13
|
from classiq.qmod.qfunc import qfunc
|
14
|
-
from classiq.qmod.qmod_variable import QArray, QBit
|
14
|
+
from classiq.qmod.qmod_variable import QArray, QBit
|
15
15
|
from classiq.qmod.symbolic import min, mod_inverse
|
16
16
|
|
17
17
|
|
18
18
|
@qfunc
|
19
19
|
def _check_msb(ref: CInt, x: QArray[QBit], aux: QBit) -> None:
|
20
20
|
within_apply(
|
21
|
-
lambda: invert(lambda: qft_no_swap(x)),
|
21
|
+
lambda: invert(lambda: qft_no_swap(x)),
|
22
|
+
lambda: control(x[0] == ref, lambda: X(aux)),
|
22
23
|
)
|
23
24
|
|
24
25
|
|
25
|
-
@qfunc
|
26
|
-
def _ctrl_x(
|
27
|
-
ref: CInt, ctrl: QNum, aux: QBit
|
28
|
-
) -> None: # TODO: remove qfunc when expressions of QBit is supported
|
29
|
-
control(ctrl == ref, lambda: X(aux))
|
30
|
-
|
31
|
-
|
32
26
|
@qfunc
|
33
27
|
def qft_space_add_const(value: CInt, phi_b: QArray[QBit]) -> None:
|
34
28
|
"""
|
@@ -72,12 +66,12 @@ def cc_modular_add(n: CInt, a: CInt, phi_b: QArray[QBit], c1: QBit, c2: QBit) ->
|
|
72
66
|
c2: a control qubit.
|
73
67
|
|
74
68
|
"""
|
75
|
-
ctrl: QArray[QBit] = QArray(
|
76
|
-
aux = QBit(
|
69
|
+
ctrl: QArray[QBit] = QArray()
|
70
|
+
aux = QBit()
|
77
71
|
|
78
72
|
within_apply(
|
79
73
|
lambda: ( # type:ignore[arg-type]
|
80
|
-
allocate(
|
74
|
+
allocate(aux),
|
81
75
|
bind([c1, c2], ctrl), # type:ignore[func-returns-value]
|
82
76
|
),
|
83
77
|
lambda: ( # type:ignore[arg-type]
|
@@ -162,7 +156,7 @@ def inplace_c_modular_multiply(n: CInt, a: CInt, x: QArray[QBit], ctrl: QBit) ->
|
|
162
156
|
x: The quantum factor.
|
163
157
|
ctrl: The control bit.
|
164
158
|
"""
|
165
|
-
b: QArray[QBit] = QArray(
|
159
|
+
b: QArray[QBit] = QArray()
|
166
160
|
|
167
161
|
within_apply(
|
168
162
|
lambda: allocate(x.len + 1, b),
|
@@ -3,12 +3,9 @@ from typing import Literal
|
|
3
3
|
|
4
4
|
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
5
5
|
|
6
|
-
from classiq.open_library.functions.utility_functions import
|
7
|
-
hadamard_transform,
|
8
|
-
modular_increment,
|
9
|
-
)
|
6
|
+
from classiq.open_library.functions.utility_functions import hadamard_transform
|
10
7
|
from classiq.qmod.builtins.functions.standard_gates import CX, IDENTITY, RY, H, X
|
11
|
-
from classiq.qmod.builtins.operations import allocate, control, if_, repeat
|
8
|
+
from classiq.qmod.builtins.operations import allocate, control, if_, inplace_add, repeat
|
12
9
|
from classiq.qmod.cparam import CBool, CInt
|
13
10
|
from classiq.qmod.qfunc import qfunc
|
14
11
|
from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
|
@@ -48,7 +45,7 @@ def allocate_num(
|
|
48
45
|
allocate(num_qubits, out)
|
49
46
|
|
50
47
|
|
51
|
-
def
|
48
|
+
def _prepare_uniform_trimmed_state_apply_rotation(
|
52
49
|
size_lsb: CInt, lsbs_val: CInt, rotation_var: QBit
|
53
50
|
) -> None:
|
54
51
|
# max hold for the case where the value is on the left side
|
@@ -68,7 +65,7 @@ def _prepare_uniform_trimmed_state_step(
|
|
68
65
|
lsbs_val != 0, # stop condition
|
69
66
|
lambda: control(
|
70
67
|
ctrl_var == ctrl_val,
|
71
|
-
lambda:
|
68
|
+
lambda: _prepare_uniform_trimmed_state_apply_rotation(
|
72
69
|
size_lsb, lsbs_val, rotation_var
|
73
70
|
),
|
74
71
|
),
|
@@ -102,7 +99,7 @@ def prepare_uniform_trimmed_state(m: CInt, q: QArray[QBit]) -> None:
|
|
102
99
|
if_(
|
103
100
|
m < 2**q.len,
|
104
101
|
# initial step without control
|
105
|
-
lambda:
|
102
|
+
lambda: _prepare_uniform_trimmed_state_apply_rotation(
|
106
103
|
q.len - 1, # type:ignore[arg-type]
|
107
104
|
m,
|
108
105
|
q[q.len - 1],
|
@@ -122,7 +119,7 @@ def prepare_uniform_trimmed_state(m: CInt, q: QArray[QBit]) -> None:
|
|
122
119
|
|
123
120
|
|
124
121
|
@qfunc
|
125
|
-
def prepare_uniform_interval_state(start: CInt, end: CInt, q:
|
122
|
+
def prepare_uniform_interval_state(start: CInt, end: CInt, q: QNum) -> None:
|
126
123
|
"""
|
127
124
|
[Qmod Classiq-library function]
|
128
125
|
|
@@ -144,7 +141,7 @@ def prepare_uniform_interval_state(start: CInt, end: CInt, q: QArray[QBit]) -> N
|
|
144
141
|
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
145
142
|
"""
|
146
143
|
prepare_uniform_trimmed_state(end - start, q)
|
147
|
-
|
144
|
+
inplace_add(start, q)
|
148
145
|
|
149
146
|
|
150
147
|
@qfunc
|
@@ -199,7 +196,9 @@ def prepare_exponential_state(rate: CInt, q: QArray[QBit]) -> None:
|
|
199
196
|
|
200
197
|
|
201
198
|
@qfunc
|
202
|
-
def prepare_bell_state(
|
199
|
+
def prepare_bell_state(
|
200
|
+
state_num: CInt, qpair: Output[QArray[QBit, Literal[2]]]
|
201
|
+
) -> None:
|
203
202
|
"""
|
204
203
|
[Qmod Classiq-library function]
|
205
204
|
|
@@ -207,7 +206,7 @@ def prepare_bell_state(state_num: CInt, q: Output[QArray[QBit, Literal[2]]]) ->
|
|
207
206
|
|
208
207
|
Args:
|
209
208
|
state_num: The number of the Bell state to be prepared. Must be an integer between 0 and 3.
|
210
|
-
|
209
|
+
qpair: The quantum variable that will receive the initialized state. Must be uninitialized.
|
211
210
|
|
212
211
|
Bell States:
|
213
212
|
The four Bell states are defined as follows (each state correlates to an integer between 0 and 3 as defined by the `state_num` argument):
|
@@ -241,11 +240,11 @@ def prepare_bell_state(state_num: CInt, q: Output[QArray[QBit, Literal[2]]]) ->
|
|
241
240
|
|
242
241
|
|
243
242
|
"""
|
244
|
-
allocate(
|
245
|
-
if_(logical_or(state_num == 1, state_num == 3), lambda: X(
|
246
|
-
if_(logical_or(state_num == 2, state_num == 3), lambda: X(
|
247
|
-
H(
|
248
|
-
CX(
|
243
|
+
allocate(qpair)
|
244
|
+
if_(logical_or(state_num == 1, state_num == 3), lambda: X(qpair[0]))
|
245
|
+
if_(logical_or(state_num == 2, state_num == 3), lambda: X(qpair[1]))
|
246
|
+
H(qpair[0])
|
247
|
+
CX(qpair[0], qpair[1])
|
249
248
|
|
250
249
|
|
251
250
|
@qfunc
|
@@ -21,7 +21,7 @@ def swap_test(state1: QArray[QBit], state2: QArray[QBit], test: Output[QBit]) ->
|
|
21
21
|
state2: A quantum state to check its overlap with state1.
|
22
22
|
test: A qubit for which the probability of measuring 0 is $0.5*(|\\langle state1 | state2 \\rangle |^2+1)$
|
23
23
|
"""
|
24
|
-
allocate(
|
24
|
+
allocate(test)
|
25
25
|
H(test)
|
26
26
|
control(test, lambda: repeat(state1.len, lambda i: SWAP(state1[i], state2[i])))
|
27
27
|
H(test)
|
@@ -1,5 +1,8 @@
|
|
1
|
+
import warnings
|
1
2
|
from typing import Annotated
|
2
3
|
|
4
|
+
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
5
|
+
|
3
6
|
from classiq.open_library.functions.qft_functions import qft
|
4
7
|
from classiq.qmod.builtins.functions.standard_gates import PHASE, H
|
5
8
|
from classiq.qmod.builtins.operations import bind, repeat, within_apply
|
@@ -44,7 +47,7 @@ def hadamard_transform(target: QArray[QBit]) -> None:
|
|
44
47
|
target: qubits to apply to Hadamard transform to.
|
45
48
|
|
46
49
|
"""
|
47
|
-
|
50
|
+
repeat(target.len, lambda index: H(target[index]))
|
48
51
|
|
49
52
|
|
50
53
|
@qfunc
|
@@ -69,7 +72,12 @@ def modular_increment(a: CInt, x: QNum) -> None:
|
|
69
72
|
x: A quantum number that is assumed to be non-negative integer.
|
70
73
|
|
71
74
|
"""
|
72
|
-
|
75
|
+
warnings.warn(
|
76
|
+
"Function 'modular_increment' is deprecated. Use in-place-add statement in the form '<var> += <expression>' or 'inplace_add(<expression>, <var>)' instead.",
|
77
|
+
ClassiqDeprecationWarning,
|
78
|
+
stacklevel=1,
|
79
|
+
)
|
80
|
+
array_cast: QArray = QArray()
|
73
81
|
within_apply(
|
74
82
|
lambda: ( # type:ignore[arg-type]
|
75
83
|
bind(x, array_cast), # type:ignore[func-returns-value]
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Literal
|
2
|
-
|
3
1
|
from classiq.qmod.builtins.structs import (
|
4
2
|
FockHamiltonianProblem,
|
5
3
|
MoleculeProblem,
|
@@ -13,12 +11,7 @@ from classiq.qmod.qmod_variable import QArray, QBit
|
|
13
11
|
def molecule_ucc(
|
14
12
|
molecule_problem: MoleculeProblem,
|
15
13
|
excitations: CArray[CInt],
|
16
|
-
qbv: QArray[
|
17
|
-
QBit,
|
18
|
-
Literal[
|
19
|
-
"get_field(get_field(molecule_problem_to_hamiltonian(molecule_problem)[0], 'pauli'), 'len')"
|
20
|
-
],
|
21
|
-
],
|
14
|
+
qbv: QArray[QBit],
|
22
15
|
) -> None:
|
23
16
|
pass
|
24
17
|
|
@@ -27,12 +20,7 @@ def molecule_ucc(
|
|
27
20
|
def molecule_hva(
|
28
21
|
molecule_problem: MoleculeProblem,
|
29
22
|
reps: CInt,
|
30
|
-
qbv: QArray[
|
31
|
-
QBit,
|
32
|
-
Literal[
|
33
|
-
"get_field(get_field(molecule_problem_to_hamiltonian(molecule_problem)[0], 'pauli'), 'len')"
|
34
|
-
],
|
35
|
-
],
|
23
|
+
qbv: QArray[QBit],
|
36
24
|
) -> None:
|
37
25
|
pass
|
38
26
|
|
@@ -40,12 +28,7 @@ def molecule_hva(
|
|
40
28
|
@qfunc(external=True)
|
41
29
|
def molecule_hartree_fock(
|
42
30
|
molecule_problem: MoleculeProblem,
|
43
|
-
qbv: QArray[
|
44
|
-
QBit,
|
45
|
-
Literal[
|
46
|
-
"get_field(get_field(molecule_problem_to_hamiltonian(molecule_problem)[0], 'pauli'), 'len')"
|
47
|
-
],
|
48
|
-
],
|
31
|
+
qbv: QArray[QBit],
|
49
32
|
) -> None:
|
50
33
|
pass
|
51
34
|
|
@@ -54,12 +37,7 @@ def molecule_hartree_fock(
|
|
54
37
|
def fock_hamiltonian_ucc(
|
55
38
|
fock_hamiltonian_problem: FockHamiltonianProblem,
|
56
39
|
excitations: CArray[CInt],
|
57
|
-
qbv: QArray[
|
58
|
-
QBit,
|
59
|
-
Literal[
|
60
|
-
"get_field(get_field(fock_hamiltonian_problem_to_hamiltonian(fock_hamiltonian_problem)[0], 'pauli'), 'len')"
|
61
|
-
],
|
62
|
-
],
|
40
|
+
qbv: QArray[QBit],
|
63
41
|
) -> None:
|
64
42
|
pass
|
65
43
|
|
@@ -68,12 +46,7 @@ def fock_hamiltonian_ucc(
|
|
68
46
|
def fock_hamiltonian_hva(
|
69
47
|
fock_hamiltonian_problem: FockHamiltonianProblem,
|
70
48
|
reps: CInt,
|
71
|
-
qbv: QArray[
|
72
|
-
QBit,
|
73
|
-
Literal[
|
74
|
-
"get_field(get_field(fock_hamiltonian_problem_to_hamiltonian(fock_hamiltonian_problem)[0], 'pauli'), 'len')"
|
75
|
-
],
|
76
|
-
],
|
49
|
+
qbv: QArray[QBit],
|
77
50
|
) -> None:
|
78
51
|
pass
|
79
52
|
|
@@ -81,11 +54,6 @@ def fock_hamiltonian_hva(
|
|
81
54
|
@qfunc(external=True)
|
82
55
|
def fock_hamiltonian_hartree_fock(
|
83
56
|
fock_hamiltonian_problem: FockHamiltonianProblem,
|
84
|
-
qbv: QArray[
|
85
|
-
QBit,
|
86
|
-
Literal[
|
87
|
-
"get_field(get_field(fock_hamiltonian_problem_to_hamiltonian(fock_hamiltonian_problem)[0], 'pauli'), 'len')"
|
88
|
-
],
|
89
|
-
],
|
57
|
+
qbv: QArray[QBit],
|
90
58
|
) -> None:
|
91
59
|
pass
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import inspect
|
2
2
|
from abc import ABC
|
3
|
+
from collections.abc import Generator, Iterable
|
3
4
|
from dataclasses import is_dataclass
|
4
5
|
from enum import Enum as PythonEnum
|
5
6
|
from types import TracebackType
|
@@ -67,7 +68,10 @@ from classiq.qmod.qmod_variable import (
|
|
67
68
|
from classiq.qmod.quantum_callable import QCallable, QExpandableInterface
|
68
69
|
from classiq.qmod.symbolic_expr import SymbolicExpr
|
69
70
|
from classiq.qmod.type_attribute_remover import decl_without_type_attributes
|
70
|
-
from classiq.qmod.utilities import
|
71
|
+
from classiq.qmod.utilities import (
|
72
|
+
mangle_keyword,
|
73
|
+
qmod_val_to_expr_str,
|
74
|
+
)
|
71
75
|
|
72
76
|
ArgType = Union[CParam, QVar, QCallable]
|
73
77
|
|
@@ -371,11 +375,14 @@ def prepare_arg(
|
|
371
375
|
def _validate_classical_arg(
|
372
376
|
arg: Any, arg_decl: AnonClassicalParameterDeclaration, func_name: Optional[str]
|
373
377
|
) -> None:
|
374
|
-
is_native_or_compatible_type =
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
378
|
+
is_native_or_compatible_type = (
|
379
|
+
not isinstance(
|
380
|
+
arg,
|
381
|
+
(*NativePythonClassicalTypes, CParam, SymbolicExpr, Basic, PythonEnum),
|
382
|
+
)
|
383
|
+
and not _is_legal_iterable(arg)
|
384
|
+
and not is_dataclass(arg) # type: ignore[unreachable]
|
385
|
+
)
|
379
386
|
try:
|
380
387
|
is_pydantic_classical_type = isinstance(
|
381
388
|
arg, pydantic.BaseModel
|
@@ -481,3 +488,20 @@ def _create_quantum_function_call(
|
|
481
488
|
return QuantumFunctionCall(
|
482
489
|
function=function_ident, positional_args=prepared_args, source_ref=source_ref_
|
483
490
|
)
|
491
|
+
|
492
|
+
|
493
|
+
_FORBIDDEN_ITERABLES = (set, dict, str, Generator)
|
494
|
+
|
495
|
+
|
496
|
+
def _is_legal_iterable(arg: Any) -> bool:
|
497
|
+
if not isinstance(arg, Iterable) or isinstance(arg, _FORBIDDEN_ITERABLES):
|
498
|
+
return False
|
499
|
+
return all(_is_legal_iterable_element(e) for e in arg)
|
500
|
+
|
501
|
+
|
502
|
+
def _is_legal_iterable_element(arg: Any) -> bool:
|
503
|
+
if isinstance(arg, _FORBIDDEN_ITERABLES):
|
504
|
+
return False
|
505
|
+
if isinstance(arg, Iterable):
|
506
|
+
return all(_is_legal_iterable_element(e) for e in arg)
|
507
|
+
return True
|
@@ -16,7 +16,7 @@ TYPE_EXISTS_ERROR_MESSAGE = "Type {!r} already exists"
|
|
16
16
|
|
17
17
|
|
18
18
|
def check_duplicate_types(
|
19
|
-
types: Sequence[Union[EnumDeclaration, StructDeclaration, QStructDeclaration]]
|
19
|
+
types: Sequence[Union[EnumDeclaration, StructDeclaration, QStructDeclaration]],
|
20
20
|
) -> None:
|
21
21
|
known_types = {type_.name for type_ in BUILTIN_ENUM_DECLARATIONS.values()}
|
22
22
|
known_types |= {type_.name for type_ in BUILTIN_STRUCT_DECLARATIONS.values()}
|
classiq/qmod/symbolic.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import sys
|
2
|
+
from collections.abc import Sequence
|
2
3
|
from typing import (
|
3
4
|
TYPE_CHECKING,
|
4
5
|
Any,
|
@@ -296,7 +297,7 @@ def sum(arr: SymbolicTypes) -> CParamScalar:
|
|
296
297
|
|
297
298
|
|
298
299
|
def subscript(
|
299
|
-
amplitudes: Union[
|
300
|
+
amplitudes: Union[Sequence[Union[float, CReal, CParamScalar]], CArray[CReal]],
|
300
301
|
index: QNum,
|
301
302
|
) -> CParamScalar:
|
302
303
|
return CParamScalar(expr=f"{amplitudes}[{index}]")
|
classiq/qmod/utilities.py
CHANGED
@@ -3,6 +3,7 @@ import inspect
|
|
3
3
|
import itertools
|
4
4
|
import keyword
|
5
5
|
import sys
|
6
|
+
from collections.abc import Iterable
|
6
7
|
from enum import Enum as PythonEnum
|
7
8
|
from types import FrameType
|
8
9
|
from typing import Any, ForwardRef, Literal, Optional, get_args, get_origin, overload
|
@@ -101,7 +102,7 @@ def qmod_val_to_expr_str(val: Any) -> str:
|
|
101
102
|
)
|
102
103
|
return f"struct_literal({val.struct_declaration.name}, {kwargs_str})"
|
103
104
|
|
104
|
-
if isinstance(val,
|
105
|
+
if isinstance(val, Iterable):
|
105
106
|
elements_str = ", ".join([qmod_val_to_expr_str(elem) for elem in val])
|
106
107
|
return f"[{elements_str}]"
|
107
108
|
|
classiq/qmod/write_qmod.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
import json
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional, Union
|
4
4
|
|
5
5
|
from classiq.interface.model.model import Model, SerializedModel
|
6
6
|
|
7
7
|
from classiq.qmod.native.pretty_printer import DSLPrettyPrinter
|
8
|
+
from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
|
8
9
|
from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
|
9
10
|
|
10
11
|
_QMOD_SUFFIX = "qmod"
|
@@ -12,7 +13,7 @@ _SYNTHESIS_OPTIONS_SUFFIX = "synthesis_options.json"
|
|
12
13
|
|
13
14
|
|
14
15
|
def write_qmod(
|
15
|
-
|
16
|
+
model: Union[SerializedModel, QFunc, GenerativeQFunc],
|
16
17
|
name: str,
|
17
18
|
directory: Optional[Path] = None,
|
18
19
|
decimal_precision: int = DEFAULT_DECIMAL_PRECISION,
|
@@ -22,7 +23,7 @@ def write_qmod(
|
|
22
23
|
The native Qmod file may be uploaded to the Classiq IDE.
|
23
24
|
|
24
25
|
Args:
|
25
|
-
|
26
|
+
model: The entry point of the Qmod model - a qfunc named 'main' (or alternatively the output of 'create_model').
|
26
27
|
name: The name to save the file by.
|
27
28
|
directory: The directory to save the files in. If None, the current working directory is used.
|
28
29
|
decimal_precision: The number of decimal places to use for numbers, set to 4 by default.
|
@@ -30,13 +31,15 @@ def write_qmod(
|
|
30
31
|
Returns:
|
31
32
|
None
|
32
33
|
"""
|
33
|
-
|
34
|
-
|
34
|
+
if isinstance(model, (QFunc, GenerativeQFunc)):
|
35
|
+
model_obj = model.create_model()
|
36
|
+
else:
|
37
|
+
model_obj = Model.model_validate_json(model)
|
35
38
|
pretty_printed_model = DSLPrettyPrinter(decimal_precision=decimal_precision).visit(
|
36
|
-
|
39
|
+
model_obj
|
37
40
|
)
|
38
41
|
|
39
|
-
synthesis_options =
|
42
|
+
synthesis_options = model_obj.model_dump(
|
40
43
|
include={"constraints", "preferences"}, exclude_none=True
|
41
44
|
)
|
42
45
|
|
classiq/synthesis.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any, NewType, Optional
|
1
|
+
from typing import Any, NewType, Optional, Union
|
2
2
|
|
3
3
|
import pydantic
|
4
4
|
|
@@ -12,6 +12,8 @@ from classiq.interface.model.model import Model, SerializedModel
|
|
12
12
|
from classiq import QuantumProgram
|
13
13
|
from classiq._internals import async_utils
|
14
14
|
from classiq._internals.api_wrapper import ApiWrapper
|
15
|
+
from classiq.qmod.create_model_function import create_model
|
16
|
+
from classiq.qmod.quantum_function import GenerativeQFunc, QFunc
|
15
17
|
|
16
18
|
SerializedQuantumProgram = NewType("SerializedQuantumProgram", str)
|
17
19
|
|
@@ -69,19 +71,30 @@ async def synthesize_async(
|
|
69
71
|
|
70
72
|
|
71
73
|
def synthesize(
|
72
|
-
|
74
|
+
model: Union[SerializedModel, QFunc, GenerativeQFunc],
|
75
|
+
auto_show: bool = False,
|
76
|
+
constraints: Optional[Constraints] = None,
|
77
|
+
preferences: Optional[Preferences] = None,
|
73
78
|
) -> SerializedQuantumProgram:
|
74
79
|
"""
|
75
80
|
Synthesize a model with the Classiq engine to receive a quantum program.
|
76
81
|
[More details](https://docs.classiq.io/latest/reference-manual/synthesis/)
|
77
82
|
|
78
83
|
Args:
|
79
|
-
|
80
|
-
auto_show:
|
84
|
+
model: The entry point of the Qmod model - a qfunc named 'main' (or alternatively the output of 'create_model').
|
85
|
+
auto_show: Whether to 'show' the synthesized model (False by default).
|
86
|
+
constraints: Constraints for the synthesis of the model. See Constraints (Optional).
|
87
|
+
preferences: Preferences for the synthesis of the model. See Preferences (Optional).
|
81
88
|
|
82
89
|
Returns:
|
83
90
|
SerializedQuantumProgram: Quantum program serialized as a string. (See: QuantumProgram)
|
84
91
|
"""
|
92
|
+
if isinstance(model, (QFunc, GenerativeQFunc)):
|
93
|
+
serialized_model = create_model(
|
94
|
+
model, constraints=constraints, preferences=preferences
|
95
|
+
)
|
96
|
+
else:
|
97
|
+
serialized_model = model
|
85
98
|
result = async_utils.run(synthesize_async(serialized_model))
|
86
99
|
if auto_show:
|
87
100
|
show(result)
|
@@ -91,7 +104,7 @@ def synthesize(
|
|
91
104
|
def set_preferences(
|
92
105
|
serialized_model: SerializedModel,
|
93
106
|
preferences: Optional[Preferences] = None,
|
94
|
-
**kwargs: Any
|
107
|
+
**kwargs: Any,
|
95
108
|
) -> SerializedModel:
|
96
109
|
"""
|
97
110
|
Overrides the preferences of a (serialized) model and returns the updated model.
|
@@ -139,7 +152,7 @@ def update_preferences(
|
|
139
152
|
def set_constraints(
|
140
153
|
serialized_model: SerializedModel,
|
141
154
|
constraints: Optional[Constraints] = None,
|
142
|
-
**kwargs: Any
|
155
|
+
**kwargs: Any,
|
143
156
|
) -> SerializedModel:
|
144
157
|
"""
|
145
158
|
Overrides the constraints of a (serialized) model and returns the updated model.
|
@@ -187,7 +200,7 @@ def update_constraints(
|
|
187
200
|
def set_execution_preferences(
|
188
201
|
serialized_model: SerializedModel,
|
189
202
|
execution_preferences: Optional[ExecutionPreferences] = None,
|
190
|
-
**kwargs: Any
|
203
|
+
**kwargs: Any,
|
191
204
|
) -> SerializedModel:
|
192
205
|
"""
|
193
206
|
Overrides the execution preferences of a (serialized) model and returns the updated model.
|