classiq 0.100.0__py3-none-any.whl → 0.104.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 +3 -0
  2. classiq/_internals/api_wrapper.py +29 -4
  3. classiq/applications/chemistry/op_utils.py +63 -1
  4. classiq/applications/chemistry/problems.py +18 -6
  5. classiq/applications/chemistry/ucc.py +2 -2
  6. classiq/evaluators/parameter_types.py +1 -4
  7. classiq/evaluators/qmod_annotated_expression.py +1 -1
  8. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  9. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  10. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  11. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  12. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  13. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  14. classiq/evaluators/qmod_node_evaluators/utils.py +6 -3
  15. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  16. classiq/execution/__init__.py +11 -1
  17. classiq/execution/execution_session.py +1 -1
  18. classiq/execution/functions/__init__.py +3 -0
  19. classiq/execution/functions/_logging.py +19 -0
  20. classiq/execution/functions/constants.py +9 -0
  21. classiq/execution/functions/parse_provider_backend.py +90 -0
  22. classiq/execution/functions/sample.py +257 -0
  23. classiq/execution/jobs.py +122 -5
  24. classiq/interface/_version.py +1 -1
  25. classiq/interface/backend/backend_preferences.py +15 -0
  26. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  27. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  28. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  29. classiq/interface/backend/quantum_backend_providers.py +3 -0
  30. classiq/interface/exceptions.py +0 -42
  31. classiq/interface/executor/execution_request.py +1 -0
  32. classiq/interface/executor/quantum_code.py +0 -6
  33. classiq/interface/executor/result.py +9 -5
  34. classiq/interface/generator/arith/binary_ops.py +38 -2
  35. classiq/interface/generator/function_param_list.py +4 -2
  36. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  37. classiq/interface/generator/functions/classical_type.py +45 -0
  38. classiq/interface/generator/functions/type_name.py +23 -0
  39. classiq/interface/generator/generated_circuit_data.py +0 -2
  40. classiq/interface/generator/generation_request.py +9 -4
  41. classiq/interface/generator/quantum_program.py +8 -36
  42. classiq/interface/generator/types/compilation_metadata.py +9 -0
  43. classiq/interface/hardware.py +1 -0
  44. classiq/interface/helpers/model_normalizer.py +62 -2
  45. classiq/interface/helpers/text_utils.py +17 -6
  46. classiq/interface/interface_version.py +1 -1
  47. classiq/interface/model/invert.py +15 -0
  48. classiq/interface/model/model.py +42 -3
  49. classiq/interface/model/model_visitor.py +4 -2
  50. classiq/interface/model/quantum_function_call.py +17 -5
  51. classiq/interface/model/quantum_type.py +21 -0
  52. classiq/interface/model/statement_block.py +0 -4
  53. classiq/model_expansions/capturing/captured_vars.py +16 -12
  54. classiq/model_expansions/function_builder.py +9 -1
  55. classiq/model_expansions/interpreters/base_interpreter.py +12 -10
  56. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  57. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  58. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  59. classiq/model_expansions/quantum_operations/bind.py +4 -0
  60. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  61. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  62. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  63. classiq/model_expansions/visitors/uncomputation_signature_inference.py +15 -47
  64. classiq/open_library/functions/__init__.py +42 -27
  65. classiq/open_library/functions/bit_operations.py +30 -0
  66. classiq/open_library/functions/modular_arithmetics.py +597 -0
  67. classiq/open_library/functions/qft_space_arithmetics.py +81 -0
  68. classiq/open_library/functions/state_preparation.py +6 -3
  69. classiq/open_library/functions/utility_functions.py +22 -3
  70. classiq/qmod/builtins/functions/__init__.py +9 -0
  71. classiq/qmod/builtins/functions/arithmetic.py +131 -0
  72. classiq/qmod/builtins/functions/exponentiation.py +34 -4
  73. classiq/qmod/builtins/operations.py +30 -41
  74. classiq/qmod/native/pretty_printer.py +12 -12
  75. classiq/qmod/pretty_print/pretty_printer.py +11 -15
  76. classiq/qmod/qmod_parameter.py +4 -0
  77. classiq/qmod/qmod_variable.py +38 -63
  78. classiq/qmod/quantum_callable.py +8 -2
  79. classiq/qmod/quantum_expandable.py +3 -1
  80. classiq/qmod/quantum_function.py +45 -8
  81. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  82. classiq/qmod/semantics/validation/model_validation.py +7 -2
  83. classiq/qmod/symbolic_type.py +4 -2
  84. classiq/qmod/utilities.py +7 -4
  85. classiq/synthesis_action/__init__.py +20 -0
  86. classiq/synthesis_action/actions.py +106 -0
  87. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/METADATA +1 -1
  88. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/RECORD +90 -84
  89. classiq/interface/executor/register_initialization.py +0 -36
  90. classiq/interface/generator/amplitude_loading.py +0 -103
  91. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  92. classiq/open_library/functions/modular_exponentiation.py +0 -272
  93. classiq/open_library/functions/qsvt_temp.py +0 -536
  94. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.100.0.dist-info → classiq-0.104.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -4,13 +4,13 @@ from typing import Annotated
4
4
  from classiq.interface.exceptions import ClassiqDeprecationWarning
5
5
 
6
6
  from classiq.open_library.functions.qft_functions import qft
7
- from classiq.qmod.builtins.functions.standard_gates import PHASE, H
7
+ from classiq.qmod.builtins.functions.standard_gates import PHASE, SWAP, H
8
8
  from classiq.qmod.builtins.operations import bind, repeat, within_apply
9
9
  from classiq.qmod.cparam import CInt
10
- from classiq.qmod.qfunc import qfunc
10
+ from classiq.qmod.qfunc import qfunc, qperm
11
11
  from classiq.qmod.qmod_variable import QArray, QBit, QCallable, QNum
12
12
  from classiq.qmod.quantum_callable import QCallableList
13
- from classiq.qmod.symbolic import pi
13
+ from classiq.qmod.symbolic import min, pi
14
14
 
15
15
 
16
16
  @qfunc
@@ -50,6 +50,25 @@ def hadamard_transform(target: QArray[QBit]) -> None:
50
50
  repeat(target.len, lambda index: H(target[index]))
51
51
 
52
52
 
53
+ @qperm
54
+ def multiswap(x: QArray[QBit], y: QArray[QBit]) -> None:
55
+ """
56
+ [Qmod Classiq-library function]
57
+
58
+ Swaps the qubit states between two arrays.
59
+ Qubits of respective indices are swapped, and additional qubits in the longer array are left unchanged.
60
+
61
+ Args:
62
+ x: The first array
63
+ y: The second array
64
+
65
+ """
66
+ repeat(
67
+ count=min(x.len, y.len),
68
+ iteration=lambda index: SWAP(x[index], y[index]),
69
+ )
70
+
71
+
53
72
  @qfunc
54
73
  def switch(selector: CInt, cases: QCallableList) -> None:
55
74
  cases[selector]()
@@ -48,6 +48,10 @@ CORE_LIB_DECLS = [
48
48
  integer_xor,
49
49
  modular_add_constant,
50
50
  real_xor_constant,
51
+ multiply,
52
+ multiply_constant,
53
+ canonical_multiply,
54
+ canonical_multiply_constant,
51
55
  U,
52
56
  CCX,
53
57
  free,
@@ -61,6 +65,7 @@ CORE_LIB_DECLS = [
61
65
  commuting_paulis_exponent,
62
66
  suzuki_trotter,
63
67
  unscheduled_suzuki_trotter,
68
+ sequential_suzuki_trotter,
64
69
  exponentiate,
65
70
  multi_suzuki_trotter,
66
71
  parametric_suzuki_trotter,
@@ -111,6 +116,10 @@ __all__ = [ # noqa: RUF022
111
116
  "add_inplace_right",
112
117
  "apply",
113
118
  "exponentiation_with_depth_constraint",
119
+ "multiply",
120
+ "multiply_constant",
121
+ "canonical_multiply",
122
+ "canonical_multiply_constant",
114
123
  "free",
115
124
  "drop",
116
125
  "inplace_prepare_amplitudes",
@@ -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 (
@@ -83,3 +84,133 @@ def integer_xor(left: Const[QArray[QBit]], right: QArray[QBit]) -> None:
83
84
  @qperm(external=True)
84
85
  def real_xor_constant(left: CReal, right: QNum) -> None:
85
86
  pass
87
+
88
+
89
+ @qperm(external=True)
90
+ def multiply(left: Const[QNum], right: Const[QNum], result: Output[QNum]) -> None:
91
+ """
92
+ [Qmod core-library function]
93
+
94
+ Multiplies two quantum numeric variables:
95
+
96
+ $$
97
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
98
+ \\mapsto
99
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
100
+ \\left|\\text{left} \\cdot \\text{right} \\right\\rangle
101
+ $$
102
+
103
+ Args:
104
+ left: The first argument for the multiplication.
105
+ right: The second argument for the multiplication.
106
+ result: The quantum variable to hold the multiplication result.
107
+ """
108
+ pass
109
+
110
+
111
+ @qperm(external=True)
112
+ def multiply_constant(left: CReal, right: Const[QNum], result: Output[QNum]) -> None:
113
+ """
114
+ [Qmod core-library function]
115
+
116
+ Multiplies a quantum numeric variable with a constant:
117
+
118
+ $$
119
+ \\left|\\text{right}\\right\\rangle
120
+ \\mapsto
121
+ \\left|\\text{right}\\right\\rangle
122
+ \\left|\\text{left} \\cdot \\text{right} \\right\\rangle
123
+ $$
124
+
125
+ Args:
126
+ left: The constant argument for the multiplication.
127
+ right: The variable argument for the multiplication.
128
+ result: The quantum variable to hold the multiplication result.
129
+ """
130
+ pass
131
+
132
+
133
+ @qperm(external=True)
134
+ def canonical_multiply(
135
+ left: Const[QArray],
136
+ extend_left: CBool,
137
+ right: Const[QArray],
138
+ extend_right: CBool,
139
+ result: QArray,
140
+ trim_result_lsb: CBool,
141
+ ) -> None:
142
+ """
143
+ [Qmod core-library function]
144
+
145
+ Multiplies two quantum variables representing integers (signed or unsigned) into the
146
+ result variable which is assumed to start in the $|0\\rangle$ state.
147
+
148
+ If `trim_result_lsb` is `False`, applies the transformation:
149
+
150
+ $$
151
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
152
+ \\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
153
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
154
+ \\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
155
+ $$
156
+
157
+ If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
158
+ applies the transformation:
159
+
160
+ $$
161
+ \\left|\\text{left}\\right\\rangle \\left|\\text{right}\\right\\rangle
162
+ \\left|0\\right\\rangle \\mapsto \\left|\\text{left}\\right\\rangle
163
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
164
+ \\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
165
+ $$
166
+
167
+ Args:
168
+ left: The first argument for the multiplication.
169
+ extend_left: Whether to sign-extend the left argument.
170
+ right: The second argument for the multiplication.
171
+ extend_right: Whether to sign-extend the right argument.
172
+ result: The quantum variable to hold the multiplication result.
173
+ trim_result_lsb: Whether to avoid computing the result's LSB.
174
+ """
175
+ pass
176
+
177
+
178
+ @qperm(external=True)
179
+ def canonical_multiply_constant(
180
+ left: CInt,
181
+ right: Const[QArray],
182
+ extend_right: CBool,
183
+ result: QArray,
184
+ trim_result_lsb: CBool,
185
+ ) -> None:
186
+ """
187
+ [Qmod core-library function]
188
+
189
+ Multiplies a quantum variable representing an integer (signed or unsigned) with a
190
+ constant, into the result variable which is assumed to start in the $|0\\rangle$ state.
191
+
192
+ If `trim_result_lsb` is `False`, applies the transformation:
193
+
194
+ $$
195
+ \\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
196
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
197
+ \\text{right} \\right) \\bmod 2^{\\text{result.size}} \\right\\rangle
198
+ $$
199
+
200
+ If `trim_result_lsb` is `True`, the function avoids computing the result's LSB and
201
+ applies the transformation:
202
+
203
+ $$
204
+ \\left|\\text{right}\\right\\rangle \\left|0\\right\\rangle \\mapsto
205
+ \\left|\\text{right}\\right\\rangle \\left|\\left( \\text{left} \\cdot
206
+ \\text{right} \\right) \\gg 1 \\bmod 2^{\\text{result.size}} \\right\\rangle
207
+ $$
208
+
209
+ Args:
210
+ left: The constant argument for the multiplication.
211
+ right: The variable argument for the multiplication.
212
+ extend_right: Whether to sign-extend the right argument.
213
+ result: The quantum variable to hold the multiplication result.
214
+ trim_result_lsb: Whether to avoid computing the result's LSB.
215
+ """
216
+ 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.
@@ -218,10 +248,10 @@ def sparse_suzuki_trotter(
218
248
 
219
249
  @qfunc(external=True)
220
250
  def qdrift(
221
- pauli_operator: SparsePauliOp, # FIXME: Rename to hamiltonian (CLS-4347)
251
+ pauli_operator: SparsePauliOp,
222
252
  evolution_coefficient: CReal,
223
253
  num_qdrift: CInt,
224
- qbv: QArray[QBit], # FIXME: Add length expr (CLS-4347)
254
+ qbv: QArray[QBit, Literal["pauli_operator.num_qubits"]],
225
255
  ) -> None:
226
256
  """
227
257
  [Qmod core-library function]
@@ -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,
@@ -30,12 +29,9 @@ from classiq.interface.model.classical_parameter_declaration import (
30
29
  ClassicalParameterDeclaration,
31
30
  )
32
31
  from classiq.interface.model.control import Control
33
- from classiq.interface.model.invert import Invert
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,
@@ -49,6 +45,7 @@ from classiq.interface.model.repeat import Repeat
49
45
  from classiq.interface.model.skip_control import SkipControl
50
46
  from classiq.interface.model.statement_block import StatementBlock
51
47
  from classiq.interface.model.within_apply_operation import WithinApply
48
+ from classiq.interface.source_reference import SourceReference
52
49
 
53
50
  from classiq.qmod.builtins.functions import H, S
54
51
  from classiq.qmod.generative import is_generative_mode
@@ -335,37 +332,6 @@ def assign(expression: SymbolicExpr, target_var: QScalar) -> None:
335
332
  )
336
333
 
337
334
 
338
- @suppress_return_value
339
- @qmod_statement
340
- def assign_amplitude(expression: SymbolicExpr, target_var: QScalar) -> None:
341
- """
342
- Perform an amplitude-encoding assignment operation on a quantum variable and a
343
- quantum expression.
344
-
345
- Equivalent to `<target_var> *= <expression>`.
346
-
347
- Args:
348
- expression: A quantum arithmetic expression
349
- target_var: A scalar quantum variable
350
- """
351
- warnings.warn(
352
- "The 'assign_amplitude' function is deprecated and will no longer be "
353
- "supported starting on 2025-12-03 at the earliest. Use 'assign_amplitude_table' "
354
- "instead",
355
- ClassiqDeprecationWarning,
356
- stacklevel=3,
357
- )
358
- assert QCallable.CURRENT_EXPANDABLE is not None
359
- source_ref = get_source_ref(sys._getframe(2))
360
- QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
361
- AmplitudeLoadingOperation(
362
- expression=Expression(expr=str(expression)),
363
- result_var=target_var.get_handle_binding(),
364
- source_ref=source_ref,
365
- )
366
- )
367
-
368
-
369
335
  @suppress_return_value
370
336
  @qmod_statement
371
337
  def inplace_add(expression: SymbolicExpr, target_var: QScalar) -> None:
@@ -552,7 +518,7 @@ def power(
552
518
 
553
519
  @suppress_return_value
554
520
  @qmod_statement
555
- def invert(stmt_block: QCallable | Callable[[], Statements]) -> None:
521
+ def invert(stmt_block: QCallable | Callable[[], Statements]) -> Any:
556
522
  """
557
523
  Apply the inverse of a quantum gate.
558
524
 
@@ -574,11 +540,35 @@ def invert(stmt_block: QCallable | Callable[[], Statements]) -> None:
574
540
  invert(qft(x))
575
541
  ```
576
542
  """
577
- _validate_operand(stmt_block)
578
543
  assert QCallable.CURRENT_EXPANDABLE is not None
579
544
  source_ref = get_source_ref(sys._getframe(2))
545
+
546
+ if (
547
+ isinstance(stmt_block, QCallable)
548
+ and len(stmt_block.func_decl.positional_arg_declarations) > 0
549
+ ):
550
+ return lambda *args, **kwargs: _invert(
551
+ lambda: stmt_block( # type:ignore[call-arg]
552
+ *args, **kwargs, _source_ref=source_ref
553
+ ),
554
+ source_ref,
555
+ BlockKind.SingleCall,
556
+ )
557
+ _invert(stmt_block, source_ref, BlockKind.Compound)
558
+ return None
559
+
560
+
561
+ def _invert(
562
+ stmt_block: Callable[[], Statements],
563
+ source_ref: SourceReference,
564
+ block_kind: BlockKind,
565
+ ) -> None:
566
+ assert QCallable.CURRENT_EXPANDABLE is not None
567
+ _validate_operand(stmt_block)
580
568
  invert_stmt = Invert(
581
- body=_operand_to_body(stmt_block, "stmt_block"), source_ref=source_ref
569
+ body=_operand_to_body(stmt_block, "stmt_block"),
570
+ block_kind=block_kind,
571
+ source_ref=source_ref,
582
572
  )
583
573
  if is_generative_mode():
584
574
  invert_stmt.set_generative_block("body", stmt_block)
@@ -843,7 +833,6 @@ def lookup_table(func: RealFunction, targets: QNum | list[QNum]) -> list[float]:
843
833
  __all__ = [
844
834
  "allocate",
845
835
  "assign",
846
- "assign_amplitude",
847
836
  "assign_amplitude_poly_sin",
848
837
  "bind",
849
838
  "block",
@@ -42,7 +42,7 @@ from classiq.interface.model.handle_binding import (
42
42
  SubscriptHandleBinding,
43
43
  )
44
44
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
45
- from classiq.interface.model.invert import Invert
45
+ from classiq.interface.model.invert import BlockKind, Invert
46
46
  from classiq.interface.model.model import Model
47
47
  from classiq.interface.model.model_visitor import ModelVisitor
48
48
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
@@ -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,9 +364,17 @@ class DSLPrettyPrinter(ModelVisitor):
367
364
  return power_code
368
365
 
369
366
  def visit_Invert(self, invert: Invert) -> str:
370
- invert_code = f"{self._indent}invert {{\n"
371
- invert_code += self._visit_body(invert.body)
372
- invert_code += f"{self._indent}}}\n"
367
+ invert.validate_node()
368
+ match invert.block_kind:
369
+ case BlockKind.SingleCall:
370
+ invert_code = f"{self._indent}invert "
371
+ invert_code += self.visit(invert.body[0]).lstrip()
372
+ case BlockKind.Compound:
373
+ invert_code = f"{self._indent}invert {{\n"
374
+ invert_code += self._visit_body(invert.body)
375
+ invert_code += f"{self._indent}}}\n"
376
+ case _:
377
+ raise ClassiqInternalError("Unknown block type")
373
378
  return invert_code
374
379
 
375
380
  def visit_Block(self, block: Block) -> str:
@@ -435,11 +440,6 @@ class DSLPrettyPrinter(ModelVisitor):
435
440
  op = "+="
436
441
  return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
437
442
 
438
- def visit_AmplitudeLoadingOperation(
439
- self, amplitude_loading_op: AmplitudeLoadingOperation
440
- ) -> str:
441
- return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)};\n"
442
-
443
443
  def _print_bind_handles(self, handles: list[HandleBinding]) -> str:
444
444
  if len(handles) == 1:
445
445
  return self.visit(handles[0])
@@ -45,16 +45,13 @@ from classiq.interface.model.handle_binding import (
45
45
  SubscriptHandleBinding,
46
46
  )
47
47
  from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
48
- from classiq.interface.model.invert import Invert
48
+ from classiq.interface.model.invert import BlockKind, Invert
49
49
  from classiq.interface.model.model import Model
50
50
  from classiq.interface.model.model_visitor import ModelVisitor
51
51
  from classiq.interface.model.native_function_definition import NativeFunctionDefinition
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,8 +505,17 @@ 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
- return f"{self._indent}invert({self._visit_body(invert.body)})\n"
510
+ match invert.block_kind:
511
+ case BlockKind.SingleCall:
512
+ call_str = self.visit(invert.body[0])
513
+ call_str = call_str.replace("(", ")(", 1)
514
+ return f"{self._indent}invert({call_str}\n"
515
+ case BlockKind.Compound:
516
+ return f"{self._indent}invert({self._visit_body(invert.body)})\n"
517
+ case _:
518
+ raise ClassiqInternalError("Unknown block type")
513
519
 
514
520
  def visit_Block(self, block: Block) -> str:
515
521
  self._imports["block"] = 1
@@ -528,8 +534,6 @@ class PythonPrettyPrinter(ModelVisitor):
528
534
  for i, statement in enumerate(body):
529
535
  if isinstance(statement, VariableDeclarationStatement):
530
536
  code += self.visit_VariableDeclarationStatement(statement, walrus=True)
531
- elif isinstance(statement, AmplitudeLoadingOperation):
532
- code += self.visit_AmplitudeLoadingOperation(statement, in_lambda=True)
533
537
  elif isinstance(statement, ArithmeticOperation):
534
538
  code += self.visit_ArithmeticOperation(statement, in_lambda=True)
535
539
  else:
@@ -587,14 +591,6 @@ class PythonPrettyPrinter(ModelVisitor):
587
591
  return f"{func}({self.visit(arith_op.expression)}, {self._indent}{self.visit(arith_op.result_var)})\n"
588
592
  return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)}\n"
589
593
 
590
- def visit_AmplitudeLoadingOperation(
591
- self, amplitude_loading_op: AmplitudeLoadingOperation, in_lambda: bool = False
592
- ) -> str:
593
- if in_lambda:
594
- self._imports["assign_amplitude"] = 1
595
- return f"assign_amplitude({self.visit(amplitude_loading_op.expression)}, {self._indent}{self.visit(amplitude_loading_op.result_var)})\n"
596
- return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)}\n"
597
-
598
594
  def _print_bind_handles(self, handles: list[HandleBinding]) -> str:
599
595
  if len(handles) == 1:
600
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
  ):