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,5 +1,5 @@
1
1
  from enum import Enum
2
- from typing import TYPE_CHECKING, Callable, Mapping
2
+ from typing import Mapping
3
3
 
4
4
  from classiq.interface.generator.expressions.expression import Expression
5
5
  from classiq.interface.generator.functions.classical_function_declaration import (
@@ -10,21 +10,20 @@ from classiq.interface.generator.functions.classical_type import (
10
10
  ClassicalList,
11
11
  Integer,
12
12
  Real,
13
- Struct,
14
13
  )
15
14
  from classiq.interface.generator.functions.port_declaration import (
16
15
  PortDeclarationDirection,
17
16
  )
17
+ from classiq.interface.generator.functions.type_name import Struct
18
18
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
19
+ from classiq.interface.model.classical_parameter_declaration import (
20
+ ClassicalParameterDeclaration,
21
+ )
19
22
  from classiq.interface.model.port_declaration import PortDeclaration
20
23
  from classiq.interface.model.quantum_function_declaration import (
21
- QuantumFunctionDeclaration,
24
+ NamedParamsQuantumFunctionDeclaration,
22
25
  )
23
26
 
24
- if TYPE_CHECKING:
25
- from classiq.qmod.builtins.structs import GaussianModel
26
- from classiq.qmod.symbolic_expr import SymbolicExpr
27
-
28
27
  FUNCTION_PORT_NAME = "func_port"
29
28
  OBJECTIVE_PORT_NAME = "obj_port"
30
29
 
@@ -40,44 +39,30 @@ FINANCE_FUNCTION_PORT_SIZE_MAPPING: Mapping[FinanceModelType, str] = {
40
39
  }
41
40
 
42
41
 
43
- def _get_gaussian_size(finance_model: "GaussianModel") -> "SymbolicExpr":
44
- from classiq.qmod.symbolic import floor, log, sum as sym_sum
45
-
46
- return (
47
- finance_model.num_qubits
48
- + finance_model.rhos.len
49
- + floor(log(sym_sum(finance_model.loss), 2))
50
- + 1
51
- )
52
-
53
-
54
- FINANCE_FUNCTION_PORT_SIZE_FUNCTION_MAPPING: Mapping[FinanceModelType, Callable] = {
55
- FinanceModelType.Gaussian: _get_gaussian_size,
56
- FinanceModelType.LogNormal: lambda finance_model: finance_model.num_qubits,
57
- }
58
-
59
-
60
42
  def _generate_finance_function(
61
43
  finance_model: FinanceModelType,
62
- ) -> QuantumFunctionDeclaration:
63
- return QuantumFunctionDeclaration(
44
+ ) -> NamedParamsQuantumFunctionDeclaration:
45
+ return NamedParamsQuantumFunctionDeclaration(
64
46
  name=f"{finance_model.value}_finance",
65
- param_decls={
66
- "finance_model": Struct(name=f"{finance_model.name}Model"),
67
- "finance_function": Struct(name="FinanceFunction"),
68
- },
69
- port_declarations={
70
- FUNCTION_PORT_NAME: PortDeclaration(
47
+ positional_arg_declarations=[
48
+ ClassicalParameterDeclaration(
49
+ name="finance_model",
50
+ classical_type=Struct(name=f"{finance_model.name}Model"),
51
+ ),
52
+ ClassicalParameterDeclaration(
53
+ name="finance_function", classical_type=Struct(name="FinanceFunction")
54
+ ),
55
+ PortDeclaration(
71
56
  name=FUNCTION_PORT_NAME,
72
57
  direction=PortDeclarationDirection.Inout,
73
58
  size=Expression(expr=FINANCE_FUNCTION_PORT_SIZE_MAPPING[finance_model]),
74
59
  ),
75
- OBJECTIVE_PORT_NAME: PortDeclaration(
60
+ PortDeclaration(
76
61
  name=OBJECTIVE_PORT_NAME,
77
62
  direction=PortDeclarationDirection.Inout,
78
63
  size=Expression(expr="1"),
79
64
  ),
80
- },
65
+ ],
81
66
  )
82
67
 
83
68
 
@@ -118,21 +103,29 @@ FINANCE_FUNCTION = StructDeclaration(
118
103
 
119
104
  LOG_NORMAL_FINANCE_POST_PROCESS = ClassicalFunctionDeclaration(
120
105
  name="log_normal_finance_post_process",
121
- param_decls={
122
- "finance_model": Struct(name="LogNormalModel"),
123
- "estimation_method": Struct(name="FinanceFunction"),
124
- "probability": Real(),
125
- },
106
+ positional_parameters=[
107
+ ClassicalParameterDeclaration(
108
+ name="finance_model", classical_type=Struct(name="LogNormalModel")
109
+ ),
110
+ ClassicalParameterDeclaration(
111
+ name="estimation_method", classical_type=Struct(name="FinanceFunction")
112
+ ),
113
+ ClassicalParameterDeclaration(name="probability", classical_type=Real()),
114
+ ],
126
115
  return_type=Real(),
127
116
  )
128
117
 
129
118
  GAUSSIAN_FINANCE_POST_PROCESS = ClassicalFunctionDeclaration(
130
119
  name="gaussian_finance_post_process",
131
- param_decls={
132
- "finance_model": Struct(name="GaussianModel"),
133
- "estimation_method": Struct(name="FinanceFunction"),
134
- "probability": Real(),
135
- },
120
+ positional_parameters=[
121
+ ClassicalParameterDeclaration(
122
+ name="finance_model", classical_type=Struct(name="GaussianModel")
123
+ ),
124
+ ClassicalParameterDeclaration(
125
+ name="estimation_method", classical_type=Struct(name="FinanceFunction")
126
+ ),
127
+ ClassicalParameterDeclaration(name="probability", classical_type=Real()),
128
+ ],
136
129
  return_type=Real(),
137
130
  )
138
131
 
@@ -3,18 +3,20 @@ import enum
3
3
  from classiq.interface.generator.expressions.expression import Expression
4
4
  from classiq.interface.generator.functions.classical_type import (
5
5
  ClassicalList,
6
- Enum,
7
6
  Integer,
8
7
  Real,
9
- Struct,
10
8
  )
11
9
  from classiq.interface.generator.functions.port_declaration import (
12
10
  PortDeclarationDirection,
13
11
  )
12
+ from classiq.interface.generator.functions.type_name import Enum, Struct
14
13
  from classiq.interface.generator.types.struct_declaration import StructDeclaration
14
+ from classiq.interface.model.classical_parameter_declaration import (
15
+ ClassicalParameterDeclaration,
16
+ )
15
17
  from classiq.interface.model.port_declaration import PortDeclaration
16
18
  from classiq.interface.model.quantum_function_declaration import (
17
- QuantumFunctionDeclaration,
19
+ NamedParamsQuantumFunctionDeclaration,
18
20
  )
19
21
 
20
22
 
@@ -24,29 +26,33 @@ class FeatureMapType(enum.Enum):
24
26
 
25
27
 
26
28
  QSVM_PAULI_FEATURE_MAP_SIZE = "get_field(feature_map, 'feature_dimension')"
27
- QSVM_PAULI_FEATURE_MAP = QuantumFunctionDeclaration(
29
+ QSVM_PAULI_FEATURE_MAP = NamedParamsQuantumFunctionDeclaration(
28
30
  name="pauli_feature_map",
29
- param_decls={"feature_map": Struct(name="QSVMFeatureMapPauli")},
30
- port_declarations={
31
- "qbv": PortDeclaration(
31
+ positional_arg_declarations=[
32
+ ClassicalParameterDeclaration(
33
+ name="feature_map", classical_type=Struct(name="QSVMFeatureMapPauli")
34
+ ),
35
+ PortDeclaration(
32
36
  name="qbv",
33
37
  direction=PortDeclarationDirection.Inout,
34
38
  size=Expression(expr=QSVM_PAULI_FEATURE_MAP_SIZE),
35
- )
36
- },
39
+ ),
40
+ ],
37
41
  )
38
42
 
39
43
  QSVM_BLOCH_SPHERE_FEATURE_MAP_SIZE = "ceiling(feature_dimension/2)"
40
- QSVM_BLOCH_SPHERE_FEATURE_MAP = QuantumFunctionDeclaration(
44
+ QSVM_BLOCH_SPHERE_FEATURE_MAP = NamedParamsQuantumFunctionDeclaration(
41
45
  name="bloch_sphere_feature_map",
42
- param_decls={"feature_dimension": Integer()},
43
- port_declarations={
44
- "qbv": PortDeclaration(
46
+ positional_arg_declarations=[
47
+ ClassicalParameterDeclaration(
48
+ name="feature_dimension", classical_type=Integer()
49
+ ),
50
+ PortDeclaration(
45
51
  name="qbv",
46
52
  direction=PortDeclarationDirection.Inout,
47
53
  size=Expression(expr=QSVM_BLOCH_SPHERE_FEATURE_MAP_SIZE),
48
- )
49
- },
54
+ ),
55
+ ],
50
56
  )
51
57
 
52
58
  QSVM_FEATURE_MAP_PAULI = StructDeclaration(
@@ -1,8 +1,9 @@
1
- from typing import Any, Dict, Optional, Set
1
+ from typing import Any, Dict, Final, Optional, Set
2
2
 
3
3
  import networkx as nx
4
4
  import pydantic
5
5
 
6
+ from classiq.interface.exceptions import ClassiqValueError
6
7
  from classiq.interface.generator.arith import arithmetic_expression_parser
7
8
  from classiq.interface.generator.arith.arithmetic_expression_abc import (
8
9
  ArithmeticExpressionABC,
@@ -21,10 +22,9 @@ from classiq.interface.model.quantum_type import (
21
22
  register_info_to_quantum_type,
22
23
  )
23
24
 
24
- from classiq.exceptions import ClassiqValueError
25
-
26
- ARITHMETIC_EXPRESSION_TARGET_NAME: str = "arithmetic_target"
27
- ARITHMETIC_EXPRESSION_RESULT_NAME: str = "expression_result"
25
+ ARITHMETIC_EXPRESSION_TARGET_NAME: Final[str] = "arithmetic_target"
26
+ ARITHMETIC_EXPRESSION_RESULT_NAME: Final[str] = "expression_result"
27
+ ARITHMETIC_EXPRESSION_GARBAGE_NAME: Final[str] = "expression_garbage"
28
28
 
29
29
 
30
30
  class Arithmetic(ArithmeticExpressionABC):
@@ -64,12 +64,14 @@ class Arithmetic(ArithmeticExpressionABC):
64
64
  if name in self._inputs
65
65
  }
66
66
  # TODO: avoid calling the result builder again, as it is called in validation
67
- result_info = ArithmeticResultBuilder(
67
+ result_builder = ArithmeticResultBuilder(
68
68
  graph=arithmetic_expression_parser.parse_expression(self.expression),
69
69
  definitions=self.definitions,
70
70
  machine_precision=self.machine_precision,
71
- ).result
72
- self._outputs[ARITHMETIC_EXPRESSION_RESULT_NAME] = result_info
71
+ )
72
+ self._outputs[ARITHMETIC_EXPRESSION_RESULT_NAME] = result_builder.result
73
+ if result_builder.garbage:
74
+ self._outputs[ARITHMETIC_EXPRESSION_GARBAGE_NAME] = result_builder.garbage
73
75
  if self.target:
74
76
  self._inputs[ARITHMETIC_EXPRESSION_TARGET_NAME] = self.target
75
77
 
@@ -2,11 +2,10 @@ from typing import Callable, Dict, List
2
2
 
3
3
  from typing_extensions import TypeAlias
4
4
 
5
+ from classiq.interface.exceptions import ClassiqArithmeticError
5
6
  from classiq.interface.generator.arith import argument_utils
6
7
  from classiq.interface.generator.arith.binary_ops import BOOLEAN_OP_WITH_FRACTIONS_ERROR
7
8
 
8
- from classiq.exceptions import ClassiqArithmeticError
9
-
10
9
  ArgTypeValidator: TypeAlias = Callable[[List[argument_utils.RegisterOrConst]], None]
11
10
 
12
11
 
@@ -7,6 +7,7 @@ import networkx as nx
7
7
  import pydantic
8
8
  from typing_extensions import TypeAlias
9
9
 
10
+ from classiq.interface.exceptions import ClassiqValueError
10
11
  from classiq.interface.generator.arith import number_utils
11
12
  from classiq.interface.generator.arith.arithmetic_expression_parser import (
12
13
  parse_expression,
@@ -30,8 +31,6 @@ from classiq.interface.generator.expressions.expression_constants import (
30
31
  from classiq.interface.generator.function_params import FunctionParams
31
32
  from classiq.interface.helpers.custom_pydantic_types import PydanticExpressionStr
32
33
 
33
- from classiq.exceptions import ClassiqValueError
34
-
35
34
  ValidDefinitions: TypeAlias = Union[
36
35
  pydantic.StrictInt, pydantic.StrictFloat, RegisterArithmeticInfo
37
36
  ]
@@ -88,7 +87,27 @@ class ArithmeticExpressionABC(abc.ABC, FunctionParams):
88
87
  cls._validate_ast_obj(ast_obj)
89
88
 
90
89
  graph = parse_expression(expression)
91
- cls._validate_expression_graph(graph, values)
90
+ try:
91
+ cls._validate_expression_graph(graph, values)
92
+ except ClassiqValueError as e:
93
+ # This flow was created specifically for inplace Boolean XOR operations like q1 ^ q2.
94
+ # We can't plug equality in previous stages due to SymPy restrictions.
95
+ # Note that we don't validate that the expression itself is Boolean (passing non-Boolean expressions
96
+ # as inplace is currently not supported, so it's a bug).
97
+ if not e.raw_message == "Expression does not support target assignment":
98
+ raise
99
+ ast_parsed_expression = ast.parse(expression)
100
+ ast_expr = ast_parsed_expression.body[0]
101
+ if (
102
+ not isinstance(ast_expr, ast.Expr)
103
+ or not isinstance(ast_expr.value, ast.BinOp)
104
+ or not isinstance(ast_expr.value.op, ast.BitXor)
105
+ ):
106
+ raise
107
+ expression = f"({expression}) == 1"
108
+ graph = parse_expression(expression)
109
+ cls._validate_expression_graph(graph, values)
110
+
92
111
  validate_arithmetic_result_type(
93
112
  graph=graph,
94
113
  definitions=definitions,
@@ -4,6 +4,7 @@ from typing import Collection, List, Optional, Set, Tuple, Type, Union, cast
4
4
 
5
5
  import networkx as nx
6
6
 
7
+ from classiq.interface.exceptions import ClassiqArithmeticError
7
8
  from classiq.interface.generator.arith.arithmetic_expression_validator import (
8
9
  DEFAULT_EXPRESSION_TYPE,
9
10
  DEFAULT_SUPPORTED_FUNC_NAMES,
@@ -16,11 +17,9 @@ from classiq.interface.generator.arith.ast_node_rewrite import (
16
17
  AstNodeRewrite,
17
18
  )
18
19
 
19
- from classiq.exceptions import ClassiqArithmeticError
20
-
21
- _MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple result"
20
+ _MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple results"
22
21
  _UNEXPECTED_ARITHMETIC_ERROR_MESSAGE: str = (
23
- "Unexpected arithmetic error: trivial expression. Please contact support."
22
+ "Quantum expressions that evaluate to a classical value are not supported"
24
23
  )
25
24
  _ALLOWED_MULTI_ARGUMENT_FUNCTIONS = ("min", "max")
26
25
  Node = Union[str, float, int]
@@ -5,13 +5,12 @@ from typing import Any, Dict, Optional, Set, Tuple, Type, Union
5
5
 
6
6
  from typing_extensions import TypeAlias, get_args
7
7
 
8
+ from classiq.interface.exceptions import ClassiqArithmeticError, ClassiqValueError
8
9
  from classiq.interface.generator.arith.ast_node_rewrite import AstNodeRewrite
9
10
  from classiq.interface.generator.expressions.sympy_supported_expressions import (
10
11
  SYMPY_SUPPORTED_EXPRESSIONS,
11
12
  )
12
13
 
13
- from classiq.exceptions import ClassiqArithmeticError, ClassiqValueError
14
-
15
14
  DEFAULT_SUPPORTED_FUNC_NAMES: Set[str] = {"CLShift", "CRShift", "min", "max"}
16
15
 
17
16
  DEFAULT_EXPRESSION_TYPE = "arithmetic"
@@ -1,5 +1,6 @@
1
1
  from typing import Callable, Dict, FrozenSet, List, Optional
2
2
 
3
+ from classiq.interface.exceptions import ClassiqArithmeticError
3
4
  from classiq.interface.generator.arith.argument_utils import (
4
5
  RegisterOrConst as RegisterOrFloat,
5
6
  )
@@ -35,8 +36,6 @@ from classiq.interface.generator.arith.logical_ops import LogicalAnd, LogicalOr
35
36
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
36
37
  from classiq.interface.generator.arith.unary_ops import BitwiseInvert, Negation
37
38
 
38
- from classiq.exceptions import ClassiqArithmeticError
39
-
40
39
  ParamsGetter = Callable[..., ArithmeticOperationParams] # Argument vary
41
40
 
42
41
  _TARGET_ERROR_MESSAGE: str = "Target unavailable for the requested operation"
@@ -1,14 +1,13 @@
1
- from typing import Any, Dict, List, Optional, Set
1
+ from typing import Any, Dict, List, Optional, Set, Tuple
2
2
 
3
3
  import networkx as nx
4
4
 
5
+ from classiq.interface.exceptions import ClassiqArithmeticError
5
6
  from classiq.interface.generator.arith import arithmetic_param_getters, number_utils
6
7
  from classiq.interface.generator.arith.argument_utils import RegisterOrConst
7
8
  from classiq.interface.generator.arith.ast_node_rewrite import OUTPUT_SIZE
8
9
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
9
10
 
10
- from classiq.exceptions import ClassiqArithmeticError
11
-
12
11
  ArithmeticDefinitions = Dict[str, RegisterOrConst]
13
12
 
14
13
 
@@ -20,7 +19,7 @@ class ArithmeticResultBuilder:
20
19
  definitions: ArithmeticDefinitions,
21
20
  machine_precision: int,
22
21
  ) -> None:
23
- self.result = self._fill_operation_results(
22
+ self.result, self.garbage = self._fill_operation_results(
24
23
  graph=graph,
25
24
  result_definitions=definitions,
26
25
  machine_precision=machine_precision,
@@ -62,7 +61,7 @@ class ArithmeticResultBuilder:
62
61
  graph: nx.DiGraph,
63
62
  result_definitions: ArithmeticDefinitions,
64
63
  machine_precision: int,
65
- ) -> RegisterArithmeticInfo:
64
+ ) -> Tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
66
65
  inputs_node_set: Set[str] = {
67
66
  vertex for vertex, deg in graph.in_degree if deg == 0
68
67
  }
@@ -80,29 +79,34 @@ class ArithmeticResultBuilder:
80
79
  for predecessor_node in graph.predecessors(node)
81
80
  ]
82
81
  if graph.out_degree(node) == 0:
83
- return cls._get_node_result(
82
+ return cls._get_node_result_and_garbage(
84
83
  graph, args, node, machine_precision=machine_precision
85
84
  )
86
- node_results[node] = cls._get_node_result(
85
+ node_results[node], _ = cls._get_node_result_and_garbage(
87
86
  graph, args, node, machine_precision=machine_precision
88
87
  )
89
88
  raise ClassiqArithmeticError("Expression has no result")
90
89
 
91
90
  @classmethod
92
- def _get_node_result(
91
+ def _get_node_result_and_garbage(
93
92
  cls,
94
93
  graph: nx.DiGraph,
95
94
  args: List[RegisterOrConst],
96
95
  node: str,
97
96
  *,
98
97
  machine_precision: int,
99
- ) -> RegisterArithmeticInfo:
100
- return arithmetic_param_getters.get_params(
98
+ ) -> Tuple[RegisterArithmeticInfo, Optional[RegisterArithmeticInfo]]:
99
+ node_params = arithmetic_param_getters.get_params(
101
100
  node_id=node,
102
101
  args=args,
103
102
  output_size=graph.nodes[node].get(OUTPUT_SIZE, None),
104
103
  machine_precision=machine_precision,
105
- ).result_register
104
+ )
105
+
106
+ return (
107
+ node_params.outputs[node_params.output_name],
108
+ node_params.outputs.get(node_params.garbage_output_name),
109
+ )
106
110
 
107
111
  @staticmethod
108
112
  def _convert_int_to_float_str(node: Any) -> str:
@@ -2,7 +2,7 @@ import ast
2
2
  import itertools
3
3
  from typing import Any, Iterator, Optional, Union, cast
4
4
 
5
- from classiq.exceptions import ClassiqArithmeticError
5
+ from classiq.interface.exceptions import ClassiqArithmeticError
6
6
 
7
7
  SEPARATOR: str = "_"
8
8
  OUTPUT_SIZE: str = "output_size"
@@ -16,6 +16,8 @@ from typing import (
16
16
  import pydantic
17
17
  from pydantic.generics import GenericModel
18
18
 
19
+ from classiq.interface.enum_utils import StrEnum
20
+ from classiq.interface.exceptions import ClassiqValueError
19
21
  from classiq.interface.generator.arith import argument_utils, number_utils
20
22
  from classiq.interface.generator.arith.argument_utils import RegisterOrConst
21
23
  from classiq.interface.generator.arith.arithmetic_operations import (
@@ -28,9 +30,6 @@ from classiq.interface.generator.arith.register_user_input import RegisterArithm
28
30
  from classiq.interface.generator.arith.unary_ops import Negation
29
31
  from classiq.interface.generator.function_params import get_zero_input_name
30
32
 
31
- from classiq._internals.enum_utils import StrEnum
32
- from classiq.exceptions import ClassiqValueError
33
-
34
33
  LeftDataT = TypeVar("LeftDataT")
35
34
  RightDataT = TypeVar("RightDataT")
36
35
  _NumericArgumentInplaceErrorMessage: str = "Cannot inplace the numeric argument {}"
@@ -617,7 +616,7 @@ class Power(BinaryOpParams[RegisterArithmeticInfo, pydantic.PositiveInt]):
617
616
  *,
618
617
  arg: RegisterArithmeticInfo,
619
618
  action_right_arg: RegisterOrConst,
620
- compute_power: int
619
+ compute_power: int,
621
620
  ) -> pydantic.NonNegativeInt:
622
621
  inner_compute_power_params = Power(
623
622
  left_arg=arg,
@@ -800,6 +799,7 @@ class Modulo(EffectiveUnaryOpParams[int]):
800
799
  return 2 ** (repr_qubits)
801
800
 
802
801
  def _get_result_register(self) -> RegisterArithmeticInfo:
803
- return RegisterArithmeticInfo(
804
- size=round(math.log2(self.right_arg)), is_signed=False, fraction_places=0
805
- )
802
+ size = round(math.log2(self.right_arg))
803
+ if size <= 0:
804
+ raise ClassiqValueError("Cannot use a quantum expression with zero size")
805
+ return RegisterArithmeticInfo(size=size, is_signed=False, fraction_places=0)
@@ -1,4 +1,4 @@
1
- from classiq._internals.enum_utils import StrEnum
1
+ from classiq.interface.enum_utils import StrEnum
2
2
 
3
3
 
4
4
  class Endianness(StrEnum):
@@ -3,6 +3,7 @@ from typing import Any, Dict, Iterable
3
3
 
4
4
  import pydantic
5
5
 
6
+ from classiq.interface.exceptions import ClassiqValueError
6
7
  from classiq.interface.generator.arith import argument_utils
7
8
  from classiq.interface.generator.arith.argument_utils import RegisterOrConst
8
9
  from classiq.interface.generator.arith.arithmetic_operations import (
@@ -15,8 +16,6 @@ from classiq.interface.generator.arith.binary_ops import (
15
16
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
16
17
  from classiq.interface.generator.function_params import get_zero_input_name
17
18
 
18
- from classiq.exceptions import ClassiqValueError
19
-
20
19
  Numeric = (float, int)
21
20
 
22
21
 
@@ -57,38 +56,56 @@ class Extremum(ArithmeticOperationParams):
57
56
  def _bound_calculator(cls, arg1: float, arg2: float) -> float:
58
57
  pass
59
58
 
59
+ @staticmethod
60
+ def _less_qubits_arg(
61
+ arg1: RegisterOrConst, arg2: RegisterOrConst
62
+ ) -> RegisterOrConst:
63
+ if not isinstance(arg1, RegisterArithmeticInfo):
64
+ return arg1
65
+ if not isinstance(arg2, RegisterArithmeticInfo):
66
+ return arg2
67
+ return arg1 if arg1.size <= arg2.size else arg2
68
+
60
69
  @classmethod
61
70
  @abc.abstractmethod
62
- def _preferred_arg(
71
+ def preferred_arg(
63
72
  cls, arg1: RegisterOrConst, arg2: RegisterOrConst
64
73
  ) -> RegisterOrConst:
65
74
  pass
66
75
 
67
76
  def _get_result_register(self) -> RegisterArithmeticInfo:
68
- if argument_utils.arg_bounds_overlap((self.left_arg, self.right_arg)):
69
- return self._get_general_case_result_register()
77
+ eff_left_arg = argument_utils.limit_fraction_places(
78
+ self.left_arg, self.machine_precision
79
+ )
80
+ eff_right_arg = argument_utils.limit_fraction_places(
81
+ self.right_arg, self.machine_precision
82
+ )
83
+ if argument_utils.arg_bounds_overlap((eff_left_arg, eff_right_arg)):
84
+ return self._get_general_case_result_register(eff_left_arg, eff_right_arg)
70
85
  return argument_utils.as_arithmetic_info(
71
- self._preferred_arg(self.left_arg, self.right_arg)
86
+ self.preferred_arg(eff_left_arg, eff_right_arg)
72
87
  )
73
88
 
74
- def _get_general_case_result_register(self) -> RegisterArithmeticInfo:
89
+ def _get_general_case_result_register(
90
+ self, eff_left_arg: RegisterOrConst, eff_right_arg: RegisterOrConst
91
+ ) -> RegisterArithmeticInfo:
75
92
  integer_part_size = max(
76
- argument_utils.integer_part_size(self.left_arg),
77
- argument_utils.integer_part_size(self.right_arg),
93
+ argument_utils.integer_part_size(eff_left_arg),
94
+ argument_utils.integer_part_size(eff_right_arg),
78
95
  )
79
96
  fraction_places = max(
80
- argument_utils.fraction_places(self.left_arg),
81
- argument_utils.fraction_places(self.right_arg),
97
+ argument_utils.fraction_places(eff_left_arg),
98
+ argument_utils.fraction_places(eff_right_arg),
82
99
  )
83
100
  required_size = integer_part_size + fraction_places
84
101
  bounds = (
85
102
  self._bound_calculator(
86
- argument_utils.lower_bound(self.left_arg),
87
- argument_utils.lower_bound(self.right_arg),
103
+ argument_utils.lower_bound(eff_left_arg),
104
+ argument_utils.lower_bound(eff_right_arg),
88
105
  ),
89
106
  self._bound_calculator(
90
- argument_utils.upper_bound(self.left_arg),
91
- argument_utils.upper_bound(self.right_arg),
107
+ argument_utils.upper_bound(eff_left_arg),
108
+ argument_utils.upper_bound(eff_right_arg),
92
109
  ),
93
110
  )
94
111
  return RegisterArithmeticInfo(
@@ -107,12 +124,15 @@ class Min(Extremum):
107
124
  return min(arg1, arg2)
108
125
 
109
126
  @classmethod
110
- def _preferred_arg(
127
+ def preferred_arg(
111
128
  cls, arg1: RegisterOrConst, arg2: RegisterOrConst
112
129
  ) -> RegisterOrConst:
113
- if min(argument_utils.bounds(arg1)) < min(argument_utils.bounds(arg2)):
130
+ min1, min2 = min(argument_utils.bounds(arg1)), min(argument_utils.bounds(arg2))
131
+ if min1 < min2:
114
132
  return arg1
115
- return arg2
133
+ if min2 < min1:
134
+ return arg2
135
+ return cls._less_qubits_arg(arg1, arg2)
116
136
 
117
137
 
118
138
  class Max(Extremum):
@@ -123,9 +143,12 @@ class Max(Extremum):
123
143
  return max(arg1, arg2)
124
144
 
125
145
  @classmethod
126
- def _preferred_arg(
146
+ def preferred_arg(
127
147
  cls, arg1: RegisterOrConst, arg2: RegisterOrConst
128
148
  ) -> RegisterOrConst:
129
- if max(argument_utils.bounds(arg1)) > max(argument_utils.bounds(arg2)):
149
+ max1, max2 = max(argument_utils.bounds(arg1)), max(argument_utils.bounds(arg2))
150
+ if max1 > max2:
130
151
  return arg1
131
- return arg2
152
+ if max2 > max1:
153
+ return arg2
154
+ return cls._less_qubits_arg(arg1, arg2)
@@ -2,6 +2,7 @@ from typing import Iterable, List, Optional
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.exceptions import ClassiqValueError
5
6
  from classiq.interface.generator.arith.argument_utils import RegisterOrConst
6
7
  from classiq.interface.generator.arith.arithmetic_operations import (
7
8
  ArithmeticOperationParams,
@@ -9,8 +10,6 @@ from classiq.interface.generator.arith.arithmetic_operations import (
9
10
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
10
11
  from classiq.interface.generator.function_params import get_zero_input_name
11
12
 
12
- from classiq.exceptions import ClassiqValueError
13
-
14
13
 
15
14
  def get_arg_name(idx: int) -> str:
16
15
  return f"arg_{idx}"
@@ -2,14 +2,13 @@ from typing import Any, Dict, Optional
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.exceptions import ClassiqValueError
5
6
  from classiq.interface.generator.arith import number_utils
6
7
  from classiq.interface.helpers.custom_pydantic_types import PydanticFloatTuple
7
8
  from classiq.interface.helpers.hashable_pydantic_base_model import (
8
9
  HashablePydanticBaseModel,
9
10
  )
10
11
 
11
- from classiq.exceptions import ClassiqValueError
12
-
13
12
 
14
13
  class RegisterArithmeticInfo(HashablePydanticBaseModel):
15
14
  size: pydantic.PositiveInt
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Final, Iterable, Optional
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.exceptions import ClassiqValueError
5
6
  from classiq.interface.generator.arith import argument_utils, number_utils
6
7
  from classiq.interface.generator.arith.arithmetic_operations import (
7
8
  ArithmeticOperationParams,
@@ -9,8 +10,6 @@ from classiq.interface.generator.arith.arithmetic_operations import (
9
10
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
10
11
  from classiq.interface.generator.function_params import get_zero_input_name
11
12
 
12
- from classiq.exceptions import ClassiqValueError
13
-
14
13
  UNARY_ARG_NAME: Final[str] = "arg"
15
14
 
16
15