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,4 +1,4 @@
1
- from typing import List, Optional
1
+ from typing import Any, Dict, List, Optional
2
2
 
3
3
  import pydantic
4
4
  from pydantic import BaseModel
@@ -6,6 +6,7 @@ from pydantic import BaseModel
6
6
  from classiq.interface.helpers.custom_pydantic_types import PydanticAlphaParamCVAR
7
7
 
8
8
  from classiq._internals.enum_utils import StrEnum
9
+ from classiq.exceptions import ClassiqValueError
9
10
 
10
11
 
11
12
  class CostType(StrEnum):
@@ -33,10 +34,10 @@ class OptimizerPreferences(BaseModel):
33
34
  max_iteration: pydantic.PositiveInt = pydantic.Field(
34
35
  default=100, description="Maximal number of optimizer iterations"
35
36
  )
36
- tolerance: pydantic.PositiveFloat = pydantic.Field(
37
+ tolerance: Optional[pydantic.PositiveFloat] = pydantic.Field(
37
38
  default=None, description="Final accuracy in the optimization"
38
39
  )
39
- step_size: pydantic.PositiveFloat = pydantic.Field(
40
+ step_size: Optional[pydantic.PositiveFloat] = pydantic.Field(
40
41
  default=None,
41
42
  description="step size for numerically " "calculating the gradient",
42
43
  )
@@ -54,30 +55,36 @@ class OptimizerPreferences(BaseModel):
54
55
  )
55
56
 
56
57
  @pydantic.validator("tolerance", pre=True, always=True)
57
- def check_tolerance(cls, tolerance, values):
58
+ def check_tolerance(
59
+ cls, tolerance: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
60
+ ) -> Optional[pydantic.PositiveFloat]:
58
61
  optimizer_type = values.get("type")
59
62
  if tolerance is not None and optimizer_type == OptimizerType.SPSA:
60
- raise ValueError("No tolerance param for SPSA optimizer")
63
+ raise ClassiqValueError("No tolerance param for SPSA optimizer")
61
64
 
62
65
  if tolerance is None and optimizer_type != OptimizerType.SPSA:
63
- tolerance = 0.001
66
+ tolerance = pydantic.PositiveFloat(0.001)
64
67
 
65
68
  return tolerance
66
69
 
67
70
  @pydantic.validator("step_size", pre=True, always=True)
68
- def check_step_size(cls, step_size, values):
71
+ def check_step_size(
72
+ cls, step_size: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
73
+ ) -> Optional[pydantic.PositiveFloat]:
69
74
  optimizer_type = values.get("name")
70
75
  if step_size is not None and optimizer_type not in (
71
76
  OptimizerType.L_BFGS_B,
72
77
  OptimizerType.ADAM,
73
78
  ):
74
- raise ValueError("Use step_size only for L_BFGS_B or ADAM optimizers.")
79
+ raise ClassiqValueError(
80
+ "Use step_size only for L_BFGS_B or ADAM optimizers."
81
+ )
75
82
 
76
83
  if step_size is None and optimizer_type in (
77
84
  OptimizerType.L_BFGS_B,
78
85
  OptimizerType.ADAM,
79
86
  ):
80
- step_size = 0.05
87
+ step_size = pydantic.PositiveFloat(0.05)
81
88
 
82
89
  return step_size
83
90
 
@@ -91,7 +98,7 @@ class CombinatorialOptimizer(OptimizerPreferences):
91
98
  default=CostType.CVAR,
92
99
  description="Summarizing method of the measured bit strings",
93
100
  )
94
- alpha_cvar: PydanticAlphaParamCVAR = pydantic.Field(
101
+ alpha_cvar: Optional[PydanticAlphaParamCVAR] = pydantic.Field(
95
102
  default=None, description="Parameter for the CVAR summarizing method"
96
103
  )
97
104
  is_maximization: bool = pydantic.Field(
@@ -104,12 +111,14 @@ class CombinatorialOptimizer(OptimizerPreferences):
104
111
  )
105
112
 
106
113
  @pydantic.validator("alpha_cvar", pre=True, always=True)
107
- def check_alpha_cvar(cls, alpha_cvar, values):
114
+ def check_alpha_cvar(
115
+ cls, alpha_cvar: Optional[PydanticAlphaParamCVAR], values: Dict[str, Any]
116
+ ) -> Optional[PydanticAlphaParamCVAR]:
108
117
  cost_type = values.get("cost_type")
109
118
  if alpha_cvar is not None and cost_type != CostType.CVAR:
110
- raise ValueError("Use CVAR params only for CostType.CVAR.")
119
+ raise ClassiqValueError("Use CVAR params only for CostType.CVAR.")
111
120
 
112
121
  if alpha_cvar is None and cost_type == CostType.CVAR:
113
- alpha_cvar = 0.2
122
+ alpha_cvar = PydanticAlphaParamCVAR(0.2)
114
123
 
115
124
  return alpha_cvar
@@ -6,7 +6,7 @@ from typing import Any, Dict, Optional, Tuple, Union
6
6
  import pydantic
7
7
  from pydantic import BaseModel
8
8
 
9
- from classiq.interface.backend.ionq import ionq_quantum_program
9
+ from classiq.interface.backend.ionq.ionq_quantum_program import IonqQuantumCircuit
10
10
  from classiq.interface.backend.pydantic_backend import PydanticArgumentNameType
11
11
  from classiq.interface.executor.quantum_instruction_set import QuantumInstructionSet
12
12
  from classiq.interface.executor.register_initialization import RegisterInitialization
@@ -14,15 +14,17 @@ from classiq.interface.generator.synthesis_metadata.synthesis_execution_data imp
14
14
  ExecutionData,
15
15
  )
16
16
 
17
+ from classiq.exceptions import ClassiqValueError
18
+
17
19
  Arguments = Dict[PydanticArgumentNameType, Any]
18
20
  MultipleArguments = Tuple[Arguments, ...]
19
- CodeType = Union[str, ionq_quantum_program.IonqQuantumCircuit]
21
+ CodeType = str
20
22
  RegistersInitialization = Dict[str, RegisterInitialization]
21
23
  Qubits = Tuple[int, ...]
22
24
  OutputQubitsMap = Dict[str, Qubits]
23
25
 
24
26
 
25
- class QuantumBaseProgram(BaseModel):
27
+ class QuantumBaseCode(BaseModel):
26
28
  syntax: QuantumInstructionSet = pydantic.Field(
27
29
  default=QuantumInstructionSet.QASM, description="The syntax of the program."
28
30
  )
@@ -31,17 +33,21 @@ class QuantumBaseProgram(BaseModel):
31
33
  )
32
34
 
33
35
  @pydantic.validator("code")
34
- def load_quantum_program(cls, code: CodeType, values: Dict[str, Any]) -> CodeType:
35
- if not isinstance(code, str):
36
- return code
37
-
36
+ def load_quantum_program(
37
+ cls, code: Union[CodeType, IonqQuantumCircuit], values: Dict[str, Any]
38
+ ) -> CodeType:
38
39
  syntax = values.get("syntax")
39
- if syntax == QuantumInstructionSet.IONQ:
40
- return ionq_quantum_program.IonqQuantumCircuit.from_string(code)
40
+ if isinstance(code, IonqQuantumCircuit):
41
+ if syntax != QuantumInstructionSet.IONQ:
42
+ raise ClassiqValueError(
43
+ f"Invalid code type {type(code)} for syntax: {syntax}"
44
+ )
45
+ return code.json()
46
+
41
47
  return code
42
48
 
43
49
 
44
- class QuantumProgram(QuantumBaseProgram):
50
+ class QuantumCode(QuantumBaseCode):
45
51
  arguments: MultipleArguments = pydantic.Field(
46
52
  default=(),
47
53
  description="The parameters dictionary for a parametrized quantum program.",
@@ -68,10 +74,10 @@ class QuantumProgram(QuantumBaseProgram):
68
74
  QuantumInstructionSet.QSHARP,
69
75
  QuantumInstructionSet.QASM,
70
76
  ):
71
- raise ValueError("Only QASM or Q# programs support arguments")
77
+ raise ClassiqValueError("Only QASM or Q# programs support arguments")
72
78
 
73
79
  if values.get("syntax") == QuantumInstructionSet.QSHARP and len(arguments) > 1:
74
- raise ValueError(
80
+ raise ClassiqValueError(
75
81
  f"Q# programs supports only one group of arguments. {len(arguments)} given"
76
82
  )
77
83
 
@@ -87,7 +93,7 @@ class QuantumProgram(QuantumBaseProgram):
87
93
  synthesis_execution_data is not None
88
94
  and values.get("syntax") is not QuantumInstructionSet.QASM
89
95
  ):
90
- raise ValueError("Only QASM supports the requested configuration")
96
+ raise ClassiqValueError("Only QASM supports the requested configuration")
91
97
 
92
98
  return synthesis_execution_data
93
99
 
@@ -96,9 +102,9 @@ class QuantumProgram(QuantumBaseProgram):
96
102
  file_path: Union[str, Path],
97
103
  syntax: Optional[Union[str, QuantumInstructionSet]] = None,
98
104
  arguments: MultipleArguments = (),
99
- ) -> QuantumProgram:
105
+ ) -> QuantumCode:
100
106
  path = Path(file_path)
101
107
  code = path.read_text()
102
108
  if syntax is None:
103
109
  syntax = QuantumInstructionSet.from_suffix(path.suffix.lstrip("."))
104
- return QuantumProgram(syntax=syntax, code=code, arguments=arguments)
110
+ return QuantumCode(syntax=syntax, code=code, arguments=arguments)
@@ -1,4 +1,5 @@
1
1
  from classiq._internals.enum_utils import StrEnum
2
+ from classiq.exceptions import ClassiqValueError
2
3
 
3
4
 
4
5
  class QuantumInstructionSet(StrEnum):
@@ -14,4 +15,4 @@ class QuantumInstructionSet(StrEnum):
14
15
  return QuantumInstructionSet.QSHARP
15
16
  if suffix == "ionq":
16
17
  return QuantumInstructionSet.IONQ
17
- raise ValueError("Illegal suffix")
18
+ raise ClassiqValueError("Illegal suffix")
@@ -30,9 +30,7 @@ class RegisterInitialization(pydantic.BaseModel):
30
30
  initial_condition: int = values.get("initial_condition", 0)
31
31
  name: str = values.get("name", "")
32
32
 
33
- initial_condition_length = number_utils.size(
34
- initial_condition, machine_precision=number_utils.MAX_FRACTION_PLACES
35
- )
33
+ initial_condition_length = number_utils.size(initial_condition)
36
34
  register_length = len(qubits)
37
35
  if initial_condition_length > register_length:
38
36
  raise ClassiqStateInitializationError(
@@ -17,7 +17,7 @@ import pydantic
17
17
  from pydantic import BaseModel
18
18
  from typing_extensions import TypeAlias
19
19
 
20
- from classiq.interface.executor.quantum_program import OutputQubitsMap, Qubits
20
+ from classiq.interface.executor.quantum_code import OutputQubitsMap, Qubits
21
21
  from classiq.interface.generator.arith import number_utils
22
22
  from classiq.interface.generator.complex_type import Complex
23
23
  from classiq.interface.generator.functions.classical_type import QmodPyObject
@@ -44,6 +44,9 @@ class SampledState(BaseModel):
44
44
  state: ParsedState
45
45
  shots: MeasuredShots
46
46
 
47
+ def __repr__(self) -> str:
48
+ return f"{self.state}: {self.shots}"
49
+
47
50
 
48
51
  ParsedCounts: TypeAlias = List[SampledState]
49
52
 
@@ -97,6 +100,28 @@ def get_sampled_state(
97
100
  return None
98
101
 
99
102
 
103
+ def reduce_parsed_states(
104
+ parsed_states: ParsedStates, outputs: Tuple[Name, ...]
105
+ ) -> ParsedStates:
106
+ return {
107
+ state: {
108
+ output: value for output, value in parsed_state.items() if output in outputs
109
+ }
110
+ for state, parsed_state in parsed_states.items()
111
+ }
112
+
113
+
114
+ def get_parsed_counts(counts: Counts, parsed_states: ParsedStates) -> ParsedCounts:
115
+ parsed_counts: ParsedCounts = []
116
+ for bitstring, count in counts.items():
117
+ parsed_state = parsed_states[bitstring]
118
+ if sampled_state := get_sampled_state(parsed_counts, parsed_state):
119
+ sampled_state.shots += count
120
+ else:
121
+ parsed_counts.append(SampledState(state=parsed_state, shots=count))
122
+ return sorted(parsed_counts, key=lambda k: k.shots, reverse=True)
123
+
124
+
100
125
  class ExecutionDetails(BaseModel, QmodPyObject):
101
126
  vendor_format_result: Dict[str, Any] = pydantic.Field(
102
127
  ..., description="Result in proprietary vendor format"
@@ -155,14 +180,7 @@ class ExecutionDetails(BaseModel, QmodPyObject):
155
180
 
156
181
  @property
157
182
  def parsed_counts(self) -> ParsedCounts:
158
- parsed_counts: ParsedCounts = []
159
- for bitstring, count in self.counts.items():
160
- parsed_state = self.parsed_states[bitstring]
161
- if sampled_state := get_sampled_state(parsed_counts, parsed_state):
162
- sampled_state.shots += count
163
- else:
164
- parsed_counts.append(SampledState(state=parsed_state, shots=count))
165
- return sorted(parsed_counts, key=lambda k: k.shots, reverse=True)
183
+ return get_parsed_counts(self.counts, self.parsed_states)
166
184
 
167
185
  @property
168
186
  def parsed_state_vector(self) -> Optional[ParsedStateVector]:
@@ -223,6 +241,17 @@ class ExecutionDetails(BaseModel, QmodPyObject):
223
241
  reduced_counts[reduced_strs] += state_count
224
242
  return dict(reduced_counts)
225
243
 
244
+ def parsed_counts_of_outputs(
245
+ self, output_names: Union[Name, Tuple[Name, ...]]
246
+ ) -> ParsedCounts:
247
+ if isinstance(output_names, Name):
248
+ output_names = (output_names,)
249
+ if any(name not in self.output_qubits_map for name in output_names):
250
+ raise ClassiqError(_UNAVAILABLE_OUTPUT_ERROR_MSG)
251
+
252
+ reduced_parsed_states = reduce_parsed_states(self.parsed_states, output_names)
253
+ return get_parsed_counts(self.counts, reduced_parsed_states)
254
+
226
255
  def register_output_from_qubits(self, qubits: Tuple[int, ...]) -> Dict[float, int]:
227
256
  register_output: Dict[float, int] = {}
228
257
  value_from_str_bin = functools.partial(
@@ -273,7 +302,9 @@ class EstimationResults(VersionedModel):
273
302
  def __len__(self) -> int:
274
303
  return len(self.results)
275
304
 
276
- def __iter__(self) -> Iterator[EstimationResult]: # type: ignore
305
+ def __iter__(self) -> Iterator[EstimationResult]: # type: ignore[override]
306
+ # TODO This is a bug waiting to happen. We change the meaning of
307
+ # __iter__ in a derived class.
277
308
  return iter(self.results)
278
309
 
279
310
  def __getitem__(self, index: int) -> EstimationResult:
@@ -18,7 +18,7 @@ Solution = Tuple[int, ...]
18
18
  class SolverResult(BaseModel):
19
19
  energy: float
20
20
  # TODO: add time units (like seconds)
21
- time: Optional[float]
21
+ time: Optional[float] = None
22
22
  solution: Optional[Solution]
23
23
 
24
24
 
@@ -3,12 +3,15 @@ from typing import Any, Dict, Optional, Union
3
3
  import pydantic
4
4
 
5
5
  from classiq.interface.generator.expressions.enums.finance_functions import (
6
+ FINANCE_FUNCTION_STRING,
6
7
  FinanceFunctionType,
7
8
  )
8
9
  from classiq.interface.helpers.custom_pydantic_types import (
9
10
  PydanticNonZeroProbabilityFloat,
10
11
  )
11
12
 
13
+ from classiq.exceptions import ClassiqValueError
14
+
12
15
 
13
16
  class FunctionCondition(pydantic.BaseModel):
14
17
  threshold: float
@@ -22,8 +25,9 @@ class FunctionCondition(pydantic.BaseModel):
22
25
 
23
26
 
24
27
  class FinanceFunctionInput(pydantic.BaseModel):
25
- f: Union[int, str, FinanceFunctionType] = pydantic.Field(
26
- description="A callable function to solve the model"
28
+ f: FinanceFunctionType = pydantic.Field(
29
+ description="An enumeration of the wanted financial function: VaR, expected "
30
+ "shortfall, European call options or x^2"
27
31
  )
28
32
  variable: str = pydantic.Field(
29
33
  default="x", description="Variable/s of the function"
@@ -45,13 +49,20 @@ class FinanceFunctionInput(pydantic.BaseModel):
45
49
  description="The required probability on the tail of the distribution (1 - percentile)",
46
50
  )
47
51
 
52
+ @pydantic.validator("f", pre=True)
53
+ def _convert_f_if_str(cls, f: Any) -> FinanceFunctionType:
54
+ # Keep this for backwards-compatible string support
55
+ if f in FINANCE_FUNCTION_STRING:
56
+ return FINANCE_FUNCTION_STRING[f]
57
+ return f
58
+
48
59
  @pydantic.validator("use_chebyshev_polynomial_approximation")
49
60
  def _validate_polynomial_flag(
50
61
  cls, use_chebyshev_flag: bool, values: Dict[str, Any]
51
62
  ) -> bool:
52
63
  if use_chebyshev_flag ^ (values.get("polynomial_degree") is None):
53
64
  return use_chebyshev_flag
54
- raise ValueError(
65
+ raise ClassiqValueError(
55
66
  "Degree must be positive and use_chebyshev_polynomial_approximation set to True"
56
67
  )
57
68
 
@@ -72,7 +83,9 @@ class FinanceFunctionInput(pydantic.BaseModel):
72
83
  values: Dict[str, Any],
73
84
  ) -> Optional[PydanticNonZeroProbabilityFloat]:
74
85
  if values.get("f") == FinanceFunctionType.SHORTFALL and not tail_probability:
75
- raise ValueError("Tail probability must be set for expected shortfall")
86
+ raise ClassiqValueError(
87
+ "Tail probability must be set for expected shortfall"
88
+ )
76
89
  return tail_probability
77
90
 
78
91
  class Config:
@@ -1,5 +1,5 @@
1
1
  import math
2
- from typing import List, Optional, Tuple
2
+ from typing import List, Literal, Optional, Tuple
3
3
 
4
4
  import pydantic
5
5
 
@@ -8,6 +8,8 @@ from classiq.interface.helpers.custom_pydantic_types import PydanticProbabilityF
8
8
 
9
9
 
10
10
  class GaussianModelInput(FinanceModelInput):
11
+ kind: Literal["gaussian"] = pydantic.Field(default="gaussian")
12
+
11
13
  num_qubits: pydantic.PositiveInt = pydantic.Field(
12
14
  description="The number of qubits represent"
13
15
  "the latent normal random variable Z (Resolution of "
@@ -1,4 +1,4 @@
1
- from typing import Tuple
1
+ from typing import Literal, Tuple
2
2
 
3
3
  import numpy as np
4
4
  import pydantic
@@ -7,6 +7,8 @@ from classiq.interface.finance.model_input import FinanceModelInput
7
7
 
8
8
 
9
9
  class LogNormalModelInput(FinanceModelInput):
10
+ kind: Literal["log_normal"] = pydantic.Field(default="log_normal")
11
+
10
12
  num_qubits: pydantic.PositiveInt = pydantic.Field(
11
13
  description="Number of qubits to represent the probability."
12
14
  )
@@ -7,6 +7,8 @@ from classiq.interface.helpers.hashable_pydantic_base_model import (
7
7
 
8
8
 
9
9
  class FinanceModelInput(HashablePydanticBaseModel):
10
+ kind: str
11
+
10
12
  @property
11
13
  def num_output_qubits(self) -> int:
12
14
  return 0
@@ -20,6 +20,7 @@ from classiq.interface.generator.function_params import (
20
20
  from classiq.interface.helpers.custom_pydantic_types import PydanticExpressionStr
21
21
 
22
22
  from classiq._internals.enum_utils import StrEnum
23
+ from classiq.exceptions import ClassiqValueError
23
24
 
24
25
  AMPLITUDE_IO_NAME = "AMPLITUDE"
25
26
  TARGET_OUTPUT_NAME = "TARGET"
@@ -66,14 +67,17 @@ class AmplitudeLoading(FunctionParams):
66
67
  not_allowed = literals.intersection(FORBIDDEN_LITERALS)
67
68
  variables = literals.difference(SUPPORTED_FUNC_NAMES)
68
69
  if not_allowed:
69
- raise ValueError(f"The following names: {not_allowed} are not allowed")
70
+ raise ClassiqValueError(
71
+ f"The following names: {not_allowed} are not allowed"
72
+ )
70
73
 
71
74
  if len(variables) != 1:
72
- raise ValueError(f"{variables} must contain exactly single variable")
75
+ raise ClassiqValueError(f"{variables} must contain exactly single variable")
73
76
  return values
74
77
 
75
78
  def _create_ios(self) -> None:
76
79
  self._inputs = {
80
+ TARGET_OUTPUT_NAME: RegisterUserInput(name=TARGET_OUTPUT_NAME, size=1),
77
81
  AMPLITUDE_IO_NAME: RegisterUserInput(
78
82
  name=AMPLITUDE_IO_NAME, size=self.size
79
83
  ),
@@ -82,7 +86,6 @@ class AmplitudeLoading(FunctionParams):
82
86
  TARGET_OUTPUT_NAME: RegisterUserInput(name=TARGET_OUTPUT_NAME, size=1),
83
87
  **self._inputs,
84
88
  }
85
- self._create_zero_input_registers({TARGET_OUTPUT_NAME: 1})
86
89
 
87
90
  @property
88
91
  def variable(self) -> str:
@@ -2,6 +2,7 @@ from classiq.interface.generator.builtin_api_builder import (
2
2
  populate_builtin_declarations,
3
3
  )
4
4
 
5
+ from .arithmetic_declarations import * # noqa: F403
5
6
  from .chemistry_declarations import * # noqa: F403
6
7
  from .combinatorial_optimization_declarations import * # noqa: F403
7
8
  from .entangler_declarations import * # noqa: F403
@@ -0,0 +1,14 @@
1
+ from classiq.interface.generator.functions.classical_function_declaration import (
2
+ ClassicalFunctionDeclaration,
3
+ )
4
+ from classiq.interface.generator.functions.classical_type import Integer, Real
5
+
6
+ qft_const_adder_phase = ClassicalFunctionDeclaration(
7
+ name="qft_const_adder_phase",
8
+ param_decls={
9
+ "bit_index": Integer(),
10
+ "value": Integer(),
11
+ "reg_len": Integer(),
12
+ },
13
+ return_type=Real(),
14
+ )
@@ -6,10 +6,10 @@ from classiq.interface.generator.arith.register_user_input import RegisterArithm
6
6
  RegisterOrConst = Union[RegisterArithmeticInfo, float]
7
7
 
8
8
 
9
- def fraction_places(argument: RegisterOrConst, *, machine_precision: int) -> int:
9
+ def fraction_places(argument: RegisterOrConst) -> int:
10
10
  if isinstance(argument, RegisterArithmeticInfo):
11
11
  return argument.fraction_places
12
- return number_utils.fraction_places(argument, machine_precision=machine_precision)
12
+ return number_utils.fraction_places(argument)
13
13
 
14
14
 
15
15
  def integer_part_size(argument: RegisterOrConst) -> int:
@@ -18,10 +18,10 @@ def integer_part_size(argument: RegisterOrConst) -> int:
18
18
  return number_utils.integer_part_size(argument)
19
19
 
20
20
 
21
- def size(argument: RegisterOrConst, *, machine_precision: int) -> int:
21
+ def size(argument: RegisterOrConst) -> int:
22
22
  if isinstance(argument, RegisterArithmeticInfo):
23
23
  return argument.size
24
- return number_utils.size(argument, machine_precision=machine_precision)
24
+ return number_utils.size(argument)
25
25
 
26
26
 
27
27
  def is_signed(argument: RegisterOrConst) -> bool:
@@ -46,3 +46,13 @@ def bounds(argument: RegisterOrConst) -> Tuple[float, float]:
46
46
  if isinstance(argument, RegisterArithmeticInfo):
47
47
  return argument.bounds
48
48
  return argument, argument
49
+
50
+
51
+ def limit_fraction_places(
52
+ argument: RegisterOrConst, *, machine_precision: int
53
+ ) -> RegisterOrConst:
54
+ if isinstance(argument, RegisterArithmeticInfo):
55
+ return argument.limit_fraction_places(machine_precision)
56
+ return number_utils.limit_fraction_places(
57
+ argument, machine_precision=machine_precision
58
+ )
@@ -21,6 +21,8 @@ from classiq.interface.model.quantum_type import (
21
21
  register_info_to_quantum_type,
22
22
  )
23
23
 
24
+ from classiq.exceptions import ClassiqValueError
25
+
24
26
  ARITHMETIC_EXPRESSION_TARGET_NAME: str = "arithmetic_target"
25
27
  ARITHMETIC_EXPRESSION_RESULT_NAME: str = "expression_result"
26
28
 
@@ -47,7 +49,7 @@ class Arithmetic(ArithmeticExpressionABC):
47
49
  degree or operation_allows_target(id2op(node))
48
50
  for node, degree in graph.out_degree
49
51
  ):
50
- raise ValueError("Expression does not support target assignment")
52
+ raise ClassiqValueError("Expression does not support target assignment")
51
53
 
52
54
  def _create_ios(self) -> None:
53
55
  self._inputs = {
@@ -2,23 +2,16 @@ from typing import Callable, Dict, List
2
2
 
3
3
  from typing_extensions import TypeAlias
4
4
 
5
- from classiq.interface.generator.arith.argument_utils import (
6
- RegisterOrConst,
7
- fraction_places,
8
- )
5
+ from classiq.interface.generator.arith import argument_utils
9
6
  from classiq.interface.generator.arith.binary_ops import BOOLEAN_OP_WITH_FRACTIONS_ERROR
10
7
 
11
8
  from classiq.exceptions import ClassiqArithmeticError
12
9
 
13
- ArgTypeValidator: TypeAlias = Callable[[List[RegisterOrConst], int], None]
10
+ ArgTypeValidator: TypeAlias = Callable[[List[argument_utils.RegisterOrConst]], None]
14
11
 
15
12
 
16
- def _validate_bitwise_op_args(
17
- args: List[RegisterOrConst], machine_precision: int
18
- ) -> None:
19
- if any(
20
- fraction_places(arg, machine_precision=machine_precision) > 0 for arg in args
21
- ):
13
+ def _validate_bitwise_op_args(args: List[argument_utils.RegisterOrConst]) -> None:
14
+ if any(argument_utils.fraction_places(arg) > 0 for arg in args):
22
15
  raise ClassiqArithmeticError(BOOLEAN_OP_WITH_FRACTIONS_ERROR)
23
16
 
24
17
 
@@ -30,8 +23,14 @@ arg_type_validator_map: Dict[str, ArgTypeValidator] = dict(
30
23
 
31
24
 
32
25
  def validate_operation_arg_types(
33
- operation: str, args: List[RegisterOrConst], machine_precision: int
26
+ operation: str,
27
+ arguments: List[argument_utils.RegisterOrConst],
28
+ machine_precision: int,
34
29
  ) -> None:
35
30
  if operation not in arg_type_validator_map:
36
31
  return
37
- arg_type_validator_map[operation](args, machine_precision)
32
+ limited_args = [
33
+ argument_utils.limit_fraction_places(arg, machine_precision=machine_precision)
34
+ for arg in arguments
35
+ ]
36
+ arg_type_validator_map[operation](limited_args)
@@ -17,6 +17,9 @@ from classiq.interface.generator.arith.arithmetic_expression_validator import (
17
17
  from classiq.interface.generator.arith.arithmetic_result_builder import (
18
18
  validate_arithmetic_result_type,
19
19
  )
20
+ from classiq.interface.generator.arith.machine_precision import (
21
+ DEFAULT_MACHINE_PRECISION,
22
+ )
20
23
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
21
24
  from classiq.interface.generator.arith.uncomputation_methods import UncomputationMethods
22
25
  from classiq.interface.generator.expressions.expression_constants import (
@@ -36,7 +39,7 @@ ValidDefinitions: TypeAlias = Union[
36
39
 
37
40
  class ArithmeticExpressionABC(abc.ABC, FunctionParams):
38
41
  uncomputation_method: UncomputationMethods = UncomputationMethods.optimized
39
- machine_precision: pydantic.NonNegativeInt = number_utils.MAX_FRACTION_PLACES
42
+ machine_precision: pydantic.NonNegativeInt = DEFAULT_MACHINE_PRECISION
40
43
  expression: PydanticExpressionStr
41
44
  definitions: Dict[str, ValidDefinitions]
42
45
  qubit_count: Optional[pydantic.NonNegativeInt] = None
@@ -19,7 +19,9 @@ from classiq.interface.generator.arith.ast_node_rewrite import (
19
19
  from classiq.exceptions import ClassiqArithmeticError
20
20
 
21
21
  _MULTIPLE_RESULTS_ERROR_MESSAGE: str = "Expression cannot contain multiple result"
22
- _TRIVIAL_ARITHMETIC_ERROR_MESSAGE: str = "Expression must be nontrivial"
22
+ _UNEXPECTED_ARITHMETIC_ERROR_MESSAGE: str = (
23
+ "Unexpected arithmetic error: trivial expression. Please contact support."
24
+ )
23
25
  _ALLOWED_MULTI_ARGUMENT_FUNCTIONS = ("min", "max")
24
26
  Node = Union[str, float, int]
25
27
 
@@ -34,6 +36,10 @@ class ExpressionVisitor(ExpressionValidator):
34
36
  super().__init__(supported_nodes, expression_type, supported_functions)
35
37
  self.graph = nx.DiGraph()
36
38
 
39
+ @classmethod
40
+ def rewrite_ast(cls, expression_ast: AST) -> AST:
41
+ return AstNodeRewrite().visit(expression_ast)
42
+
37
43
  def visit_Compare(self, node: ast.Compare) -> None:
38
44
  self.validate_Compare(node)
39
45
  self.update_graph(node, node.left, node.comparators[0])
@@ -122,7 +128,7 @@ class InDegreeLimiter:
122
128
  if num_results > 1:
123
129
  raise ClassiqArithmeticError(_MULTIPLE_RESULTS_ERROR_MESSAGE)
124
130
  elif num_results == 0:
125
- raise ClassiqArithmeticError(_TRIVIAL_ARITHMETIC_ERROR_MESSAGE)
131
+ raise ClassiqArithmeticError(_UNEXPECTED_ARITHMETIC_ERROR_MESSAGE)
126
132
  return graph
127
133
 
128
134