classiq 0.66.1__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.
Files changed (89) hide show
  1. classiq/_internals/api_wrapper.py +5 -1
  2. classiq/_internals/async_utils.py +1 -1
  3. classiq/_internals/authentication/password_manager.py +1 -1
  4. classiq/_internals/client.py +1 -1
  5. classiq/applications/finance/finance_model_constructor.py +9 -0
  6. classiq/applications/grover/grover_model_constructor.py +10 -0
  7. classiq/applications/qnn/qlayer.py +8 -2
  8. classiq/applications/qsvm/qsvm_model_constructor.py +9 -0
  9. classiq/execution/execution_session.py +7 -3
  10. classiq/executor.py +7 -2
  11. classiq/interface/_version.py +1 -1
  12. classiq/interface/ast_node.py +1 -1
  13. classiq/interface/chemistry/operator.py +1 -1
  14. classiq/interface/debug_info/debug_info.py +27 -0
  15. classiq/interface/exceptions.py +2 -5
  16. classiq/interface/generator/arith/argument_utils.py +1 -1
  17. classiq/interface/generator/arith/arithmetic.py +99 -2
  18. classiq/interface/generator/arith/arithmetic_expression_parser.py +1 -1
  19. classiq/interface/generator/arith/binary_ops.py +3 -0
  20. classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
  21. classiq/interface/generator/functions/type_name.py +2 -2
  22. classiq/interface/generator/generated_circuit_data.py +38 -3
  23. classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
  24. classiq/interface/generator/hva.py +1 -1
  25. classiq/interface/generator/model/preferences/preferences.py +8 -1
  26. classiq/interface/generator/quantum_program.py +18 -1
  27. classiq/interface/generator/reset.py +14 -0
  28. classiq/interface/generator/types/enum_declaration.py +33 -2
  29. classiq/interface/generator/ucc.py +1 -1
  30. classiq/interface/interface_version.py +1 -1
  31. classiq/interface/model/classical_if.py +2 -2
  32. classiq/interface/model/control.py +2 -2
  33. classiq/interface/model/invert.py +2 -2
  34. classiq/interface/model/power.py +2 -2
  35. classiq/interface/model/quantum_function_call.py +4 -0
  36. classiq/interface/model/quantum_statement.py +13 -0
  37. classiq/interface/model/repeat.py +2 -2
  38. classiq/interface/model/statement_block.py +1 -1
  39. classiq/interface/model/within_apply_operation.py +2 -2
  40. classiq/model_expansions/atomic_expression_functions_defs.py +2 -1
  41. classiq/model_expansions/capturing/captured_vars.py +184 -54
  42. classiq/model_expansions/closure.py +6 -3
  43. classiq/model_expansions/evaluators/control.py +14 -38
  44. classiq/model_expansions/function_builder.py +19 -14
  45. classiq/model_expansions/generative_functions.py +7 -11
  46. classiq/model_expansions/interpreters/base_interpreter.py +14 -5
  47. classiq/model_expansions/interpreters/generative_interpreter.py +87 -26
  48. classiq/model_expansions/quantum_operations/allocate.py +9 -3
  49. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -0
  50. classiq/model_expansions/quantum_operations/bind.py +67 -14
  51. classiq/model_expansions/quantum_operations/block_evaluator.py +76 -0
  52. classiq/model_expansions/quantum_operations/call_emitter.py +79 -10
  53. classiq/model_expansions/quantum_operations/classicalif.py +10 -6
  54. classiq/model_expansions/quantum_operations/composite_emitter.py +27 -0
  55. classiq/model_expansions/quantum_operations/emitter.py +24 -3
  56. classiq/model_expansions/quantum_operations/expression_evaluator.py +33 -0
  57. classiq/model_expansions/quantum_operations/handle_evaluator.py +28 -0
  58. classiq/model_expansions/quantum_operations/quantum_function_call.py +3 -2
  59. classiq/model_expansions/quantum_operations/repeat.py +9 -3
  60. classiq/model_expansions/quantum_operations/variable_decleration.py +13 -2
  61. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +1 -1
  62. classiq/open_library/functions/__init__.py +1 -2
  63. classiq/open_library/functions/amplitude_amplification.py +12 -9
  64. classiq/open_library/functions/discrete_sine_cosine_transform.py +16 -13
  65. classiq/open_library/functions/grover.py +11 -15
  66. classiq/open_library/functions/modular_exponentiation.py +7 -13
  67. classiq/open_library/functions/state_preparation.py +16 -17
  68. classiq/open_library/functions/swap_test.py +1 -1
  69. classiq/open_library/functions/utility_functions.py +10 -2
  70. classiq/qmod/builtins/functions/__init__.py +3 -0
  71. classiq/qmod/builtins/functions/chemistry.py +6 -38
  72. classiq/qmod/builtins/functions/mid_circuit_measurement.py +15 -0
  73. classiq/qmod/quantum_expandable.py +30 -6
  74. classiq/qmod/quantum_function.py +4 -0
  75. classiq/qmod/semantics/annotation/call_annotation.py +8 -2
  76. classiq/qmod/semantics/annotation/model_annotation.py +9 -0
  77. classiq/qmod/semantics/error_manager.py +0 -6
  78. classiq/qmod/semantics/static_semantics_visitor.py +0 -347
  79. classiq/qmod/semantics/validation/types_validation.py +1 -1
  80. classiq/qmod/symbolic.py +2 -1
  81. classiq/qmod/utilities.py +2 -1
  82. classiq/qmod/write_qmod.py +10 -7
  83. classiq/synthesis.py +20 -7
  84. {classiq-0.66.1.dist-info → classiq-0.68.0.dist-info}/METADATA +1 -1
  85. {classiq-0.66.1.dist-info → classiq-0.68.0.dist-info}/RECORD +86 -81
  86. classiq/model_expansions/quantum_operations/shallow_emitter.py +0 -166
  87. classiq/qmod/semantics/validation/func_call_validation.py +0 -99
  88. classiq/qmod/semantics/validation/handle_validation.py +0 -85
  89. {classiq-0.66.1.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(q == 1, lambda: apply_to_all(X, x))
34
- control(q == 1, lambda: modular_increment(1, x))
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: modular_increment(1, x))
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("x_num", x.len, False, 0)
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("extended_state")
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("q")
163
- within_apply(lambda: allocate(1, q), lambda: qct_qst_type2(x, q))
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("q")
180
+ q = QBit()
178
181
  within_apply(
179
- lambda: (allocate(1, q), X(q)), # type:ignore[arg-type]
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("aux")
43
+ aux = QBit()
44
44
  within_apply(
45
- within=lambda: (allocate(1, aux), X(aux), H(aux)), # type:ignore[arg-type]
45
+ within=lambda: (allocate(aux), X(aux), H(aux)), # type:ignore[arg-type]
46
46
  apply=lambda: predicate(target, aux),
47
47
  )
48
48
 
@@ -56,16 +56,16 @@ def reflect_about_zero(packed_vars: QArray[QBit]) -> None:
56
56
  besides the |0> state). Implements the operator $S_0$:
57
57
 
58
58
  $$
59
- \begin{equation}
60
- S_0|{x}\rangle = (-1)^{(x\ne0)}|{x}\rangle= (2|{0}\rangle\\langle{0}|-I)|{x}\rangle
59
+ \\begin{equation}
60
+ S_0|{x}\\rangle = (-1)^{(x\\ne0)}|{x}\\rangle= (2|{0}\\rangle\\langle{0}|-I)|{x}\\rangle
61
61
  \\end{equation}
62
62
  $$
63
63
 
64
64
  Args:
65
65
  packed_vars: The quantum state to reflect.
66
66
  """
67
- msbs: QNum = QNum("msbs", packed_vars.len - 1, False, 0)
68
- lsb = QBit("lsb")
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]
@@ -85,7 +85,7 @@ def grover_diffuser(
85
85
  is the `space_transform` parameter. It is defined as:
86
86
 
87
87
  $$
88
- \begin{equation}
88
+ \\begin{equation}
89
89
  D = A S_0 A^{\\dagger}
90
90
  \\end{equation}
91
91
  $$
@@ -118,15 +118,15 @@ def grover_operator(
118
118
  $$
119
119
 
120
120
  where $S_{\\psi_1}$ is a reflection about marked states, and $S_{\\psi_0}$ is a reflection
121
- about a given state defined by $|\\psi_0\rangle = A|0\rangle$.
121
+ about a given state defined by $|\\psi_0\\rangle = A|0\\rangle$.
122
122
 
123
123
  Args:
124
124
  oracle: A unitary operator which adds a phase of (-1) to marked states.
125
- space_transform: The operator which creates $|\\psi_0\rangle$, the initial state, used by the diffuser to reflect about it.
125
+ space_transform: The operator which creates $|\\psi_0\\rangle$, the initial state, used by the diffuser to reflect about it.
126
126
  packed_vars: The state to which to apply the grover operator.
127
127
  """
128
128
  oracle(packed_vars)
129
- grover_diffuser(lambda qba: space_transform(qba), packed_vars)
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, QNum
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)), lambda: _ctrl_x(ref, x[0], aux)
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("ctrl")
76
- aux = QBit("aux")
69
+ ctrl: QArray[QBit] = QArray()
70
+ aux = QBit()
77
71
 
78
72
  within_apply(
79
73
  lambda: ( # type:ignore[arg-type]
80
- allocate(1, aux),
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("b")
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 prepare_uniform_trimmed_state_apply_rotation(
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: prepare_uniform_trimmed_state_apply_rotation(
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: prepare_uniform_trimmed_state_apply_rotation(
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: QArray[QBit]) -> None:
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
- modular_increment(start, q)
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(state_num: CInt, q: Output[QArray[QBit, Literal[2]]]) -> None:
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
- q: The quantum variable that will receive the initialized state. Must be uninitialized.
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(2, q)
245
- if_(logical_or(state_num == 1, state_num == 3), lambda: X(q[0]))
246
- if_(logical_or(state_num == 2, state_num == 3), lambda: X(q[1]))
247
- H(q[0])
248
- CX(q[0], q[1])
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(1, test)
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
- apply_to_all(H, target)
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
- array_cast: QArray = QArray("array_cast")
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]
@@ -4,6 +4,7 @@ from .benchmarking import *
4
4
  from .chemistry import *
5
5
  from .exponentiation import *
6
6
  from .finance import *
7
+ from .mid_circuit_measurement import *
7
8
  from .operators import *
8
9
  from .qsvm import *
9
10
  from .standard_gates import *
@@ -66,6 +67,7 @@ CORE_LIB_DECLS = [
66
67
  suzuki_trotter,
67
68
  qdrift,
68
69
  exponentiation_with_depth_constraint,
70
+ RESET,
69
71
  )
70
72
  ]
71
73
 
@@ -129,6 +131,7 @@ __all__ = [ # noqa: RUF022
129
131
  "single_pauli_exponent",
130
132
  "suzuki_trotter",
131
133
  "unitary",
134
+ "RESET",
132
135
  ]
133
136
  BUILTIN_FUNCTION_DECLARATIONS = {
134
137
  func_decl.name: func_decl for func_decl in STD_QMOD_OPERATORS + CORE_LIB_DECLS
@@ -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
@@ -0,0 +1,15 @@
1
+ from classiq.qmod.qfunc import qfunc
2
+ from classiq.qmod.qmod_variable import QBit
3
+
4
+
5
+ @qfunc(external=True)
6
+ def RESET(target: QBit) -> None:
7
+ """
8
+ Resets the target qubit to the |0> state.
9
+
10
+ Performed by measuring the qubit and applying an X gate if necessary.
11
+
12
+ Args:
13
+ target: the qubit to reset
14
+ """
15
+ 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 mangle_keyword, qmod_val_to_expr_str
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 = not isinstance(
375
- arg, (*NativePythonClassicalTypes, CParam, SymbolicExpr, Basic, PythonEnum)
376
- ) and not is_dataclass(
377
- arg
378
- ) # type: ignore[unreachable]
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
@@ -31,6 +31,7 @@ from classiq.qmod.qmod_parameter import CArray, CParam
31
31
  from classiq.qmod.qmod_variable import QVar
32
32
  from classiq.qmod.quantum_callable import QCallable, QCallableList
33
33
  from classiq.qmod.quantum_expandable import QExpandable, QTerminalCallable
34
+ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
34
35
  from classiq.qmod.utilities import mangle_keyword
35
36
 
36
37
 
@@ -161,6 +162,9 @@ class QFunc(BaseQFunc):
161
162
  )
162
163
 
163
164
  generative_functions = list(self._qmodule.generative_functions.values())
165
+ QStructAnnotator().visit(model_stub)
166
+ for gen_func in generative_functions:
167
+ QStructAnnotator().visit(gen_func.func_decl)
164
168
  resolve_function_calls(
165
169
  model_stub,
166
170
  dict(model_stub.function_dict)
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Iterator, Mapping
2
2
  from contextlib import contextmanager
3
- from typing import Any
3
+ from typing import Any, Optional
4
4
 
5
5
  from classiq.interface.exceptions import ClassiqError
6
6
  from classiq.interface.generator.expressions.expression import Expression
@@ -11,6 +11,7 @@ from classiq.interface.generator.functions.port_declaration import (
11
11
  from classiq.interface.model.classical_parameter_declaration import (
12
12
  ClassicalParameterDeclaration,
13
13
  )
14
+ from classiq.interface.model.model import Model
14
15
  from classiq.interface.model.model_visitor import ModelVisitor
15
16
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
16
17
  from classiq.interface.model.port_declaration import PortDeclaration
@@ -108,8 +109,13 @@ class _CallLambdaAnnotator(ModelVisitor):
108
109
 
109
110
  def resolve_function_calls(
110
111
  root: Any,
111
- quantum_function_dict: Mapping[str, QuantumFunctionDeclaration],
112
+ quantum_function_dict: Optional[Mapping[str, QuantumFunctionDeclaration]] = None,
112
113
  ) -> None:
114
+ if quantum_function_dict is None:
115
+ quantum_function_dict = {}
116
+ quantum_function_dict = dict(quantum_function_dict)
117
+ if isinstance(root, Model):
118
+ quantum_function_dict |= root.function_dict
113
119
  all_functions: Mapping[str, QuantumFunctionDeclaration] = {
114
120
  **BUILTIN_FUNCTION_DECLARATIONS,
115
121
  **quantum_function_dict,
@@ -0,0 +1,9 @@
1
+ from classiq.interface.model.model import Model
2
+
3
+ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
4
+ from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
5
+
6
+
7
+ def annotate_model(model: Model) -> None:
8
+ QStructAnnotator().visit(model)
9
+ resolve_function_calls(model)
@@ -94,9 +94,3 @@ class ErrorManager:
94
94
  self._call_stack.append(func_name)
95
95
  yield
96
96
  self._call_stack.pop()
97
-
98
-
99
- def append_error(node: ASTNode, message: str) -> None:
100
- instance = ErrorManager()
101
- with instance.node_context(node):
102
- instance.add_error(message)