classiq 0.37.0__py3-none-any.whl → 0.38.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 (228) hide show
  1. classiq/__init__.py +2 -2
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
  3. classiq/_analyzer_extras/interactive_hardware.py +3 -3
  4. classiq/_internals/api_wrapper.py +24 -16
  5. classiq/_internals/async_utils.py +1 -74
  6. classiq/_internals/authentication/device.py +9 -4
  7. classiq/_internals/authentication/password_manager.py +25 -10
  8. classiq/_internals/authentication/token_manager.py +2 -2
  9. classiq/_internals/client.py +13 -5
  10. classiq/_internals/jobs.py +10 -7
  11. classiq/analyzer/analyzer.py +26 -28
  12. classiq/analyzer/analyzer_utilities.py +5 -5
  13. classiq/analyzer/rb.py +4 -5
  14. classiq/analyzer/show_interactive_hack.py +6 -6
  15. classiq/applications/benchmarking/mirror_benchmarking.py +9 -6
  16. classiq/applications/combinatorial_optimization/__init__.py +5 -0
  17. classiq/applications/qnn/circuit_utils.py +2 -2
  18. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  19. classiq/applications/qnn/types.py +2 -2
  20. classiq/applications/qsvm/qsvm.py +4 -7
  21. classiq/applications/qsvm/qsvm_data_generation.py +2 -5
  22. classiq/applications_model_constructors/__init__.py +9 -1
  23. classiq/applications_model_constructors/chemistry_model_constructor.py +9 -16
  24. classiq/applications_model_constructors/combinatorial_helpers/__init__.py +0 -0
  25. classiq/applications_model_constructors/combinatorial_helpers/allowed_constraints.py +20 -0
  26. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/__init__.py +0 -0
  27. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  28. classiq/applications_model_constructors/combinatorial_helpers/arithmetic/isolation.py +42 -0
  29. classiq/applications_model_constructors/combinatorial_helpers/combinatorial_problem_utils.py +130 -0
  30. classiq/applications_model_constructors/combinatorial_helpers/encoding_mapping.py +107 -0
  31. classiq/applications_model_constructors/combinatorial_helpers/encoding_utils.py +122 -0
  32. classiq/applications_model_constructors/combinatorial_helpers/memory.py +79 -0
  33. classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +34 -0
  34. classiq/applications_model_constructors/combinatorial_helpers/optimization_model.py +166 -0
  35. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
  36. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  37. classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_utils.py +65 -0
  38. classiq/applications_model_constructors/combinatorial_helpers/py.typed +0 -0
  39. classiq/applications_model_constructors/combinatorial_helpers/pyomo_utils.py +243 -0
  40. classiq/applications_model_constructors/combinatorial_helpers/sympy_utils.py +22 -0
  41. classiq/applications_model_constructors/combinatorial_helpers/transformations/__init__.py +0 -0
  42. classiq/applications_model_constructors/combinatorial_helpers/transformations/encoding.py +194 -0
  43. classiq/applications_model_constructors/combinatorial_helpers/transformations/fixed_variables.py +144 -0
  44. classiq/applications_model_constructors/combinatorial_helpers/transformations/ising_converter.py +124 -0
  45. classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty.py +32 -0
  46. classiq/applications_model_constructors/combinatorial_helpers/transformations/penalty_support.py +41 -0
  47. classiq/applications_model_constructors/combinatorial_helpers/transformations/sign_seperation.py +75 -0
  48. classiq/applications_model_constructors/combinatorial_helpers/transformations/slack_variables.py +90 -0
  49. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +48 -91
  50. classiq/applications_model_constructors/finance_model_constructor.py +4 -17
  51. classiq/applications_model_constructors/grover_model_constructor.py +20 -91
  52. classiq/applications_model_constructors/libraries/qmci_library.py +17 -19
  53. classiq/builtin_functions/standard_gates.py +1 -1
  54. classiq/exceptions.py +43 -1
  55. classiq/executor.py +10 -9
  56. classiq/interface/_version.py +1 -1
  57. classiq/interface/analyzer/analysis_params.py +6 -3
  58. classiq/interface/analyzer/result.py +12 -4
  59. classiq/interface/applications/qsvm.py +13 -1
  60. classiq/interface/backend/backend_preferences.py +4 -2
  61. classiq/interface/backend/pydantic_backend.py +3 -1
  62. classiq/interface/backend/quantum_backend_providers.py +1 -0
  63. classiq/interface/chemistry/fermionic_operator.py +15 -13
  64. classiq/interface/chemistry/ground_state_problem.py +18 -3
  65. classiq/interface/chemistry/molecule.py +8 -6
  66. classiq/interface/chemistry/operator.py +20 -14
  67. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
  68. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  69. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  70. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
  71. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  72. classiq/interface/combinatorial_optimization/examples/mht.py +3 -3
  73. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  74. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  75. classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
  76. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  77. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  78. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
  79. classiq/interface/executor/aws_execution_cost.py +4 -3
  80. classiq/interface/executor/estimation.py +2 -2
  81. classiq/interface/executor/execution_preferences.py +5 -34
  82. classiq/interface/executor/execution_request.py +19 -17
  83. classiq/interface/executor/optimizer_preferences.py +22 -13
  84. classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
  85. classiq/interface/executor/quantum_instruction_set.py +2 -1
  86. classiq/interface/executor/register_initialization.py +1 -3
  87. classiq/interface/executor/result.py +41 -10
  88. classiq/interface/executor/vqe_result.py +1 -1
  89. classiq/interface/finance/function_input.py +17 -4
  90. classiq/interface/finance/gaussian_model_input.py +3 -1
  91. classiq/interface/finance/log_normal_model_input.py +3 -1
  92. classiq/interface/finance/model_input.py +2 -0
  93. classiq/interface/generator/amplitude_loading.py +6 -3
  94. classiq/interface/generator/application_apis/__init__.py +1 -0
  95. classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
  96. classiq/interface/generator/arith/argument_utils.py +14 -4
  97. classiq/interface/generator/arith/arithmetic.py +3 -1
  98. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
  99. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
  100. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
  101. classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
  102. classiq/interface/generator/arith/arithmetic_operations.py +5 -10
  103. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  104. classiq/interface/generator/arith/binary_ops.py +202 -54
  105. classiq/interface/generator/arith/extremum_operations.py +5 -3
  106. classiq/interface/generator/arith/logical_ops.py +4 -2
  107. classiq/interface/generator/arith/machine_precision.py +3 -0
  108. classiq/interface/generator/arith/number_utils.py +34 -44
  109. classiq/interface/generator/arith/register_user_input.py +21 -1
  110. classiq/interface/generator/arith/unary_ops.py +16 -25
  111. classiq/interface/generator/chemistry_function_params.py +4 -4
  112. classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
  113. classiq/interface/generator/compiler_keywords.py +4 -0
  114. classiq/interface/generator/complex_type.py +3 -10
  115. classiq/interface/generator/control_state.py +5 -3
  116. classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
  117. classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
  118. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
  119. classiq/interface/generator/expressions/evaluated_expression.py +18 -4
  120. classiq/interface/generator/expressions/expression.py +1 -1
  121. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
  122. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  123. classiq/interface/generator/finance.py +1 -1
  124. classiq/interface/generator/function_params.py +7 -6
  125. classiq/interface/generator/functions/__init__.py +1 -1
  126. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +505 -138
  127. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +25 -99
  128. classiq/interface/generator/functions/foreign_function_definition.py +12 -4
  129. classiq/interface/generator/functions/function_implementation.py +8 -4
  130. classiq/interface/generator/functions/native_function_definition.py +4 -2
  131. classiq/interface/generator/functions/register.py +4 -2
  132. classiq/interface/generator/functions/register_mapping_data.py +14 -10
  133. classiq/interface/generator/generated_circuit_data.py +2 -2
  134. classiq/interface/generator/grover_operator.py +5 -3
  135. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
  136. classiq/interface/generator/hardware/hardware_data.py +6 -4
  137. classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
  138. classiq/interface/generator/hartree_fock.py +3 -1
  139. classiq/interface/generator/linear_pauli_rotations.py +3 -1
  140. classiq/interface/generator/mcu.py +5 -3
  141. classiq/interface/generator/mcx.py +7 -5
  142. classiq/interface/generator/model/constraints.py +2 -1
  143. classiq/interface/generator/model/model.py +11 -19
  144. classiq/interface/generator/model/preferences/preferences.py +4 -3
  145. classiq/interface/generator/oracles/custom_oracle.py +4 -2
  146. classiq/interface/generator/oracles/oracle_abc.py +2 -2
  147. classiq/interface/generator/qpe.py +6 -4
  148. classiq/interface/generator/qsvm.py +5 -8
  149. classiq/interface/generator/quantum_function_call.py +21 -16
  150. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
  151. classiq/interface/generator/range_types.py +3 -1
  152. classiq/interface/generator/slice_parsing_utils.py +8 -3
  153. classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
  154. classiq/interface/generator/state_preparation/metrics.py +2 -1
  155. classiq/interface/generator/state_preparation/state_preparation.py +7 -5
  156. classiq/interface/generator/state_propagator.py +16 -5
  157. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  158. classiq/interface/generator/types/struct_declaration.py +8 -3
  159. classiq/interface/generator/ucc.py +6 -4
  160. classiq/interface/generator/unitary_gate.py +7 -3
  161. classiq/interface/generator/validations/flow_graph.py +6 -4
  162. classiq/interface/generator/validations/validator_functions.py +6 -4
  163. classiq/interface/hardware.py +2 -2
  164. classiq/interface/helpers/custom_encoders.py +3 -0
  165. classiq/interface/helpers/pydantic_model_helpers.py +0 -6
  166. classiq/interface/helpers/validation_helpers.py +1 -1
  167. classiq/interface/helpers/versioned_model.py +4 -1
  168. classiq/interface/ide/show.py +2 -2
  169. classiq/interface/jobs.py +72 -3
  170. classiq/interface/model/bind_operation.py +18 -11
  171. classiq/interface/model/call_synthesis_data.py +68 -0
  172. classiq/interface/model/inplace_binary_operation.py +2 -2
  173. classiq/interface/model/model.py +27 -21
  174. classiq/interface/model/native_function_definition.py +3 -5
  175. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
  176. classiq/interface/model/quantum_expressions/control_state.py +2 -2
  177. classiq/interface/model/quantum_function_call.py +25 -139
  178. classiq/interface/model/quantum_function_declaration.py +8 -0
  179. classiq/interface/model/quantum_if_operation.py +2 -3
  180. classiq/interface/model/quantum_lambda_function.py +64 -0
  181. classiq/interface/model/quantum_type.py +57 -56
  182. classiq/interface/model/quantum_variable_declaration.py +1 -1
  183. classiq/interface/model/statement_block.py +32 -0
  184. classiq/interface/model/validations/handles_validator.py +14 -12
  185. classiq/interface/model/within_apply_operation.py +11 -0
  186. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  187. classiq/interface/server/routes.py +5 -0
  188. classiq/model/function_handler.py +5 -9
  189. classiq/model/model.py +2 -19
  190. classiq/qmod/__init__.py +13 -6
  191. classiq/qmod/builtins/classical_execution_primitives.py +27 -36
  192. classiq/qmod/builtins/classical_functions.py +24 -14
  193. classiq/qmod/builtins/functions.py +162 -145
  194. classiq/qmod/builtins/operations.py +24 -35
  195. classiq/qmod/builtins/structs.py +15 -15
  196. classiq/qmod/cfunc.py +42 -0
  197. classiq/qmod/classical_function.py +6 -14
  198. classiq/qmod/declaration_inferrer.py +12 -21
  199. classiq/qmod/expression_query.py +23 -0
  200. classiq/qmod/model_state_container.py +2 -0
  201. classiq/qmod/native/__init__.py +0 -0
  202. classiq/qmod/native/expression_to_qmod.py +189 -0
  203. classiq/qmod/native/pretty_printer.py +311 -0
  204. classiq/qmod/qfunc.py +27 -0
  205. classiq/qmod/qmod_constant.py +76 -0
  206. classiq/qmod/qmod_parameter.py +34 -12
  207. classiq/qmod/qmod_struct.py +3 -3
  208. classiq/qmod/qmod_variable.py +102 -18
  209. classiq/qmod/quantum_expandable.py +16 -16
  210. classiq/qmod/quantum_function.py +37 -8
  211. classiq/qmod/symbolic.py +47 -4
  212. classiq/qmod/symbolic_expr.py +9 -0
  213. classiq/qmod/utilities.py +13 -0
  214. classiq/qmod/write_qmod.py +39 -0
  215. classiq/quantum_functions/__init__.py +2 -2
  216. classiq/quantum_functions/annotation_parser.py +9 -11
  217. classiq/quantum_functions/function_parser.py +1 -1
  218. classiq/quantum_functions/quantum_function.py +3 -3
  219. classiq/quantum_register.py +17 -9
  220. {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/METADATA +2 -1
  221. {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/RECORD +222 -186
  222. {classiq-0.37.0.dist-info → classiq-0.38.0.dist-info}/WHEEL +1 -1
  223. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  224. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  225. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  226. classiq/interface/model/numeric_reinterpretation.py +0 -25
  227. classiq/interface/model/operator_synthesis_data.py +0 -48
  228. classiq/model/function_handler.pyi +0 -152
@@ -1,7 +1,6 @@
1
- from typing import Tuple, Union
1
+ from typing import Final, Tuple, Union
2
2
 
3
- MAXIMAL_MACHINE_PRECISION: int = 20
4
- MAX_FRACTION_PLACES: int = 8
3
+ MAXIMAL_MACHINE_PRECISION: Final[int] = 20
5
4
 
6
5
 
7
6
  def signed_int_to_unsigned(number: int) -> int:
@@ -32,8 +31,8 @@ def binary_to_float_or_int(
32
31
  return binary_to_float(bin_rep, fraction_part_size, is_signed)
33
32
 
34
33
 
35
- def _get_fraction_places(*, binary_value: str, machine_precision: int) -> int:
36
- fraction_places = machine_precision
34
+ def _get_fraction_places(*, binary_value: str) -> int:
35
+ fraction_places = MAXIMAL_MACHINE_PRECISION
37
36
  for bit in reversed(binary_value):
38
37
  if bit == "1" or fraction_places == 0:
39
38
  return fraction_places
@@ -41,79 +40,70 @@ def _get_fraction_places(*, binary_value: str, machine_precision: int) -> int:
41
40
  return fraction_places
42
41
 
43
42
 
44
- def get_int_representation_and_fraction_places(
45
- float_value: float, *, machine_precision: int
46
- ) -> Tuple[int, int]:
47
- int_val = signed_int_to_unsigned(int(float_value * 2**machine_precision))
43
+ def get_int_representation_and_fraction_places(float_value: float) -> Tuple[int, int]:
44
+ int_val = signed_int_to_unsigned(int(float_value * 2**MAXIMAL_MACHINE_PRECISION))
48
45
  if int_val == 0:
49
46
  return 0, 0
50
- fraction_places = _get_fraction_places(
51
- binary_value=bin(int_val)[2:], machine_precision=machine_precision
52
- )
53
- int_val = int_val >> (machine_precision - fraction_places)
47
+ fraction_places = _get_fraction_places(binary_value=bin(int_val)[2:])
48
+ int_val = int_val >> (MAXIMAL_MACHINE_PRECISION - fraction_places)
54
49
  return int_val, fraction_places
55
50
 
56
51
 
57
- def fraction_places(float_value: float, *, machine_precision: int) -> int:
58
- int_val = signed_int_to_unsigned(int(float_value * 2**machine_precision))
52
+ def fraction_places(float_value: float) -> int:
53
+ int_val = signed_int_to_unsigned(int(float_value * 2**MAXIMAL_MACHINE_PRECISION))
59
54
  if int_val == 0:
60
55
  return 0
61
- return _get_fraction_places(
62
- binary_value=bin(int_val)[2:], machine_precision=machine_precision
63
- )
56
+ return _get_fraction_places(binary_value=bin(int_val)[2:])
64
57
 
65
58
 
66
59
  def _bit_length(integer_representation: int) -> int:
67
60
  return 1 if integer_representation == 0 else integer_representation.bit_length()
68
61
 
69
62
 
70
- def binary_string(
71
- float_value: float, *, machine_precision: int = MAXIMAL_MACHINE_PRECISION
72
- ) -> str:
73
- int_val, _ = get_int_representation_and_fraction_places(
74
- float_value=float_value, machine_precision=machine_precision
75
- )
63
+ def binary_string(float_value: float) -> str:
64
+ int_val, _ = get_int_representation_and_fraction_places(float_value)
76
65
  bin_rep = bin(int_val)[2:]
77
- size_diff = size(
78
- float_value=float_value, machine_precision=machine_precision
79
- ) - len(bin_rep)
66
+ size_diff = size(float_value=float_value) - len(bin_rep)
80
67
  extension_bit = "0" if float_value >= 0 else "1"
81
68
  return bin_rep[::-1] + extension_bit * size_diff
82
69
 
83
70
 
84
71
  def integer_part_size(float_value: float) -> int:
85
- int_val, fraction_places = get_int_representation_and_fraction_places(
86
- float_value=float_value, machine_precision=MAXIMAL_MACHINE_PRECISION
87
- )
72
+ int_val, fraction_places = get_int_representation_and_fraction_places(float_value)
88
73
  return max(_bit_length(int_val) - fraction_places, 0)
89
74
 
90
75
 
91
- def size(float_value: float, *, machine_precision: int) -> int:
92
- int_val, fraction_places = get_int_representation_and_fraction_places(
93
- float_value=float_value, machine_precision=machine_precision
94
- )
76
+ def size(float_value: float) -> int:
77
+ int_val, fraction_places = get_int_representation_and_fraction_places(float_value)
95
78
  return max(_bit_length(int_val), fraction_places)
96
79
 
97
80
 
81
+ def _is_extra_sign_bit_needed(*, lb: float, ub: float) -> bool:
82
+ integer_lb = lb * 2 ** fraction_places(lb)
83
+ max_represented_number = (
84
+ 2 ** (len(binary_string(integer_lb)) - 1) - 1
85
+ ) / 2 ** fraction_places(lb)
86
+ return ub > max_represented_number
87
+
88
+
98
89
  def bounds_to_integer_part_size(lb: float, ub: float) -> int:
99
90
  lb, ub = min(lb, ub), max(lb, ub)
100
91
  ub_integer_part_size: int = integer_part_size(float_value=ub)
101
92
  lb_integer_part_size: int = integer_part_size(float_value=lb)
102
- if lb == 0:
93
+ if lb >= 0:
103
94
  return ub_integer_part_size
104
- if ub == 0:
95
+ if ub <= 0:
105
96
  return lb_integer_part_size
106
- is_extra_bit_needed = lb < 0 < ub and ub_integer_part_size >= lb_integer_part_size
107
- return max(ub_integer_part_size + 1 * is_extra_bit_needed, lb_integer_part_size)
97
+ return max(
98
+ ub_integer_part_size + 1 * _is_extra_sign_bit_needed(lb=lb, ub=ub),
99
+ lb_integer_part_size,
100
+ )
108
101
 
109
102
 
110
103
  def limit_fraction_places(number: float, *, machine_precision: int) -> float:
111
- orig_bin_rep = binary_string(number, machine_precision=MAXIMAL_MACHINE_PRECISION)[
112
- ::-1
113
- ]
114
- orig_fractions = fraction_places(
115
- number, machine_precision=MAXIMAL_MACHINE_PRECISION
116
- )
104
+ orig_bin_rep = binary_string(number)[::-1]
105
+ orig_fractions = fraction_places(number)
106
+
117
107
  removed_fractions = max(orig_fractions - machine_precision, 0)
118
108
  return binary_to_float(
119
109
  bin_rep=orig_bin_rep[: len(orig_bin_rep) - removed_fractions],
@@ -2,6 +2,7 @@ from typing import Any, Dict, Optional
2
2
 
3
3
  import pydantic
4
4
 
5
+ from classiq.interface.generator.arith import number_utils
5
6
  from classiq.interface.helpers.custom_pydantic_types import PydanticFloatTuple
6
7
  from classiq.interface.helpers.hashable_pydantic_base_model import (
7
8
  HashablePydanticBaseModel,
@@ -29,7 +30,17 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
29
30
  if bounds is not None:
30
31
  if min(bounds) < 0:
31
32
  assert values.get("is_signed")
32
- return tuple(bounds) # type: ignore[return-value]
33
+ fraction_places = values.get("fraction_places")
34
+ if not isinstance(fraction_places, int):
35
+ raise ClassiqValueError(
36
+ "RegisterUserInput must have an integer fraction_places"
37
+ )
38
+ return number_utils.limit_fraction_places(
39
+ min(bounds), machine_precision=fraction_places
40
+ ), number_utils.limit_fraction_places(
41
+ max(bounds), machine_precision=fraction_places
42
+ )
43
+
33
44
  size = values.get("size")
34
45
  if not isinstance(size, int):
35
46
  raise ClassiqValueError("RegisterUserInput must have an integer size")
@@ -39,6 +50,15 @@ class RegisterArithmeticInfo(HashablePydanticBaseModel):
39
50
  fraction_factor = float(2 ** -values.get("fraction_places", 0))
40
51
  return (lb * fraction_factor, ub * fraction_factor)
41
52
 
53
+ def limit_fraction_places(self, machine_precision: int) -> "RegisterArithmeticInfo":
54
+ truncated_bits: int = max(self.fraction_places - machine_precision, 0)
55
+ return RegisterArithmeticInfo(
56
+ size=self.size - truncated_bits,
57
+ is_signed=self.is_signed,
58
+ fraction_places=self.fraction_places - truncated_bits,
59
+ bounds=self.bounds,
60
+ )
61
+
42
62
  @property
43
63
  def is_boolean_register(self) -> bool:
44
64
  return (not self.is_signed) and (self.size == 1) and (self.fraction_places == 0)
@@ -1,17 +1,16 @@
1
- from __future__ import annotations
2
-
3
- import abc
4
- from typing import Iterable, Optional
1
+ from typing import TYPE_CHECKING, Iterable, Optional
5
2
 
6
3
  import pydantic
7
4
 
8
- from classiq.interface.generator.arith import number_utils
5
+ from classiq.interface.generator.arith import argument_utils, number_utils
9
6
  from classiq.interface.generator.arith.arithmetic_operations import (
10
7
  ArithmeticOperationParams,
11
8
  )
12
9
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
13
10
  from classiq.interface.generator.function_params import get_zero_input_name
14
11
 
12
+ from classiq.exceptions import ClassiqValueError
13
+
15
14
  UNARY_ARG_NAME: str = "arg"
16
15
 
17
16
 
@@ -19,16 +18,9 @@ class UnaryOpParams(ArithmeticOperationParams):
19
18
  arg: RegisterArithmeticInfo
20
19
  inplace: bool = False
21
20
 
22
- @abc.abstractmethod
23
- def _expected_result_size(self) -> pydantic.PositiveInt:
24
- pass
25
-
26
- def actual_result_size(self) -> int:
27
- return self.output_size or self._expected_result_size()
28
-
29
21
  def garbage_output_size(self) -> pydantic.NonNegativeInt:
30
22
  return int(self.is_inplaced()) * max(
31
- self.arg.size - self.actual_result_size(), 0
23
+ self.arg.size - self.result_register.size, 0
32
24
  )
33
25
 
34
26
  def should_add_zero_inputs(self) -> bool:
@@ -60,7 +52,7 @@ class UnaryOpParams(ArithmeticOperationParams):
60
52
  def is_inplaced(self) -> bool:
61
53
  return self.inplace
62
54
 
63
- def get_params_inplace_options(self) -> Iterable[UnaryOpParams]:
55
+ def get_params_inplace_options(self) -> Iterable["UnaryOpParams"]:
64
56
  params_kwargs = self.copy().__dict__
65
57
  params_kwargs["inplace"] = True
66
58
  yield self.__class__(**params_kwargs)
@@ -72,14 +64,16 @@ class UnaryOpParams(ArithmeticOperationParams):
72
64
  class BitwiseInvert(UnaryOpParams):
73
65
  output_name = "inverted"
74
66
 
75
- def _expected_result_size(self) -> pydantic.PositiveInt:
76
- return self.arg.size
77
-
78
67
  def _get_result_register(self) -> RegisterArithmeticInfo:
68
+ eff_arg = argument_utils.limit_fraction_places(
69
+ self.arg, machine_precision=self.machine_precision
70
+ )
71
+ if TYPE_CHECKING:
72
+ assert isinstance(eff_arg, RegisterArithmeticInfo)
79
73
  return RegisterArithmeticInfo(
80
- size=self.actual_result_size(),
81
- fraction_places=self.arg.fraction_places,
82
- is_signed=self.arg.is_signed and self._include_sign,
74
+ size=self.output_size or eff_arg.size,
75
+ fraction_places=eff_arg.fraction_places,
76
+ is_signed=eff_arg.is_signed and self._include_sign,
83
77
  )
84
78
 
85
79
 
@@ -97,7 +91,7 @@ class Negation(UnaryOpParams):
97
91
  is_signed = max(self.arg.bounds) > 0 and self._include_sign
98
92
  bounds = (-max(self.arg.bounds), -min(self.arg.bounds))
99
93
  return RegisterArithmeticInfo(
100
- size=self.actual_result_size(),
94
+ size=self.output_size or self._expected_result_size(),
101
95
  fraction_places=self.arg.fraction_places,
102
96
  is_signed=is_signed,
103
97
  bounds=bounds if (is_signed or min(bounds) >= 0) else None,
@@ -112,10 +106,7 @@ class Sign(UnaryOpParams):
112
106
  cls, output_size: Optional[pydantic.PositiveInt]
113
107
  ) -> pydantic.PositiveInt:
114
108
  if output_size is not None and output_size != 1:
115
- raise ValueError("Sign output size must be 1")
116
- return 1
117
-
118
- def _expected_result_size(self) -> pydantic.PositiveInt:
109
+ raise ClassiqValueError("Sign output size must be 1")
119
110
  return 1
120
111
 
121
112
  def _get_result_register(self) -> RegisterArithmeticInfo:
@@ -11,18 +11,18 @@ from classiq.interface.generator.function_params import (
11
11
  FunctionParams,
12
12
  )
13
13
 
14
+ from classiq.exceptions import ClassiqValueError
15
+
14
16
 
15
17
  class ChemistryFunctionParams(FunctionParams):
16
- gs_problem: CHEMISTRY_PROBLEMS_TYPE = pydantic.Field(
17
- description="Ground state problem object describing the system."
18
- )
18
+ gs_problem: CHEMISTRY_PROBLEMS_TYPE
19
19
 
20
20
  @pydantic.validator("gs_problem")
21
21
  def validate_gs_problem_contains_num_qubits(
22
22
  cls, gs_problem: CHEMISTRY_PROBLEMS_TYPE
23
23
  ) -> CHEMISTRY_PROBLEMS_TYPE:
24
24
  if not gs_problem.num_qubits:
25
- raise ValueError(
25
+ raise ClassiqValueError(
26
26
  "Ground state problem doesn't contain num_qubits. "
27
27
  "Use update_problem method."
28
28
  )
@@ -10,6 +10,8 @@ from classiq.interface.generator.function_params import (
10
10
  )
11
11
  from classiq.interface.generator.parameters import ParameterFloatType
12
12
 
13
+ from classiq.exceptions import ClassiqValueError
14
+
13
15
 
14
16
  class CommutingPauliExponentiation(FunctionParams):
15
17
  """
@@ -32,7 +34,7 @@ class CommutingPauliExponentiation(FunctionParams):
32
34
  @pydantic.validator("pauli_operator")
33
35
  def _validate_paulis_commute(cls, pauli_operator: PauliOperator) -> PauliOperator:
34
36
  if not pauli_operator.is_commutative:
35
- raise ValueError("Pauli strings are not commutative")
37
+ raise ClassiqValueError("Pauli strings are not commutative")
36
38
  return pauli_operator
37
39
 
38
40
  def _create_ios(self) -> None:
@@ -0,0 +1,4 @@
1
+ EXPANDED_KEYWORD = "expanded__"
2
+ CAPTURE_SUFFIX = "_captured__"
3
+ LAMBDA_KEYWORD = "lambda__"
4
+ GENERAL_INPLACE_ARITHMETIC_AUXILIARY_VARIABLE = "result__temp__"
@@ -1,17 +1,16 @@
1
- from typing import Any
1
+ from typing import Any, Callable, Dict, Iterator
2
2
 
3
- import pydantic.json
4
3
  from typing_extensions import Self
5
4
 
6
5
 
7
6
  # Use this class as a type for complex data from the json, e.g., in the state_propagator function.
8
7
  class Complex(complex):
9
8
  @classmethod
10
- def __get_validators__(cls):
9
+ def __get_validators__(cls) -> Iterator[Callable]:
11
10
  yield cls.validate
12
11
 
13
12
  @classmethod
14
- def __modify_schema__(cls, field_schema):
13
+ def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
15
14
  field_schema.update(
16
15
  pattern=r"[+-]?\d+\.?\d* *[+-] *\d+\.?\d*j",
17
16
  )
@@ -22,9 +21,3 @@ class Complex(complex):
22
21
  v = "".join(v.split())
23
22
 
24
23
  return cls(v)
25
-
26
-
27
- assert (
28
- complex not in pydantic.json.ENCODERS_BY_TYPE
29
- ), "Is complex type supported on newer version of pydantic?"
30
- pydantic.json.ENCODERS_BY_TYPE[complex] = str
@@ -7,6 +7,8 @@ from pydantic import BaseModel
7
7
 
8
8
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
9
9
 
10
+ from classiq.exceptions import ClassiqValueError
11
+
10
12
  _DEFAULT_CONTROL_NAME: str = "ctrl"
11
13
  _DEFAULT_NUM_CONTROL_QUBITS = 1
12
14
  _INVALID_CONTROL_STATE = "invalid_control_state"
@@ -39,7 +41,7 @@ class ControlState(BaseModel):
39
41
  values["num_ctrl_qubits"] = num_ctrl_qubits
40
42
 
41
43
  if len(ctrl_state) != num_ctrl_qubits:
42
- raise ValueError(
44
+ raise ClassiqValueError(
43
45
  "Control state length should be equal to the number of control qubits"
44
46
  )
45
47
 
@@ -51,11 +53,11 @@ class ControlState(BaseModel):
51
53
  @staticmethod
52
54
  def validate_control_string(ctrl_state: str) -> None:
53
55
  if not set(ctrl_state) <= {"1", "0"}:
54
- raise ValueError(
56
+ raise ClassiqValueError(
55
57
  f"Control state can only be constructed from 0 and 1, received: {ctrl_state}"
56
58
  )
57
59
  if not ctrl_state:
58
- raise ValueError("Control state cannot be empty")
60
+ raise ClassiqValueError("Control state cannot be empty")
59
61
 
60
62
  def __str__(self) -> str:
61
63
  return self.ctrl_state
@@ -1,5 +1,5 @@
1
1
  from statistics import NormalDist
2
- from typing import List, Tuple
2
+ from typing import Any, Dict, List, Tuple
3
3
 
4
4
  import numpy as np
5
5
  import pydantic
@@ -11,6 +11,8 @@ from classiq.interface.helpers.custom_pydantic_types import (
11
11
  PydanticProbabilityFloat,
12
12
  )
13
13
 
14
+ from classiq.exceptions import ClassiqValueError
15
+
14
16
  RHOS_PZEROS_LENGTH_ERROR_MSG = "rhos and p_zeros must have the same length"
15
17
 
16
18
 
@@ -42,10 +44,15 @@ class LinearGCI(function_params.FunctionParams):
42
44
  )
43
45
 
44
46
  @pydantic.validator("rhos")
45
- def validate_rhos(cls, rhos, values):
47
+ def validate_rhos(
48
+ cls, rhos: List[PydanticNonOneProbabilityFloat], values: Dict[str, Any]
49
+ ) -> List[PydanticNonOneProbabilityFloat]:
46
50
  p_zeros = values.get("p_zeros")
51
+ if p_zeros is None:
52
+ raise ClassiqValueError("Cannot validate rhos, p_zeros is missing")
53
+
47
54
  if len(p_zeros) != len(rhos):
48
- raise ValueError(RHOS_PZEROS_LENGTH_ERROR_MSG)
55
+ raise ClassiqValueError(RHOS_PZEROS_LENGTH_ERROR_MSG)
49
56
  return rhos
50
57
 
51
58
  @property
@@ -1,4 +1,4 @@
1
- from typing import List
1
+ from typing import Any, Dict, List, Optional
2
2
 
3
3
  import numpy as np
4
4
  import pydantic
@@ -7,6 +7,8 @@ from classiq.interface.generator import function_params
7
7
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
8
8
  from classiq.interface.generator.function_params import get_zero_input_name
9
9
 
10
+ from classiq.exceptions import ClassiqValueError
11
+
10
12
  LENGTH_ERROR_MESSAGE = "Input length error: Length of weights vector has to be identical to the number of input qubits"
11
13
  STATE = "state"
12
14
  SUM = "sum"
@@ -33,12 +35,20 @@ class WeightedAdder(function_params.FunctionParams):
33
35
  )
34
36
 
35
37
  @pydantic.validator("weights", always=True, pre=True)
36
- def validate_weights(cls, weights, values):
38
+ def validate_weights(
39
+ cls,
40
+ weights: Optional[List[PydanticStrictNonNegativeInteger]],
41
+ values: Dict[str, Any],
42
+ ) -> List[PydanticStrictNonNegativeInteger]:
37
43
  num_state_qubits = values.get("num_state_qubits")
44
+ if num_state_qubits is None:
45
+ raise ClassiqValueError(
46
+ "Missing num_state_qubits and weights, either must be provided"
47
+ )
38
48
  if weights is None:
39
- return [1] * num_state_qubits
49
+ return [PydanticStrictNonNegativeInteger(1)] * num_state_qubits
40
50
  if len(weights) != num_state_qubits:
41
- raise ValueError(LENGTH_ERROR_MESSAGE)
51
+ raise ClassiqValueError(LENGTH_ERROR_MESSAGE)
42
52
  return weights
43
53
 
44
54
  def num_sum_qubits(self) -> int:
@@ -3,9 +3,7 @@ SUPPORTED_BUILTIN_FUNCTIONS = {"len", "sum", "print"}
3
3
  SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
4
4
  "hypercube_entangler_graph",
5
5
  "grid_entangler_graph",
6
- "optimization_problem_to_hamiltonian",
7
- "compute_qaoa_initial_point",
8
- "get_optimization_solution",
6
+ "qft_const_adder_phase",
9
7
  "log_normal_finance_post_process",
10
8
  "gaussian_finance_post_process",
11
9
  "get_type",
@@ -16,5 +14,9 @@ SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
16
14
  "molecule_problem_to_hamiltonian",
17
15
  "fock_hamiltonian_problem_to_hamiltonian",
18
16
  "molecule_ground_state_solution_post_process",
17
+ "BitwiseAnd",
18
+ "BitwiseXor",
19
+ "BitwiseNot",
20
+ "BitwiseOr",
19
21
  *SUPPORTED_BUILTIN_FUNCTIONS,
20
22
  }
@@ -1,8 +1,11 @@
1
+ import re
1
2
  from dataclasses import dataclass
2
- from typing import Any, Mapping, Type
3
+ from typing import Any, Mapping, Optional, Type
3
4
 
5
+ from sympy import Expr
4
6
  from typing_extensions import get_args
5
7
 
8
+ from classiq.interface.backend.pydantic_backend import EXECUTION_PARAMETER_PATTERN
6
9
  from classiq.interface.generator.expressions.expression_types import (
7
10
  ExpressionValue,
8
11
  QmodStructInstance,
@@ -17,15 +20,20 @@ from classiq.exceptions import ClassiqValueError
17
20
  class EvaluatedExpression:
18
21
  value: ExpressionValue
19
22
 
20
- def is_constant(self) -> bool:
23
+ def is_constant(self, constant_type: Optional[Type] = None) -> bool:
21
24
  if self.value is None:
22
25
  return False
23
26
 
24
- return isinstance(self.value, get_args(RuntimeConstant))
27
+ return isinstance(
28
+ self.value,
29
+ get_args(RuntimeConstant) if constant_type is None else constant_type,
30
+ )
25
31
 
26
32
  def as_constant_type(self, constant_type: Type) -> Any:
27
33
  if not self.is_constant():
28
- raise ClassiqValueError(f"Invalid access to expression as {constant_type}")
34
+ raise ClassiqValueError(
35
+ f"Invalid access to expression {self.value!r} as {constant_type}"
36
+ )
29
37
 
30
38
  return constant_type(self.value)
31
39
 
@@ -62,3 +70,9 @@ class EvaluatedExpression:
62
70
  raise ClassiqValueError("Invalid access to unevaluated expression")
63
71
 
64
72
  return str(self.value)
73
+
74
+ def is_identifier(self) -> bool:
75
+ return (
76
+ isinstance(self.value, Expr)
77
+ and re.fullmatch(EXECUTION_PARAMETER_PATTERN, str(self.value)) is not None
78
+ )
@@ -69,7 +69,7 @@ class Expression(HashablePydanticBaseModel):
69
69
  result = ast.literal_eval(self.expr)
70
70
  if isinstance(result, (int, float, bool)):
71
71
  self._evaluated_expr = EvaluatedExpression(value=result)
72
- except Exception: # nosec B110
72
+ except Exception: # noqa: S110
73
73
  pass
74
74
 
75
75
  @property
@@ -0,0 +1,33 @@
1
+ from sympy import Symbol
2
+
3
+ from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
4
+
5
+
6
+ class QmodQScalarProxy(Symbol, QmodSizedProxy):
7
+ def __new__(cls, name, **assumptions):
8
+ return super().__new__(cls, name, **assumptions)
9
+
10
+ def __init__(self, name: str, size: int) -> None:
11
+ super().__init__(size)
12
+
13
+
14
+ class QmodQBitProxy(QmodQScalarProxy):
15
+ pass
16
+
17
+
18
+ class QmodQNumProxy(QmodQScalarProxy):
19
+
20
+ def __init__(
21
+ self, name: str, size: int, fraction_digits: int, is_signed: bool
22
+ ) -> None:
23
+ super().__init__(name, size)
24
+ self._fraction_digits = fraction_digits
25
+ self._is_signed = is_signed
26
+
27
+ @property
28
+ def fraction_digits(self) -> int:
29
+ return self._fraction_digits
30
+
31
+ @property
32
+ def is_signed(self) -> bool:
33
+ return self._is_signed
@@ -34,6 +34,7 @@ MATHEMATICAL_FUNCTIONS: List[str] = [
34
34
  "ceiling",
35
35
  "Max",
36
36
  "Min",
37
+ "mod_inverse",
37
38
  ]
38
39
  SPECIAL_FUNCTIONS: List[str] = [
39
40
  "erf",
@@ -69,7 +70,7 @@ LOGIC_OPERATORS: List[str] = [
69
70
  "Nand",
70
71
  "Nor",
71
72
  ]
72
- RELATIONAL_OPERATORS: List[str] = ["<", "<=", ">", ">=", "!=", "<>", "Eq"]
73
+ RELATIONAL_OPERATORS: List[str] = ["<", "<=", ">", ">=", "!=", "<>", "Eq", "Ne"]
73
74
 
74
75
  SYMPY_SUPPORTED_EXPRESSIONS: List[str] = (
75
76
  BASIC_ARITHMETIC_OPERATORS
@@ -20,7 +20,7 @@ DEFAULT_POST_INPUT_NAME = "post_function_input"
20
20
 
21
21
  class Finance(function_params.FunctionParams):
22
22
  model: Union[GaussianModelInput, LogNormalModelInput] = pydantic.Field(
23
- description="Load a financial model"
23
+ description="Load a financial model", discriminator="kind"
24
24
  )
25
25
  finance_function: FinanceFunctionInput = pydantic.Field(
26
26
  description="The finance function to solve the model"
@@ -30,6 +30,7 @@ from classiq.interface.helpers.hashable_pydantic_base_model import (
30
30
  )
31
31
 
32
32
  from classiq._internals.enum_utils import StrEnum
33
+ from classiq.exceptions import ClassiqValueError
33
34
 
34
35
  FunctionParamsDiscriminator = str
35
36
 
@@ -84,7 +85,6 @@ ExecutionExpressionSupportedNodeTypes = Union[
84
85
  ]
85
86
 
86
87
  GenerationOnlyExpressionSupportedNodeTypes = Union[
87
- ast.FloorDiv,
88
88
  ast.Pow,
89
89
  ast.List,
90
90
  ast.Subscript,
@@ -96,6 +96,7 @@ GenerationOnlyExpressionSupportedNodeTypes = Union[
96
96
  ast.Lt,
97
97
  ast.LtE,
98
98
  ast.Eq,
99
+ ast.NotEq,
99
100
  ast.Call,
100
101
  ast.Dict,
101
102
  ast.Slice,
@@ -243,7 +244,7 @@ class FunctionParams(HashablePydanticBaseModel):
243
244
  error_msg += self._get_error_msg(self._outputs, BAD_OUTPUT_REGISTER_ERROR_MSG)
244
245
  if error_msg:
245
246
  error_msg += [END_BAD_REGISTER_ERROR_MSG]
246
- raise ValueError("\n".join(error_msg))
247
+ raise ClassiqValueError("\n".join(error_msg))
247
248
 
248
249
  @staticmethod
249
250
  def _sum_registers_sizes(registers: Iterable[RegisterArithmeticInfo]) -> int:
@@ -255,7 +256,7 @@ class FunctionParams(HashablePydanticBaseModel):
255
256
  )
256
257
  total_outputs_size = self._sum_registers_sizes(self._outputs.values())
257
258
  if total_inputs_size != total_outputs_size:
258
- raise ValueError(REGISTER_SIZES_MISMATCH_ERROR_MSG)
259
+ raise ClassiqValueError(REGISTER_SIZES_MISMATCH_ERROR_MSG)
259
260
 
260
261
  def _get_error_msg(self, names: Iterable[IOName], msg: str) -> List[str]:
261
262
  bad_names = [name for name in names if re.fullmatch(NAME_REGEX, name) is None]
@@ -312,7 +313,7 @@ def parse_function_params(
312
313
  try:
313
314
  return default_parser_class.parse_obj(params)
314
315
  except Exception:
315
- raise bad_function_error
316
+ raise bad_function_error from None
316
317
  raise bad_function_error
317
318
 
318
319
  return matching_classes[0].parse_obj(params)
@@ -335,10 +336,10 @@ def parse_function_params_values(
335
336
  params=params,
336
337
  discriminator=discriminator,
337
338
  param_classes=param_classes,
338
- no_discriminator_error=ValueError(
339
+ no_discriminator_error=ClassiqValueError(
339
340
  f"The {discriminator_key} {NO_DISCRIMINATOR_ERROR_MSG} {params_key} type."
340
341
  ),
341
- bad_function_error=ValueError(
342
+ bad_function_error=ClassiqValueError(
342
343
  f"{BAD_FUNCTION_ERROR_MSG} {discriminator_key}: {discriminator}"
343
344
  ),
344
345
  default_parser_class=default_parser_class,
@@ -1,7 +1,7 @@
1
1
  from typing import List
2
2
 
3
3
  import classiq.interface.generator.functions.core_lib_declarations.quantum_functions
4
- import classiq.interface.generator.functions.core_lib_declarations.quantum_operators # noqa: F401
4
+ import classiq.interface.generator.functions.core_lib_declarations.quantum_operators
5
5
  from classiq.interface.generator.functions.foreign_function_definition import *
6
6
  from classiq.interface.generator.functions.foreign_function_definition import (
7
7
  SynthesisForeignFunctionDefinition as ForeignFunctionDefinition,