classiq 0.39.0__py3-none-any.whl → 0.41.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 (100) hide show
  1. classiq/__init__.py +5 -2
  2. classiq/_internals/api_wrapper.py +3 -21
  3. classiq/applications/chemistry/chemistry_model_constructor.py +87 -101
  4. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +7 -26
  5. classiq/applications/combinatorial_helpers/optimization_model.py +7 -6
  6. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -55
  7. classiq/applications/combinatorial_optimization/__init__.py +4 -0
  8. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
  9. classiq/applications/finance/finance_model_constructor.py +23 -26
  10. classiq/applications/grover/grover_model_constructor.py +37 -38
  11. classiq/applications/qsvm/qsvm.py +1 -2
  12. classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
  13. classiq/execution/__init__.py +4 -0
  14. classiq/execution/execution_session.py +151 -0
  15. classiq/execution/qnn.py +80 -0
  16. classiq/executor.py +2 -109
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +11 -0
  19. classiq/interface/applications/qsvm.py +0 -8
  20. classiq/interface/ast_node.py +12 -2
  21. classiq/interface/backend/backend_preferences.py +30 -6
  22. classiq/interface/backend/quantum_backend_providers.py +11 -11
  23. classiq/interface/executor/execution_preferences.py +7 -67
  24. classiq/interface/executor/execution_result.py +22 -1
  25. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  26. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  27. classiq/interface/generator/arith/binary_ops.py +88 -25
  28. classiq/interface/generator/arith/unary_ops.py +28 -19
  29. classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
  30. classiq/interface/generator/expressions/enums/__init__.py +10 -0
  31. classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
  32. classiq/interface/generator/expressions/expression.py +9 -2
  33. classiq/interface/generator/expressions/qmod_qarray_proxy.py +89 -0
  34. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +20 -0
  35. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  36. classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
  37. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +8 -6
  38. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +10 -4
  39. classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
  40. classiq/interface/generator/functions/builtins/open_lib_functions.py +1627 -271
  41. classiq/interface/generator/functions/classical_type.py +27 -17
  42. classiq/interface/generator/model/preferences/preferences.py +4 -2
  43. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  44. classiq/interface/model/bind_operation.py +3 -1
  45. classiq/interface/model/call_synthesis_data.py +2 -13
  46. classiq/interface/model/classical_if.py +3 -1
  47. classiq/interface/model/classical_parameter_declaration.py +13 -0
  48. classiq/interface/model/control.py +6 -8
  49. classiq/interface/model/inplace_binary_operation.py +3 -1
  50. classiq/interface/model/invert.py +3 -1
  51. classiq/interface/model/port_declaration.py +8 -1
  52. classiq/interface/model/power.py +3 -1
  53. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
  54. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
  55. classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
  56. classiq/interface/model/quantum_function_call.py +4 -10
  57. classiq/interface/model/quantum_function_declaration.py +26 -4
  58. classiq/interface/model/quantum_lambda_function.py +1 -20
  59. classiq/interface/model/quantum_statement.py +9 -2
  60. classiq/interface/model/quantum_type.py +6 -5
  61. classiq/interface/model/repeat.py +3 -1
  62. classiq/interface/model/resolvers/function_call_resolver.py +0 -5
  63. classiq/interface/model/statement_block.py +19 -16
  64. classiq/interface/model/validations/handles_validator.py +8 -2
  65. classiq/interface/model/variable_declaration_statement.py +3 -1
  66. classiq/interface/model/within_apply_operation.py +3 -1
  67. classiq/interface/server/routes.py +0 -5
  68. classiq/qmod/__init__.py +5 -2
  69. classiq/qmod/builtins/classical_execution_primitives.py +22 -2
  70. classiq/qmod/builtins/classical_functions.py +30 -35
  71. classiq/qmod/builtins/functions.py +263 -153
  72. classiq/qmod/builtins/operations.py +50 -26
  73. classiq/qmod/builtins/structs.py +50 -48
  74. classiq/qmod/declaration_inferrer.py +32 -27
  75. classiq/qmod/native/__init__.py +9 -0
  76. classiq/qmod/native/expression_to_qmod.py +8 -4
  77. classiq/qmod/native/pretty_printer.py +11 -18
  78. classiq/qmod/pretty_print/__init__.py +9 -0
  79. classiq/qmod/pretty_print/expression_to_python.py +221 -0
  80. classiq/qmod/pretty_print/pretty_printer.py +421 -0
  81. classiq/qmod/qmod_constant.py +7 -7
  82. classiq/qmod/qmod_parameter.py +57 -33
  83. classiq/qmod/qmod_struct.py +2 -2
  84. classiq/qmod/qmod_variable.py +40 -29
  85. classiq/qmod/quantum_callable.py +8 -4
  86. classiq/qmod/quantum_expandable.py +22 -15
  87. classiq/qmod/quantum_function.py +15 -4
  88. classiq/qmod/symbolic.py +73 -68
  89. classiq/qmod/symbolic_expr.py +1 -1
  90. classiq/qmod/symbolic_type.py +1 -4
  91. classiq/qmod/utilities.py +29 -0
  92. classiq/synthesis.py +15 -16
  93. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/METADATA +5 -4
  94. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/RECORD +95 -94
  95. classiq/interface/executor/error_mitigation.py +0 -6
  96. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  97. classiq/interface/model/common_model_types.py +0 -23
  98. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  99. classiq/interface/model/quantum_if_operation.py +0 -94
  100. {classiq-0.39.0.dist-info → classiq-0.41.0.dist-info}/WHEEL +0 -0
@@ -14,6 +14,8 @@ from classiq.interface.generator.expressions.enums.pauli import Pauli as PauliEn
14
14
  from classiq.interface.generator.expressions.expression_types import RuntimeExpression
15
15
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
16
16
 
17
+ CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
18
+
17
19
  NamedSymbol = Union[IndexedBase, Symbol]
18
20
 
19
21
 
@@ -29,9 +31,9 @@ class ClassicalType(HashableASTNode):
29
31
  )
30
32
 
31
33
  @property
32
- def python_type(self) -> type:
34
+ def qmod_type(self) -> type:
33
35
  raise NotImplementedError(
34
- f"{self.__class__.__name__!r} has no Python SDK equivalent"
36
+ f"{self.__class__.__name__!r} has no QMOD SDK equivalent"
35
37
  )
36
38
 
37
39
  class Config:
@@ -53,8 +55,10 @@ class Integer(ClassicalType):
53
55
  return values_with_discriminator(values, "kind", "int")
54
56
 
55
57
  @property
56
- def python_type(self) -> type:
57
- return int
58
+ def qmod_type(self) -> type:
59
+ from classiq.qmod.qmod_parameter import CInt
60
+
61
+ return CInt
58
62
 
59
63
 
60
64
  class Real(ClassicalType):
@@ -72,8 +76,10 @@ class Real(ClassicalType):
72
76
  return values_with_discriminator(values, "kind", "real")
73
77
 
74
78
  @property
75
- def python_type(self) -> type:
76
- return float
79
+ def qmod_type(self) -> type:
80
+ from classiq.qmod.qmod_parameter import CReal
81
+
82
+ return CReal
77
83
 
78
84
 
79
85
  class Bool(ClassicalType):
@@ -88,8 +94,10 @@ class Bool(ClassicalType):
88
94
  return values_with_discriminator(values, "kind", "bool")
89
95
 
90
96
  @property
91
- def python_type(self) -> type:
92
- return bool
97
+ def qmod_type(self) -> type:
98
+ from classiq.qmod.qmod_parameter import CBool
99
+
100
+ return CBool
93
101
 
94
102
 
95
103
  class ClassicalList(ClassicalType):
@@ -108,8 +116,10 @@ class ClassicalList(ClassicalType):
108
116
  return values_with_discriminator(values, "kind", "list")
109
117
 
110
118
  @property
111
- def python_type(self) -> type:
112
- return List[self.element_type.python_type] # type:ignore[name-defined]
119
+ def qmod_type(self) -> type:
120
+ from classiq.qmod.qmod_parameter import CArray
121
+
122
+ return CArray[self.element_type.qmod_type] # type:ignore[name-defined]
113
123
 
114
124
 
115
125
  class Pauli(ClassicalType):
@@ -124,8 +134,8 @@ class Pauli(ClassicalType):
124
134
  return values_with_discriminator(values, "kind", "pauli")
125
135
 
126
136
  @property
127
- def python_type(self) -> type:
128
- return int
137
+ def qmod_type(self) -> type:
138
+ return PauliEnum
129
139
 
130
140
 
131
141
  class StructMetaType(ClassicalType):
@@ -140,7 +150,7 @@ class StructMetaType(ClassicalType):
140
150
  return values_with_discriminator(values, "kind", "type_proxy")
141
151
 
142
152
 
143
- class QStructBase: # marker for Qmod structs in the Python SDK
153
+ class CStructBase: # marker for Qmod structs in the Python SDK
144
154
  pass
145
155
 
146
156
 
@@ -157,8 +167,8 @@ class Struct(ClassicalType):
157
167
  return values_with_discriminator(values, "kind", "struct_instance")
158
168
 
159
169
  @property
160
- def python_type(self) -> type:
161
- return type(self.name, (QStructBase,), dict())
170
+ def qmod_type(self) -> type:
171
+ return type(self.name, (CStructBase,), dict())
162
172
 
163
173
 
164
174
  class ClassicalArray(ClassicalType):
@@ -228,8 +238,8 @@ class LadderOperator(ClassicalType):
228
238
  return values_with_discriminator(values, "kind", "ladder_operator")
229
239
 
230
240
  @property
231
- def python_type(self) -> type:
232
- return int
241
+ def qmod_type(self) -> type:
242
+ return LadderOperatorEnum
233
243
 
234
244
 
235
245
  ConcreteClassicalType = Annotated[
@@ -11,7 +11,9 @@ from classiq.interface.backend.quantum_backend_providers import (
11
11
  AllBackendsNameByVendor,
12
12
  ProviderVendor,
13
13
  )
14
- from classiq.interface.generator.arith.number_utils import MAXIMAL_MACHINE_PRECISION
14
+ from classiq.interface.generator.arith.machine_precision import (
15
+ DEFAULT_MACHINE_PRECISION,
16
+ )
15
17
  from classiq.interface.generator.hardware.hardware_data import (
16
18
  BACKEND_VALIDATION_ERROR_MESSAGE,
17
19
  CustomHardwareSettings,
@@ -78,7 +80,7 @@ class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
78
80
  _backend_preferences: Optional[BackendPreferences] = pydantic.PrivateAttr(
79
81
  default=None
80
82
  )
81
- machine_precision: PydanticMachinePrecision = MAXIMAL_MACHINE_PRECISION
83
+ machine_precision: PydanticMachinePrecision = DEFAULT_MACHINE_PRECISION
82
84
 
83
85
  backend_service_provider: Optional[Union[Provider, ProviderVendor, str]] = (
84
86
  pydantic.Field(
@@ -1,10 +1,7 @@
1
- from typing import Optional
2
-
3
1
  import pydantic
4
2
 
5
3
 
6
4
  class SynthesisStepDurations(pydantic.BaseModel):
7
- model_preprocessing: Optional[float] = None
8
5
  preprocessing: float
9
6
  solving: float
10
7
  conversion_to_circuit: float
@@ -14,7 +11,6 @@ class SynthesisStepDurations(pydantic.BaseModel):
14
11
  return sum(
15
12
  time if time is not None else 0
16
13
  for time in (
17
- self.model_preprocessing,
18
14
  self.preprocessing,
19
15
  self.solving,
20
16
  self.conversion_to_circuit,
@@ -1,4 +1,4 @@
1
- from typing import List, Mapping
1
+ from typing import List, Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
@@ -12,6 +12,8 @@ BIND_OUTPUT_NAME = "bind_output"
12
12
 
13
13
 
14
14
  class BindOperation(QuantumOperation):
15
+ kind: Literal["BindOperation"]
16
+
15
17
  in_handles: List[HandleBinding]
16
18
  out_handles: List[HandleBinding]
17
19
 
@@ -36,24 +36,13 @@ class CallSynthesisData(Mapping):
36
36
  should_control=self.should_control and other.should_control,
37
37
  )
38
38
 
39
- def set_control(self, ctrl_name: str, ctrl_size: int) -> None:
39
+ def set_control(self, ctrl_name: str, ctrl_size: int, ctrl_state: str) -> None:
40
40
  self.control_states = [
41
41
  ControlState(
42
- name=ctrl_name,
43
- num_ctrl_qubits=ctrl_size,
42
+ name=ctrl_name, num_ctrl_qubits=ctrl_size, ctrl_state=ctrl_state
44
43
  )
45
44
  ]
46
45
 
47
- def update_control_state(self, ctrl_size: int, ctrl_state: str) -> None:
48
- prev_ctrl_state = self.control_states.pop()
49
- self.control_states.append(
50
- ControlState(
51
- name=prev_ctrl_state.name,
52
- num_ctrl_qubits=ctrl_size,
53
- ctrl_state=ctrl_state,
54
- )
55
- )
56
-
57
46
  @property
58
47
  def has_control(self) -> bool:
59
48
  return bool(self.control_states)
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,6 +8,8 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class ClassicalIf(QuantumOperation):
11
+ kind: Literal["ClassicalIf"]
12
+
11
13
  condition: Expression
12
14
  then: "StatementBlock"
13
15
  else_: "StatementBlock"
@@ -1,7 +1,20 @@
1
+ from typing import Any, Dict, Literal
2
+
3
+ import pydantic
4
+
1
5
  from classiq.interface.ast_node import ASTNode
2
6
  from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
7
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
3
8
 
4
9
 
5
10
  class ClassicalParameterDeclaration(ASTNode):
11
+ kind: Literal["ClassicalParameterDeclaration"]
12
+
6
13
  name: str
7
14
  classical_type: ConcreteClassicalType
15
+
16
+ @pydantic.root_validator(pre=True)
17
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
18
+ return values_with_discriminator(
19
+ values, "kind", "ClassicalParameterDeclaration"
20
+ )
@@ -1,16 +1,14 @@
1
- from typing import TYPE_CHECKING, Union
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
- from classiq.interface.model.handle_binding import (
4
- HandleBinding,
5
- SlicedHandleBinding,
6
- SubscriptHandleBinding,
3
+ from classiq.interface.model.quantum_expressions.quantum_expression import (
4
+ QuantumExpressionOperation,
7
5
  )
8
- from classiq.interface.model.quantum_statement import QuantumOperation
9
6
 
10
7
  if TYPE_CHECKING:
11
8
  from classiq.interface.model.statement_block import StatementBlock
12
9
 
13
10
 
14
- class Control(QuantumOperation):
15
- control: Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
11
+ class Control(QuantumExpressionOperation):
12
+ kind: Literal["Control"]
13
+
16
14
  body: "StatementBlock"
@@ -1,4 +1,4 @@
1
- from typing import Mapping
1
+ from typing import Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
@@ -23,6 +23,8 @@ class BinaryOperation(StrEnum):
23
23
 
24
24
 
25
25
  class InplaceBinaryOperation(QuantumOperation):
26
+ kind: Literal["InplaceBinaryOperation"]
27
+
26
28
  target: HandleBinding
27
29
  value: HandleBinding
28
30
  operation: BinaryOperation
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.model.quantum_statement import QuantumOperation
4
4
 
@@ -7,4 +7,6 @@ if TYPE_CHECKING:
7
7
 
8
8
 
9
9
  class Invert(QuantumOperation):
10
+ kind: Literal["Invert"]
11
+
10
12
  body: "StatementBlock"
@@ -1,10 +1,11 @@
1
- from typing import Any, Mapping
1
+ from typing import Any, Dict, Literal, Mapping
2
2
 
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.generator.functions.port_declaration import (
6
6
  PortDeclarationDirection,
7
7
  )
8
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
8
9
  from classiq.interface.model.quantum_variable_declaration import (
9
10
  QuantumVariableDeclaration,
10
11
  )
@@ -13,8 +14,14 @@ from classiq.exceptions import ClassiqValueError
13
14
 
14
15
 
15
16
  class PortDeclaration(QuantumVariableDeclaration):
17
+ kind: Literal["PortDeclaration"]
18
+
16
19
  direction: PortDeclarationDirection
17
20
 
21
+ @pydantic.root_validator(pre=True)
22
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
23
+ return values_with_discriminator(values, "kind", "PortDeclaration")
24
+
18
25
  @pydantic.validator("direction")
19
26
  def _direction_validator(
20
27
  cls, direction: PortDeclarationDirection, values: Mapping[str, Any]
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,5 +8,7 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class Power(QuantumOperation):
11
+ kind: Literal["Power"]
12
+
11
13
  power: Expression
12
14
  body: "StatementBlock"
@@ -1,4 +1,4 @@
1
- from typing import Dict, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Union
2
2
 
3
3
  import pydantic
4
4
 
@@ -28,6 +28,8 @@ VAR_DOMAIN_ILLEGAL = (
28
28
 
29
29
 
30
30
  class AmplitudeLoadingOperation(QuantumAssignmentOperation):
31
+ kind: Literal["AmplitudeLoadingOperation"]
32
+
31
33
  _result_type: QuantumType = pydantic.PrivateAttr(default_factory=QuantumBit)
32
34
 
33
35
  @property
@@ -52,7 +54,7 @@ class AmplitudeLoadingOperation(QuantumAssignmentOperation):
52
54
  ) -> None:
53
55
  if len(var_types) != 1:
54
56
  raise ClassiqValueError(MULTI_VARS_UNSUPPORTED_ERROR)
55
- var_type = var_types[self.var_handles[0].name]
57
+ var_type = list(var_types.values())[0]
56
58
  if not (
57
59
  isinstance(var_type, QuantumNumeric)
58
60
  and var_type.fraction_digits_value == var_type.size_in_bits
@@ -1,4 +1,4 @@
1
- from typing import Dict, Mapping, Union
1
+ from typing import Dict, Literal, Mapping, Union
2
2
 
3
3
  import pydantic
4
4
 
@@ -18,6 +18,8 @@ from classiq.interface.model.quantum_type import QuantumType
18
18
 
19
19
 
20
20
  class ArithmeticOperation(QuantumAssignmentOperation):
21
+ kind: Literal["ArithmeticOperation"]
22
+
21
23
  inplace_result: bool = pydantic.Field(
22
24
  description="Determines whether the result variable is initialized",
23
25
  )
@@ -33,6 +33,16 @@ class VarRefCollector(ast.NodeVisitor):
33
33
  super().generic_visit(node)
34
34
 
35
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
+
36
46
  class QuantumExpressionOperation(QuantumOperation):
37
47
  expression: Expression = pydantic.Field()
38
48
  _var_handles: List[HandleBinding] = pydantic.PrivateAttr(
@@ -58,7 +68,7 @@ class QuantumExpressionOperation(QuantumOperation):
58
68
  var_types: Dict[str, QuantumType],
59
69
  machine_precision: int,
60
70
  ) -> None:
61
- assert len(var_types) == len(self.var_handles)
71
+ assert len(var_types) == len(self.var_handles) or len(self.var_handles) == 0
62
72
  self._var_types = var_types
63
73
 
64
74
  @property
@@ -1,6 +1,6 @@
1
1
  import itertools
2
2
  import re
3
- from typing import Any, Dict, List, Mapping, Optional, Set, Type, Union
3
+ from typing import Any, Dict, List, Literal, Mapping, Optional, Set, Type, Union
4
4
 
5
5
  import pydantic
6
6
 
@@ -23,7 +23,6 @@ from classiq.interface.model.quantum_function_declaration import (
23
23
  QuantumOperandDeclaration,
24
24
  )
25
25
  from classiq.interface.model.quantum_lambda_function import (
26
- LambdaListComprehension,
27
26
  QuantumCallable,
28
27
  QuantumLambdaFunction,
29
28
  QuantumOperand,
@@ -114,6 +113,8 @@ class OperandIdentifier(ASTNode):
114
113
 
115
114
 
116
115
  class QuantumFunctionCall(QuantumOperation):
116
+ kind: Literal["QuantumFunctionCall"]
117
+
117
118
  function: Union[str, OperandIdentifier] = pydantic.Field(
118
119
  description="The function that is called"
119
120
  )
@@ -304,10 +305,7 @@ class QuantumFunctionCall(QuantumOperation):
304
305
  def get_lambda_defs(operand: QuantumOperand) -> List[QuantumCallable]:
305
306
  if isinstance(operand, list):
306
307
  return operand
307
- elif isinstance(operand, LambdaListComprehension):
308
- return [operand.func]
309
- else:
310
- return [operand]
308
+ return [operand]
311
309
 
312
310
 
313
311
  def _check_ports_against_declaration(
@@ -368,10 +366,6 @@ def _check_operand_against_declaration(
368
366
  if operand_argument.func_decl is None:
369
367
  return
370
368
  operand_arg_decl = operand_argument.func_decl
371
- elif isinstance(operand_argument, LambdaListComprehension):
372
- if operand_argument.func.func_decl is None:
373
- return
374
- operand_arg_decl = operand_argument.func.func_decl
375
369
  else:
376
370
  raise ClassiqValueError(
377
371
  f"{str(operand_argument)!r} argument to {call.func_decl.name!r} is not a "
@@ -1,6 +1,18 @@
1
- from typing import Any, ClassVar, Dict, List, Mapping, Sequence, Set, Type, Union
1
+ from typing import (
2
+ Any,
3
+ ClassVar,
4
+ Dict,
5
+ List,
6
+ Literal,
7
+ Mapping,
8
+ Sequence,
9
+ Set,
10
+ Type,
11
+ Union,
12
+ )
2
13
 
3
14
  import pydantic
15
+ from typing_extensions import Annotated
4
16
 
5
17
  from classiq.interface.generator.function_params import ArithmeticIODict, PortDirection
6
18
  from classiq.interface.generator.functions.function_declaration import (
@@ -9,7 +21,10 @@ from classiq.interface.generator.functions.function_declaration import (
9
21
  from classiq.interface.generator.functions.port_declaration import (
10
22
  PortDeclarationDirection,
11
23
  )
12
- from classiq.interface.helpers.pydantic_model_helpers import Nameable
24
+ from classiq.interface.helpers.pydantic_model_helpers import (
25
+ Nameable,
26
+ values_with_discriminator,
27
+ )
13
28
  from classiq.interface.helpers.validation_helpers import (
14
29
  validate_nameables_mapping,
15
30
  validate_nameables_no_overlap,
@@ -49,8 +64,9 @@ def _populate_declaration_dicts_with_positional_lists(
49
64
  )
50
65
 
51
66
 
52
- PositionalArg = Union[
53
- ClassicalParameterDeclaration, "QuantumOperandDeclaration", PortDeclaration
67
+ PositionalArg = Annotated[
68
+ Union[ClassicalParameterDeclaration, "QuantumOperandDeclaration", PortDeclaration],
69
+ pydantic.Field(..., discriminator="kind"),
54
70
  ]
55
71
 
56
72
 
@@ -218,10 +234,16 @@ class QuantumFunctionDeclaration(FunctionDeclaration):
218
234
 
219
235
 
220
236
  class QuantumOperandDeclaration(QuantumFunctionDeclaration):
237
+ kind: Literal["QuantumOperandDeclaration"]
238
+
221
239
  is_list: bool = pydantic.Field(
222
240
  description="Indicate whether the operand expects an unnamed list of lambdas",
223
241
  default=False,
224
242
  )
225
243
 
244
+ @pydantic.root_validator(pre=True)
245
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
246
+ return values_with_discriminator(values, "kind", "QuantumOperandDeclaration")
247
+
226
248
 
227
249
  QuantumFunctionDeclaration.update_forward_refs()
@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Union
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
- from classiq.interface.generator.expressions.expression import Expression
7
6
  from classiq.interface.model.quantum_function_declaration import (
8
7
  QuantumOperandDeclaration,
9
8
  )
@@ -36,23 +35,5 @@ class QuantumLambdaFunction(ASTNode):
36
35
  self._func_decl = fd
37
36
 
38
37
 
39
- class LambdaListComprehension(ASTNode):
40
- """
41
- Specification of a list of lambda functions iteratively
42
- """
43
-
44
- count: Expression = pydantic.Field(
45
- description="The number of lambda functions in the list"
46
- )
47
-
48
- index_var: str = pydantic.Field(
49
- description="The name of the integer variable holding the iteration index"
50
- )
51
-
52
- func: QuantumLambdaFunction = pydantic.Field(
53
- description="A lambda function definition replicated for index values 0 to count-1"
54
- )
55
-
56
-
57
38
  QuantumCallable = Union[str, QuantumLambdaFunction]
58
- QuantumOperand = Union[QuantumCallable, List[QuantumCallable], LambdaListComprehension]
39
+ QuantumOperand = Union[QuantumCallable, List[QuantumCallable]]
@@ -1,8 +1,9 @@
1
- from typing import Mapping, Union
1
+ from typing import Any, Dict, Mapping, Union
2
2
 
3
- from pydantic import Extra
3
+ from pydantic import Extra, root_validator
4
4
 
5
5
  from classiq.interface.ast_node import ASTNode
6
+ from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
6
7
  from classiq.interface.model.handle_binding import (
7
8
  HandleBinding,
8
9
  SlicedHandleBinding,
@@ -11,9 +12,15 @@ from classiq.interface.model.handle_binding import (
11
12
 
12
13
 
13
14
  class QuantumStatement(ASTNode):
15
+ kind: str
16
+
14
17
  class Config:
15
18
  extra = Extra.forbid
16
19
 
20
+ @root_validator(pre=True)
21
+ def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
22
+ return values_with_discriminator(values, "kind", cls.__name__) # type: ignore[attr-defined]
23
+
17
24
 
18
25
  class QuantumOperation(QuantumStatement):
19
26
  @property
@@ -10,6 +10,7 @@ from classiq.interface.generator.arith.register_user_input import (
10
10
  RegisterUserInput,
11
11
  )
12
12
  from classiq.interface.generator.expressions.expression import Expression
13
+ from classiq.interface.generator.expressions.qmod_qarray_proxy import QmodQArrayProxy
13
14
  from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
14
15
  QmodQNumProxy,
15
16
  QmodQScalarProxy,
@@ -65,12 +66,9 @@ class QuantumBit(QuantumScalar):
65
66
  return values_with_discriminator(values, "kind", "qbit")
66
67
 
67
68
 
68
- class QuantumArray(QuantumType):
69
- length: Optional[Expression]
70
-
71
-
72
- class QuantumBitvector(QuantumArray):
69
+ class QuantumBitvector(QuantumType):
73
70
  kind: Literal["qvec"]
71
+ length: Optional[Expression]
74
72
 
75
73
  @pydantic.root_validator(pre=True)
76
74
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -80,6 +78,9 @@ class QuantumBitvector(QuantumArray):
80
78
  if self.length is not None and self.length.is_evaluated():
81
79
  self._size_in_bits = self.length.to_int_value()
82
80
 
81
+ def get_proxy(self, name: str) -> QmodQArrayProxy:
82
+ return QmodQArrayProxy(name, self.size_in_bits)
83
+
83
84
 
84
85
  class QuantumNumeric(QuantumScalar):
85
86
  kind: Literal["qnum"]
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Literal
2
2
 
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.model.quantum_statement import QuantumOperation
@@ -8,6 +8,8 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class Repeat(QuantumOperation):
11
+ kind: Literal["Repeat"]
12
+
11
13
  iter_var: str
12
14
  count: Expression
13
15
  body: "StatementBlock"
@@ -9,7 +9,6 @@ from classiq.interface.model.quantum_function_call import QuantumFunctionCall
9
9
  from classiq.interface.model.quantum_function_declaration import (
10
10
  QuantumFunctionDeclaration,
11
11
  )
12
- from classiq.interface.model.quantum_if_operation import QuantumIf
13
12
  from classiq.interface.model.repeat import Repeat
14
13
  from classiq.interface.model.within_apply_operation import WithinApply
15
14
 
@@ -33,10 +32,6 @@ class FunctionCallResolver(Visitor):
33
32
  for fc in control.body:
34
33
  self.visit(fc)
35
34
 
36
- def visit_QuantumIf(self, quantum_if: QuantumIf) -> None:
37
- for fc in quantum_if.then:
38
- self.visit(fc)
39
-
40
35
  def visit_WithinApply(self, within_apply: WithinApply) -> None:
41
36
  for fc in itertools.chain(within_apply.compute, within_apply.action):
42
37
  self.visit(fc)