classiq 0.43.3__py3-none-any.whl → 0.45.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 (220) hide show
  1. classiq/__init__.py +8 -3
  2. classiq/_internals/api_wrapper.py +2 -2
  3. classiq/_internals/authentication/auth0.py +1 -1
  4. classiq/_internals/authentication/device.py +5 -1
  5. classiq/_internals/authentication/token_manager.py +5 -4
  6. classiq/_internals/client.py +5 -8
  7. classiq/_internals/config.py +1 -2
  8. classiq/_internals/host_checker.py +34 -13
  9. classiq/_internals/jobs.py +3 -3
  10. classiq/analyzer/analyzer.py +1 -1
  11. classiq/analyzer/analyzer_utilities.py +1 -1
  12. classiq/analyzer/rb.py +1 -1
  13. classiq/applications/chemistry/chemistry_model_constructor.py +13 -7
  14. classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
  15. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +1 -1
  16. classiq/applications/combinatorial_helpers/encoding_mapping.py +1 -1
  17. classiq/applications/combinatorial_helpers/encoding_utils.py +2 -1
  18. classiq/applications/combinatorial_helpers/optimization_model.py +1 -1
  19. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +1 -1
  20. classiq/applications/combinatorial_helpers/pyomo_utils.py +1 -2
  21. classiq/applications/combinatorial_helpers/transformations/encoding.py +1 -1
  22. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -4
  23. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +1 -1
  24. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -1
  25. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
  26. classiq/applications/finance/finance_model_constructor.py +4 -3
  27. classiq/applications/grover/grover_model_constructor.py +7 -5
  28. classiq/applications/hamiltonian/__init__.py +0 -0
  29. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  30. classiq/applications/qnn/circuit_utils.py +1 -1
  31. classiq/applications/qnn/datasets/dataset_base_classes.py +2 -1
  32. classiq/applications/qnn/datasets/dataset_not.py +2 -1
  33. classiq/applications/qnn/qlayer.py +3 -2
  34. classiq/applications/qnn/torch_utils.py +2 -1
  35. classiq/applications/qsvm/qsvm_model_constructor.py +1 -1
  36. classiq/execution/execution_session.py +1 -1
  37. classiq/execution/jobs.py +5 -2
  38. classiq/interface/_version.py +1 -1
  39. classiq/interface/analyzer/cytoscape_graph.py +1 -2
  40. classiq/interface/analyzer/result.py +2 -3
  41. classiq/interface/ast_node.py +1 -18
  42. classiq/interface/backend/backend_preferences.py +11 -18
  43. classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
  44. classiq/interface/backend/pydantic_backend.py +0 -5
  45. classiq/interface/backend/quantum_backend_providers.py +4 -3
  46. classiq/interface/chemistry/fermionic_operator.py +1 -2
  47. classiq/interface/chemistry/ground_state_problem.py +2 -3
  48. classiq/interface/chemistry/molecule.py +1 -2
  49. classiq/interface/chemistry/operator.py +8 -10
  50. classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
  51. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +1 -1
  52. classiq/interface/combinatorial_optimization/solver_types.py +1 -1
  53. classiq/interface/debug_info/__init__.py +0 -0
  54. classiq/interface/debug_info/debug_info.py +32 -0
  55. classiq/{exceptions.py → interface/exceptions.py} +4 -0
  56. classiq/interface/executor/aws_execution_cost.py +2 -2
  57. classiq/interface/executor/execution_preferences.py +2 -47
  58. classiq/interface/executor/execution_result.py +1 -2
  59. classiq/interface/executor/optimizer_preferences.py +2 -3
  60. classiq/interface/executor/quantum_code.py +1 -2
  61. classiq/interface/executor/quantum_instruction_set.py +2 -2
  62. classiq/interface/executor/register_initialization.py +1 -2
  63. classiq/interface/executor/result.py +29 -14
  64. classiq/interface/finance/function_input.py +6 -11
  65. classiq/interface/generator/amplitude_loading.py +2 -3
  66. classiq/interface/generator/ansatz_library.py +1 -1
  67. classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
  68. classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
  69. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
  70. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  71. classiq/interface/generator/application_apis/finance_declarations.py +37 -44
  72. classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
  73. classiq/interface/generator/arith/arithmetic.py +10 -8
  74. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +1 -2
  75. classiq/interface/generator/arith/arithmetic_expression_abc.py +22 -3
  76. classiq/interface/generator/arith/arithmetic_expression_parser.py +3 -4
  77. classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -2
  78. classiq/interface/generator/arith/arithmetic_param_getters.py +1 -2
  79. classiq/interface/generator/arith/arithmetic_result_builder.py +15 -11
  80. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  81. classiq/interface/generator/arith/binary_ops.py +7 -7
  82. classiq/interface/generator/arith/endianness.py +1 -1
  83. classiq/interface/generator/arith/extremum_operations.py +44 -21
  84. classiq/interface/generator/arith/logical_ops.py +1 -2
  85. classiq/interface/generator/arith/register_user_input.py +1 -2
  86. classiq/interface/generator/arith/unary_ops.py +1 -2
  87. classiq/interface/generator/arith/uncomputation_methods.py +1 -1
  88. classiq/interface/generator/chemistry_function_params.py +1 -2
  89. classiq/interface/generator/circuit_code/circuit_code.py +1 -2
  90. classiq/interface/generator/circuit_code/types_and_constants.py +1 -2
  91. classiq/interface/generator/commuting_pauli_exponentiation.py +1 -2
  92. classiq/interface/generator/constant.py +1 -1
  93. classiq/interface/generator/control_state.py +1 -2
  94. classiq/interface/generator/custom_ansatz.py +1 -2
  95. classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
  96. classiq/interface/generator/expressions/enums/finance_functions.py +4 -5
  97. classiq/interface/generator/expressions/evaluated_expression.py +1 -2
  98. classiq/interface/generator/expressions/expression.py +1 -2
  99. classiq/interface/generator/expressions/expression_constants.py +3 -1
  100. classiq/interface/generator/expressions/non_symbolic_expr.py +1 -1
  101. classiq/interface/generator/expressions/qmod_qarray_proxy.py +53 -70
  102. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -7
  103. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
  104. classiq/interface/generator/expressions/qmod_sized_proxy.py +1 -1
  105. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  106. classiq/interface/generator/function_params.py +2 -3
  107. classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
  108. classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
  109. classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
  110. classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
  111. classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
  112. classiq/interface/generator/functions/classical_function_declaration.py +14 -6
  113. classiq/interface/generator/functions/classical_type.py +7 -114
  114. classiq/interface/generator/functions/concrete_types.py +55 -0
  115. classiq/interface/generator/functions/function_declaration.py +10 -10
  116. classiq/interface/generator/functions/port_declaration.py +1 -2
  117. classiq/interface/generator/functions/type_name.py +80 -0
  118. classiq/interface/generator/generated_circuit_data.py +3 -3
  119. classiq/interface/generator/grover_diffuser.py +1 -2
  120. classiq/interface/generator/grover_operator.py +1 -2
  121. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +1 -2
  122. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +1 -2
  123. classiq/interface/generator/hardware/hardware_data.py +1 -2
  124. classiq/interface/generator/hardware_efficient_ansatz.py +2 -3
  125. classiq/interface/generator/hartree_fock.py +1 -2
  126. classiq/interface/generator/linear_pauli_rotations.py +1 -2
  127. classiq/interface/generator/mcmt_method.py +1 -1
  128. classiq/interface/generator/mcu.py +1 -2
  129. classiq/interface/generator/mcx.py +1 -2
  130. classiq/interface/generator/model/constraints.py +2 -3
  131. classiq/interface/generator/model/model.py +12 -2
  132. classiq/interface/generator/model/preferences/preferences.py +7 -3
  133. classiq/interface/generator/model/quantum_register.py +1 -2
  134. classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
  135. classiq/interface/generator/oracles/custom_oracle.py +1 -2
  136. classiq/interface/generator/oracles/oracle_abc.py +1 -2
  137. classiq/interface/generator/partitioned_register.py +1 -2
  138. classiq/interface/generator/piecewise_linear_amplitude_loading.py +1 -2
  139. classiq/interface/generator/preferences/optimization.py +1 -2
  140. classiq/interface/generator/qpe.py +1 -2
  141. classiq/interface/generator/qsvm.py +2 -3
  142. classiq/interface/generator/quantum_function_call.py +4 -2
  143. classiq/interface/generator/quantum_program.py +6 -7
  144. classiq/interface/generator/range_types.py +1 -1
  145. classiq/interface/generator/register_role.py +8 -2
  146. classiq/interface/generator/slice_parsing_utils.py +1 -2
  147. classiq/interface/generator/standard_gates/controlled_standard_gates.py +1 -2
  148. classiq/interface/generator/state_preparation/metrics.py +2 -3
  149. classiq/interface/generator/state_preparation/state_preparation.py +1 -2
  150. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
  151. classiq/interface/generator/transpiler_basis_gates.py +1 -1
  152. classiq/interface/generator/types/builtin_enum_declarations.py +38 -45
  153. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
  154. classiq/interface/generator/types/enum_declaration.py +1 -2
  155. classiq/interface/generator/types/qstruct_declaration.py +17 -0
  156. classiq/interface/generator/types/struct_declaration.py +2 -3
  157. classiq/interface/generator/ucc.py +1 -2
  158. classiq/interface/generator/unitary_gate.py +1 -2
  159. classiq/interface/generator/validations/flow_graph.py +1 -2
  160. classiq/interface/generator/validations/validator_functions.py +1 -2
  161. classiq/interface/hardware.py +1 -1
  162. classiq/interface/helpers/validation_helpers.py +2 -19
  163. classiq/interface/ide/visual_model.py +10 -4
  164. classiq/interface/interface_version.py +1 -0
  165. classiq/interface/jobs.py +2 -3
  166. classiq/interface/model/bind_operation.py +26 -7
  167. classiq/interface/model/classical_parameter_declaration.py +8 -5
  168. classiq/interface/model/control.py +5 -5
  169. classiq/interface/model/handle_binding.py +185 -12
  170. classiq/interface/model/inplace_binary_operation.py +17 -6
  171. classiq/interface/model/model.py +29 -7
  172. classiq/interface/model/native_function_definition.py +8 -4
  173. classiq/interface/model/parameter.py +13 -0
  174. classiq/interface/model/port_declaration.py +21 -4
  175. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +22 -8
  176. classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
  177. classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
  178. classiq/interface/model/quantum_function_call.py +136 -194
  179. classiq/interface/model/quantum_function_declaration.py +147 -165
  180. classiq/interface/model/quantum_lambda_function.py +23 -6
  181. classiq/interface/model/quantum_statement.py +34 -8
  182. classiq/interface/model/quantum_type.py +41 -11
  183. classiq/interface/model/quantum_variable_declaration.py +1 -1
  184. classiq/interface/model/statement_block.py +2 -0
  185. classiq/interface/model/validation_handle.py +8 -2
  186. classiq/interface/server/global_versions.py +4 -4
  187. classiq/interface/server/routes.py +2 -0
  188. classiq/interface/source_reference.py +59 -0
  189. classiq/qmod/__init__.py +2 -3
  190. classiq/qmod/builtins/classical_execution_primitives.py +1 -1
  191. classiq/qmod/builtins/functions.py +39 -11
  192. classiq/qmod/builtins/operations.py +172 -41
  193. classiq/qmod/classical_function.py +1 -1
  194. classiq/qmod/declaration_inferrer.py +102 -57
  195. classiq/qmod/expression_query.py +1 -1
  196. classiq/qmod/model_state_container.py +2 -0
  197. classiq/qmod/native/pretty_printer.py +71 -53
  198. classiq/qmod/pretty_print/pretty_printer.py +98 -52
  199. classiq/qmod/qfunc.py +11 -5
  200. classiq/qmod/qmod_constant.py +1 -1
  201. classiq/qmod/qmod_parameter.py +27 -4
  202. classiq/qmod/qmod_variable.py +405 -174
  203. classiq/qmod/quantum_callable.py +3 -3
  204. classiq/qmod/quantum_expandable.py +128 -68
  205. classiq/qmod/quantum_function.py +24 -5
  206. classiq/qmod/semantics/annotation.py +13 -15
  207. classiq/qmod/semantics/error_manager.py +36 -10
  208. classiq/qmod/semantics/static_semantics_visitor.py +164 -76
  209. classiq/qmod/semantics/validation/func_call_validation.py +43 -97
  210. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  211. classiq/qmod/semantics/validation/types_validation.py +108 -1
  212. classiq/qmod/symbolic.py +2 -1
  213. classiq/qmod/type_attribute_remover.py +32 -0
  214. classiq/qmod/utilities.py +26 -5
  215. classiq/{interface/ide/show.py → show.py} +1 -1
  216. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/METADATA +3 -3
  217. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/RECORD +219 -207
  218. classiq/qmod/qmod_struct.py +0 -13
  219. /classiq/{_internals → interface}/enum_utils.py +0 -0
  220. {classiq-0.43.3.dist-info → classiq-0.45.0.dist-info}/WHEEL +0 -0
@@ -1,9 +1,8 @@
1
- from typing import Hashable, List, Mapping, Optional
1
+ from typing import Hashable, List, Mapping
2
2
 
3
+ from classiq.interface.exceptions import ClassiqValueError
3
4
  from classiq.interface.helpers.pydantic_model_helpers import Nameable
4
5
 
5
- from classiq.exceptions import ClassiqValueError
6
-
7
6
 
8
7
  def is_list_unique(lst: List[Hashable]) -> bool:
9
8
  return len(set(lst)) == len(lst)
@@ -16,19 +15,3 @@ def validate_nameables_mapping(
16
15
  raise ClassiqValueError(
17
16
  f"{declaration_type} declaration names should match the keys of their names."
18
17
  )
19
-
20
-
21
- def validate_nameables_no_overlap(
22
- left_nameables_dict: Optional[Mapping[str, Nameable]],
23
- right_nameables_dict: Optional[Mapping[str, Nameable]],
24
- left_declaration_type: str,
25
- right_declaration_type: str,
26
- ) -> Optional[str]:
27
- if left_nameables_dict is None or right_nameables_dict is None:
28
- return None
29
-
30
- matched_names = left_nameables_dict.keys() & right_nameables_dict.keys()
31
- if matched_names:
32
- return f"{left_declaration_type} declaration names overlap with {right_declaration_type} declaration names: {matched_names}"
33
-
34
- return None
@@ -2,15 +2,15 @@ from typing import Dict, List, Optional, Tuple
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.enum_utils import StrEnum
5
6
  from classiq.interface.generator.hardware.hardware_data import SynthesisHardwareData
6
7
  from classiq.interface.helpers.versioned_model import VersionedModel
7
8
 
8
- from classiq._internals.enum_utils import StrEnum
9
-
10
9
 
11
10
  class OperationLevel(StrEnum):
12
- USER_DEFINED = "USER_DEFINED"
13
- ENGINE_GENERATED = "ENGINE_GENERATED"
11
+ QMOD_FUNCTION_CALL = "QMOD_CALL"
12
+ QMOD_STATEMENT = "QMOD_STATEMENT"
13
+ ENGINE_FUNCTION_CALL = "ENGINE_CALL"
14
14
  BASIS_GATE = "BASIS_GATE"
15
15
  UNKNOWN = "UNKNOWN"
16
16
 
@@ -41,6 +41,12 @@ class OperationLink(pydantic.BaseModel):
41
41
  qubits: Tuple[int, ...]
42
42
  type: str
43
43
 
44
+ class Config:
45
+ allow_mutation = False
46
+
47
+ def __hash__(self) -> int:
48
+ return hash((type(self), self.label, self.qubits, self.type))
49
+
44
50
 
45
51
  class OperationLinks(pydantic.BaseModel):
46
52
  inputs: List[OperationLink]
@@ -0,0 +1 @@
1
+ INTERFACE_VERSION = "2"
classiq/interface/jobs.py CHANGED
@@ -4,11 +4,10 @@ import pydantic
4
4
  from pydantic import BaseModel
5
5
  from pydantic.generics import GenericModel
6
6
 
7
+ from classiq.interface.enum_utils import StrEnum
8
+ from classiq.interface.exceptions import ClassiqAPIError
7
9
  from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
8
10
 
9
- from classiq._internals.enum_utils import StrEnum
10
- from classiq.exceptions import ClassiqAPIError
11
-
12
11
  JSONObject = Dict[str, Any]
13
12
  T = TypeVar("T", bound=Union[pydantic.BaseModel, JSONObject])
14
13
  AUTH_HEADER = "Classiq-BE-Auth"
@@ -1,11 +1,10 @@
1
- from typing import List, Literal, Mapping
1
+ from typing import List, Literal, Mapping, Sequence
2
2
 
3
3
  import pydantic
4
4
 
5
- from classiq.interface.model.handle_binding import HandleBinding
6
- from classiq.interface.model.quantum_statement import QuantumOperation
7
-
8
- from classiq.exceptions import ClassiqValueError
5
+ from classiq.interface.exceptions import ClassiqValueError
6
+ from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
7
+ from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
9
8
 
10
9
  BIND_INPUT_NAME = "bind_input"
11
10
  BIND_OUTPUT_NAME = "bind_output"
@@ -14,8 +13,8 @@ BIND_OUTPUT_NAME = "bind_output"
14
13
  class BindOperation(QuantumOperation):
15
14
  kind: Literal["BindOperation"]
16
15
 
17
- in_handles: List[HandleBinding]
18
- out_handles: List[HandleBinding]
16
+ in_handles: List[ConcreteHandleBinding]
17
+ out_handles: List[ConcreteHandleBinding]
19
18
 
20
19
  @property
21
20
  def wiring_inputs(self) -> Mapping[str, HandleBinding]:
@@ -23,6 +22,16 @@ class BindOperation(QuantumOperation):
23
22
  f"{BIND_INPUT_NAME}_{i}": handle for i, handle in enumerate(self.in_handles)
24
23
  }
25
24
 
25
+ @property
26
+ def readable_inputs(self) -> Sequence[HandleMetadata]:
27
+ return [
28
+ HandleMetadata(
29
+ handle=handle,
30
+ readable_location="on the left-hand side of a bind statement",
31
+ )
32
+ for handle in self.in_handles
33
+ ]
34
+
26
35
  @property
27
36
  def wiring_outputs(self) -> Mapping[str, HandleBinding]:
28
37
  return {
@@ -30,6 +39,16 @@ class BindOperation(QuantumOperation):
30
39
  for i, handle in enumerate(self.out_handles)
31
40
  }
32
41
 
42
+ @property
43
+ def readable_outputs(self) -> Sequence[HandleMetadata]:
44
+ return [
45
+ HandleMetadata(
46
+ handle=handle,
47
+ readable_location="on the right-hand side of a bind statement",
48
+ )
49
+ for handle in self.out_handles
50
+ ]
51
+
33
52
  @pydantic.validator("in_handles", "out_handles")
34
53
  def validate_handle(cls, handles: List[HandleBinding]) -> List[HandleBinding]:
35
54
  for handle in handles:
@@ -2,15 +2,14 @@ from typing import Any, Dict, Literal
2
2
 
3
3
  import pydantic
4
4
 
5
- from classiq.interface.ast_node import ASTNode
6
- from classiq.interface.generator.functions.classical_type import ConcreteClassicalType
5
+ from classiq.interface.generator.functions.concrete_types import ConcreteClassicalType
7
6
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
7
+ from classiq.interface.model.parameter import Parameter
8
8
 
9
9
 
10
- class ClassicalParameterDeclaration(ASTNode):
10
+ class AnonClassicalParameterDeclaration(Parameter):
11
11
  kind: Literal["ClassicalParameterDeclaration"]
12
12
 
13
- name: str
14
13
  classical_type: ConcreteClassicalType
15
14
 
16
15
  @pydantic.root_validator(pre=True)
@@ -20,4 +19,8 @@ class ClassicalParameterDeclaration(ASTNode):
20
19
  )
21
20
 
22
21
  def rename(self, new_name: str) -> "ClassicalParameterDeclaration":
23
- return self.copy(update=dict(name=new_name))
22
+ return ClassicalParameterDeclaration(**{**self.__dict__, "name": new_name})
23
+
24
+
25
+ class ClassicalParameterDeclaration(AnonClassicalParameterDeclaration):
26
+ name: str
@@ -14,11 +14,11 @@ class Control(QuantumExpressionOperation):
14
14
  kind: Literal["Control"]
15
15
  body: "StatementBlock"
16
16
 
17
- _ctrl_state: str = pydantic.PrivateAttr(default="")
17
+ _ctrl_size: int = pydantic.PrivateAttr(default=0)
18
18
 
19
19
  @property
20
- def ctrl_state(self) -> str:
21
- return self._ctrl_state
20
+ def ctrl_size(self) -> int:
21
+ return self._ctrl_size
22
22
 
23
- def set_ctrl_state(self, ctrl_state: str) -> None:
24
- self._ctrl_state = ctrl_state
23
+ def set_ctrl_size(self, ctrl_size: int) -> None:
24
+ self._ctrl_size = ctrl_size
@@ -1,13 +1,17 @@
1
- from typing import Union
1
+ from itertools import chain
2
+ from typing import TYPE_CHECKING, Any, Dict, Sequence, Union
2
3
 
3
- from pydantic import Extra
4
+ import pydantic
5
+ from pydantic import Extra, Field
4
6
 
5
7
  from classiq.interface.ast_node import ASTNode
6
8
  from classiq.interface.generator.expressions.expression import Expression
7
9
 
10
+ HANDLE_ID_SEPARATOR = "___"
11
+
8
12
 
9
13
  class HandleBinding(ASTNode):
10
- name: str
14
+ name: str = Field(default=None)
11
15
 
12
16
  class Config:
13
17
  frozen = True
@@ -19,8 +23,49 @@ class HandleBinding(ASTNode):
19
23
  def is_bindable(self) -> bool:
20
24
  return True
21
25
 
26
+ @property
27
+ def identifier(self) -> str:
28
+ return self.name
29
+
30
+ def collapse(self) -> "HandleBinding":
31
+ return self
32
+
33
+ def prefixes(self) -> Sequence["HandleBinding"]:
34
+ """
35
+ Split the handle into prefixes:
36
+ a.b[0].c --> [a, a.b, a.b[0], a.b[0].c]
37
+ """
38
+ return [self]
39
+
40
+ def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
41
+ return self.name == other_handle.name
42
+
43
+ def overlaps(self, other_handle: "HandleBinding") -> bool:
44
+ self_prefixes = self.collapse().prefixes()
45
+ other_prefixes = other_handle.collapse().prefixes()
46
+ return all(
47
+ self_prefix._tail_overlaps(other_prefix)
48
+ for self_prefix, other_prefix in zip(self_prefixes, other_prefixes)
49
+ )
50
+
51
+
52
+ class NestedHandleBinding(HandleBinding):
53
+ base_handle: "ConcreteHandleBinding"
54
+
55
+ @pydantic.root_validator(pre=False)
56
+ def _set_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
57
+ if "base_handle" in values:
58
+ values["name"] = values["base_handle"].name
59
+ return values
60
+
61
+ def is_bindable(self) -> bool:
62
+ return False
63
+
64
+ def prefixes(self) -> Sequence["HandleBinding"]:
65
+ return list(chain.from_iterable([self.base_handle.prefixes(), [self]]))
66
+
22
67
 
23
- class SubscriptHandleBinding(HandleBinding):
68
+ class SubscriptHandleBinding(NestedHandleBinding):
24
69
  index: Expression
25
70
 
26
71
  class Config:
@@ -28,13 +73,52 @@ class SubscriptHandleBinding(HandleBinding):
28
73
  extra = Extra.forbid
29
74
 
30
75
  def __str__(self) -> str:
31
- return f"{self.name}[{self.index}]"
32
-
33
- def is_bindable(self) -> bool:
76
+ return f"{self.base_handle}[{self.index}]"
77
+
78
+ @property
79
+ def identifier(self) -> str:
80
+ return f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.index}"
81
+
82
+ def collapse(self) -> HandleBinding:
83
+ if isinstance(self.base_handle, SlicedHandleBinding):
84
+ return SubscriptHandleBinding(
85
+ base_handle=self.base_handle.base_handle,
86
+ index=self._get_collapsed_index(),
87
+ ).collapse()
88
+ return SubscriptHandleBinding(
89
+ base_handle=self.base_handle.collapse(),
90
+ index=self.index,
91
+ )
92
+
93
+ def _get_collapsed_index(self) -> Expression:
94
+ if TYPE_CHECKING:
95
+ assert isinstance(self.base_handle, SlicedHandleBinding)
96
+ if self.index.is_evaluated() and self.base_handle.start.is_evaluated():
97
+ return Expression(
98
+ expr=str(
99
+ self.base_handle.start.to_int_value() + self.index.to_int_value()
100
+ )
101
+ )
102
+ return Expression(expr=f"({self.base_handle.start})+({self.index})")
103
+
104
+ def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
105
+ if isinstance(other_handle, SubscriptHandleBinding):
106
+ return self.index == other_handle.index
107
+ if (
108
+ isinstance(other_handle, SlicedHandleBinding)
109
+ and self.index.is_evaluated()
110
+ and other_handle.start.is_evaluated()
111
+ and other_handle.end.is_evaluated()
112
+ ):
113
+ return (
114
+ other_handle.start.to_int_value()
115
+ <= self.index.to_int_value()
116
+ < other_handle.end.to_int_value()
117
+ )
34
118
  return False
35
119
 
36
120
 
37
- class SlicedHandleBinding(HandleBinding):
121
+ class SlicedHandleBinding(NestedHandleBinding):
38
122
  start: Expression
39
123
  end: Expression
40
124
 
@@ -43,12 +127,101 @@ class SlicedHandleBinding(HandleBinding):
43
127
  extra = Extra.forbid
44
128
 
45
129
  def __str__(self) -> str:
46
- return f"{self.name}[{self.start}:{self.end}]"
47
-
48
- def is_bindable(self) -> bool:
130
+ return f"{self.base_handle}[{self.start}:{self.end}]"
131
+
132
+ @property
133
+ def identifier(self) -> str:
134
+ return (
135
+ f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.start}_{self.end}"
136
+ )
137
+
138
+ def collapse(self) -> HandleBinding:
139
+ if isinstance(self.base_handle, SlicedHandleBinding):
140
+ return SubscriptHandleBinding(
141
+ base_handle=self.base_handle.base_handle,
142
+ start=self._get_collapsed_start(),
143
+ end=self._get_collapsed_stop(),
144
+ ).collapse()
145
+ return SlicedHandleBinding(
146
+ base_handle=self.base_handle.collapse(),
147
+ start=self.start,
148
+ end=self.end,
149
+ )
150
+
151
+ def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
152
+ if not self.start.is_evaluated() or not self.end.is_evaluated():
153
+ return False
154
+ start = self.start.to_int_value()
155
+ end = self.end.to_int_value()
156
+ if (
157
+ isinstance(other_handle, SubscriptHandleBinding)
158
+ and other_handle.index.is_evaluated()
159
+ ):
160
+ return start <= other_handle.index.to_int_value() < end
161
+ if (
162
+ isinstance(other_handle, SlicedHandleBinding)
163
+ and other_handle.start.is_evaluated()
164
+ and other_handle.end.is_evaluated()
165
+ ):
166
+ other_start = other_handle.start.to_int_value()
167
+ other_end = other_handle.end.to_int_value()
168
+ return start <= other_start < end or other_start <= start < other_end
49
169
  return False
50
170
 
171
+ def _get_collapsed_start(self) -> Expression:
172
+ if TYPE_CHECKING:
173
+ assert isinstance(self.base_handle, SlicedHandleBinding)
174
+ if self.start.is_evaluated() and self.base_handle.start.is_evaluated():
175
+ return Expression(
176
+ expr=str(
177
+ self.base_handle.start.to_int_value() + self.start.to_int_value()
178
+ )
179
+ )
180
+ return Expression(expr=f"({self.base_handle.start})+({self.start})")
181
+
182
+ def _get_collapsed_stop(self) -> Expression:
183
+ if TYPE_CHECKING:
184
+ assert isinstance(self.base_handle, SlicedHandleBinding)
185
+ if self.end.is_evaluated() and self.base_handle.end.is_evaluated():
186
+ return Expression(
187
+ expr=str(self.base_handle.end.to_int_value() - self.end.to_int_value())
188
+ )
189
+ return Expression(expr=f"({self.base_handle.end})-({self.end})")
190
+
191
+
192
+ class FieldHandleBinding(NestedHandleBinding):
193
+ field: str
194
+
195
+ class Config:
196
+ frozen = True
197
+ extra = Extra.forbid
198
+
199
+ def __str__(self) -> str:
200
+ return f"{self.base_handle}.{self.field}"
201
+
202
+ @property
203
+ def identifier(self) -> str:
204
+ return f"{self.base_handle.identifier}{HANDLE_ID_SEPARATOR}{self.field}"
205
+
206
+ def collapse(self) -> HandleBinding:
207
+ return FieldHandleBinding(
208
+ base_handle=self.base_handle.collapse(),
209
+ field=self.field,
210
+ )
211
+
212
+ def _tail_overlaps(self, other_handle: "HandleBinding") -> bool:
213
+ return (
214
+ isinstance(other_handle, FieldHandleBinding)
215
+ and self.field == other_handle.field
216
+ )
217
+
51
218
 
52
219
  ConcreteHandleBinding = Union[
53
- HandleBinding, SubscriptHandleBinding, SlicedHandleBinding
220
+ HandleBinding,
221
+ SubscriptHandleBinding,
222
+ SlicedHandleBinding,
223
+ FieldHandleBinding,
54
224
  ]
225
+ SubscriptHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
226
+ SlicedHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
227
+ FieldHandleBinding.update_forward_refs(ConcreteHandleBinding=ConcreteHandleBinding)
@@ -1,5 +1,6 @@
1
- from typing import Literal, Mapping
1
+ from typing import Literal, Mapping, Sequence
2
2
 
3
+ from classiq.interface.enum_utils import StrEnum
3
4
  from classiq.interface.generator.functions.builtins.core_library import (
4
5
  INTEGER_XOR_FUNCTION,
5
6
  MODULAR_ADD_FUNCTION,
@@ -7,11 +8,9 @@ from classiq.interface.generator.functions.builtins.core_library import (
7
8
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
8
9
  from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
9
10
  from classiq.interface.model.quantum_function_declaration import (
10
- QuantumFunctionDeclaration,
11
+ NamedParamsQuantumFunctionDeclaration,
11
12
  )
12
- from classiq.interface.model.quantum_statement import QuantumOperation
13
-
14
- from classiq._internals.enum_utils import StrEnum
13
+ from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
15
14
 
16
15
 
17
16
  class BinaryOperation(StrEnum):
@@ -19,7 +18,7 @@ class BinaryOperation(StrEnum):
19
18
  Xor = "inplace_xor"
20
19
 
21
20
  @property
22
- def internal_function_declaration(self) -> QuantumFunctionDeclaration:
21
+ def internal_function_declaration(self) -> NamedParamsQuantumFunctionDeclaration:
23
22
  return {
24
23
  BinaryOperation.Addition: MODULAR_ADD_FUNCTION,
25
24
  BinaryOperation.Xor: INTEGER_XOR_FUNCTION,
@@ -36,3 +35,15 @@ class InplaceBinaryOperation(QuantumOperation):
36
35
  @property
37
36
  def wiring_inouts(self) -> Mapping[str, HandleBinding]:
38
37
  return nameables_to_dict([self.target, self.value])
38
+
39
+ @property
40
+ def readable_inouts(self) -> Sequence[HandleMetadata]:
41
+ suffix = f" of an in-place {self.operation.name.lower()} statement"
42
+ return [
43
+ HandleMetadata(
44
+ handle=self.target, readable_location=f"as the target{suffix}"
45
+ ),
46
+ HandleMetadata(
47
+ handle=self.value, readable_location=f"as the value{suffix}"
48
+ ),
49
+ ]
@@ -1,9 +1,11 @@
1
1
  from collections import Counter
2
- from typing import Dict, List, Literal, NewType, Set
2
+ from typing import List, Literal, Mapping, NewType, Set
3
3
 
4
4
  import pydantic
5
5
 
6
6
  from classiq.interface.ast_node import ASTNode
7
+ from classiq.interface.debug_info.debug_info import DebugInfoCollection
8
+ from classiq.interface.exceptions import ClassiqValueError
7
9
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
8
10
  from classiq.interface.generator.constant import Constant
9
11
  from classiq.interface.generator.functions.port_declaration import (
@@ -13,17 +15,18 @@ from classiq.interface.generator.model.constraints import Constraints
13
15
  from classiq.interface.generator.model.preferences.preferences import Preferences
14
16
  from classiq.interface.generator.quantum_function_call import SUFFIX_RANDOMIZER
15
17
  from classiq.interface.generator.types.enum_declaration import EnumDeclaration
18
+ from classiq.interface.generator.types.qstruct_declaration import QStructDeclaration
16
19
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
17
20
  from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
18
21
  from classiq.interface.helpers.versioned_model import VersionedModel
19
- from classiq.interface.model.native_function_definition import NativeFunctionDefinition
22
+ from classiq.interface.model.native_function_definition import (
23
+ NativeFunctionDefinition,
24
+ )
20
25
  from classiq.interface.model.quantum_function_declaration import (
21
- QuantumFunctionDeclaration,
26
+ NamedParamsQuantumFunctionDeclaration,
22
27
  )
23
28
  from classiq.interface.model.statement_block import StatementBlock
24
29
 
25
- from classiq.exceptions import ClassiqValueError
26
-
27
30
  USER_MODEL_MARKER = "user"
28
31
 
29
32
  MAIN_FUNCTION_NAME = "main"
@@ -73,6 +76,11 @@ class Model(VersionedModel, ASTNode):
73
76
  description="user-defined structs",
74
77
  )
75
78
 
79
+ qstructs: List[QStructDeclaration] = pydantic.Field(
80
+ default_factory=list,
81
+ description="user-defined quantum structs",
82
+ )
83
+
76
84
  classical_execution_code: str = pydantic.Field(
77
85
  description="The classical execution code of the model", default=""
78
86
  )
@@ -88,6 +96,10 @@ class Model(VersionedModel, ASTNode):
88
96
  )
89
97
  preferences: Preferences = pydantic.Field(default_factory=Preferences)
90
98
 
99
+ debug_info: DebugInfoCollection = pydantic.Field(
100
+ default_factory=DebugInfoCollection
101
+ )
102
+
91
103
  @property
92
104
  def main_func(self) -> NativeFunctionDefinition:
93
105
  return self.function_dict[MAIN_FUNCTION_NAME] # type:ignore[return-value]
@@ -109,7 +121,7 @@ class Model(VersionedModel, ASTNode):
109
121
  return direction
110
122
 
111
123
  @property
112
- def function_dict(self) -> Dict[str, QuantumFunctionDeclaration]:
124
+ def function_dict(self) -> Mapping[str, NamedParamsQuantumFunctionDeclaration]:
113
125
  return nameables_to_dict(self.functions)
114
126
 
115
127
  @pydantic.validator("functions", always=True)
@@ -149,7 +161,7 @@ class Model(VersionedModel, ASTNode):
149
161
  raise ClassiqValueError("The model must contain a `main` function")
150
162
  if any(
151
163
  pd.direction != PortDeclarationDirection.Output
152
- for pd in function_dict[MAIN_FUNCTION_NAME].port_declarations.values()
164
+ for pd in function_dict[MAIN_FUNCTION_NAME].port_declarations
153
165
  ):
154
166
  raise ClassiqValueError("Function 'main' cannot declare quantum inputs")
155
167
 
@@ -169,3 +181,13 @@ class Model(VersionedModel, ASTNode):
169
181
  f"{multiply_defined_constants}"
170
182
  )
171
183
  return constants
184
+
185
+ def json_no_preferences_and_constraints(self) -> str:
186
+ return self.json(
187
+ indent=2,
188
+ exclude={
189
+ "constraints",
190
+ "execution_preferences",
191
+ "preferences",
192
+ },
193
+ )
@@ -1,12 +1,16 @@
1
+ from typing import TYPE_CHECKING
2
+
1
3
  import pydantic
2
4
 
3
5
  from classiq.interface.model.quantum_function_declaration import (
4
- QuantumFunctionDeclaration,
6
+ NamedParamsQuantumFunctionDeclaration,
5
7
  )
6
- from classiq.interface.model.statement_block import StatementBlock
8
+
9
+ if TYPE_CHECKING:
10
+ from classiq.interface.model.statement_block import StatementBlock
7
11
 
8
12
 
9
- class NativeFunctionDefinition(QuantumFunctionDeclaration):
13
+ class NativeFunctionDefinition(NamedParamsQuantumFunctionDeclaration):
10
14
  """
11
15
  Facilitates the creation of a user-defined composite function
12
16
 
@@ -14,6 +18,6 @@ class NativeFunctionDefinition(QuantumFunctionDeclaration):
14
18
  objects from other classes.
15
19
  """
16
20
 
17
- body: StatementBlock = pydantic.Field(
21
+ body: "StatementBlock" = pydantic.Field(
18
22
  default_factory=list, description="List of function calls to perform."
19
23
  )
@@ -0,0 +1,13 @@
1
+ from typing import Optional
2
+
3
+ from classiq.interface.ast_node import ASTNode
4
+ from classiq.interface.exceptions import ClassiqError
5
+
6
+
7
+ class Parameter(ASTNode):
8
+ name: Optional[str]
9
+
10
+ def get_name(self) -> str:
11
+ if self.name is None:
12
+ raise ClassiqError("Cannot resolve parameter name")
13
+ return self.name
@@ -1,21 +1,25 @@
1
- from typing import Any, Dict, Literal, Mapping
1
+ from typing import Any, Dict, Literal, Mapping, Optional
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.exceptions import ClassiqValueError
6
+ from classiq.interface.generator.expressions.expression import Expression
7
+ from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
5
8
  from classiq.interface.generator.functions.port_declaration import (
6
9
  PortDeclarationDirection,
7
10
  )
8
11
  from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
12
+ from classiq.interface.model.parameter import Parameter
9
13
  from classiq.interface.model.quantum_variable_declaration import (
10
14
  QuantumVariableDeclaration,
11
15
  )
12
16
 
13
- from classiq.exceptions import ClassiqValueError
14
17
 
15
-
16
- class PortDeclaration(QuantumVariableDeclaration):
18
+ class AnonPortDeclaration(Parameter):
17
19
  kind: Literal["PortDeclaration"]
18
20
 
21
+ quantum_type: ConcreteQuantumType
22
+ size: Optional[Expression] = pydantic.Field(default=None)
19
23
  direction: PortDeclarationDirection
20
24
 
21
25
  @pydantic.root_validator(pre=True)
@@ -32,3 +36,16 @@ class PortDeclaration(QuantumVariableDeclaration):
32
36
  raise ClassiqValueError("Port declaration is missing a type")
33
37
 
34
38
  return direction
39
+
40
+ @pydantic.validator("size")
41
+ def _propagate_size_to_type(
42
+ cls, size: Optional[Expression], values: Mapping[str, Any]
43
+ ) -> Optional[Expression]:
44
+ return QuantumVariableDeclaration._propagate_size_to_type(size, values)
45
+
46
+ def rename(self, new_name: str) -> "PortDeclaration":
47
+ return PortDeclaration(**{**self.__dict__, "name": new_name})
48
+
49
+
50
+ class PortDeclaration(AnonPortDeclaration):
51
+ name: str