classiq 0.63.1__py3-none-any.whl → 0.65.1__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 (77) hide show
  1. classiq/_internals/api_wrapper.py +30 -0
  2. classiq/analyzer/url_utils.py +2 -3
  3. classiq/applications/chemistry/chemistry_model_constructor.py +8 -9
  4. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
  5. classiq/applications/combinatorial_optimization/combinatorial_problem.py +2 -5
  6. classiq/applications/finance/finance_model_constructor.py +7 -12
  7. classiq/applications/grover/grover_model_constructor.py +4 -6
  8. classiq/applications/qsvm/qsvm_model_constructor.py +6 -4
  9. classiq/execution/execution_session.py +14 -13
  10. classiq/interface/_version.py +1 -1
  11. classiq/interface/analyzer/result.py +1 -2
  12. classiq/interface/backend/backend_preferences.py +1 -9
  13. classiq/interface/executor/result.py +6 -3
  14. classiq/interface/generator/expressions/qmod_qarray_proxy.py +11 -13
  15. classiq/interface/generator/functions/type_name.py +6 -0
  16. classiq/interface/helpers/datastructures.py +26 -0
  17. classiq/interface/interface_version.py +1 -1
  18. classiq/interface/model/allocate.py +16 -0
  19. classiq/interface/model/handle_binding.py +11 -3
  20. classiq/interface/model/quantum_type.py +26 -0
  21. classiq/interface/model/statement_block.py +2 -0
  22. classiq/interface/server/routes.py +5 -0
  23. classiq/model_expansions/atomic_expression_functions_defs.py +6 -6
  24. classiq/model_expansions/capturing/captured_vars.py +27 -10
  25. classiq/model_expansions/evaluators/arg_type_match.py +4 -7
  26. classiq/model_expansions/evaluators/quantum_type_utils.py +25 -8
  27. classiq/model_expansions/expression_evaluator.py +8 -2
  28. classiq/model_expansions/function_builder.py +35 -11
  29. classiq/model_expansions/generative_functions.py +6 -4
  30. classiq/model_expansions/interpreters/__init__.py +0 -0
  31. classiq/model_expansions/interpreters/base_interpreter.py +263 -0
  32. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
  33. classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
  34. classiq/model_expansions/model_tables.py +1 -92
  35. classiq/model_expansions/quantum_operations/__init__.py +0 -10
  36. classiq/model_expansions/quantum_operations/call_emitter.py +45 -93
  37. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
  38. classiq/model_expansions/quantum_operations/emitter.py +7 -2
  39. classiq/model_expansions/quantum_operations/quantum_function_call.py +11 -2
  40. classiq/model_expansions/quantum_operations/shallow_emitter.py +22 -3
  41. classiq/model_expansions/scope.py +15 -15
  42. classiq/model_expansions/scope_initialization.py +11 -5
  43. classiq/open_library/functions/discrete_sine_cosine_transform.py +8 -2
  44. classiq/open_library/functions/grover.py +1 -1
  45. classiq/open_library/functions/modular_exponentiation.py +8 -2
  46. classiq/open_library/functions/state_preparation.py +23 -13
  47. classiq/open_library/functions/swap_test.py +1 -2
  48. classiq/open_library/functions/variational.py +1 -2
  49. classiq/qmod/builtins/__init__.py +1 -1
  50. classiq/qmod/builtins/operations.py +51 -0
  51. classiq/qmod/declaration_inferrer.py +0 -3
  52. classiq/qmod/generative.py +4 -4
  53. classiq/qmod/native/pretty_printer.py +9 -1
  54. classiq/qmod/pretty_print/pretty_printer.py +12 -1
  55. classiq/qmod/qfunc.py +4 -2
  56. classiq/qmod/qmod_variable.py +55 -48
  57. classiq/qmod/quantum_function.py +7 -5
  58. classiq/qmod/semantics/annotation/__init__.py +0 -0
  59. classiq/qmod/semantics/annotation/call_annotation.py +92 -0
  60. classiq/qmod/semantics/lambdas.py +25 -0
  61. classiq/qmod/semantics/static_semantics_visitor.py +8 -46
  62. classiq/qmod/utilities.py +23 -1
  63. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/METADATA +1 -1
  64. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/RECORD +66 -67
  65. classiq/interface/helpers/dotdict.py +0 -18
  66. classiq/model_expansions/interpreter.py +0 -475
  67. classiq/model_expansions/quantum_operations/control.py +0 -290
  68. classiq/model_expansions/quantum_operations/expression_operation.py +0 -103
  69. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +0 -535
  70. classiq/model_expansions/quantum_operations/invert.py +0 -36
  71. classiq/model_expansions/quantum_operations/phase.py +0 -187
  72. classiq/model_expansions/quantum_operations/power.py +0 -71
  73. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +0 -230
  74. classiq/model_expansions/quantum_operations/within_apply.py +0 -25
  75. classiq/qmod/semantics/annotation.py +0 -36
  76. /classiq/qmod/semantics/{qstruct_annotator.py → annotation/qstruct_annotator.py} +0 -0
  77. {classiq-0.63.1.dist-info → classiq-0.65.1.dist-info}/WHEEL +0 -0
@@ -4,14 +4,17 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
4
4
 
5
5
  from classiq.model_expansions.closure import FunctionClosure
6
6
  from classiq.model_expansions.quantum_operations.call_emitter import CallEmitter
7
+ from classiq.model_expansions.quantum_operations.declarative_call_emitter import (
8
+ DeclarativeCallEmitter,
9
+ )
7
10
  from classiq.qmod.semantics.error_manager import ErrorManager
8
11
 
9
12
  if TYPE_CHECKING:
10
- from classiq.model_expansions.interpreter import Interpreter
13
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
11
14
 
12
15
 
13
16
  class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
14
- def __init__(self, interpreter: "Interpreter") -> None:
17
+ def __init__(self, interpreter: "BaseInterpreter") -> None:
15
18
  super().__init__(interpreter)
16
19
  self._model = self._interpreter._model
17
20
 
@@ -22,3 +25,9 @@ class QuantumFunctionCallEmitter(CallEmitter[QuantumFunctionCall]):
22
25
  self._emit_quantum_function_call(
23
26
  function, args, self._debug_info.get(call.uuid)
24
27
  )
28
+
29
+
30
+ class DeclarativeQuantumFunctionCallEmitter(
31
+ QuantumFunctionCallEmitter, DeclarativeCallEmitter
32
+ ):
33
+ pass
@@ -6,6 +6,7 @@ from classiq.interface.generator.expressions.expression import Expression
6
6
  from classiq.interface.generator.functions.port_declaration import (
7
7
  PortDeclarationDirection,
8
8
  )
9
+ from classiq.interface.model.allocate import Allocate
9
10
  from classiq.interface.model.handle_binding import HandleBinding
10
11
  from classiq.interface.model.quantum_expressions.arithmetic_operation import (
11
12
  ArithmeticOperation,
@@ -17,14 +18,17 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
17
18
  from classiq.interface.model.quantum_statement import QuantumOperation, QuantumStatement
18
19
 
19
20
  from classiq.model_expansions.closure import Closure
20
- from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
21
+ from classiq.model_expansions.evaluators.quantum_type_utils import (
22
+ copy_type_information,
23
+ set_size,
24
+ )
21
25
  from classiq.model_expansions.quantum_operations.emitter import Emitter
22
26
  from classiq.model_expansions.scope import QuantumSymbol, Scope
23
27
  from classiq.model_expansions.transformers.ast_renamer import rename_variables
24
28
  from classiq.model_expansions.visitors.variable_references import VarRefCollector
25
29
 
26
30
  if TYPE_CHECKING:
27
- from classiq.model_expansions.interpreter import Interpreter
31
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
28
32
 
29
33
 
30
34
  QuantumOperationT = TypeVar("QuantumOperationT", bound=QuantumOperation)
@@ -38,7 +42,7 @@ _REVERSE_BLOCK_RENAMES = {rename: name for name, rename in _BLOCK_RENAMES.items(
38
42
  class ShallowEmitter(Emitter[QuantumOperation]):
39
43
  def __init__(
40
44
  self,
41
- interpreter: "Interpreter",
45
+ interpreter: "BaseInterpreter",
42
46
  operation_name: str,
43
47
  *,
44
48
  components: Optional[list[str]] = None,
@@ -73,6 +77,8 @@ class ShallowEmitter(Emitter[QuantumOperation]):
73
77
  op = op.model_copy(update=expanded_components)
74
78
  if isinstance(op, QuantumAssignmentOperation):
75
79
  self._post_process_assignment(op)
80
+ if isinstance(op, Allocate):
81
+ self._post_process_allocate(op)
76
82
  self._builder.emit_statement(op)
77
83
 
78
84
  def _post_process_assignment(self, op: QuantumAssignmentOperation) -> None:
@@ -86,6 +92,19 @@ class ShallowEmitter(Emitter[QuantumOperation]):
86
92
  direction = PortDeclarationDirection.Inout
87
93
  self._capture_handle(op.result_var, direction)
88
94
 
95
+ def _post_process_allocate(self, allocate: Allocate) -> None:
96
+ target_symbol = self._interpreter.evaluate(allocate.target).value
97
+ if not isinstance(target_symbol, QuantumSymbol):
98
+ return
99
+ self._capture_handle(target_symbol.handle, PortDeclarationDirection.Output)
100
+ if allocate.size is None or not allocate.size.is_evaluated():
101
+ return
102
+ set_size(
103
+ target_symbol.quantum_type,
104
+ allocate.size.to_int_value(),
105
+ str(target_symbol.handle),
106
+ )
107
+
89
108
  def _split_components(
90
109
  self, op: QuantumOperation
91
110
  ) -> tuple[list[str], list[str], list[str]]:
@@ -19,9 +19,6 @@ from classiq.interface.generator.expressions.expression import Expression
19
19
  from classiq.interface.generator.expressions.expression_constants import (
20
20
  CPARAM_EXECUTION_SUFFIX_PATTERN,
21
21
  )
22
- from classiq.interface.generator.expressions.qmod_qarray_proxy import (
23
- ILLEGAL_SLICE_BOUNDS_MSG,
24
- )
25
22
  from classiq.interface.generator.expressions.qmod_struct_instance import (
26
23
  QmodStructInstance,
27
24
  )
@@ -65,16 +62,19 @@ class QuantumSymbol:
65
62
  def _slice(self, start: int, end: int) -> "QuantumSymbol":
66
63
  if not isinstance(self.quantum_type, QuantumBitvector):
67
64
  raise ClassiqExpansionError(
68
- f"{self.quantum_type.type_name} is not subscriptable."
65
+ f"{self.quantum_type.type_name} is not subscriptable"
69
66
  )
70
67
  if start >= end:
71
- raise ClassiqExpansionError(ILLEGAL_SLICE_BOUNDS_MSG.format(start, end))
72
- if (
73
- self.quantum_type.has_length
74
- and end - start > self.quantum_type.length_value
75
- ):
76
68
  raise ClassiqExpansionError(
77
- f"Slice [{start}:{end}] is out of bounds for {self.handle}."
69
+ f"{self.quantum_type.type_name} slice '{self.handle}[{start}:{end}]' "
70
+ f"has non-positive length"
71
+ )
72
+ array_length = self.quantum_type.length_value
73
+ if start < 0 or end > array_length:
74
+ raise ClassiqExpansionError(
75
+ f"Slice [{start}:{end}] is out of bounds of "
76
+ f"{self.quantum_type.type_name} {str(self.handle)!r} of length "
77
+ f"{array_length}"
78
78
  )
79
79
  return QuantumSymbol(
80
80
  handle=SlicedHandleBinding(
@@ -91,13 +91,13 @@ class QuantumSymbol:
91
91
  def _subscript(self, index: int) -> "QuantumSymbol":
92
92
  if not isinstance(self.quantum_type, QuantumBitvector):
93
93
  raise ClassiqExpansionError(
94
- f"{self.quantum_type.type_name} is not subscriptable."
94
+ f"{self.quantum_type.type_name} is not subscriptable"
95
95
  )
96
- if index < 0 or (
97
- self.quantum_type.has_length and index > self.quantum_type.length_value
98
- ):
96
+ array_length = self.quantum_type.length_value
97
+ if index < 0 or index >= array_length:
99
98
  raise ClassiqExpansionError(
100
- f"Subscript [{index}] is out of bounds for {self.handle}."
99
+ f"Subscript {index} is out of bounds of {self.quantum_type.type_name} "
100
+ f"{str(self.handle)!r} of length {array_length}"
101
101
  )
102
102
  return QuantumSymbol(
103
103
  handle=SubscriptHandleBinding(
@@ -29,10 +29,13 @@ from classiq.model_expansions.evaluators.parameter_types import (
29
29
  from classiq.model_expansions.expression_renamer import ExpressionRenamer
30
30
  from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
31
31
  from classiq.qmod.builtins import BUILTIN_CONSTANTS
32
+ from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
32
33
  from classiq.qmod.builtins.functions import (
33
34
  CORE_LIB_DECLS,
34
35
  STD_QMOD_OPERATORS,
35
36
  )
37
+ from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
38
+ from classiq.qmod.model_state_container import QMODULE
36
39
  from classiq.qmod.quantum_function import GenerativeQFunc
37
40
 
38
41
 
@@ -75,7 +78,8 @@ def add_generative_functions_to_scope(
75
78
  functions: Sequence[GenerativeQFunc], scope: Scope
76
79
  ) -> None:
77
80
  for function in functions:
78
- if function.func_decl.name not in scope:
81
+ name = function.func_decl.name
82
+ if name == MAIN_FUNCTION_NAME or name not in scope:
79
83
  scope[function.func_decl.name] = Evaluated(
80
84
  value=GenerativeFunctionClosure.create(
81
85
  name=function.func_decl.name,
@@ -135,10 +139,12 @@ def add_entry_point_params_to_scope(
135
139
  )
136
140
 
137
141
 
138
- def init_top_level_scope(
139
- model: Model, generative_functions: list[GenerativeQFunc], scope: Scope
140
- ) -> None:
141
- add_generative_functions_to_scope(generative_functions, scope)
142
+ def init_top_level_scope(model: Model, scope: Scope) -> None:
142
143
  add_functions_to_scope(model.functions, scope)
143
144
  add_constants_to_scope(model.constants, scope)
144
145
  _init_builtins_scope(scope)
146
+
147
+
148
+ def init_builtin_types() -> None:
149
+ QMODULE.enum_decls |= BUILTIN_ENUM_DECLARATIONS
150
+ QMODULE.type_decls |= BUILTIN_STRUCT_DECLARATIONS
@@ -3,9 +3,15 @@ from classiq.open_library.functions.utility_functions import (
3
3
  apply_to_all,
4
4
  modular_increment,
5
5
  )
6
- from classiq.qmod.builtins.functions import allocate
7
6
  from classiq.qmod.builtins.functions.standard_gates import PHASE, H, S, X, Z
8
- from classiq.qmod.builtins.operations import bind, control, invert, repeat, within_apply
7
+ from classiq.qmod.builtins.operations import (
8
+ allocate,
9
+ bind,
10
+ control,
11
+ invert,
12
+ repeat,
13
+ within_apply,
14
+ )
9
15
  from classiq.qmod.qfunc import qfunc
10
16
  from classiq.qmod.qmod_variable import QArray, QBit, QNum
11
17
  from classiq.qmod.symbolic import pi
@@ -1,7 +1,7 @@
1
1
  from classiq.open_library.functions.utility_functions import hadamard_transform
2
- from classiq.qmod.builtins.functions import allocate
3
2
  from classiq.qmod.builtins.functions.standard_gates import H, U, X
4
3
  from classiq.qmod.builtins.operations import (
4
+ allocate,
5
5
  bind,
6
6
  control,
7
7
  invert,
@@ -1,8 +1,14 @@
1
1
  from classiq.open_library.functions.qft_functions import qft, qft_no_swap
2
2
  from classiq.qmod.builtins.classical_functions import qft_const_adder_phase
3
- from classiq.qmod.builtins.functions import allocate
4
3
  from classiq.qmod.builtins.functions.standard_gates import PHASE, SWAP, X
5
- from classiq.qmod.builtins.operations import bind, control, invert, repeat, within_apply
4
+ from classiq.qmod.builtins.operations import (
5
+ allocate,
6
+ bind,
7
+ control,
8
+ invert,
9
+ repeat,
10
+ within_apply,
11
+ )
6
12
  from classiq.qmod.cparam import CInt
7
13
  from classiq.qmod.qfunc import qfunc
8
14
  from classiq.qmod.qmod_variable import QArray, QBit, QNum
@@ -1,12 +1,14 @@
1
+ import warnings
1
2
  from typing import Literal
2
3
 
4
+ from classiq.interface.exceptions import ClassiqDeprecationWarning
5
+
3
6
  from classiq.open_library.functions.utility_functions import (
4
7
  hadamard_transform,
5
8
  modular_increment,
6
9
  )
7
- from classiq.qmod.builtins.functions import allocate
8
10
  from classiq.qmod.builtins.functions.standard_gates import CX, IDENTITY, RY, H, X
9
- from classiq.qmod.builtins.operations import control, if_, repeat
11
+ from classiq.qmod.builtins.operations import allocate, control, if_, repeat
10
12
  from classiq.qmod.cparam import CBool, CInt
11
13
  from classiq.qmod.qfunc import qfunc
12
14
  from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
@@ -16,6 +18,7 @@ from classiq.qmod.symbolic import (
16
18
  exp,
17
19
  floor,
18
20
  log,
21
+ logical_or,
19
22
  max as qmax,
20
23
  min as qmin,
21
24
  pi,
@@ -239,16 +242,19 @@ def prepare_bell_state(state_num: CInt, q: Output[QArray[QBit, Literal[2]]]) ->
239
242
 
240
243
  """
241
244
  allocate(2, q)
242
- inplace_prepare_int(state_num, 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]))
243
247
  H(q[0])
244
248
  CX(q[0], q[1])
245
249
 
246
250
 
247
251
  @qfunc
248
- def inplace_prepare_int(value: CInt, target: QArray[QBit]) -> None:
252
+ def inplace_prepare_int(value: CInt, target: QNum) -> None:
249
253
  """
250
254
  [Qmod Classiq-library function]
251
255
 
256
+ This function is **deprecated**. Use in-place-xor assignment statement in the form _target-var_ **^=** _quantum-expression_ or **inplace_xor(**_quantum-expression_**,** _target-var_**)** instead.
257
+
252
258
  Transitions a quantum variable in the zero state $|0\\rangle$ into the computational basis state $|\\text{value}\\rangle$.
253
259
  In the general case, the function performs a bitwise-XOR, i.e. transitions the state $|\\psi\\rangle$ into $|\\psi \\oplus \\text{value}\\rangle$.
254
260
 
@@ -259,14 +265,12 @@ def inplace_prepare_int(value: CInt, target: QArray[QBit]) -> None:
259
265
  Note:
260
266
  If the value cannot fit into the quantum variable, it is truncated, i.e. treated as the value modulo $2^\\text{target.size}$.
261
267
  """
262
- repeat(
263
- target.len,
264
- lambda index: if_(
265
- (floor(value / (2**index)) % 2) == 1,
266
- lambda: X(target[index]),
267
- lambda: IDENTITY(target[index]),
268
- ),
268
+ warnings.warn(
269
+ "Function 'inplace_prepare_int' is deprecated. Use in-place-xor assignment statement in the form '<var> ^= <expression>' or 'inplace_xor(<expression>, <var>)' instead.",
270
+ ClassiqDeprecationWarning,
271
+ stacklevel=1,
269
272
  )
273
+ target ^= value
270
274
 
271
275
 
272
276
  @qfunc
@@ -277,6 +281,8 @@ def prepare_int(
277
281
  """
278
282
  [Qmod Classiq-library function]
279
283
 
284
+ This function is **deprecated**. Use assignment statement in the form _target-var_ **|=** _quantum-expression_ or **assign(**_quantum-expression_**,** _target-var_**)** instead.
285
+
280
286
  Initializes a quantum variable to the computational basis state $|\\text{value}\\rangle$.
281
287
  The number of allocated qubits is automatically computed from the value, and is the minimal number required for representation in the computational basis.
282
288
 
@@ -287,5 +293,9 @@ def prepare_int(
287
293
  Note:
288
294
  If the output variable has been declared with a specific number of qubits, it must match the number of allocated qubits.
289
295
  """
290
- allocate(floor(log(value, 2)) + 1, out)
291
- inplace_prepare_int(value, out)
296
+ warnings.warn(
297
+ "Function 'prepare_int' is deprecated. Use assignment statement in the form '<var> |= <expression>' or 'assign(<expression>, <var>)' instead.",
298
+ ClassiqDeprecationWarning,
299
+ stacklevel=1,
300
+ )
301
+ out |= value
@@ -1,6 +1,5 @@
1
- from classiq.qmod.builtins.functions import allocate
2
1
  from classiq.qmod.builtins.functions.standard_gates import SWAP, H
3
- from classiq.qmod.builtins.operations import control, repeat
2
+ from classiq.qmod.builtins.operations import allocate, control, repeat
4
3
  from classiq.qmod.qfunc import qfunc
5
4
  from classiq.qmod.qmod_variable import Output, QArray, QBit
6
5
 
@@ -1,6 +1,5 @@
1
- from classiq.qmod.builtins.functions import allocate
2
1
  from classiq.qmod.builtins.functions.standard_gates import RX, RY, RZ
3
- from classiq.qmod.builtins.operations import repeat
2
+ from classiq.qmod.builtins.operations import allocate, repeat
4
3
  from classiq.qmod.cparam import CReal
5
4
  from classiq.qmod.qfunc import qfunc
6
5
  from classiq.qmod.qmod_parameter import CArray
@@ -12,7 +12,7 @@ from .enums import * # noqa: F403
12
12
  from .enums import __all__ as _builtin_enums
13
13
  from .functions import * # noqa: F403
14
14
  from .functions import __all__ as _builtin_functions
15
- from .operations import * # noqa: F403
15
+ from .operations import * # type:ignore[assignment] # noqa: F403
16
16
  from .operations import __all__ as _builtin_operations
17
17
  from .structs import * # noqa: F403
18
18
  from .structs import __all__ as _builtin_structs
@@ -7,6 +7,7 @@ from typing import (
7
7
  Callable,
8
8
  Final,
9
9
  Union,
10
+ overload,
10
11
  )
11
12
 
12
13
  from classiq.interface.exceptions import ClassiqValueError
@@ -15,6 +16,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
15
16
  REPEAT_OPERATOR_NAME,
16
17
  )
17
18
  from classiq.interface.generator.functions.classical_type import Integer
19
+ from classiq.interface.model.allocate import Allocate
18
20
  from classiq.interface.model.bind_operation import BindOperation
19
21
  from classiq.interface.model.classical_if import ClassicalIf
20
22
  from classiq.interface.model.classical_parameter_declaration import (
@@ -41,6 +43,7 @@ from classiq.interface.model.statement_block import StatementBlock
41
43
  from classiq.interface.model.within_apply_operation import WithinApply
42
44
 
43
45
  from classiq.qmod.generative import is_generative_mode
46
+ from classiq.qmod.qmod_constant import QConstant
44
47
  from classiq.qmod.qmod_variable import Input, Output, QArray, QBit, QScalar, QVar
45
48
  from classiq.qmod.quantum_callable import QCallable
46
49
  from classiq.qmod.quantum_expandable import prepare_arg
@@ -50,6 +53,53 @@ from classiq.qmod.utilities import get_source_ref
50
53
  _MISSING_VALUE: Final[int] = -1
51
54
 
52
55
 
56
+ @overload
57
+ def allocate(num_qubits: Union[int, SymbolicExpr], out: Output[QVar]) -> None:
58
+ pass
59
+
60
+
61
+ @overload
62
+ def allocate(out: Output[QVar]) -> None:
63
+ pass
64
+
65
+
66
+ def allocate(*args: Any, **kwargs: Any) -> None:
67
+ """
68
+ Initialize a quantum variable.
69
+
70
+ If 'num_qubits' is specified, 'num_qubits' qubits will be allocated for variable
71
+ 'out'. Otherwise, the number of qubits will be inferred according to the type of
72
+ 'out'.
73
+
74
+ Args:
75
+ size: The number of qubits to be allocated (optional)
76
+ out: The target variable
77
+ """
78
+ assert QCallable.CURRENT_EXPANDABLE is not None
79
+ source_ref = get_source_ref(sys._getframe(1))
80
+ if len(args) == 0:
81
+ size = kwargs.get("num_qubits", None)
82
+ target = kwargs["out"]
83
+ elif len(args) == 1:
84
+ if "out" in kwargs:
85
+ size = args[0]
86
+ target = kwargs["out"]
87
+ else:
88
+ size = None
89
+ target = args[0]
90
+ else:
91
+ size, target = args
92
+ if isinstance(size, QConstant):
93
+ size.add_to_model()
94
+ QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
95
+ Allocate(
96
+ size=None if size is None else Expression(expr=str(size)),
97
+ target=target.get_handle_binding(),
98
+ source_ref=source_ref,
99
+ )
100
+ )
101
+
102
+
53
103
  def bind(
54
104
  source: Union[Input[QVar], list[Input[QVar]]],
55
105
  destination: Union[Output[QVar], list[Output[QVar]]],
@@ -369,6 +419,7 @@ def _operand_to_body(
369
419
 
370
420
 
371
421
  __all__ = [
422
+ "allocate",
372
423
  "assign",
373
424
  "assign_amplitude",
374
425
  "bind",
@@ -32,7 +32,6 @@ from classiq.interface.model.quantum_function_declaration import (
32
32
  PositionalArg,
33
33
  )
34
34
 
35
- from classiq.model_expansions.model_tables import SymbolTable
36
35
  from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
37
36
  from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
38
37
  from classiq.qmod.model_state_container import ModelStateContainer
@@ -60,7 +59,6 @@ class _PythonClassicalType(PythonClassicalType):
60
59
 
61
60
  enum_decl = declaration_from_enum(py_type)
62
61
  self.qmodule.enum_decls[py_type.__name__] = enum_decl
63
- SymbolTable.enum_table[py_type.__name__] = enum_decl
64
62
 
65
63
  def register_struct(self, py_type: type) -> None:
66
64
  if (
@@ -77,7 +75,6 @@ class _PythonClassicalType(PythonClassicalType):
77
75
  },
78
76
  )
79
77
  self.qmodule.type_decls[py_type.__name__] = struct_decl
80
- SymbolTable.type_table[py_type.__name__] = struct_decl
81
78
 
82
79
 
83
80
  def python_type_to_qmod(
@@ -6,10 +6,10 @@ from classiq.interface.exceptions import ClassiqError
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
7
 
8
8
  if TYPE_CHECKING:
9
- from classiq.model_expansions.interpreter import Interpreter
9
+ from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
10
10
 
11
11
  _GENERATIVE_MODE: bool = False
12
- _FRONTEND_INTERPRETER: Optional["Interpreter"] = None
12
+ _FRONTEND_INTERPRETER: Optional["BaseInterpreter"] = None
13
13
 
14
14
 
15
15
  def is_generative_mode() -> bool:
@@ -27,12 +27,12 @@ def generative_mode_context(generative: bool) -> Iterator[None]:
27
27
  _GENERATIVE_MODE = previous
28
28
 
29
29
 
30
- def set_frontend_interpreter(interpreter: "Interpreter") -> None:
30
+ def set_frontend_interpreter(interpreter: "BaseInterpreter") -> None:
31
31
  global _FRONTEND_INTERPRETER
32
32
  _FRONTEND_INTERPRETER = interpreter
33
33
 
34
34
 
35
- def get_frontend_interpreter() -> "Interpreter":
35
+ def get_frontend_interpreter() -> "BaseInterpreter":
36
36
  if _FRONTEND_INTERPRETER is None:
37
37
  raise ClassiqError("Interpreter was not set")
38
38
  return _FRONTEND_INTERPRETER
@@ -22,6 +22,7 @@ from classiq.interface.generator.types.enum_declaration import EnumDeclaration
22
22
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
23
23
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
24
24
  from classiq.interface.generator.visitor import NodeType, Visitor
25
+ from classiq.interface.model.allocate import Allocate
25
26
  from classiq.interface.model.bind_operation import BindOperation
26
27
  from classiq.interface.model.classical_if import ClassicalIf
27
28
  from classiq.interface.model.classical_parameter_declaration import (
@@ -80,7 +81,7 @@ from classiq.interface.model.within_apply_operation import WithinApply
80
81
 
81
82
  from classiq.open_library.functions import OPEN_LIBRARY_FUNCTIONS
82
83
  from classiq.qmod.native.expression_to_qmod import transform_expression
83
- from classiq.qmod.semantics.static_semantics_visitor import resolve_function_calls
84
+ from classiq.qmod.semantics.annotation.call_annotation import resolve_function_calls
84
85
  from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
85
86
 
86
87
 
@@ -253,6 +254,13 @@ class DSLPrettyPrinter(Visitor):
253
254
  self._level -= 1
254
255
  return f"{self.visit_QuantumFunctionDeclaration(func_def)} {{\n{body}}}\n"
255
256
 
257
+ def visit_Allocate(self, allocate: Allocate) -> str:
258
+ if allocate.size is not None:
259
+ size = f"{self.visit(allocate.size)}, "
260
+ else:
261
+ size = ""
262
+ return f"{self._indent}allocate({size}{self.visit(allocate.target)});\n"
263
+
256
264
  def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
257
265
  positional_args = ", ".join(
258
266
  self.visit(arg_decl) for arg_decl in func_call.positional_args
@@ -25,6 +25,7 @@ from classiq.interface.generator.types.enum_declaration import EnumDeclaration
25
25
  from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
26
26
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
27
27
  from classiq.interface.generator.visitor import NodeType, Visitor
28
+ from classiq.interface.model.allocate import Allocate
28
29
  from classiq.interface.model.bind_operation import BindOperation
29
30
  from classiq.interface.model.classical_if import ClassicalIf
30
31
  from classiq.interface.model.classical_parameter_declaration import (
@@ -376,7 +377,10 @@ class PythonPrettyPrinter(Visitor):
376
377
 
377
378
  def visit_NativeFunctionDefinition(self, func_def: NativeFunctionDefinition) -> str:
378
379
  self._level += 1
379
- body = "".join(self.visit(statement) for statement in func_def.body)
380
+ if len(func_def.body) == 0:
381
+ body = " pass"
382
+ else:
383
+ body = "".join(self.visit(statement) for statement in func_def.body)
380
384
  self._level -= 1
381
385
  return f"{self.visit_QuantumFunctionDeclaration(func_def)} \n{body}\n"
382
386
 
@@ -402,6 +406,13 @@ class PythonPrettyPrinter(Visitor):
402
406
  )
403
407
  return ", ".join(self.visit(arg) for arg in func_call.positional_args)
404
408
 
409
+ def visit_Allocate(self, allocate: Allocate) -> str:
410
+ if allocate.size is not None:
411
+ size = f"{self.visit(allocate.size)}, "
412
+ else:
413
+ size = ""
414
+ return f"{self._indent}allocate({size}{self.visit(allocate.target)})\n"
415
+
405
416
  def visit_Control(self, op: Control) -> str:
406
417
  self._imports["control"] = 1
407
418
  control_else = (
classiq/qmod/qfunc.py CHANGED
@@ -20,8 +20,10 @@ def set_global_generative_switch() -> Iterator[None]:
20
20
  global _GENERATIVE_SWITCH
21
21
  previous = _GENERATIVE_SWITCH
22
22
  _GENERATIVE_SWITCH = True
23
- yield
24
- _GENERATIVE_SWITCH = previous
23
+ try:
24
+ yield
25
+ finally:
26
+ _GENERATIVE_SWITCH = previous
25
27
 
26
28
 
27
29
  @overload