classiq 0.41.2__py3-none-any.whl → 0.42.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 (48) hide show
  1. classiq/applications/chemistry/chemistry_model_constructor.py +31 -31
  2. classiq/execution/execution_session.py +42 -3
  3. classiq/interface/_version.py +1 -1
  4. classiq/interface/analyzer/analysis_params.py +16 -6
  5. classiq/interface/analyzer/result.py +2 -1
  6. classiq/interface/ast_node.py +2 -2
  7. classiq/interface/backend/pydantic_backend.py +1 -3
  8. classiq/interface/chemistry/fermionic_operator.py +17 -7
  9. classiq/interface/generator/amplitude_loading.py +12 -3
  10. classiq/interface/generator/application_apis/finance_declarations.py +22 -1
  11. classiq/interface/generator/expressions/atomic_expression_functions.py +2 -1
  12. classiq/interface/generator/expressions/enums/classical_enum.py +11 -0
  13. classiq/interface/generator/expressions/enums/ladder_operator.py +0 -10
  14. classiq/interface/generator/expressions/expression_constants.py +1 -0
  15. classiq/interface/generator/expressions/qmod_qarray_proxy.py +14 -1
  16. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +7 -2
  17. classiq/interface/generator/expressions/qmod_sized_proxy.py +8 -3
  18. classiq/interface/generator/expressions/qmod_struct_instance.py +12 -1
  19. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +262 -195
  20. classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
  21. classiq/interface/generator/functions/builtins/open_lib_functions.py +1645 -44
  22. classiq/interface/generator/functions/classical_type.py +21 -3
  23. classiq/interface/generator/generated_circuit_data.py +2 -0
  24. classiq/interface/generator/model/model.py +1 -1
  25. classiq/interface/{model → generator/model}/quantum_register.py +3 -0
  26. classiq/interface/helpers/classproperty.py +8 -0
  27. classiq/interface/ide/visual_model.py +68 -0
  28. classiq/interface/model/control.py +11 -1
  29. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +3 -8
  30. classiq/interface/model/quantum_expressions/quantum_expression.py +1 -30
  31. classiq/interface/model/quantum_function_call.py +0 -12
  32. classiq/interface/model/validations/handles_validator.py +2 -7
  33. classiq/interface/server/routes.py +1 -0
  34. classiq/qmod/builtins/classical_execution_primitives.py +1 -1
  35. classiq/qmod/builtins/functions.py +83 -31
  36. classiq/qmod/builtins/operations.py +16 -1
  37. classiq/qmod/declaration_inferrer.py +28 -4
  38. classiq/qmod/pretty_print/pretty_printer.py +22 -2
  39. classiq/qmod/qmod_constant.py +2 -1
  40. classiq/qmod/qmod_parameter.py +9 -2
  41. classiq/qmod/quantum_expandable.py +35 -11
  42. classiq/qmod/quantum_function.py +6 -5
  43. classiq/qmod/symbolic.py +22 -1
  44. classiq/qmod/utilities.py +5 -5
  45. {classiq-0.41.2.dist-info → classiq-0.42.1.dist-info}/METADATA +2 -2
  46. {classiq-0.41.2.dist-info → classiq-0.42.1.dist-info}/RECORD +47 -46
  47. classiq/interface/model/call_synthesis_data.py +0 -57
  48. {classiq-0.41.2.dist-info → classiq-0.42.1.dist-info}/WHEEL +0 -0
@@ -7,6 +7,7 @@ from sympy import IndexedBase, Symbol
7
7
  from typing_extensions import Annotated
8
8
 
9
9
  from classiq.interface.ast_node import HashableASTNode
10
+ from classiq.interface.generator.expressions.enums.classical_enum import ClassicalEnum
10
11
  from classiq.interface.generator.expressions.enums.ladder_operator import (
11
12
  LadderOperator as LadderOperatorEnum,
12
13
  )
@@ -39,6 +40,13 @@ class ClassicalType(HashableASTNode):
39
40
  class Config:
40
41
  extra = Extra.forbid
41
42
 
43
+ def __str__(self) -> str:
44
+ return str(type(self).__name__)
45
+
46
+
47
+ class EnumType(ClassicalType):
48
+ pass
49
+
42
50
 
43
51
  class Integer(ClassicalType):
44
52
  kind: Literal["int"]
@@ -69,7 +77,7 @@ class Real(ClassicalType):
69
77
 
70
78
  @property
71
79
  def default_value(self) -> float:
72
- return 0
80
+ return 0.0
73
81
 
74
82
  @pydantic.root_validator(pre=True)
75
83
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -122,7 +130,7 @@ class ClassicalList(ClassicalType):
122
130
  return CArray[self.element_type.qmod_type] # type:ignore[name-defined]
123
131
 
124
132
 
125
- class Pauli(ClassicalType):
133
+ class Pauli(EnumType):
126
134
  kind: Literal["pauli"]
127
135
 
128
136
  @property
@@ -187,6 +195,14 @@ class ClassicalArray(ClassicalType):
187
195
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
188
196
  return values_with_discriminator(values, "kind", "array")
189
197
 
198
+ @property
199
+ def qmod_type(self) -> type:
200
+ from classiq.qmod.qmod_parameter import CArray
201
+
202
+ return CArray[
203
+ self.element_type.qmod_type, self.size # type:ignore[name-defined]
204
+ ]
205
+
190
206
 
191
207
  class OpaqueHandle(ClassicalType):
192
208
  @property
@@ -226,7 +242,7 @@ class IQAERes(OpaqueHandle):
226
242
  return values_with_discriminator(values, "kind", "iqae_result")
227
243
 
228
244
 
229
- class LadderOperator(ClassicalType):
245
+ class LadderOperator(EnumType):
230
246
  kind: Literal["ladder_operator"]
231
247
 
232
248
  @property
@@ -263,6 +279,8 @@ ConcreteClassicalType = Annotated[
263
279
  ClassicalList.update_forward_refs()
264
280
  ClassicalArray.update_forward_refs()
265
281
 
282
+ PythonClassicalTypes = (int, float, bool, list, CStructBase, ClassicalEnum)
283
+
266
284
 
267
285
  def as_symbolic(symbols: Dict[str, ClassicalType]) -> Dict[str, RuntimeExpression]:
268
286
  return {
@@ -98,6 +98,8 @@ class FunctionDebugInfo(pydantic.BaseModel):
98
98
  generated_function: Optional[GeneratedFunction]
99
99
  children: List["FunctionDebugInfo"]
100
100
  relative_qubits: Tuple[int, ...]
101
+ absolute_qubits: Optional[Tuple[int, ...]]
102
+ is_basis_gate: Optional[bool]
101
103
 
102
104
  @property
103
105
  def registers(self) -> List[GeneratedRegister]:
@@ -16,6 +16,7 @@ from classiq.interface.generator.functions.port_declaration import (
16
16
  )
17
17
  from classiq.interface.generator.model.constraints import Constraints
18
18
  from classiq.interface.generator.model.preferences.preferences import Preferences
19
+ from classiq.interface.generator.model.quantum_register import QReg, QRegGenericAlias
19
20
  from classiq.interface.generator.quantum_function_call import (
20
21
  SUFFIX_RANDOMIZER,
21
22
  SynthesisQuantumFunctionCall,
@@ -26,7 +27,6 @@ from classiq.interface.generator.types.struct_declaration import StructDeclarati
26
27
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
27
28
  from classiq.interface.helpers.validation_helpers import is_list_unique
28
29
  from classiq.interface.helpers.versioned_model import VersionedModel
29
- from classiq.interface.model.quantum_register import QReg, QRegGenericAlias
30
30
 
31
31
  from classiq import ForeignFunctionDefinition as SynthesisForeignFunctionDefinition
32
32
  from classiq.exceptions import ClassiqValueError
@@ -87,6 +87,9 @@ class QReg:
87
87
  raise ClassiqQRegError(f"Cannot create {size} new qubits")
88
88
  self._qubits = [Qubit() for _ in range(size)]
89
89
 
90
+ def __hash__(self) -> int:
91
+ return super.__hash__(self)
92
+
90
93
  @classmethod
91
94
  def _from_qubits(cls, qubits: List[Qubit]) -> "QReg":
92
95
  if (
@@ -0,0 +1,8 @@
1
+ from typing import TYPE_CHECKING, Any, Optional
2
+
3
+
4
+ class classproperty(property): # noqa: N801
5
+ def __get__(self, owner_self: Any, owner_cls: Optional[type] = None) -> Any:
6
+ if TYPE_CHECKING:
7
+ assert self.fget is not None
8
+ return self.fget(owner_cls)
@@ -0,0 +1,68 @@
1
+ from typing import Dict, List, Optional, Tuple
2
+
3
+ import pydantic
4
+
5
+ from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
6
+ from classiq.interface.helpers.versioned_model import VersionedModel
7
+
8
+ from classiq._internals.enum_utils import StrEnum
9
+
10
+
11
+ class OperationLevel(StrEnum):
12
+ USER_DEFINED = "USER_DEFINED"
13
+ ENGINE_GENERATED = "ENGINE_GENERATED"
14
+ BASIS_GATE = "BASIS_GATE"
15
+ UNKNOWN = "UNKNOWN"
16
+
17
+
18
+ class OperationType(StrEnum):
19
+ REGULAR = "REGULAR"
20
+ VAR_INITIALIZATION = "VAR_INITIALIZATION"
21
+ BIND = "BIND"
22
+
23
+
24
+ class OperationData(pydantic.BaseModel):
25
+ approximated_depth: Optional[int]
26
+ width: int
27
+ gate_count: Dict[str, int] = pydantic.Field(default_factory=dict)
28
+
29
+
30
+ class ProgramData(pydantic.BaseModel):
31
+ hardware_data: SynthesisHardwareData
32
+
33
+
34
+ class OperationParameter(pydantic.BaseModel):
35
+ label: str
36
+ value: Optional[float]
37
+
38
+
39
+ class OperationLink(pydantic.BaseModel):
40
+ label: str
41
+ qubits: Tuple[int, ...]
42
+ type: str
43
+
44
+
45
+ class OperationLinks(pydantic.BaseModel):
46
+ inputs: List[OperationLink]
47
+ outputs: List[OperationLink]
48
+
49
+
50
+ class Operation(pydantic.BaseModel):
51
+ name: str
52
+ children: List["Operation"]
53
+ operation_data: Optional[OperationData]
54
+ operation_links: OperationLinks
55
+ control_qubits: Tuple[int, ...] = pydantic.Field(default_factory=tuple)
56
+ auxiliary_qubits: Tuple[int, ...]
57
+ target_qubits: Tuple[int, ...]
58
+ parameters: List[OperationParameter] = pydantic.Field(default_factory=list)
59
+ operation_level: OperationLevel
60
+ # This field is meant to identify unique operations, such as variable initialization
61
+ # These will be visualized differently. We don't identify them yet, though, so
62
+ # we always set this field to be REGULAR
63
+ operation_type: OperationType = pydantic.Field(default=OperationType.REGULAR)
64
+
65
+
66
+ class ProgramVisualModel(VersionedModel):
67
+ main_operation: Operation
68
+ program_data: ProgramData
@@ -1,5 +1,7 @@
1
1
  from typing import TYPE_CHECKING, Literal
2
2
 
3
+ import pydantic
4
+
3
5
  from classiq.interface.model.quantum_expressions.quantum_expression import (
4
6
  QuantumExpressionOperation,
5
7
  )
@@ -10,5 +12,13 @@ if TYPE_CHECKING:
10
12
 
11
13
  class Control(QuantumExpressionOperation):
12
14
  kind: Literal["Control"]
13
-
14
15
  body: "StatementBlock"
16
+
17
+ _ctrl_state: str = pydantic.PrivateAttr(default="")
18
+
19
+ @property
20
+ def ctrl_state(self) -> str:
21
+ return self._ctrl_state
22
+
23
+ def set_ctrl_state(self, ctrl_state: str) -> None:
24
+ self._ctrl_state = ctrl_state
@@ -22,9 +22,7 @@ MULTI_VARS_UNSUPPORTED_ERROR = (
22
22
  "Amplitude Loading with more than one input variable is unsupported."
23
23
  )
24
24
 
25
- VAR_DOMAIN_ILLEGAL = (
26
- "Amplitude Loading input variable should be a fixed-point number between 0 and 1"
27
- )
25
+ VAR_TYPE_ILLEGAL = "Amplitude Loading input variable should be a quantum numeric"
28
26
 
29
27
 
30
28
  class AmplitudeLoadingOperation(QuantumAssignmentOperation):
@@ -55,11 +53,8 @@ class AmplitudeLoadingOperation(QuantumAssignmentOperation):
55
53
  if len(var_types) != 1:
56
54
  raise ClassiqValueError(MULTI_VARS_UNSUPPORTED_ERROR)
57
55
  var_type = list(var_types.values())[0]
58
- if not (
59
- isinstance(var_type, QuantumNumeric)
60
- and var_type.fraction_digits_value == var_type.size_in_bits
61
- ):
62
- raise ClassiqValueError(VAR_DOMAIN_ILLEGAL)
56
+ if not isinstance(var_type, QuantumNumeric):
57
+ raise ClassiqValueError(VAR_TYPE_ILLEGAL)
63
58
  super().initialize_var_types(var_types, machine_precision)
64
59
 
65
60
  @classmethod
@@ -1,16 +1,9 @@
1
1
  import abc
2
- import ast
3
- from typing import Dict, List, Mapping, Optional, Set, Union
2
+ from typing import Dict, List, Mapping, Optional, Union
4
3
 
5
4
  import pydantic
6
5
 
7
- from classiq.interface.generator.arith.arithmetic_expression_validator import (
8
- DEFAULT_SUPPORTED_FUNC_NAMES,
9
- )
10
6
  from classiq.interface.generator.expressions.expression import Expression
11
- from classiq.interface.generator.expressions.sympy_supported_expressions import (
12
- SYMPY_SUPPORTED_EXPRESSIONS,
13
- )
14
7
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
15
8
  from classiq.interface.model.handle_binding import (
16
9
  HandleBinding,
@@ -21,28 +14,6 @@ from classiq.interface.model.quantum_statement import QuantumOperation
21
14
  from classiq.interface.model.quantum_type import QuantumType
22
15
 
23
16
 
24
- class VarRefCollector(ast.NodeVisitor):
25
- def __init__(self) -> None:
26
- self.var_names: Set[str] = set()
27
-
28
- def generic_visit(self, node: ast.AST) -> None:
29
- if isinstance(node, ast.Name) and node.id not in set(
30
- SYMPY_SUPPORTED_EXPRESSIONS
31
- ) | set(DEFAULT_SUPPORTED_FUNC_NAMES):
32
- self.var_names.add(node.id)
33
- super().generic_visit(node)
34
-
35
-
36
- class VarRefTransformer(ast.NodeTransformer):
37
- def __init__(self, var_mapping: Dict[str, str]) -> None:
38
- self.var_mapping = var_mapping
39
-
40
- def visit_Name(self, node: ast.Name) -> ast.Name:
41
- if node.id in self.var_mapping:
42
- node.id = self.var_mapping[node.id]
43
- return node
44
-
45
-
46
17
  class QuantumExpressionOperation(QuantumOperation):
47
18
  expression: Expression = pydantic.Field()
48
19
  _var_handles: List[HandleBinding] = pydantic.PrivateAttr(
@@ -12,7 +12,6 @@ from classiq.interface.generator.functions.function_declaration import (
12
12
  from classiq.interface.generator.functions.port_declaration import (
13
13
  PortDeclarationDirection,
14
14
  )
15
- from classiq.interface.model.call_synthesis_data import CallSynthesisData
16
15
  from classiq.interface.model.handle_binding import (
17
16
  HandleBinding,
18
17
  SlicedHandleBinding,
@@ -143,10 +142,6 @@ class QuantumFunctionCall(QuantumOperation):
143
142
  default=None
144
143
  )
145
144
 
146
- _synthesis_data: CallSynthesisData = pydantic.PrivateAttr(
147
- default_factory=CallSynthesisData
148
- )
149
-
150
145
  @property
151
146
  def func_decl(self) -> QuantumFunctionDeclaration:
152
147
  if self._func_decl is None:
@@ -282,13 +277,6 @@ class QuantumFunctionCall(QuantumOperation):
282
277
  if isinstance(qlambda, QuantumLambdaFunction):
283
278
  qlambda.set_op_decl(op_decl)
284
279
 
285
- @property
286
- def synthesis_data(self) -> CallSynthesisData:
287
- return self._synthesis_data
288
-
289
- def merge_synthesis_data(self, other: CallSynthesisData) -> None:
290
- self._synthesis_data = self._synthesis_data.merge(other)
291
-
292
280
  @pydantic.root_validator()
293
281
  def validate_handles(cls, values: Dict[str, Any]) -> Dict[str, Any]:
294
282
  inputs = values.get("inputs", dict())
@@ -62,13 +62,8 @@ class HandleValidator(HandleValidationBase):
62
62
  elif isinstance(op, WithinApply):
63
63
  self._handle_apply(op.action)
64
64
 
65
- if isinstance(op, QuantumFunctionCall) and op.synthesis_data.is_inverse:
66
- self._handle_inputs(op.wiring_outputs)
67
- self._handle_outputs(op.wiring_inputs)
68
- else:
69
- self._handle_inputs(op.wiring_inputs)
70
- self._handle_outputs(op.wiring_outputs)
71
-
65
+ self._handle_inputs(op.wiring_inputs)
66
+ self._handle_outputs(op.wiring_outputs)
72
67
  self._handle_inouts(op.wiring_inouts)
73
68
 
74
69
  def handle_variable_declaration(
@@ -37,6 +37,7 @@ IDE_QASM_TASK = f"{TASKS_SUFFIX}/generated_circuit_from_qasm"
37
37
  IDE_QASM_FULL_PATH = f"{ANALYZER_PREFIX}{IDE_QASM_TASK}"
38
38
  TASKS_GENERATE_SUFFIX = TASKS_SUFFIX + "/generate"
39
39
  TASKS_VISUALIZE_SUFFIX = TASKS_SUFFIX + "/visualize"
40
+ TASKS_VISUAL_MODEL_SUFFIX = TASKS_SUFFIX + "/visual_model"
40
41
  TASKS_SOLVE_SUFFIX = "/tasks/solve"
41
42
  MODEL_GENERATE_PREFIX = "/generate_model"
42
43
  CHEMISTRY_GENERATE_MODEL_PATH = MODEL_GENERATE_PREFIX + "/chemistry"
@@ -15,7 +15,7 @@ from classiq.interface.generator.functions.qmod_python_interface import QmodPySt
15
15
  from classiq.applications.qsvm.qsvm import Data, Labels
16
16
  from classiq.exceptions import ClassiqError
17
17
 
18
- ExecutionParams = Dict[str, Union[float, int]]
18
+ ExecutionParams = Dict[str, Union[float, int, List[int], List[float]]]
19
19
 
20
20
  _CALL_IN_QFUNC_ERROR = (
21
21
  'Cannot call "{}" in a quantum context. "{}" is a classical execution primitive.'
@@ -474,13 +474,6 @@ def exponentiation_with_depth_constraint(
474
474
  pass
475
475
 
476
476
 
477
- @qfunc(external=True)
478
- def qft_step(
479
- target: QArray[QBit],
480
- ) -> None:
481
- pass
482
-
483
-
484
477
  @qfunc(external=True)
485
478
  def qft(
486
479
  target: QArray[QBit],
@@ -538,7 +531,7 @@ def amplitude_estimation(
538
531
 
539
532
  @qfunc(external=True)
540
533
  def phase_oracle(
541
- predicate: QCallable[QArray[QBit], QArray[QBit]],
534
+ predicate: QCallable[QArray[QBit], QBit],
542
535
  target: QArray[QBit],
543
536
  ) -> None:
544
537
  pass
@@ -603,7 +596,7 @@ def qft_no_swap(
603
596
  def _check_msb(
604
597
  ref: CInt,
605
598
  x: QArray[QBit],
606
- aux: QArray[QBit],
599
+ aux: QBit,
607
600
  ) -> None:
608
601
  pass
609
602
 
@@ -612,7 +605,7 @@ def _check_msb(
612
605
  def _ctrl_x(
613
606
  ref: CInt,
614
607
  ctrl: QNum,
615
- aux: QArray[QBit],
608
+ aux: QBit,
616
609
  ) -> None:
617
610
  pass
618
611
 
@@ -630,9 +623,9 @@ def cc_modular_add(
630
623
  n: CInt,
631
624
  a: CInt,
632
625
  phi_b: QArray[QBit],
633
- c1: QArray[QBit],
634
- c2: QArray[QBit],
635
- aux: QArray[QBit],
626
+ c1: QBit,
627
+ c2: QBit,
628
+ aux: QBit,
636
629
  ) -> None:
637
630
  pass
638
631
 
@@ -643,8 +636,8 @@ def c_modular_multiply(
643
636
  a: CInt,
644
637
  b: QArray[QBit],
645
638
  x: QArray[QBit],
646
- ctrl: QArray[QBit],
647
- aux: QArray[QBit],
639
+ ctrl: QBit,
640
+ aux: QBit,
648
641
  ) -> None:
649
642
  pass
650
643
 
@@ -662,8 +655,8 @@ def inplace_c_modular_multiply(
662
655
  n: CInt,
663
656
  a: CInt,
664
657
  x: QArray[QBit],
665
- ctrl: QArray[QBit],
666
- aux: QArray[QBit],
658
+ ctrl: QBit,
659
+ aux: QBit,
667
660
  ) -> None:
668
661
  pass
669
662
 
@@ -680,13 +673,13 @@ def modular_exp(
680
673
 
681
674
  @qfunc(external=True)
682
675
  def qsvt_step(
683
- phase_seq: CArray[CReal],
684
- index: CInt,
685
- proj_cnot_1: QCallable[QArray[QBit], QArray[QBit]],
686
- proj_cnot_2: QCallable[QArray[QBit], QArray[QBit]],
676
+ phase1: CReal,
677
+ phase2: CReal,
678
+ proj_cnot_1: QCallable[QArray[QBit], QBit],
679
+ proj_cnot_2: QCallable[QArray[QBit], QBit],
687
680
  u: QCallable[QArray[QBit]],
688
681
  qvar: QArray[QBit],
689
- aux: QArray[QBit],
682
+ aux: QBit,
690
683
  ) -> None:
691
684
  pass
692
685
 
@@ -694,11 +687,11 @@ def qsvt_step(
694
687
  @qfunc(external=True)
695
688
  def qsvt(
696
689
  phase_seq: CArray[CReal],
697
- proj_cnot_1: QCallable[QArray[QBit], QArray[QBit]],
698
- proj_cnot_2: QCallable[QArray[QBit], QArray[QBit]],
690
+ proj_cnot_1: QCallable[QArray[QBit], QBit],
691
+ proj_cnot_2: QCallable[QArray[QBit], QBit],
699
692
  u: QCallable[QArray[QBit]],
700
693
  qvar: QArray[QBit],
701
- aux: QArray[QBit],
694
+ aux: QBit,
702
695
  ) -> None:
703
696
  pass
704
697
 
@@ -706,9 +699,9 @@ def qsvt(
706
699
  @qfunc(external=True)
707
700
  def projector_controlled_phase(
708
701
  phase: CReal,
709
- proj_cnot: QCallable[QArray[QBit], QArray[QBit]],
702
+ proj_cnot: QCallable[QArray[QBit], QBit],
710
703
  qvar: QArray[QBit],
711
- aux: QArray[QBit],
704
+ aux: QBit,
712
705
  ) -> None:
713
706
  pass
714
707
 
@@ -716,10 +709,10 @@ def projector_controlled_phase(
716
709
  @qfunc(external=True)
717
710
  def qsvt_inversion(
718
711
  phase_seq: CArray[CReal],
719
- block_encoding_cnot: QCallable[QArray[QBit], QArray[QBit]],
712
+ block_encoding_cnot: QCallable[QArray[QBit], QBit],
720
713
  u: QCallable[QArray[QBit]],
721
714
  qvar: QArray[QBit],
722
- aux: QArray[QBit],
715
+ aux: QBit,
723
716
  ) -> None:
724
717
  pass
725
718
 
@@ -796,7 +789,7 @@ def full_hea(
796
789
  def swap_test(
797
790
  state1: QArray[QBit],
798
791
  state2: QArray[QBit],
799
- test: Output[QArray[QBit]],
792
+ test: Output[QBit],
800
793
  ) -> None:
801
794
  pass
802
795
 
@@ -849,6 +842,59 @@ def switch(
849
842
  pass
850
843
 
851
844
 
845
+ @qfunc(external=True)
846
+ def _qct_d_operator(
847
+ x: QNum,
848
+ q: QBit,
849
+ ) -> None:
850
+ pass
851
+
852
+
853
+ @qfunc(external=True)
854
+ def _qct_pi_operator(
855
+ x: QArray[QBit],
856
+ q: QBit,
857
+ ) -> None:
858
+ pass
859
+
860
+
861
+ @qfunc(external=True)
862
+ def qct_qst_type1(
863
+ x: QArray[QBit],
864
+ ) -> None:
865
+ pass
866
+
867
+
868
+ @qfunc(external=True)
869
+ def qct_qst_type2(
870
+ x: QArray[QBit],
871
+ q: QBit,
872
+ ) -> None:
873
+ pass
874
+
875
+
876
+ @qfunc(external=True)
877
+ def qct_type2(
878
+ x: QArray[QBit],
879
+ ) -> None:
880
+ pass
881
+
882
+
883
+ @qfunc(external=True)
884
+ def qst_type2(
885
+ x: QArray[QBit],
886
+ ) -> None:
887
+ pass
888
+
889
+
890
+ @qfunc(external=True)
891
+ def modular_increment(
892
+ a: CInt,
893
+ x: QArray[QBit],
894
+ ) -> None:
895
+ pass
896
+
897
+
852
898
  __all__ = [
853
899
  "permute",
854
900
  "apply",
@@ -906,7 +952,6 @@ __all__ = [
906
952
  "suzuki_trotter",
907
953
  "qdrift",
908
954
  "exponentiation_with_depth_constraint",
909
- "qft_step",
910
955
  "qft",
911
956
  "qpe_flexible",
912
957
  "qpe",
@@ -947,4 +992,11 @@ __all__ = [
947
992
  "inplace_prepare_int",
948
993
  "prepare_int",
949
994
  "switch",
995
+ "_qct_d_operator",
996
+ "_qct_pi_operator",
997
+ "qct_qst_type1",
998
+ "qct_qst_type2",
999
+ "qct_type2",
1000
+ "qst_type2",
1001
+ "modular_increment",
950
1002
  ]
@@ -161,7 +161,12 @@ def repeat(count: Union[SymbolicExpr, int], iteration: Callable[[int], None]) ->
161
161
  name=REPEAT_OPERATOR_NAME, param_decls={"index": Integer()}
162
162
  ),
163
163
  iteration,
164
+ repeat.__name__,
164
165
  )
166
+ if not isinstance(iteration_operand, QuantumLambdaFunction):
167
+ raise ClassiqValueError(
168
+ "`repeat`'s `iteration` argument must be a lambda function"
169
+ )
165
170
  QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
166
171
  Repeat(
167
172
  iter_var=inspect.getfullargspec(iteration).args[0],
@@ -251,7 +256,17 @@ def _get_operand_hint(
251
256
 
252
257
 
253
258
  def _operand_to_body(callable_: Union[QCallable, Callable[[], None]]) -> StatementBlock:
254
- to_operand = prepare_arg(QuantumOperandDeclaration(name=""), callable_)
259
+ op_name = sys._getframe(1).f_code.co_name
260
+ if (
261
+ isinstance(callable_, QCallable)
262
+ and len(callable_.func_decl.positional_arg_declarations) > 0
263
+ ):
264
+ raise ClassiqValueError(
265
+ f"Operand argument {callable_.func_decl.name!r} to {op_name!r} should "
266
+ f"receive 0 parameters, not "
267
+ f"{len(callable_.func_decl.positional_arg_declarations)}"
268
+ )
269
+ to_operand = prepare_arg(QuantumOperandDeclaration(name=""), callable_, op_name)
255
270
  if isinstance(to_operand, str):
256
271
  return [QuantumFunctionCall(function=to_operand)]
257
272
  elif isinstance(to_operand, QuantumLambdaFunction):
@@ -1,9 +1,23 @@
1
1
  import dataclasses
2
2
  import inspect
3
- from typing import Any, Callable, Dict, List, Optional, Type, get_args, get_origin
3
+ from typing import (
4
+ Any,
5
+ Callable,
6
+ Dict,
7
+ List,
8
+ Mapping,
9
+ Optional,
10
+ Type,
11
+ get_args,
12
+ get_origin,
13
+ )
4
14
 
5
15
  from typing_extensions import _AnnotatedAlias
6
16
 
17
+ from classiq.interface.generator.expressions.enums.ladder_operator import (
18
+ LadderOperator as LadderOperatorEnum,
19
+ )
20
+ from classiq.interface.generator.expressions.enums.pauli import Pauli as PauliEnum
7
21
  from classiq.interface.generator.functions.classical_type import (
8
22
  Bool,
9
23
  ClassicalArray,
@@ -11,6 +25,8 @@ from classiq.interface.generator.functions.classical_type import (
11
25
  ConcreteClassicalType,
12
26
  CStructBase,
13
27
  Integer,
28
+ LadderOperator as LadderOperatorType,
29
+ Pauli as PauliType,
14
30
  Real,
15
31
  Struct,
16
32
  )
@@ -33,6 +49,10 @@ from classiq.qmod.quantum_callable import QCallable, QCallableList
33
49
  from classiq.qmod.utilities import unmangle_keyword, version_portable_get_args
34
50
 
35
51
  OPERAND_ARG_NAME = "arg{i}"
52
+ ENUM_TYPE_MAPPING: Mapping[type, type] = {
53
+ PauliEnum: PauliType,
54
+ LadderOperatorEnum: LadderOperatorType,
55
+ }
36
56
 
37
57
 
38
58
  def python_type_to_qmod(
@@ -44,6 +64,8 @@ def python_type_to_qmod(
44
64
  return Real()
45
65
  elif py_type == bool or py_type is CBool:
46
66
  return Bool()
67
+ elif py_type in ENUM_TYPE_MAPPING:
68
+ return ENUM_TYPE_MAPPING[py_type]()
47
69
  elif get_origin(py_type) == list:
48
70
  return ClassicalList(
49
71
  element_type=python_type_to_qmod(get_args(py_type)[0], qmodule=qmodule)
@@ -124,9 +146,11 @@ def _extract_positional_args(
124
146
  name = unmangle_keyword(name)
125
147
  if (
126
148
  inspect.isclass(py_type)
127
- and issubclass(py_type, CParam)
128
- or inspect.isclass(py_type)
129
- and issubclass(py_type, CStructBase)
149
+ and (
150
+ issubclass(py_type, CParam)
151
+ or issubclass(py_type, CStructBase)
152
+ or py_type in ENUM_TYPE_MAPPING
153
+ )
130
154
  or get_origin(py_type) == CArray
131
155
  ):
132
156
  result.append(