classiq 0.102.0__py3-none-any.whl → 1.0.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 (95) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/_internals/authentication/auth0.py +29 -0
  3. classiq/_internals/authentication/auth_flow_factory.py +43 -0
  4. classiq/_internals/authentication/machine_credentials_flow.py +26 -0
  5. classiq/_internals/authentication/password_manager.py +84 -0
  6. classiq/_internals/authentication/token_manager.py +24 -8
  7. classiq/analyzer/show_interactive_hack.py +0 -8
  8. classiq/applications/chemistry/op_utils.py +32 -0
  9. classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
  10. classiq/evaluators/qmod_annotated_expression.py +1 -1
  11. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  12. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  13. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  14. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  15. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  16. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  17. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  18. classiq/execution/all_hardware_devices.py +59 -1
  19. classiq/execution/execution_session.py +1 -1
  20. classiq/execution/functions/__init__.py +13 -0
  21. classiq/execution/functions/expectation_value.py +106 -0
  22. classiq/execution/functions/minimize.py +90 -0
  23. classiq/execution/functions/sample.py +76 -0
  24. classiq/execution/functions/state_vector.py +113 -0
  25. classiq/execution/functions/util/__init__.py +0 -0
  26. classiq/execution/functions/util/_logging.py +19 -0
  27. classiq/execution/functions/util/backend_preferences.py +188 -0
  28. classiq/execution/functions/util/constants.py +9 -0
  29. classiq/execution/functions/util/parse_provider_backend.py +90 -0
  30. classiq/interface/_version.py +1 -1
  31. classiq/interface/backend/backend_preferences.py +81 -0
  32. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  33. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  34. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  35. classiq/interface/backend/quantum_backend_providers.py +14 -0
  36. classiq/interface/exceptions.py +0 -4
  37. classiq/interface/executor/result.py +9 -5
  38. classiq/interface/generator/arith/binary_ops.py +62 -2
  39. classiq/interface/generator/arith/number_utils.py +15 -6
  40. classiq/interface/generator/compiler_keywords.py +1 -0
  41. classiq/interface/generator/function_param_list.py +8 -2
  42. classiq/interface/generator/function_params.py +1 -1
  43. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  44. classiq/interface/generator/functions/classical_type.py +60 -0
  45. classiq/interface/generator/functions/type_name.py +36 -0
  46. classiq/interface/generator/generated_circuit_data.py +0 -2
  47. classiq/interface/generator/transpiler_basis_gates.py +1 -0
  48. classiq/interface/generator/types/compilation_metadata.py +18 -0
  49. classiq/interface/hardware.py +2 -0
  50. classiq/interface/helpers/model_normalizer.py +42 -6
  51. classiq/interface/interface_version.py +1 -1
  52. classiq/interface/model/invert.py +8 -0
  53. classiq/interface/model/model.py +19 -0
  54. classiq/interface/model/model_visitor.py +4 -2
  55. classiq/interface/model/quantum_type.py +36 -0
  56. classiq/interface/model/statement_block.py +0 -4
  57. classiq/interface/qubits_mapping/__init__.py +4 -0
  58. classiq/interface/qubits_mapping/path_expr_range.py +69 -0
  59. classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
  60. classiq/interface/qubits_mapping/slices.py +112 -0
  61. classiq/model_expansions/arithmetic.py +6 -0
  62. classiq/model_expansions/capturing/captured_vars.py +16 -12
  63. classiq/model_expansions/function_builder.py +9 -1
  64. classiq/model_expansions/interpreters/base_interpreter.py +9 -8
  65. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  66. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  67. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  68. classiq/model_expansions/quantum_operations/bind.py +4 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  70. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  72. classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
  73. classiq/qmod/builtins/functions/__init__.py +21 -9
  74. classiq/qmod/builtins/functions/allocation.py +0 -36
  75. classiq/qmod/builtins/functions/arithmetic.py +183 -0
  76. classiq/qmod/builtins/functions/exponentiation.py +32 -2
  77. classiq/qmod/builtins/functions/gray_code.py +23 -0
  78. classiq/qmod/builtins/functions/mcx_func.py +10 -0
  79. classiq/qmod/builtins/operations.py +2 -38
  80. classiq/qmod/builtins/structs.py +22 -3
  81. classiq/qmod/native/pretty_printer.py +1 -12
  82. classiq/qmod/pretty_print/pretty_printer.py +1 -17
  83. classiq/qmod/qmod_parameter.py +4 -0
  84. classiq/qmod/qmod_variable.py +38 -63
  85. classiq/qmod/quantum_function.py +43 -7
  86. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  87. classiq/qmod/semantics/validation/model_validation.py +7 -2
  88. classiq/qmod/symbolic_type.py +4 -2
  89. classiq/qprog_to_cudaq.py +347 -0
  90. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
  91. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
  92. classiq/interface/generator/amplitude_loading.py +0 -103
  93. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  94. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  from typing import Literal
2
2
 
3
+ from classiq.qmod.cparam import CInt
3
4
  from classiq.qmod.qfunc import qfunc, qperm
4
5
  from classiq.qmod.qmod_parameter import CArray, CBool, CReal
5
6
  from classiq.qmod.qmod_variable import (
@@ -65,6 +66,58 @@ def add_inplace_right(
65
66
  pass
66
67
 
67
68
 
69
+ @qperm(external=True)
70
+ def canonical_add(
71
+ left: Const[QArray],
72
+ extend_left: CBool,
73
+ right: QArray,
74
+ ) -> None:
75
+ """
76
+ [Qmod core-library function]
77
+
78
+ Adds two quantum variables representing integers (signed or unsigned), storing the
79
+ result in the second variable (in-place):
80
+
81
+ $$
82
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
83
+ \\mapsto
84
+ \\left|\\text{left}\\right\\rangle \\left|\\left(\\text{right} +
85
+ \\text{left}\\right) \\bmod 2^{\\text{right.size}} \\right\\rangle
86
+ $$
87
+
88
+ Args:
89
+ left: The out-of-place argument for the addition.
90
+ extend_left: Whether to sign-extend the left argument.
91
+ right: The in-place argument for the addition, holds the final result.
92
+ """
93
+ pass
94
+
95
+
96
+ @qperm(external=True)
97
+ def canonical_add_constant(
98
+ left: CInt,
99
+ right: QArray,
100
+ ) -> None:
101
+ """
102
+ [Qmod core-library function]
103
+
104
+ Adds an integer constant to a quantum variable representing an integer (signed or
105
+ unsigned):
106
+
107
+ $$
108
+ \\left|\\text{right}\\right\\rangle
109
+ \\mapsto
110
+ \\left|\\left(\\text{right} +
111
+ \\text{left}\\right) \\bmod 2^{\\text{right.size}} \\right\\rangle
112
+ $$
113
+
114
+ Args:
115
+ left: The constant argument for the addition.
116
+ right: The quantum argument for the addition, holds the final result.
117
+ """
118
+ pass
119
+
120
+
68
121
  @qperm(external=True)
69
122
  def modular_add(left: Const[QArray[QBit]], right: QArray[QBit]) -> None:
70
123
  pass
@@ -83,3 +136,133 @@ def integer_xor(left: Const[QArray[QBit]], right: QArray[QBit]) -> None:
83
136
  @qperm(external=True)
84
137
  def real_xor_constant(left: CReal, right: QNum) -> None:
85
138
  pass
139
+
140
+
141
+ @qperm(external=True)
142
+ def multiply(left: Const[QNum], right: Const[QNum], result: Output[QNum]) -> None:
143
+ """
144
+ [Qmod core-library function]
145
+
146
+ Multiplies two quantum numeric variables:
147
+
148
+ $$
149
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
150
+ \\mapsto
151
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
152
+ \\left|\\text{left} \\cdot \\text{right} \\right\\rangle
153
+ $$
154
+
155
+ Args:
156
+ left: The first argument for the multiplication.
157
+ right: The second argument for the multiplication.
158
+ result: The quantum variable to hold the multiplication result.
159
+ """
160
+ pass
161
+
162
+
163
+ @qperm(external=True)
164
+ def multiply_constant(left: CReal, right: Const[QNum], result: Output[QNum]) -> None:
165
+ """
166
+ [Qmod core-library function]
167
+
168
+ Multiplies a quantum numeric variable with a constant:
169
+
170
+ $$
171
+ \\left|\\text{right}\\right\\rangle
172
+ \\mapsto
173
+ \\left|\\text{right}\\right\\rangle
174
+ \\left|\\text{left} \\cdot \\text{right} \\right\\rangle
175
+ $$
176
+
177
+ Args:
178
+ left: The constant argument for the multiplication.
179
+ right: The variable argument for the multiplication.
180
+ result: The quantum variable to hold the multiplication result.
181
+ """
182
+ pass
183
+
184
+
185
+ @qperm(external=True)
186
+ def canonical_multiply(
187
+ left: Const[QArray],
188
+ extend_left: CBool,
189
+ right: Const[QArray],
190
+ extend_right: CBool,
191
+ result: QArray,
192
+ trim_result_lsb: CBool,
193
+ ) -> None:
194
+ """
195
+ [Qmod core-library function]
196
+
197
+ Multiplies two quantum variables representing integers (signed or unsigned) into the
198
+ result variable which is assumed to start in the $|0\\rangle$ state.
199
+
200
+ If `trim_result_lsb` is `False`, applies the transformation:
201
+
202
+ $$
203
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
204
+ \\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
205
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
206
+ \\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
207
+ $$
208
+
209
+ If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
210
+ applies the transformation:
211
+
212
+ $$
213
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
214
+ \\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
215
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
216
+ \\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
217
+ $$
218
+
219
+ Args:
220
+ left: The first argument for the multiplication.
221
+ extend_left: Whether to sign-extend the left argument.
222
+ right: The second argument for the multiplication.
223
+ extend_right: Whether to sign-extend the right argument.
224
+ result: The quantum variable to hold the multiplication result.
225
+ trim_result_lsb: Whether to avoid computing the result's LSB.
226
+ """
227
+ pass
228
+
229
+
230
+ @qperm(external=True)
231
+ def canonical_multiply_constant(
232
+ left: CInt,
233
+ right: Const[QArray],
234
+ extend_right: CBool,
235
+ result: QArray,
236
+ trim_result_lsb: CBool,
237
+ ) -> None:
238
+ """
239
+ [Qmod core-library function]
240
+
241
+ Multiplies a quantum variable representing an integer (signed or unsigned) with a
242
+ constant, into the result variable which is assumed to start in the $|0\\rangle$ state.
243
+
244
+ If `trim_result_lsb` is `False`, applies the transformation:
245
+
246
+ $$
247
+ \\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
248
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
249
+ \\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
250
+ $$
251
+
252
+ If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
253
+ applies the transformation:
254
+
255
+ $$
256
+ \\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
257
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
258
+ \\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
259
+ $$
260
+
261
+ Args:
262
+ left: The constant argument for the multiplication.
263
+ right: The variable argument for the multiplication.
264
+ extend_right: Whether to sign-extend the right argument.
265
+ result: The quantum variable to hold the multiplication result.
266
+ trim_result_lsb: Whether to avoid computing the result's LSB.
267
+ """
268
+ pass
@@ -99,7 +99,7 @@ def multi_suzuki_trotter(
99
99
  The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
100
100
 
101
101
  Args:
102
- hamiltonians: The hamitonians to be exponentiated, in sparse representation.
102
+ hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
103
103
  evolution_coefficients: The hamiltonian coefficients (can be link-time).
104
104
  order: The order of the Suzuki-Trotter decomposition.
105
105
  repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
@@ -129,7 +129,37 @@ def unscheduled_suzuki_trotter(
129
129
  The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
130
130
 
131
131
  Args:
132
- hamiltonians: The hamitonians to be exponentiated, in sparse representation.
132
+ hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
133
+ evolution_coefficients: The hamiltonian coefficients (can be link-time).
134
+ order: The order of the Suzuki-Trotter decomposition.
135
+ repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
136
+ qbv: The target quantum variable of the exponentiation.
137
+ """
138
+ pass
139
+
140
+
141
+ @qfunc(external=True)
142
+ def sequential_suzuki_trotter(
143
+ hamiltonians: CArray[SparsePauliOp],
144
+ evolution_coefficients: CArray[CReal],
145
+ order: CInt,
146
+ repetitions: CInt,
147
+ qbv: QArray,
148
+ ) -> None:
149
+ """
150
+ [Qmod core-library function]
151
+
152
+ Applies the Suzuki-Trotter decomposition jointly to a sum of Hamiltonians
153
+ (represented as Pauli operators), each with its separate evolution coefficient,
154
+ approximating $\\exp{-iH_1t_1+H_2t_2+\\dots}$ with a specified order and number of
155
+ repetitions. Does not reorder the Pauli terms.
156
+
157
+ The Suzuki-Trotter decomposition is a method for approximating the exponential of a sum of operators by a product of exponentials of each operator.
158
+ 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.
159
+ The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
160
+
161
+ Args:
162
+ hamiltonians: The hamiltonians to be exponentiated, in sparse representation.
133
163
  evolution_coefficients: The hamiltonian coefficients (can be link-time).
134
164
  order: The order of the Suzuki-Trotter decomposition.
135
165
  repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
@@ -0,0 +1,23 @@
1
+ from classiq.qmod.builtins.enums import Pauli
2
+ from classiq.qmod.qfunc import qfunc
3
+ from classiq.qmod.qmod_parameter import CArray, CReal
4
+ from classiq.qmod.qmod_variable import QBit, QNum
5
+
6
+
7
+ @qfunc(external=True)
8
+ def select_rotation(
9
+ basis: Pauli, angles: CArray[CReal], selector: QNum, target: QBit
10
+ ) -> None:
11
+ """
12
+ [Qmod core-library function]
13
+
14
+ Applies a set of controlled single-qubit rotations to a target qubit, using
15
+ a specified rotation axis and a list of rotation angles.
16
+
17
+ Args:
18
+ basis: The Pauli operator defining the rotation axis.
19
+ angles: The list of rotation angles in radians. The list must have length 2**selector.size.
20
+ selector: The qubits that act as the selection register.
21
+ target: The qubit on which the selected rotation is applied.
22
+ """
23
+ pass
@@ -5,3 +5,13 @@ from classiq.qmod.qmod_variable import Const, QArray, QBit
5
5
  @qperm(external=True)
6
6
  def mcx(ctrl: Const[QArray[QBit]], target: QBit) -> None:
7
7
  pass
8
+
9
+
10
+ @qperm(external=True)
11
+ def mcx_gray_code(ctrl: Const[QArray[QBit]], target: QBit) -> None:
12
+ pass
13
+
14
+
15
+ @qperm(external=True)
16
+ def mcx_hybrid_rec(ctrl: Const[QArray[QBit]], target: QBit, aux: QArray[QBit]) -> None:
17
+ pass
@@ -1,6 +1,5 @@
1
1
  import inspect
2
2
  import sys
3
- import warnings
4
3
  from collections.abc import Callable, Mapping
5
4
  from functools import wraps
6
5
  from itertools import product
@@ -14,7 +13,7 @@ from typing import (
14
13
  overload,
15
14
  )
16
15
 
17
- from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqValueError
16
+ from classiq.interface.exceptions import ClassiqValueError
18
17
  from classiq.interface.generator.expressions.expression import Expression
19
18
  from classiq.interface.generator.functions.builtins.internal_operators import (
20
19
  REPEAT_OPERATOR_NAME,
@@ -33,9 +32,6 @@ from classiq.interface.model.control import Control
33
32
  from classiq.interface.model.invert import BlockKind, Invert
34
33
  from classiq.interface.model.phase_operation import PhaseOperation
35
34
  from classiq.interface.model.power import Power
36
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
37
- AmplitudeLoadingOperation,
38
- )
39
35
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
40
36
  ArithmeticOperation,
41
37
  ArithmeticOperationKind,
@@ -336,37 +332,6 @@ def assign(expression: SymbolicExpr, target_var: QScalar) -> None:
336
332
  )
337
333
 
338
334
 
339
- @suppress_return_value
340
- @qmod_statement
341
- def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
342
- """
343
- Perform an amplitude-encoding assignment operation on a quantum variable and a
344
- quantum expression.
345
-
346
- Equivalent to `<target_var> *= <expression>`.
347
-
348
- Args:
349
- expression: A quantum arithmetic expression
350
- target_var: A scalar quantum variable
351
- """
352
- warnings.warn(
353
- "The 'assign_amplitude' function is deprecated and will no longer be "
354
- "supported starting on 2025-12-03 at the earliest. Use 'assign_amplitude_table' "
355
- "instead",
356
- ClassiqDeprecationWarning,
357
- stacklevel=3,
358
- )
359
- assert QCallable.CURRENT_EXPANDABLE is not None
360
- source_ref = get_source_ref(sys._getframe(2))
361
- QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
362
- AmplitudeLoadingOperation(
363
- expression=Expression(expr=str(expression)),
364
- result_var=target_var.get_handle_binding(),
365
- source_ref=source_ref,
366
- )
367
- )
368
-
369
-
370
335
  @suppress_return_value
371
336
  @qmod_statement
372
337
  def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
@@ -553,7 +518,7 @@ def power(
553
518
 
554
519
  @suppress_return_value
555
520
  @qmod_statement
556
- def invert(stmt_block: QCallable | Callable[[], Statements]) -> Callable | None:
521
+ def invert(stmt_block: QCallable | Callable[[], Statements]) -> Any:
557
522
  """
558
523
  Apply the inverse of a quantum gate.
559
524
 
@@ -868,7 +833,6 @@ def lookup_table(func: RealFunction, targets: QNum | list[QNum]) -> list[float]:
868
833
  __all__ = [
869
834
  "allocate",
870
835
  "assign",
871
- "assign_amplitude",
872
836
  "assign_amplitude_poly_sin",
873
837
  "bind",
874
838
  "block",
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, fields, is_dataclass
2
- from typing import Union
2
+ from typing import Any, Union
3
3
 
4
4
  from classiq.interface.exceptions import ClassiqValueError
5
5
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
@@ -117,13 +117,21 @@ class SparsePauliOp:
117
117
  def __rmul__(self, obj: Union[float, "SparsePauliOp"]) -> "SparsePauliOp":
118
118
  return self.__mul__(obj)
119
119
 
120
- def __add__(self, other: "SparsePauliOp") -> "SparsePauliOp":
120
+ def __add__(self, other: Any) -> "SparsePauliOp":
121
+ if not isinstance(other, SparsePauliOp):
122
+ raise ClassiqValueError(
123
+ f"Cannot add an object of type {type(other).__name__} to SparsePauliOp"
124
+ )
121
125
  return SparsePauliOp(
122
126
  terms=LenList(self.terms + other.terms),
123
127
  num_qubits=max(self.num_qubits, other.num_qubits),
124
128
  )
125
129
 
126
- def __sub__(self, other: "SparsePauliOp") -> "SparsePauliOp":
130
+ def __sub__(self, other: Any) -> "SparsePauliOp":
131
+ if not isinstance(other, SparsePauliOp):
132
+ raise ClassiqValueError(
133
+ f"Cannot substruct an object of type {type(other).__name__} to SparsePauliOp"
134
+ )
127
135
  return self + -1.0 * other
128
136
 
129
137
  def __str__(self) -> str:
@@ -136,6 +144,17 @@ class SparsePauliOp:
136
144
  for term in self.terms
137
145
  )
138
146
 
147
+ def __truediv__(self, other: Any) -> "SparsePauliOp":
148
+ if not isinstance(other, (int, float)):
149
+ raise ClassiqValueError(
150
+ f"Cannot divide SparsePauliOp by object of type {type(other).__name__}"
151
+ )
152
+ if other == 0:
153
+ raise ClassiqValueError("Cannot divide by zero")
154
+ return SparsePauliOp(terms=self.terms, num_qubits=self.num_qubits) * float(
155
+ 1 / other
156
+ )
157
+
139
158
 
140
159
  @dataclass
141
160
  class CombinatorialOptimizationSolution:
@@ -51,9 +51,6 @@ from classiq.interface.model.port_declaration import (
51
51
  AnonPortDeclaration,
52
52
  )
53
53
  from classiq.interface.model.power import Power
54
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
55
- AmplitudeLoadingOperation,
56
- )
57
54
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
58
55
  ArithmeticOperation,
59
56
  ArithmeticOperationKind,
@@ -367,12 +364,9 @@ class DSLPrettyPrinter(ModelVisitor):
367
364
  return power_code
368
365
 
369
366
  def visit_Invert(self, invert: Invert) -> str:
367
+ invert.validate_node()
370
368
  match invert.block_kind:
371
369
  case BlockKind.SingleCall:
372
- if len(invert.body) != 1 or not isinstance(
373
- invert.body[0], QuantumFunctionCall
374
- ):
375
- raise ClassiqInternalError("Malformed single-call invert")
376
370
  invert_code = f"{self._indent}invert "
377
371
  invert_code += self.visit(invert.body[0]).lstrip()
378
372
  case BlockKind.Compound:
@@ -446,11 +440,6 @@ class DSLPrettyPrinter(ModelVisitor):
446
440
  op = "+="
447
441
  return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
448
442
 
449
- def visit_AmplitudeLoadingOperation(
450
- self, amplitude_loading_op: AmplitudeLoadingOperation
451
- ) -> str:
452
- return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)};\n"
453
-
454
443
  def _print_bind_handles(self, handles: list[HandleBinding]) -> str:
455
444
  if len(handles) == 1:
456
445
  return self.visit(handles[0])
@@ -52,9 +52,6 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
52
52
  from classiq.interface.model.phase_operation import PhaseOperation
53
53
  from classiq.interface.model.port_declaration import AnonPortDeclaration
54
54
  from classiq.interface.model.power import Power
55
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
56
- AmplitudeLoadingOperation,
57
- )
58
55
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
59
56
  ArithmeticOperation,
60
57
  ArithmeticOperationKind,
@@ -508,13 +505,10 @@ class PythonPrettyPrinter(ModelVisitor):
508
505
  return f"{self._indent}power({self.visit(power.power)}, {self._visit_body(power.body)})\n"
509
506
 
510
507
  def visit_Invert(self, invert: Invert) -> str:
508
+ invert.validate_node()
511
509
  self._imports["invert"] = 1
512
510
  match invert.block_kind:
513
511
  case BlockKind.SingleCall:
514
- if len(invert.body) != 1 or not isinstance(
515
- invert.body[0], QuantumFunctionCall
516
- ):
517
- raise ClassiqInternalError("Malformed single-call invert")
518
512
  call_str = self.visit(invert.body[0])
519
513
  call_str = call_str.replace("(", ")(", 1)
520
514
  return f"{self._indent}invert({call_str}\n"
@@ -540,8 +534,6 @@ class PythonPrettyPrinter(ModelVisitor):
540
534
  for i, statement in enumerate(body):
541
535
  if isinstance(statement, VariableDeclarationStatement):
542
536
  code += self.visit_VariableDeclarationStatement(statement, walrus=True)
543
- elif isinstance(statement, AmplitudeLoadingOperation):
544
- code += self.visit_AmplitudeLoadingOperation(statement, in_lambda=True)
545
537
  elif isinstance(statement, ArithmeticOperation):
546
538
  code += self.visit_ArithmeticOperation(statement, in_lambda=True)
547
539
  else:
@@ -599,14 +591,6 @@ class PythonPrettyPrinter(ModelVisitor):
599
591
  return f"{func}({self.visit(arith_op.expression)}, {self._indent}{self.visit(arith_op.result_var)})\n"
600
592
  return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)}\n"
601
593
 
602
- def visit_AmplitudeLoadingOperation(
603
- self, amplitude_loading_op: AmplitudeLoadingOperation, in_lambda: bool = False
604
- ) -> str:
605
- if in_lambda:
606
- self._imports["assign_amplitude"] = 1
607
- return f"assign_amplitude({self.visit(amplitude_loading_op.expression)}, {self._indent}{self.visit(amplitude_loading_op.result_var)})\n"
608
- return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)}\n"
609
-
610
594
  def _print_bind_handles(self, handles: list[HandleBinding]) -> str:
611
595
  if len(handles) == 1:
612
596
  return self.visit(handles[0])
@@ -63,6 +63,10 @@ class CParamList(CParam):
63
63
  else:
64
64
  param_type = self._list_type.element_type
65
65
  else:
66
+ if key.start is None:
67
+ key = slice(0, key.stop, None)
68
+ if key.stop is None:
69
+ key = slice(key.start, self.len, None)
66
70
  if not isinstance(self._list_type, ClassicalTuple):
67
71
  param_type = self._list_type
68
72
  else:
@@ -1,6 +1,5 @@
1
1
  import abc
2
2
  import sys
3
- import warnings
4
3
  from collections.abc import Iterator, Mapping
5
4
  from contextlib import contextmanager
6
5
  from typing import ( # type: ignore[attr-defined]
@@ -23,7 +22,6 @@ from typing import ( # type: ignore[attr-defined]
23
22
  from typing_extensions import ParamSpec, Self, _AnnotatedAlias
24
23
 
25
24
  from classiq.interface.exceptions import (
26
- ClassiqDeprecationWarning,
27
25
  ClassiqInternalError,
28
26
  ClassiqNotImplementedError,
29
27
  ClassiqValueError,
@@ -45,9 +43,6 @@ from classiq.interface.model.handle_binding import (
45
43
  SlicedHandleBinding,
46
44
  SubscriptHandleBinding,
47
45
  )
48
- from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
49
- AmplitudeLoadingOperation,
50
- )
51
46
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
52
47
  ArithmeticOperation,
53
48
  ArithmeticOperationKind,
@@ -161,37 +156,6 @@ class QVar(Symbolic):
161
156
  def type_name(self) -> str:
162
157
  return self.get_qmod_type().type_name
163
158
 
164
-
165
- class QmodExpressionCreator(Protocol):
166
- """
167
- A callable that creates a Qmod expression from the provided QVars.
168
- """
169
-
170
- def __call__(self, **kwargs: QVar) -> SymbolicExpr: ...
171
-
172
-
173
- _Q = TypeVar("_Q", bound=QVar)
174
- Output = Annotated[_Q, PortDeclarationDirection.Output]
175
- Input = Annotated[_Q, PortDeclarationDirection.Input]
176
- Const = Annotated[
177
- _Q, TypeModifier.Const
178
- ] # A constant variable, up to a phase dependent on the computational basis state
179
-
180
-
181
- class QScalar(QVar, SymbolicExpr):
182
- CONSTRUCTOR_DEPTH: int = 2
183
-
184
- def __init__(
185
- self,
186
- origin: None | str | HandleBinding = None,
187
- *,
188
- _expr_str: str | None = None,
189
- depth: int = 2,
190
- ) -> None:
191
- origin = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
192
- QVar.__init__(self, origin, expr_str=_expr_str, depth=depth)
193
- SymbolicExpr.__init__(self, str(origin), True)
194
-
195
159
  def _insert_arith_operation(
196
160
  self,
197
161
  expr: SymbolicTypes,
@@ -210,19 +174,6 @@ class QScalar(QVar, SymbolicExpr):
210
174
  )
211
175
  )
212
176
 
213
- def _insert_amplitude_loading(
214
- self, expr: SymbolicTypes, source_ref: SourceReference
215
- ) -> None:
216
- if TYPE_CHECKING:
217
- assert QCallable.CURRENT_EXPANDABLE is not None
218
- QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
219
- AmplitudeLoadingOperation(
220
- expression=Expression(expr=str(expr)),
221
- result_var=self.get_handle_binding(),
222
- source_ref=source_ref,
223
- )
224
- )
225
-
226
177
  def __ior__(self, other: Any) -> Self:
227
178
  if not isinstance(other, SYMBOLIC_TYPES):
228
179
  raise ClassiqValueError(
@@ -245,6 +196,37 @@ class QScalar(QVar, SymbolicExpr):
245
196
  )
246
197
  return self
247
198
 
199
+
200
+ class QmodExpressionCreator(Protocol):
201
+ """
202
+ A callable that creates a Qmod expression from the provided QVars.
203
+ """
204
+
205
+ def __call__(self, **kwargs: QVar) -> SymbolicExpr: ...
206
+
207
+
208
+ _Q = TypeVar("_Q", bound=QVar)
209
+ Output = Annotated[_Q, PortDeclarationDirection.Output]
210
+ Input = Annotated[_Q, PortDeclarationDirection.Input]
211
+ Const = Annotated[
212
+ _Q, TypeModifier.Const
213
+ ] # A constant variable, up to a phase dependent on the computational basis state
214
+
215
+
216
+ class QScalar(QVar, SymbolicExpr):
217
+ CONSTRUCTOR_DEPTH: int = 2
218
+
219
+ def __init__(
220
+ self,
221
+ origin: None | str | HandleBinding = None,
222
+ *,
223
+ _expr_str: str | None = None,
224
+ depth: int = 2,
225
+ ) -> None:
226
+ origin = _infer_variable_name(origin, self.CONSTRUCTOR_DEPTH)
227
+ QVar.__init__(self, origin, expr_str=_expr_str, depth=depth)
228
+ SymbolicExpr.__init__(self, str(origin), True)
229
+
248
230
  def __iadd__(self, other: Any) -> Self:
249
231
  if not isinstance(other, SYMBOLIC_TYPES):
250
232
  raise ClassiqValueError(
@@ -256,21 +238,10 @@ class QScalar(QVar, SymbolicExpr):
256
238
  )
257
239
  return self
258
240
 
259
- def __imul__(self, other: Any) -> Self:
260
- warnings.warn(
261
- "The '*=' operator is deprecated and will no longer be supported "
262
- "starting on 2025-12-03 at the earliest. Use the 'assign_amplitude_table' "
263
- "function instead",
264
- ClassiqDeprecationWarning,
265
- stacklevel=2,
241
+ def __imul__(self, other: Any) -> NoReturn:
242
+ raise ClassiqNotImplementedError(
243
+ f"{self.get_qmod_type().raw_qmod_type_name} does not support '*='"
266
244
  )
267
- if not isinstance(other, SYMBOLIC_TYPES):
268
- raise ClassiqValueError(
269
- f"Invalid argument {str(other)!r} for out of ampltiude encoding operation"
270
- )
271
-
272
- self._insert_amplitude_loading(other, get_source_ref(sys._getframe(1)))
273
- return self
274
245
 
275
246
  def __iand__(self, other: Any) -> NoReturn:
276
247
  raise ClassiqNotImplementedError(
@@ -558,6 +529,10 @@ class QArray(ArrayBase[_P], QVar, NonSymbolicExpr):
558
529
  def _get_slice(self, slice_: slice) -> Any:
559
530
  if slice_.step is not None:
560
531
  raise ClassiqValueError(ILLEGAL_SLICING_STEP_MSG)
532
+ if slice_.start is None:
533
+ slice_ = slice(0, slice_.stop, None)
534
+ if slice_.stop is None:
535
+ slice_ = slice(slice_.start, self.len, None)
561
536
  if not isinstance(slice_.start, (int, SymbolicExpr)) or not isinstance(
562
537
  slice_.stop, (int, SymbolicExpr)
563
538
  ):