classiq 0.38.0__py3-none-any.whl → 0.40.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 (154) hide show
  1. classiq/__init__.py +22 -22
  2. classiq/_internals/api_wrapper.py +13 -1
  3. classiq/_internals/client.py +12 -2
  4. classiq/analyzer/analyzer.py +3 -1
  5. classiq/applications/__init__.py +1 -8
  6. classiq/applications/chemistry/__init__.py +6 -0
  7. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +1 -1
  8. classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/arithmetic_expression.py +1 -1
  9. classiq/{applications_model_constructors → applications}/combinatorial_helpers/combinatorial_problem_utils.py +25 -6
  10. classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_mapping.py +1 -1
  11. classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_utils.py +1 -1
  12. classiq/{applications_model_constructors → applications}/combinatorial_helpers/memory.py +2 -4
  13. classiq/{applications_model_constructors → applications}/combinatorial_helpers/optimization_model.py +13 -16
  14. classiq/{applications_model_constructors → applications}/combinatorial_helpers/pyomo_utils.py +4 -2
  15. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/encoding.py +3 -10
  16. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/fixed_variables.py +4 -6
  17. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/ising_converter.py +3 -5
  18. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty_support.py +3 -7
  19. classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/slack_variables.py +4 -6
  20. classiq/applications/combinatorial_optimization/__init__.py +11 -3
  21. classiq/{applications_model_constructors → applications/combinatorial_optimization}/combinatorial_optimization_model_constructor.py +9 -10
  22. classiq/applications/finance/__init__.py +3 -2
  23. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +24 -14
  24. classiq/applications/grover/__init__.py +11 -0
  25. classiq/applications/libraries/qmci_library.py +35 -0
  26. classiq/applications/qsvm/__init__.py +5 -1
  27. classiq/execution/all_hardware_devices.py +13 -0
  28. classiq/executor.py +2 -1
  29. classiq/interface/_version.py +1 -1
  30. classiq/interface/analyzer/result.py +1 -5
  31. classiq/interface/applications/qsvm.py +4 -2
  32. classiq/interface/ast_node.py +23 -0
  33. classiq/interface/backend/backend_preferences.py +5 -5
  34. classiq/interface/backend/quantum_backend_providers.py +7 -7
  35. classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
  36. classiq/interface/executor/execution_preferences.py +4 -9
  37. classiq/interface/executor/execution_request.py +2 -37
  38. classiq/interface/executor/vqe_result.py +1 -1
  39. classiq/interface/generator/application_apis/chemistry_declarations.py +2 -4
  40. classiq/interface/generator/application_apis/finance_declarations.py +1 -1
  41. classiq/interface/generator/arith/arithmetic_expression_validator.py +2 -0
  42. classiq/interface/generator/builtin_api_builder.py +0 -5
  43. classiq/interface/generator/constant.py +2 -3
  44. classiq/interface/generator/expressions/expression.py +2 -4
  45. classiq/interface/generator/expressions/qmod_qarray_proxy.py +82 -0
  46. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +22 -1
  47. classiq/interface/generator/expressions/qmod_sized_proxy.py +22 -0
  48. classiq/interface/generator/functions/__init__.py +2 -2
  49. classiq/interface/generator/functions/builtins/__init__.py +15 -0
  50. classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
  51. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +8 -6
  52. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +10 -4
  53. classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
  54. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +893 -319
  55. classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
  56. classiq/interface/generator/functions/classical_type.py +31 -21
  57. classiq/interface/generator/functions/function_declaration.py +2 -2
  58. classiq/interface/generator/hartree_fock.py +10 -2
  59. classiq/interface/generator/model/classical_main_validator.py +1 -1
  60. classiq/interface/generator/model/model.py +1 -1
  61. classiq/interface/generator/model/preferences/preferences.py +4 -2
  62. classiq/interface/generator/quantum_function_call.py +1 -1
  63. classiq/interface/generator/types/struct_declaration.py +2 -4
  64. classiq/interface/model/call_synthesis_data.py +3 -3
  65. classiq/interface/model/classical_if.py +13 -0
  66. classiq/interface/model/classical_parameter_declaration.py +2 -3
  67. classiq/interface/model/{quantum_if_operation.py → control.py} +39 -21
  68. classiq/interface/model/handle_binding.py +3 -2
  69. classiq/interface/model/invert.py +10 -0
  70. classiq/interface/model/model.py +2 -1
  71. classiq/interface/model/power.py +12 -0
  72. classiq/interface/model/quantum_function_call.py +9 -4
  73. classiq/interface/model/quantum_lambda_function.py +3 -9
  74. classiq/interface/model/quantum_statement.py +3 -2
  75. classiq/interface/model/quantum_type.py +8 -9
  76. classiq/interface/model/quantum_variable_declaration.py +2 -2
  77. classiq/interface/model/repeat.py +13 -0
  78. classiq/interface/model/resolvers/function_call_resolver.py +21 -0
  79. classiq/interface/model/statement_block.py +18 -4
  80. classiq/interface/model/validations/handles_validator.py +8 -12
  81. classiq/interface/model/within_apply_operation.py +4 -4
  82. classiq/interface/server/routes.py +0 -4
  83. classiq/qmod/__init__.py +6 -2
  84. classiq/qmod/builtins/classical_functions.py +34 -39
  85. classiq/qmod/builtins/functions.py +287 -300
  86. classiq/qmod/builtins/operations.py +217 -16
  87. classiq/qmod/builtins/structs.py +50 -48
  88. classiq/qmod/declaration_inferrer.py +30 -18
  89. classiq/qmod/native/expression_to_qmod.py +5 -4
  90. classiq/qmod/native/pretty_printer.py +48 -26
  91. classiq/qmod/qmod_constant.py +29 -5
  92. classiq/qmod/qmod_parameter.py +56 -34
  93. classiq/qmod/qmod_struct.py +2 -2
  94. classiq/qmod/qmod_variable.py +87 -43
  95. classiq/qmod/quantum_callable.py +8 -4
  96. classiq/qmod/quantum_expandable.py +25 -20
  97. classiq/qmod/quantum_function.py +29 -2
  98. classiq/qmod/symbolic.py +79 -69
  99. classiq/qmod/symbolic_expr.py +1 -1
  100. classiq/qmod/symbolic_type.py +1 -4
  101. classiq/qmod/utilities.py +29 -0
  102. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/METADATA +1 -1
  103. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/RECORD +122 -141
  104. classiq/applications/benchmarking/__init__.py +0 -9
  105. classiq/applications/benchmarking/mirror_benchmarking.py +0 -70
  106. classiq/applications/numpy_utils.py +0 -37
  107. classiq/applications_model_constructors/__init__.py +0 -25
  108. classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +0 -34
  109. classiq/applications_model_constructors/libraries/qmci_library.py +0 -107
  110. classiq/builtin_functions/__init__.py +0 -43
  111. classiq/builtin_functions/amplitude_loading.py +0 -3
  112. classiq/builtin_functions/binary_ops.py +0 -1
  113. classiq/builtin_functions/exponentiation.py +0 -5
  114. classiq/builtin_functions/qpe.py +0 -4
  115. classiq/builtin_functions/qsvm.py +0 -7
  116. classiq/builtin_functions/range_types.py +0 -5
  117. classiq/builtin_functions/standard_gates.py +0 -1
  118. classiq/builtin_functions/state_preparation.py +0 -6
  119. classiq/builtin_functions/suzuki_trotter.py +0 -3
  120. classiq/interface/executor/error_mitigation.py +0 -6
  121. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  122. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py +0 -0
  123. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -95
  124. classiq/model/__init__.py +0 -14
  125. classiq/model/composite_function_generator.py +0 -33
  126. classiq/model/function_handler.py +0 -462
  127. classiq/model/logic_flow.py +0 -149
  128. classiq/model/logic_flow_change_handler.py +0 -71
  129. classiq/model/model.py +0 -229
  130. classiq/quantum_functions/__init__.py +0 -17
  131. classiq/quantum_functions/annotation_parser.py +0 -205
  132. classiq/quantum_functions/decorators.py +0 -22
  133. classiq/quantum_functions/function_library.py +0 -181
  134. classiq/quantum_functions/function_parser.py +0 -74
  135. classiq/quantum_functions/quantum_function.py +0 -236
  136. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/__init__.py +0 -0
  137. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/allowed_constraints.py +0 -0
  138. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/__init__.py +0 -0
  139. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/isolation.py +0 -0
  140. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
  141. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +0 -0
  142. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_utils.py +0 -0
  143. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/py.typed +0 -0
  144. /classiq/{applications_model_constructors/combinatorial_helpers/transformations → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
  145. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/sympy_utils.py +0 -0
  146. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
  147. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty.py +0 -0
  148. /classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/sign_seperation.py +0 -0
  149. /classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +0 -0
  150. /classiq/{interface/generator/functions/core_lib_declarations → applications/libraries}/__init__.py +0 -0
  151. /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
  152. /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
  153. /classiq/{quantum_register.py → interface/model/quantum_register.py} +0 -0
  154. {classiq-0.38.0.dist-info → classiq-0.40.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,37 @@
1
+ from typing import Any
2
+
3
+ from classiq.interface.model.quantum_function_declaration import (
4
+ QuantumFunctionDeclaration,
5
+ QuantumOperandDeclaration,
6
+ )
7
+
8
+
9
+ def get_single_empty_operand_operator(
10
+ operator_name: str, **kwargs: Any
11
+ ) -> QuantumFunctionDeclaration:
12
+ operand_field_name = "operand"
13
+ return QuantumFunctionDeclaration(
14
+ name=operator_name,
15
+ operand_declarations={
16
+ operand_field_name: QuantumOperandDeclaration(name=operand_field_name)
17
+ },
18
+ **kwargs,
19
+ )
20
+
21
+
22
+ PERMUTE_OPERATOR = QuantumFunctionDeclaration(
23
+ name="permute",
24
+ operand_declarations={
25
+ "functions": QuantumOperandDeclaration(
26
+ name="functions",
27
+ is_list=True,
28
+ )
29
+ },
30
+ )
31
+
32
+ APPLY_OPERATOR = get_single_empty_operand_operator(operator_name="apply")
33
+
34
+ STD_QMOD_OPERATORS = [
35
+ PERMUTE_OPERATOR,
36
+ APPLY_OPERATOR,
37
+ ]
@@ -6,20 +6,22 @@ from pydantic import Extra, Field
6
6
  from sympy import IndexedBase, Symbol
7
7
  from typing_extensions import Annotated
8
8
 
9
+ from classiq.interface.ast_node import HashableASTNode
9
10
  from classiq.interface.generator.expressions.enums.ladder_operator import (
10
11
  LadderOperator as LadderOperatorEnum,
11
12
  )
12
13
  from classiq.interface.generator.expressions.enums.pauli import Pauli as PauliEnum
13
14
  from classiq.interface.generator.expressions.expression_types import RuntimeExpression
14
- from classiq.interface.helpers.hashable_pydantic_base_model import (
15
- HashablePydanticBaseModel,
16
- )
17
15
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
18
16
 
17
+ CLASSICAL_ATTRIBUTES = {
18
+ "len": len,
19
+ }
20
+
19
21
  NamedSymbol = Union[IndexedBase, Symbol]
20
22
 
21
23
 
22
- class ClassicalType(HashablePydanticBaseModel):
24
+ class ClassicalType(HashableASTNode):
23
25
  def as_symbolic(self, name: str) -> Union[NamedSymbol, List[NamedSymbol]]:
24
26
  return Symbol(name)
25
27
 
@@ -31,9 +33,9 @@ class ClassicalType(HashablePydanticBaseModel):
31
33
  )
32
34
 
33
35
  @property
34
- def python_type(self) -> type:
36
+ def qmod_type(self) -> type:
35
37
  raise NotImplementedError(
36
- f"{self.__class__.__name__!r} has no Python SDK equivalent"
38
+ f"{self.__class__.__name__!r} has no QMOD SDK equivalent"
37
39
  )
38
40
 
39
41
  class Config:
@@ -55,8 +57,10 @@ class Integer(ClassicalType):
55
57
  return values_with_discriminator(values, "kind", "int")
56
58
 
57
59
  @property
58
- def python_type(self) -> type:
59
- return int
60
+ def qmod_type(self) -> type:
61
+ from classiq.qmod.qmod_parameter import CInt
62
+
63
+ return CInt
60
64
 
61
65
 
62
66
  class Real(ClassicalType):
@@ -74,8 +78,10 @@ class Real(ClassicalType):
74
78
  return values_with_discriminator(values, "kind", "real")
75
79
 
76
80
  @property
77
- def python_type(self) -> type:
78
- return float
81
+ def qmod_type(self) -> type:
82
+ from classiq.qmod.qmod_parameter import CReal
83
+
84
+ return CReal
79
85
 
80
86
 
81
87
  class Bool(ClassicalType):
@@ -90,8 +96,10 @@ class Bool(ClassicalType):
90
96
  return values_with_discriminator(values, "kind", "bool")
91
97
 
92
98
  @property
93
- def python_type(self) -> type:
94
- return bool
99
+ def qmod_type(self) -> type:
100
+ from classiq.qmod.qmod_parameter import CBool
101
+
102
+ return CBool
95
103
 
96
104
 
97
105
  class ClassicalList(ClassicalType):
@@ -110,8 +118,10 @@ class ClassicalList(ClassicalType):
110
118
  return values_with_discriminator(values, "kind", "list")
111
119
 
112
120
  @property
113
- def python_type(self) -> type:
114
- return List[self.element_type.python_type] # type:ignore[name-defined]
121
+ def qmod_type(self) -> type:
122
+ from classiq.qmod.qmod_parameter import CArray
123
+
124
+ return CArray[self.element_type.qmod_type] # type:ignore[name-defined]
115
125
 
116
126
 
117
127
  class Pauli(ClassicalType):
@@ -126,8 +136,8 @@ class Pauli(ClassicalType):
126
136
  return values_with_discriminator(values, "kind", "pauli")
127
137
 
128
138
  @property
129
- def python_type(self) -> type:
130
- return int
139
+ def qmod_type(self) -> type:
140
+ return PauliEnum
131
141
 
132
142
 
133
143
  class StructMetaType(ClassicalType):
@@ -142,7 +152,7 @@ class StructMetaType(ClassicalType):
142
152
  return values_with_discriminator(values, "kind", "type_proxy")
143
153
 
144
154
 
145
- class QStructBase: # marker for Qmod structs in the Python SDK
155
+ class CStructBase: # marker for Qmod structs in the Python SDK
146
156
  pass
147
157
 
148
158
 
@@ -159,8 +169,8 @@ class Struct(ClassicalType):
159
169
  return values_with_discriminator(values, "kind", "struct_instance")
160
170
 
161
171
  @property
162
- def python_type(self) -> type:
163
- return type(self.name, (QStructBase,), dict())
172
+ def qmod_type(self) -> type:
173
+ return type(self.name, (CStructBase,), dict())
164
174
 
165
175
 
166
176
  class ClassicalArray(ClassicalType):
@@ -230,8 +240,8 @@ class LadderOperator(ClassicalType):
230
240
  return values_with_discriminator(values, "kind", "ladder_operator")
231
241
 
232
242
  @property
233
- def python_type(self) -> type:
234
- return int
243
+ def qmod_type(self) -> type:
244
+ return LadderOperatorEnum
235
245
 
236
246
 
237
247
  ConcreteClassicalType = Annotated[
@@ -2,12 +2,12 @@ import abc
2
2
  from typing import Dict
3
3
 
4
4
  import pydantic
5
- from pydantic.main import BaseModel
6
5
 
6
+ from classiq.interface.ast_node import ASTNode
7
7
  from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
8
8
 
9
9
 
10
- class FunctionDeclaration(BaseModel, abc.ABC):
10
+ class FunctionDeclaration(ASTNode, abc.ABC):
11
11
  """
12
12
  Facilitates the creation of a common function interface object.
13
13
  """
@@ -1,6 +1,12 @@
1
+ from typing import Any, Union
2
+
1
3
  import pydantic
2
4
 
3
- from classiq.interface.chemistry.ground_state_problem import CHEMISTRY_PROBLEMS
5
+ from classiq.interface.chemistry.ground_state_problem import (
6
+ CHEMISTRY_PROBLEMS,
7
+ HamiltonianProblem,
8
+ MoleculeProblem,
9
+ )
4
10
  from classiq.interface.generator.chemistry_function_params import (
5
11
  ChemistryFunctionParams,
6
12
  )
@@ -10,7 +16,9 @@ from classiq.exceptions import ClassiqValueError
10
16
 
11
17
  class HartreeFock(ChemistryFunctionParams):
12
18
  @pydantic.validator("gs_problem")
13
- def validate_gs_problem(cls, gs_problem):
19
+ def validate_gs_problem(
20
+ cls, gs_problem: Any
21
+ ) -> Union[MoleculeProblem, HamiltonianProblem]:
14
22
  if not isinstance(gs_problem, CHEMISTRY_PROBLEMS):
15
23
  raise ClassiqValueError(
16
24
  f"ground state problem must be of type {CHEMISTRY_PROBLEMS}"
@@ -1,7 +1,7 @@
1
1
  import ast
2
2
  from typing import Dict, List
3
3
 
4
- from classiq.model.model import DEFAULT_RESULT_NAME
4
+ from classiq.executor import DEFAULT_RESULT_NAME
5
5
 
6
6
  STANDARD_CMAIN_BODY_LENGTH = 2 # assignment of sample call, save statement
7
7
 
@@ -26,10 +26,10 @@ from classiq.interface.generator.types.struct_declaration import StructDeclarati
26
26
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
27
27
  from classiq.interface.helpers.validation_helpers import is_list_unique
28
28
  from classiq.interface.helpers.versioned_model import VersionedModel
29
+ from classiq.interface.model.quantum_register import QReg, QRegGenericAlias
29
30
 
30
31
  from classiq import ForeignFunctionDefinition as SynthesisForeignFunctionDefinition
31
32
  from classiq.exceptions import ClassiqValueError
32
- from classiq.quantum_register import QReg, QRegGenericAlias
33
33
 
34
34
  MAIN_FUNCTION_NAME = "main"
35
35
  CLASSICAL_ENTRY_FUNCTION_NAME = "cmain"
@@ -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(
@@ -80,7 +80,7 @@ class WirePair(HashablePydanticBaseModel):
80
80
  out_wire: WireName
81
81
 
82
82
 
83
- SUFFIX_RANDOMIZER = random.Random()
83
+ SUFFIX_RANDOMIZER = random.Random() # noqa: S311
84
84
 
85
85
 
86
86
  def split_wire_pair_to_wires(
@@ -2,15 +2,13 @@ from typing import Any, ClassVar, Dict, Mapping
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.ast_node import HashableASTNode
5
6
  from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
6
- from classiq.interface.helpers.hashable_pydantic_base_model import (
7
- HashablePydanticBaseModel,
8
- )
9
7
 
10
8
  from classiq.exceptions import ClassiqValueError
11
9
 
12
10
 
13
- class StructDeclaration(HashablePydanticBaseModel):
11
+ class StructDeclaration(HashableASTNode):
14
12
  name: str
15
13
 
16
14
  variables: Dict[str, ConcreteClassicalType] = pydantic.Field(
@@ -1,5 +1,5 @@
1
1
  import dataclasses
2
- from typing import Any, List, Mapping
2
+ from typing import Any, Iterator, List, Mapping
3
3
 
4
4
  from sympy import sympify
5
5
 
@@ -61,8 +61,8 @@ class CallSynthesisData(Mapping):
61
61
  def __getitem__(self, key: str) -> Any:
62
62
  return dataclasses.asdict(self)[key]
63
63
 
64
- def __iter__(self):
64
+ def __iter__(self) -> Iterator[str]:
65
65
  return iter(dataclasses.asdict(self))
66
66
 
67
- def __len__(self):
67
+ def __len__(self) -> int:
68
68
  return len(dataclasses.asdict(self))
@@ -0,0 +1,13 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.generator.expressions.expression import Expression
4
+ from classiq.interface.model.quantum_statement import QuantumOperation
5
+
6
+ if TYPE_CHECKING:
7
+ from classiq.interface.model.statement_block import StatementBlock
8
+
9
+
10
+ class ClassicalIf(QuantumOperation):
11
+ condition: Expression
12
+ then: "StatementBlock"
13
+ else_: "StatementBlock"
@@ -1,8 +1,7 @@
1
- import pydantic
2
-
1
+ from classiq.interface.ast_node import ASTNode
3
2
  from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
4
3
 
5
4
 
6
- class ClassicalParameterDeclaration(pydantic.BaseModel):
5
+ class ClassicalParameterDeclaration(ASTNode):
7
6
  name: str
8
7
  classical_type: ConcreteClassicalType
@@ -5,7 +5,10 @@ from sympy import Equality
5
5
  from sympy.core.numbers import Integer
6
6
 
7
7
  from classiq.interface.generator.expressions.expression import Expression
8
- from classiq.interface.generator.expressions.qmod_qscalar_proxy import QmodQNumProxy
8
+ from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
9
+ QmodQNumProxy,
10
+ QmodSizedProxy,
11
+ )
9
12
  from classiq.interface.model.quantum_expressions.control_state import (
10
13
  min_bit_length,
11
14
  to_twos_complement,
@@ -17,18 +20,18 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
17
20
  from classiq.exceptions import ClassiqValueError
18
21
 
19
22
  if TYPE_CHECKING:
20
- from classiq.interface.model.quantum_lambda_function import QuantumOperand
23
+ from classiq.interface.model.statement_block import StatementBlock
21
24
 
22
- QUANTUM_IF_INOUT_NAME = "ctrl"
23
- QUANTUM_IF_CONDITION_ARG_ERROR_MESSAGE_FORMAT = (
24
- "quantum_if condition must be of the form '<quantum-variable> == "
25
+ CONTROL_INOUT_NAME = "ctrl"
26
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT = (
27
+ "control condition must be of the form '<quantum-variable> == "
25
28
  "<classical-integer-expression>', but condition's {}-hand side was {!r}"
26
29
  )
27
30
 
28
31
 
29
- class QuantumIfOperation(QuantumExpressionOperation):
30
- then: "QuantumOperand"
31
- _ctrl: Optional[QmodQNumProxy] = pydantic.PrivateAttr(
32
+ class Control(QuantumExpressionOperation):
33
+ body: "StatementBlock"
34
+ _ctrl: Optional[QmodSizedProxy] = pydantic.PrivateAttr(
32
35
  default=None,
33
36
  )
34
37
  _ctrl_val: Optional[int] = pydantic.PrivateAttr(
@@ -40,7 +43,7 @@ class QuantumIfOperation(QuantumExpressionOperation):
40
43
  return self.expression
41
44
 
42
45
  @property
43
- def ctrl(self) -> QmodQNumProxy:
46
+ def ctrl(self) -> QmodSizedProxy:
44
47
  assert self._ctrl is not None
45
48
  return self._ctrl
46
49
 
@@ -51,44 +54,59 @@ class QuantumIfOperation(QuantumExpressionOperation):
51
54
 
52
55
  def resolve_condition(self) -> None:
53
56
  condition = self.condition.value.value
54
- if not isinstance(condition, Equality):
57
+ if isinstance(condition, QmodSizedProxy):
58
+ self._resolve_port_condition(condition)
59
+ elif isinstance(condition, Equality):
60
+ self._resolve_num_condition(condition)
61
+ else:
55
62
  raise ClassiqValueError(
56
- f"quantum_if condition must be an equality, was {str(condition)!r}"
63
+ f"control condition must be a qubit, an array of qubits, or a quantum "
64
+ f"numeric equality, was {str(condition)!r}"
57
65
  )
66
+
67
+ def _resolve_port_condition(self, condition: QmodSizedProxy) -> None:
68
+ self._ctrl = condition
69
+
70
+ def _resolve_num_condition(self, condition: Equality) -> None:
58
71
  ctrl, ctrl_val = condition.args
59
72
  if isinstance(ctrl, Integer) and isinstance(ctrl_val, QmodQNumProxy):
60
73
  ctrl, ctrl_val = ctrl_val, ctrl
61
74
  if not isinstance(ctrl, QmodQNumProxy):
62
75
  raise ClassiqValueError(
63
- QUANTUM_IF_CONDITION_ARG_ERROR_MESSAGE_FORMAT.format("left", str(ctrl))
76
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("left", str(ctrl))
64
77
  )
65
78
  if not isinstance(ctrl_val, Integer):
66
79
  raise ClassiqValueError(
67
- QUANTUM_IF_CONDITION_ARG_ERROR_MESSAGE_FORMAT.format(
68
- "right", str(ctrl_val)
69
- )
80
+ CONTROL_CTRL_ARG_ERROR_MESSAGE_FORMAT.format("right", str(ctrl_val))
70
81
  )
71
82
  self._ctrl, self._ctrl_val = ctrl, int(ctrl_val)
72
83
 
84
+ @property
85
+ def has_ctrl_state(self) -> bool:
86
+ assert self._ctrl is not None
87
+ return self._ctrl_val is not None
88
+
73
89
  @property
74
90
  def ctrl_state(self) -> str:
75
- is_signed = self.ctrl.is_signed
76
- fraction_places = self.ctrl.fraction_digits
77
- ctrl_size = len(self.ctrl)
91
+ ctrl = self.ctrl
92
+ assert isinstance(ctrl, QmodQNumProxy)
93
+ is_signed = ctrl.is_signed
94
+ fraction_places = ctrl.fraction_digits
95
+ ctrl_size = len(ctrl)
78
96
  if not is_signed and self.ctrl_val < 0:
79
97
  raise ClassiqValueError(
80
- f"Variable {str(self.ctrl)!r} is not signed but control value "
98
+ f"Variable {str(ctrl)!r} is not signed but control value "
81
99
  f"{self.ctrl_val} is negative"
82
100
  )
83
101
  required_qubits = min_bit_length(self.ctrl_val, is_signed)
84
102
  if ctrl_size < required_qubits:
85
103
  raise ClassiqValueError(
86
- f"Variable {str(self.ctrl)!r} has {ctrl_size} qubits but control value "
104
+ f"Variable {str(ctrl)!r} has {ctrl_size} qubits but control value "
87
105
  f"{str(self.ctrl_val)!r} requires at least {required_qubits} qubits"
88
106
  )
89
107
  if fraction_places != 0:
90
108
  raise ClassiqValueError(
91
- f"quantum-if on a non-integer quantum variable {str(self.ctrl)!r} is "
109
+ f"Comparison (`==`) on a non-integer quantum variable {str(ctrl)!r} is "
92
110
  f"not supported at the moment"
93
111
  )
94
112
  return to_twos_complement(self.ctrl_val, ctrl_size, is_signed)
@@ -1,9 +1,10 @@
1
- from pydantic import BaseModel, Extra
1
+ from pydantic import Extra
2
2
 
3
+ from classiq.interface.ast_node import ASTNode
3
4
  from classiq.interface.generator.expressions.expression import Expression
4
5
 
5
6
 
6
- class HandleBinding(BaseModel):
7
+ class HandleBinding(ASTNode):
7
8
  name: str
8
9
 
9
10
  class Config:
@@ -0,0 +1,10 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.model.quantum_statement import QuantumOperation
4
+
5
+ if TYPE_CHECKING:
6
+ from classiq.interface.model.statement_block import StatementBlock
7
+
8
+
9
+ class Invert(QuantumOperation):
10
+ body: "StatementBlock"
@@ -3,6 +3,7 @@ from typing import Any, Dict, List, Literal, NewType, Optional, Set
3
3
 
4
4
  import pydantic
5
5
 
6
+ from classiq.interface.ast_node import ASTNode
6
7
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
7
8
  from classiq.interface.generator.constant import Constant
8
9
  from classiq.interface.generator.functions.port_declaration import (
@@ -51,7 +52,7 @@ class VersionedSerializedModel(VersionedModel):
51
52
  model: SerializedModel
52
53
 
53
54
 
54
- class Model(VersionedModel):
55
+ class Model(VersionedModel, ASTNode):
55
56
  """
56
57
  All the relevant data for generating quantum circuit in one place.
57
58
  """
@@ -0,0 +1,12 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from classiq.interface.generator.expressions.expression import Expression
4
+ from classiq.interface.model.quantum_statement import QuantumOperation
5
+
6
+ if TYPE_CHECKING:
7
+ from classiq.interface.model.statement_block import StatementBlock
8
+
9
+
10
+ class Power(QuantumOperation):
11
+ power: Expression
12
+ body: "StatementBlock"
@@ -1,10 +1,10 @@
1
1
  import itertools
2
2
  import re
3
- from typing import Any, Dict, List, Mapping, Optional, Set, Union
3
+ from typing import Any, Dict, List, Mapping, Optional, Set, Type, Union
4
4
 
5
5
  import pydantic
6
- from pydantic import BaseModel
7
6
 
7
+ from classiq.interface.ast_node import ASTNode
8
8
  from classiq.interface.generator.expressions.expression import Expression
9
9
  from classiq.interface.generator.functions.function_declaration import (
10
10
  FunctionDeclaration,
@@ -77,8 +77,13 @@ def _validate_no_duplicated_handles(
77
77
  def _validate_no_mixing_sliced_and_whole_handles(
78
78
  inouts: Mapping[str, HandleBinding],
79
79
  ) -> None:
80
+ def _treat_subscript_as_slice(type_: Type[HandleBinding]) -> Type[HandleBinding]:
81
+ if type_ == SubscriptHandleBinding:
82
+ return SlicedHandleBinding
83
+ return type_
84
+
80
85
  inout_handle_names_to_types = {
81
- handle_name: {type(handle) for handle in handles}
86
+ handle_name: {_treat_subscript_as_slice(type(handle)) for handle in handles}
82
87
  for handle_name, handles in itertools.groupby(
83
88
  inouts.values(), lambda handle: handle.name
84
89
  )
@@ -103,7 +108,7 @@ ArgValue = Union[
103
108
  ]
104
109
 
105
110
 
106
- class OperandIdentifier(BaseModel):
111
+ class OperandIdentifier(ASTNode):
107
112
  name: str
108
113
  index: Expression
109
114
 
@@ -1,21 +1,18 @@
1
1
  from typing import TYPE_CHECKING, Dict, List, Optional, Union
2
2
 
3
3
  import pydantic
4
- from pydantic import BaseModel
5
4
 
5
+ from classiq.interface.ast_node import ASTNode
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
7
  from classiq.interface.model.quantum_function_declaration import (
8
8
  QuantumOperandDeclaration,
9
9
  )
10
- from classiq.interface.model.quantum_if_operation import QuantumIfOperation
11
10
 
12
11
  if TYPE_CHECKING:
13
12
  from classiq.interface.model.statement_block import StatementBlock
14
13
 
15
- from classiq.interface.model.within_apply_operation import WithinApplyOperation
16
14
 
17
-
18
- class QuantumLambdaFunction(BaseModel):
15
+ class QuantumLambdaFunction(ASTNode):
19
16
  """
20
17
  The definition of an anonymous function passed as operand to higher-level functions
21
18
  """
@@ -39,7 +36,7 @@ class QuantumLambdaFunction(BaseModel):
39
36
  self._func_decl = fd
40
37
 
41
38
 
42
- class LambdaListComprehension(BaseModel):
39
+ class LambdaListComprehension(ASTNode):
43
40
  """
44
41
  Specification of a list of lambda functions iteratively
45
42
  """
@@ -59,6 +56,3 @@ class LambdaListComprehension(BaseModel):
59
56
 
60
57
  QuantumCallable = Union[str, QuantumLambdaFunction]
61
58
  QuantumOperand = Union[QuantumCallable, List[QuantumCallable], LambdaListComprehension]
62
-
63
- QuantumIfOperation.update_forward_refs(QuantumOperand=QuantumOperand)
64
- WithinApplyOperation.update_forward_refs(QuantumOperand=QuantumOperand)
@@ -1,7 +1,8 @@
1
1
  from typing import Mapping, Union
2
2
 
3
- from pydantic import BaseModel, Extra
3
+ from pydantic import Extra
4
4
 
5
+ from classiq.interface.ast_node import ASTNode
5
6
  from classiq.interface.model.handle_binding import (
6
7
  HandleBinding,
7
8
  SlicedHandleBinding,
@@ -9,7 +10,7 @@ from classiq.interface.model.handle_binding import (
9
10
  )
10
11
 
11
12
 
12
- class QuantumStatement(BaseModel):
13
+ class QuantumStatement(ASTNode):
13
14
  class Config:
14
15
  extra = Extra.forbid
15
16
 
@@ -4,25 +4,24 @@ import pydantic
4
4
  from pydantic import Extra, Field
5
5
  from typing_extensions import Annotated
6
6
 
7
+ from classiq.interface.ast_node import HashableASTNode
7
8
  from classiq.interface.generator.arith.register_user_input import (
8
9
  RegisterArithmeticInfo,
9
10
  RegisterUserInput,
10
11
  )
11
12
  from classiq.interface.generator.expressions.expression import Expression
13
+ from classiq.interface.generator.expressions.qmod_qarray_proxy import QmodQArrayProxy
12
14
  from classiq.interface.generator.expressions.qmod_qscalar_proxy import (
13
15
  QmodQNumProxy,
14
16
  QmodQScalarProxy,
15
17
  )
16
18
  from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
17
- from classiq.interface.helpers.hashable_pydantic_base_model import (
18
- HashablePydanticBaseModel,
19
- )
20
19
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
21
20
 
22
21
  from classiq.exceptions import ClassiqValueError
23
22
 
24
23
 
25
- class QuantumType(HashablePydanticBaseModel):
24
+ class QuantumType(HashableASTNode):
26
25
  class Config:
27
26
  extra = Extra.forbid
28
27
 
@@ -67,12 +66,9 @@ class QuantumBit(QuantumScalar):
67
66
  return values_with_discriminator(values, "kind", "qbit")
68
67
 
69
68
 
70
- class QuantumArray(QuantumType):
71
- length: Optional[Expression]
72
-
73
-
74
- class QuantumBitvector(QuantumArray):
69
+ class QuantumBitvector(QuantumType):
75
70
  kind: Literal["qvec"]
71
+ length: Optional[Expression]
76
72
 
77
73
  @pydantic.root_validator(pre=True)
78
74
  def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@@ -82,6 +78,9 @@ class QuantumBitvector(QuantumArray):
82
78
  if self.length is not None and self.length.is_evaluated():
83
79
  self._size_in_bits = self.length.to_int_value()
84
80
 
81
+ def get_proxy(self, name: str) -> QmodQArrayProxy:
82
+ return QmodQArrayProxy(name, self.size_in_bits)
83
+
85
84
 
86
85
  class QuantumNumeric(QuantumScalar):
87
86
  kind: Literal["qnum"]
@@ -1,8 +1,8 @@
1
1
  from typing import Any, Mapping, Optional
2
2
 
3
3
  import pydantic
4
- from pydantic import BaseModel
5
4
 
5
+ from classiq.interface.ast_node import ASTNode
6
6
  from classiq.interface.generator.expressions.expression import Expression
7
7
  from classiq.interface.model.quantum_type import (
8
8
  ConcreteQuantumType,
@@ -11,7 +11,7 @@ from classiq.interface.model.quantum_type import (
11
11
  )
12
12
 
13
13
 
14
- class QuantumVariableDeclaration(BaseModel):
14
+ class QuantumVariableDeclaration(ASTNode):
15
15
  name: str
16
16
  quantum_type: ConcreteQuantumType
17
17
  size: Optional[Expression] = pydantic.Field(default=None)