classiq 0.37.1__py3-none-any.whl → 0.39.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 (280) hide show
  1. classiq/__init__.py +23 -24
  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 +37 -17
  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 +24 -6
  10. classiq/_internals/jobs.py +10 -7
  11. classiq/analyzer/analyzer.py +29 -29
  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/__init__.py +1 -8
  16. classiq/applications/chemistry/__init__.py +6 -0
  17. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +9 -16
  18. classiq/applications/combinatorial_helpers/allowed_constraints.py +20 -0
  19. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  20. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
  21. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +150 -0
  22. classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
  23. classiq/applications/combinatorial_helpers/encoding_utils.py +122 -0
  24. classiq/applications/combinatorial_helpers/memory.py +77 -0
  25. classiq/applications/combinatorial_helpers/optimization_model.py +162 -0
  26. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  27. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +75 -0
  28. classiq/applications/combinatorial_helpers/py.typed +0 -0
  29. classiq/applications/combinatorial_helpers/pyomo_utils.py +245 -0
  30. classiq/applications/combinatorial_helpers/solvers/__init__.py +0 -0
  31. classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
  32. classiq/applications/combinatorial_helpers/transformations/__init__.py +0 -0
  33. classiq/applications/combinatorial_helpers/transformations/encoding.py +187 -0
  34. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +142 -0
  35. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +122 -0
  36. classiq/applications/combinatorial_helpers/transformations/penalty.py +32 -0
  37. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
  38. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +75 -0
  39. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +88 -0
  40. classiq/applications/combinatorial_optimization/__init__.py +13 -2
  41. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +134 -0
  42. classiq/applications/finance/__init__.py +3 -2
  43. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +27 -30
  44. classiq/applications/grover/__init__.py +11 -0
  45. classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +20 -91
  46. classiq/applications/libraries/__init__.py +0 -0
  47. classiq/applications/libraries/qmci_library.py +35 -0
  48. classiq/applications/qnn/circuit_utils.py +2 -2
  49. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  50. classiq/applications/qnn/types.py +2 -2
  51. classiq/applications/qsvm/__init__.py +5 -1
  52. classiq/applications/qsvm/qsvm.py +4 -7
  53. classiq/applications/qsvm/qsvm_data_generation.py +2 -5
  54. classiq/exceptions.py +43 -1
  55. classiq/execution/all_hardware_devices.py +13 -0
  56. classiq/executor.py +12 -10
  57. classiq/interface/_version.py +1 -1
  58. classiq/interface/analyzer/analysis_params.py +6 -3
  59. classiq/interface/analyzer/result.py +12 -8
  60. classiq/interface/applications/qsvm.py +17 -3
  61. classiq/interface/ast_node.py +23 -0
  62. classiq/interface/backend/backend_preferences.py +4 -2
  63. classiq/interface/backend/pydantic_backend.py +3 -1
  64. classiq/interface/backend/quantum_backend_providers.py +1 -0
  65. classiq/interface/chemistry/fermionic_operator.py +15 -13
  66. classiq/interface/chemistry/ground_state_problem.py +18 -3
  67. classiq/interface/chemistry/molecule.py +8 -6
  68. classiq/interface/chemistry/operator.py +20 -14
  69. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
  70. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  71. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  72. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
  73. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  74. classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
  75. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  76. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  77. classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
  78. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  79. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  80. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
  81. classiq/interface/executor/aws_execution_cost.py +4 -3
  82. classiq/interface/executor/estimation.py +2 -2
  83. classiq/interface/executor/execution_preferences.py +5 -34
  84. classiq/interface/executor/execution_request.py +15 -48
  85. classiq/interface/executor/optimizer_preferences.py +22 -13
  86. classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
  87. classiq/interface/executor/quantum_instruction_set.py +2 -1
  88. classiq/interface/executor/register_initialization.py +1 -3
  89. classiq/interface/executor/result.py +41 -10
  90. classiq/interface/executor/vqe_result.py +2 -2
  91. classiq/interface/finance/function_input.py +17 -4
  92. classiq/interface/finance/gaussian_model_input.py +3 -1
  93. classiq/interface/finance/log_normal_model_input.py +3 -1
  94. classiq/interface/finance/model_input.py +2 -0
  95. classiq/interface/generator/amplitude_loading.py +6 -3
  96. classiq/interface/generator/application_apis/__init__.py +1 -0
  97. classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
  98. classiq/interface/generator/arith/argument_utils.py +14 -4
  99. classiq/interface/generator/arith/arithmetic.py +3 -1
  100. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
  101. classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
  102. classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
  103. classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
  104. classiq/interface/generator/arith/arithmetic_operations.py +5 -10
  105. classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
  106. classiq/interface/generator/arith/binary_ops.py +202 -54
  107. classiq/interface/generator/arith/extremum_operations.py +5 -3
  108. classiq/interface/generator/arith/logical_ops.py +4 -2
  109. classiq/interface/generator/arith/machine_precision.py +3 -0
  110. classiq/interface/generator/arith/number_utils.py +34 -44
  111. classiq/interface/generator/arith/register_user_input.py +21 -1
  112. classiq/interface/generator/arith/unary_ops.py +16 -25
  113. classiq/interface/generator/builtin_api_builder.py +0 -5
  114. classiq/interface/generator/chemistry_function_params.py +4 -4
  115. classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
  116. classiq/interface/generator/compiler_keywords.py +4 -0
  117. classiq/interface/generator/complex_type.py +3 -10
  118. classiq/interface/generator/constant.py +2 -3
  119. classiq/interface/generator/control_state.py +5 -3
  120. classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
  121. classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
  122. classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
  123. classiq/interface/generator/expressions/evaluated_expression.py +18 -4
  124. classiq/interface/generator/expressions/expression.py +3 -5
  125. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
  126. classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
  127. classiq/interface/generator/finance.py +1 -1
  128. classiq/interface/generator/function_params.py +7 -6
  129. classiq/interface/generator/functions/__init__.py +2 -2
  130. classiq/interface/generator/functions/builtins/__init__.py +15 -0
  131. classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
  132. classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
  133. classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
  134. classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +612 -219
  135. classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
  136. classiq/interface/generator/functions/classical_type.py +2 -4
  137. classiq/interface/generator/functions/foreign_function_definition.py +12 -4
  138. classiq/interface/generator/functions/function_declaration.py +2 -2
  139. classiq/interface/generator/functions/function_implementation.py +8 -4
  140. classiq/interface/generator/functions/native_function_definition.py +4 -2
  141. classiq/interface/generator/functions/register.py +4 -2
  142. classiq/interface/generator/functions/register_mapping_data.py +14 -10
  143. classiq/interface/generator/generated_circuit_data.py +2 -2
  144. classiq/interface/generator/grover_operator.py +5 -3
  145. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
  146. classiq/interface/generator/hardware/hardware_data.py +6 -4
  147. classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
  148. classiq/interface/generator/hartree_fock.py +13 -3
  149. classiq/interface/generator/linear_pauli_rotations.py +3 -1
  150. classiq/interface/generator/mcu.py +5 -3
  151. classiq/interface/generator/mcx.py +7 -5
  152. classiq/interface/generator/model/classical_main_validator.py +1 -1
  153. classiq/interface/generator/model/constraints.py +2 -1
  154. classiq/interface/generator/model/model.py +12 -20
  155. classiq/interface/generator/model/preferences/preferences.py +4 -3
  156. classiq/interface/generator/oracles/custom_oracle.py +4 -2
  157. classiq/interface/generator/oracles/oracle_abc.py +2 -2
  158. classiq/interface/generator/qpe.py +6 -4
  159. classiq/interface/generator/qsvm.py +5 -8
  160. classiq/interface/generator/quantum_function_call.py +21 -16
  161. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
  162. classiq/interface/generator/range_types.py +3 -1
  163. classiq/interface/generator/slice_parsing_utils.py +8 -3
  164. classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
  165. classiq/interface/generator/state_preparation/metrics.py +2 -1
  166. classiq/interface/generator/state_preparation/state_preparation.py +7 -5
  167. classiq/interface/generator/state_propagator.py +16 -5
  168. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
  169. classiq/interface/generator/types/struct_declaration.py +10 -7
  170. classiq/interface/generator/ucc.py +6 -4
  171. classiq/interface/generator/unitary_gate.py +7 -3
  172. classiq/interface/generator/validations/flow_graph.py +6 -4
  173. classiq/interface/generator/validations/validator_functions.py +6 -4
  174. classiq/interface/hardware.py +2 -2
  175. classiq/interface/helpers/custom_encoders.py +3 -0
  176. classiq/interface/helpers/pydantic_model_helpers.py +0 -6
  177. classiq/interface/helpers/validation_helpers.py +1 -1
  178. classiq/interface/helpers/versioned_model.py +4 -1
  179. classiq/interface/ide/show.py +2 -2
  180. classiq/interface/jobs.py +72 -3
  181. classiq/interface/model/bind_operation.py +18 -11
  182. classiq/interface/model/call_synthesis_data.py +68 -0
  183. classiq/interface/model/classical_if.py +13 -0
  184. classiq/interface/model/classical_parameter_declaration.py +2 -3
  185. classiq/interface/model/control.py +16 -0
  186. classiq/interface/model/handle_binding.py +3 -2
  187. classiq/interface/model/inplace_binary_operation.py +2 -2
  188. classiq/interface/model/invert.py +10 -0
  189. classiq/interface/model/model.py +29 -22
  190. classiq/interface/model/native_function_definition.py +3 -5
  191. classiq/interface/model/power.py +12 -0
  192. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
  193. classiq/interface/model/quantum_expressions/control_state.py +2 -2
  194. classiq/interface/model/quantum_function_call.py +33 -142
  195. classiq/interface/model/quantum_function_declaration.py +8 -0
  196. classiq/interface/model/quantum_if_operation.py +4 -5
  197. classiq/interface/model/quantum_lambda_function.py +58 -0
  198. classiq/{quantum_register.py → interface/model/quantum_register.py} +17 -9
  199. classiq/interface/model/quantum_statement.py +3 -2
  200. classiq/interface/model/quantum_type.py +58 -59
  201. classiq/interface/model/quantum_variable_declaration.py +3 -3
  202. classiq/interface/model/repeat.py +13 -0
  203. classiq/interface/model/resolvers/function_call_resolver.py +26 -0
  204. classiq/interface/model/statement_block.py +49 -0
  205. classiq/interface/model/validations/handles_validator.py +16 -18
  206. classiq/interface/model/within_apply_operation.py +11 -0
  207. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  208. classiq/interface/server/routes.py +5 -4
  209. classiq/qmod/__init__.py +13 -6
  210. classiq/qmod/builtins/classical_execution_primitives.py +27 -36
  211. classiq/qmod/builtins/classical_functions.py +22 -12
  212. classiq/qmod/builtins/functions.py +272 -328
  213. classiq/qmod/builtins/operations.py +171 -35
  214. classiq/qmod/builtins/structs.py +15 -15
  215. classiq/qmod/cfunc.py +42 -0
  216. classiq/qmod/classical_function.py +6 -14
  217. classiq/qmod/declaration_inferrer.py +12 -21
  218. classiq/qmod/expression_query.py +23 -0
  219. classiq/qmod/model_state_container.py +2 -0
  220. classiq/qmod/native/__init__.py +0 -0
  221. classiq/qmod/native/expression_to_qmod.py +189 -0
  222. classiq/qmod/native/pretty_printer.py +340 -0
  223. classiq/qmod/qfunc.py +27 -0
  224. classiq/qmod/qmod_constant.py +100 -0
  225. classiq/qmod/qmod_parameter.py +36 -13
  226. classiq/qmod/qmod_struct.py +3 -3
  227. classiq/qmod/qmod_variable.py +148 -31
  228. classiq/qmod/quantum_callable.py +1 -0
  229. classiq/qmod/quantum_expandable.py +18 -19
  230. classiq/qmod/quantum_function.py +41 -8
  231. classiq/qmod/symbolic.py +48 -5
  232. classiq/qmod/symbolic_expr.py +9 -0
  233. classiq/qmod/utilities.py +13 -0
  234. classiq/qmod/write_qmod.py +39 -0
  235. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/METADATA +2 -1
  236. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/RECORD +244 -225
  237. {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/WHEEL +1 -1
  238. classiq/applications/benchmarking/__init__.py +0 -9
  239. classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
  240. classiq/applications/numpy_utils.py +0 -37
  241. classiq/applications_model_constructors/__init__.py +0 -17
  242. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
  243. classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
  244. classiq/builtin_functions/__init__.py +0 -43
  245. classiq/builtin_functions/amplitude_loading.py +0 -3
  246. classiq/builtin_functions/binary_ops.py +0 -1
  247. classiq/builtin_functions/exponentiation.py +0 -5
  248. classiq/builtin_functions/qpe.py +0 -4
  249. classiq/builtin_functions/qsvm.py +0 -7
  250. classiq/builtin_functions/range_types.py +0 -5
  251. classiq/builtin_functions/standard_gates.py +0 -1
  252. classiq/builtin_functions/state_preparation.py +0 -6
  253. classiq/builtin_functions/suzuki_trotter.py +0 -3
  254. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  255. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  256. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
  257. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  258. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  259. classiq/interface/model/numeric_reinterpretation.py +0 -25
  260. classiq/interface/model/operator_synthesis_data.py +0 -48
  261. classiq/model/__init__.py +0 -14
  262. classiq/model/composite_function_generator.py +0 -33
  263. classiq/model/function_handler.py +0 -466
  264. classiq/model/function_handler.pyi +0 -152
  265. classiq/model/logic_flow.py +0 -149
  266. classiq/model/logic_flow_change_handler.py +0 -71
  267. classiq/model/model.py +0 -246
  268. classiq/quantum_functions/__init__.py +0 -17
  269. classiq/quantum_functions/annotation_parser.py +0 -207
  270. classiq/quantum_functions/decorators.py +0 -22
  271. classiq/quantum_functions/function_library.py +0 -181
  272. classiq/quantum_functions/function_parser.py +0 -74
  273. classiq/quantum_functions/quantum_function.py +0 -236
  274. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
  275. /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
  276. /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/pauli_helpers/__init__.py} +0 -0
  277. /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
  278. /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
  279. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +0 -0
  280. /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +0 -0
@@ -0,0 +1,189 @@
1
+ import ast
2
+ import re
3
+ from dataclasses import dataclass
4
+ from typing import Callable, Dict, List, Mapping, Type
5
+
6
+ import numpy as np
7
+
8
+ from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
9
+
10
+ IDENTIFIER = re.compile(r"[a-zA-Z_]\w*")
11
+ BINARY_OPS: Mapping[Type[ast.operator], str] = {
12
+ ast.Add: "+",
13
+ ast.Sub: "-",
14
+ ast.Mult: "*",
15
+ ast.Div: "/",
16
+ ast.Mod: "%",
17
+ ast.Pow: "**",
18
+ ast.BitAnd: "&",
19
+ ast.BitOr: "|",
20
+ ast.BitXor: "^",
21
+ ast.LShift: "<<",
22
+ ast.RShift: ">>",
23
+ }
24
+ BOOL_OPS: Mapping[Type[ast.boolop], str] = {ast.And: "and", ast.Or: "or"}
25
+ UNARY_OPS: Mapping[Type[ast.unaryop], str] = {
26
+ ast.UAdd: "+",
27
+ ast.USub: "-",
28
+ ast.Invert: "~",
29
+ ast.Not: "not",
30
+ }
31
+ COMPARE_OPS: Mapping[Type[ast.cmpop], str] = {
32
+ ast.Eq: "==",
33
+ ast.NotEq: "!=",
34
+ ast.Lt: "<",
35
+ ast.LtE: "<=",
36
+ ast.Gt: ">",
37
+ ast.GtE: ">=",
38
+ }
39
+ LIST_FORMAT_CHAR_LIMIT = 20
40
+
41
+
42
+ @dataclass
43
+ class ASTToQMODCode:
44
+ level: int
45
+ decimal_precision: int
46
+ indent_seq: str = " "
47
+
48
+ @property
49
+ def indent(self) -> str:
50
+ return self.level * self.indent_seq
51
+
52
+ def visit(self, node: ast.AST) -> str:
53
+ return self.ast_to_code(node)
54
+
55
+ def ast_to_code(self, node: ast.AST) -> str:
56
+ if isinstance(node, ast.Module):
57
+ return self.indent.join(self.ast_to_code(child) for child in node.body)
58
+ elif isinstance(node, ast.Attribute):
59
+ # Enum attribute access
60
+ if not isinstance(node.value, ast.Name) or not isinstance(node.attr, str):
61
+ raise AssertionError("Error parsing enum attribute access")
62
+ if not (IDENTIFIER.match(node.value.id) and IDENTIFIER.match(node.attr)):
63
+ raise AssertionError("Error parsing enum attribute access")
64
+ return f"{node.value.id!s}::{node.attr!s}"
65
+ elif isinstance(node, ast.Name):
66
+ return node.id
67
+ elif isinstance(node, ast.Num):
68
+ return str(np.round(node.n, self.decimal_precision))
69
+ elif isinstance(node, ast.Str):
70
+ return repr(node.s)
71
+ elif isinstance(node, ast.Constant):
72
+ return repr(node.value)
73
+ elif isinstance(node, ast.BinOp):
74
+ return "({} {} {})".format(
75
+ self.ast_to_code(node.left),
76
+ BINARY_OPS[type(node.op)],
77
+ self.ast_to_code(node.right),
78
+ )
79
+ elif isinstance(node, ast.UnaryOp):
80
+ unary_op = UNARY_OPS[type(node.op)]
81
+ space = " " if unary_op == "not" else ""
82
+ return f"({unary_op}{space}{self.ast_to_code(node.operand)})"
83
+ elif isinstance(node, ast.BoolOp):
84
+ return "({})".format(
85
+ (" " + BOOL_OPS[type(node.op)] + " ").join(
86
+ self.ast_to_code(value) for value in node.values
87
+ )
88
+ )
89
+ elif isinstance(node, ast.Compare):
90
+ if len(node.ops) != 1 or len(node.comparators) != 1:
91
+ raise AssertionError("Error parsing comparison expression.")
92
+ return "({} {} {})".format(
93
+ self.ast_to_code(node.left),
94
+ COMPARE_OPS[type(node.ops[0])],
95
+ self.ast_to_code(node.comparators[0]),
96
+ )
97
+ elif isinstance(node, ast.List):
98
+ elts = node.elts
99
+ elements = self.indent_items(
100
+ lambda: [self.ast_to_code(element) for element in elts]
101
+ )
102
+ return f"[{elements}]"
103
+ elif isinstance(node, ast.Subscript):
104
+ return f"{self.ast_to_code(node.value)}[{_remove_redundant_parentheses(self.ast_to_code(node.slice))}]"
105
+ elif isinstance(node, ast.Slice):
106
+ # A QMOD expression does not support slice step
107
+ if node.lower is None or node.upper is None or node.step is not None:
108
+ raise AssertionError("Error parsing slice expression.")
109
+ return f"{self.ast_to_code(node.lower)}:{self.ast_to_code(node.upper)}"
110
+ elif isinstance(node, ast.Call):
111
+ func = self.ast_to_code(node.func)
112
+ if func == "get_field":
113
+ if len(node.args) != 2:
114
+ raise AssertionError("Error parsing struct field access.")
115
+ field = str(self.ast_to_code(node.args[1])).replace("'", "")
116
+ if not IDENTIFIER.match(field):
117
+ raise AssertionError("Error parsing struct field access.")
118
+ return f"{self.ast_to_code(node.args[0])}.{field}"
119
+ elif func == "struct_literal":
120
+ if len(node.args) != 1 or not isinstance(node.args[0], ast.Name):
121
+ raise AssertionError("Error parsing struct literal.")
122
+ keywords = node.keywords
123
+ initializer_list = self.indent_items(
124
+ lambda: [
125
+ f"{keyword.arg} = {self._cleaned_ast_to_code(keyword.value)}"
126
+ for keyword in keywords
127
+ if keyword.arg is not None
128
+ ]
129
+ )
130
+ return f"{self.ast_to_code(node.args[0])} {{{initializer_list}}}"
131
+ else:
132
+ return "{}({})".format(
133
+ func, ", ".join(self._cleaned_ast_to_code(arg) for arg in node.args)
134
+ )
135
+ elif isinstance(node, ast.Expr):
136
+ return self._cleaned_ast_to_code(node.value)
137
+ else:
138
+ raise AssertionError("Error parsing expression: unsupported AST node.")
139
+
140
+ def indent_items(self, items: Callable[[], List[str]]) -> str:
141
+ should_indent = (
142
+ len("".join([i.strip() for i in items()])) >= LIST_FORMAT_CHAR_LIMIT
143
+ )
144
+ if should_indent:
145
+ self.level += 1
146
+ left_ws = "\n" + self.indent
147
+ inner_ws = ",\n" + self.indent
148
+ else:
149
+ left_ws = ""
150
+ inner_ws = ", "
151
+ items_ = items()
152
+ if should_indent:
153
+ self.level -= 1
154
+ right_ws = "\n" + self.indent
155
+ else:
156
+ right_ws = ""
157
+ return f"{left_ws}{inner_ws.join(items_)}{right_ws}"
158
+
159
+ def _cleaned_ast_to_code(self, node: ast.AST) -> str:
160
+ return _remove_redundant_parentheses(self.ast_to_code(node))
161
+
162
+
163
+ def _remove_redundant_parentheses(expr: str) -> str:
164
+ if not (expr.startswith("(") and expr.endswith(")")):
165
+ return expr
166
+ parentheses_map: Dict[int, int] = dict()
167
+ stack: List[int] = []
168
+ for index, char in enumerate(expr):
169
+ if char == "(":
170
+ stack.append(index)
171
+ elif char == ")":
172
+ parentheses_map[stack.pop()] = index
173
+ index = 0
174
+ original_length = len(expr)
175
+ while (
176
+ index in parentheses_map
177
+ and parentheses_map[index] == original_length - index - 1
178
+ ):
179
+ expr = expr[1:-1]
180
+ index += 1
181
+ return expr
182
+
183
+
184
+ def transform_expression(
185
+ expr: str, level: int = 0, decimal_precision: int = DEFAULT_DECIMAL_PRECISION
186
+ ) -> str:
187
+ return ASTToQMODCode(level=level, decimal_precision=decimal_precision).visit(
188
+ ast.parse(expr)
189
+ )
@@ -0,0 +1,340 @@
1
+ from typing import Dict, List
2
+
3
+ from classiq.interface.generator.constant import Constant
4
+ from classiq.interface.generator.expressions.expression import Expression
5
+ from classiq.interface.generator.functions.classical_type import (
6
+ ClassicalArray,
7
+ ConcreteClassicalType,
8
+ )
9
+ from classiq.interface.generator.functions.port_declaration import (
10
+ PortDeclarationDirection,
11
+ )
12
+ from classiq.interface.generator.visitor import NodeType, Visitor
13
+ from classiq.interface.model.bind_operation import BindOperation
14
+ from classiq.interface.model.classical_if import ClassicalIf
15
+ from classiq.interface.model.classical_parameter_declaration import (
16
+ ClassicalParameterDeclaration,
17
+ )
18
+ from classiq.interface.model.control import Control
19
+ from classiq.interface.model.handle_binding import (
20
+ HandleBinding,
21
+ SlicedHandleBinding,
22
+ SubscriptHandleBinding,
23
+ )
24
+ from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
25
+ from classiq.interface.model.invert import Invert
26
+ from classiq.interface.model.model import Model
27
+ from classiq.interface.model.native_function_definition import NativeFunctionDefinition
28
+ from classiq.interface.model.port_declaration import PortDeclaration
29
+ from classiq.interface.model.power import Power
30
+ from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
31
+ AmplitudeLoadingOperation,
32
+ )
33
+ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
34
+ ArithmeticOperation,
35
+ )
36
+ from classiq.interface.model.quantum_function_call import (
37
+ OperandIdentifier,
38
+ QuantumFunctionCall,
39
+ )
40
+ from classiq.interface.model.quantum_function_declaration import (
41
+ QuantumFunctionDeclaration,
42
+ QuantumOperandDeclaration,
43
+ )
44
+ from classiq.interface.model.quantum_if_operation import QuantumIf
45
+ from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
46
+ from classiq.interface.model.quantum_type import (
47
+ QuantumBit,
48
+ QuantumBitvector,
49
+ QuantumNumeric,
50
+ )
51
+ from classiq.interface.model.quantum_variable_declaration import (
52
+ QuantumVariableDeclaration,
53
+ )
54
+ from classiq.interface.model.repeat import Repeat
55
+ from classiq.interface.model.statement_block import StatementBlock
56
+ from classiq.interface.model.variable_declaration_statement import (
57
+ VariableDeclarationStatement,
58
+ )
59
+ from classiq.interface.model.within_apply_operation import WithinApply
60
+
61
+ from classiq import Bool, ClassicalList, Integer, Pauli, Real, Struct, StructDeclaration
62
+ from classiq.qmod.native.expression_to_qmod import transform_expression
63
+ from classiq.qmod.utilities import DEFAULT_DECIMAL_PRECISION
64
+
65
+
66
+ class DSLPrettyPrinter(Visitor):
67
+ def __init__(self, decimal_precision: int = DEFAULT_DECIMAL_PRECISION) -> None:
68
+ self._level = 0
69
+ self._decimal_precision = decimal_precision
70
+
71
+ def visit(self, node: NodeType) -> str:
72
+ res = super().visit(node)
73
+ if not isinstance(res, str):
74
+ raise AssertionError(f"Pretty printing for {type(node)} is not supported ")
75
+ return res
76
+
77
+ def visit_Model(self, model: Model) -> str:
78
+ struct_decls = [self.visit(struct_decl) for struct_decl in model.types]
79
+ func_defs = [self.visit(func_def) for func_def in model.functions]
80
+ constants = [self.visit(constant) for constant in model.constants]
81
+ classical_code = (
82
+ f"cscope ```\n{model.classical_execution_code}\n```"
83
+ if model.classical_execution_code
84
+ else ""
85
+ )
86
+ return "\n".join([*constants, *struct_decls, *func_defs, classical_code])
87
+
88
+ def visit_Constant(self, constant: Constant) -> str:
89
+ return f"{self._indent}{self.visit(constant.name)}: {self.visit(constant.const_type)} = {self.visit(constant.value)};\n"
90
+
91
+ def _visit_arg_decls(self, func_def: QuantumFunctionDeclaration) -> str:
92
+ gen_time_args = ", ".join(
93
+ self.visit(arg_decl)
94
+ for arg_decl in func_def.get_positional_arg_decls()
95
+ if not isinstance(arg_decl, PortDeclaration)
96
+ )
97
+ quantum_args = ", ".join(
98
+ self.visit(arg_decl)
99
+ for arg_decl in func_def.get_positional_arg_decls()
100
+ if isinstance(arg_decl, PortDeclaration)
101
+ )
102
+ gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
103
+ return f"{gen_time_arg_list}({quantum_args})"
104
+
105
+ def visit_QuantumFunctionDeclaration(
106
+ self, func_decl: QuantumFunctionDeclaration
107
+ ) -> str:
108
+ return f"qfunc {func_decl.name}{self._visit_arg_decls(func_decl)}"
109
+
110
+ def visit_StructDeclaration(self, struct_decl: StructDeclaration) -> str:
111
+ return f"struct {struct_decl.name} {{\n{self._visit_variables(struct_decl.variables)}}}\n"
112
+
113
+ def _visit_variables(self, variables: Dict[str, ConcreteClassicalType]) -> str:
114
+ self._level += 1
115
+ variables_str = "".join(
116
+ f"{self._indent}{self.visit(field_name)}: {self.visit(var_decl)};\n"
117
+ for field_name, var_decl in variables.items()
118
+ )
119
+ self._level -= 1
120
+ return variables_str
121
+
122
+ def visit_QuantumVariableDeclaration(
123
+ self, var_decl: QuantumVariableDeclaration
124
+ ) -> str:
125
+ return f"{var_decl.name}: {self.visit(var_decl.quantum_type)}"
126
+
127
+ def visit_PortDeclaration(self, port_decl: PortDeclaration) -> str:
128
+ dir_str = (
129
+ f"{port_decl.direction} "
130
+ if port_decl.direction != PortDeclarationDirection.Inout
131
+ else ""
132
+ )
133
+ return f"{dir_str}{self.visit_QuantumVariableDeclaration(port_decl)}"
134
+
135
+ def visit_QuantumBit(self, qtype: QuantumBit) -> str:
136
+ return "qbit"
137
+
138
+ def visit_QuantumBitvector(self, qtype: QuantumBitvector) -> str:
139
+ if qtype.length is not None:
140
+ if qtype.length.is_evaluated() and qtype.length.to_int_value() == 1:
141
+ return "qbit"
142
+ return f"qbit[{self.visit(qtype.length)}]"
143
+ return "qbit[]"
144
+
145
+ def visit_QuantumNumeric(self, qtype: QuantumNumeric) -> str:
146
+ params = ""
147
+ if qtype.size is not None:
148
+ assert qtype.is_signed is not None
149
+ assert qtype.fraction_digits is not None
150
+
151
+ params = "<{}>".format(
152
+ ", ".join(
153
+ self.visit(param)
154
+ for param in [qtype.size, qtype.is_signed, qtype.fraction_digits]
155
+ )
156
+ )
157
+
158
+ return f"qnum{params}"
159
+
160
+ def visit_ClassicalParameterDeclaration(
161
+ self, cparam: ClassicalParameterDeclaration
162
+ ) -> str:
163
+ return f"{cparam.name}: {self.visit(cparam.classical_type)}"
164
+
165
+ def visit_Integer(self, ctint: Integer) -> str:
166
+ return "int"
167
+
168
+ def visit_Real(self, ctint: Real) -> str:
169
+ return "real"
170
+
171
+ def visit_Bool(self, ctbool: Bool) -> str:
172
+ return "bool"
173
+
174
+ def visit_Pauli(self, ctbool: Pauli) -> str:
175
+ return "Pauli"
176
+
177
+ def visit_ClassicalList(self, ctlist: ClassicalList) -> str:
178
+ return f"{self.visit(ctlist.element_type)}[]"
179
+
180
+ def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
181
+ return f"{self.visit(ctarray.element_type)}[{ctarray.size}]"
182
+
183
+ def visit_Struct(self, struct: Struct) -> str:
184
+ return struct.name
185
+
186
+ def visit_VariableDeclarationStatement(
187
+ self, local_decl: VariableDeclarationStatement
188
+ ) -> str:
189
+ return f"{self._indent}{self.visit_QuantumVariableDeclaration(local_decl)};\n"
190
+
191
+ def visit_QuantumOperandDeclaration(
192
+ self, op_decl: QuantumOperandDeclaration
193
+ ) -> str:
194
+ return f"{op_decl.name}: qfunc{[] if op_decl.is_list else ''} {self._visit_arg_decls(op_decl)}"
195
+
196
+ def visit_NativeFunctionDefinition(self, func_def: NativeFunctionDefinition) -> str:
197
+ self._level += 1
198
+ body = "".join(self.visit(qvar_decl) for qvar_decl in func_def.body)
199
+ self._level -= 1
200
+ return f"{self.visit_QuantumFunctionDeclaration(func_def)} {{\n{body}}}\n"
201
+
202
+ def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
203
+ gen_time_args = ", ".join(
204
+ self.visit(arg_decl)
205
+ for arg_decl in func_call.get_positional_args()
206
+ if not isinstance(arg_decl, HandleBinding)
207
+ )
208
+ gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
209
+ quantum_args = ", ".join(
210
+ self.visit(arg_decl)
211
+ for arg_decl in func_call.get_positional_args()
212
+ if isinstance(arg_decl, HandleBinding)
213
+ )
214
+ return f"{self._indent}{func_call.func_name}{f'[{self.visit(func_call.function.index)}]' if isinstance(func_call.function, OperandIdentifier) else ''}{gen_time_arg_list}({quantum_args});\n"
215
+
216
+ def visit_Control(self, control: Control) -> str:
217
+ control_code = f"{self._indent}control ({self.visit(control.control)}) {{\n"
218
+ control_code += self._visit_body(control.body)
219
+ control_code += f"{self._indent}}}\n"
220
+ return control_code
221
+
222
+ def visit_QuantumIf(self, op: QuantumIf) -> str:
223
+ quantum_if = f"{self._indent}quantum_if ({self.visit(op.expression)}) {{\n"
224
+ quantum_if += self._visit_body(op.then)
225
+ quantum_if += f"{self._indent}}}\n"
226
+ return quantum_if
227
+
228
+ def visit_ClassicalIf(self, op: ClassicalIf) -> str:
229
+ classical_if = f"{self._indent}if ({self.visit(op.condition)}) {{\n"
230
+ if not op.then:
231
+ raise AssertionError('Expected non empty "then" block')
232
+ classical_if += self._visit_body(op.then)
233
+
234
+ if op.else_:
235
+ classical_if += f"{self._indent}}} else {{\n"
236
+ classical_if += self._visit_body(op.else_)
237
+
238
+ classical_if += f"{self._indent}}}\n"
239
+ return classical_if
240
+
241
+ def visit_WithinApply(self, op: WithinApply) -> str:
242
+ within_apply_code = f"{self._indent}within {{\n"
243
+ within_apply_code += self._visit_body(op.compute)
244
+ within_apply_code += f"{self._indent}}} apply {{\n"
245
+ within_apply_code += self._visit_body(op.action)
246
+ within_apply_code += f"{self._indent}}}\n"
247
+ return within_apply_code
248
+
249
+ def visit_Repeat(self, repeat: Repeat) -> str:
250
+ repeat_code = f"{self._indent}repeat ({self.visit(repeat.iter_var)}: {self.visit(repeat.count)}) {{\n"
251
+ repeat_code += self._visit_body(repeat.body)
252
+ repeat_code += f"{self._indent}}}\n"
253
+ return repeat_code
254
+
255
+ def visit_Power(self, power: Power) -> str:
256
+ power_code = f"{self._indent}power ({self.visit(power.power)}) {{\n"
257
+ power_code += self._visit_body(power.body)
258
+ power_code += f"{self._indent}}}\n"
259
+ return power_code
260
+
261
+ def visit_Invert(self, invert: Invert) -> str:
262
+ invert_code = f"{self._indent}invert {{\n"
263
+ invert_code += self._visit_body(invert.body)
264
+ invert_code += f"{self._indent}}}\n"
265
+ return invert_code
266
+
267
+ def _visit_body(self, body: StatementBlock) -> str:
268
+ code = ""
269
+ self._level += 1
270
+ for statement in body:
271
+ code += self.visit(statement)
272
+ self._level -= 1
273
+ return code
274
+
275
+ def visit_InplaceBinaryOperation(self, op: InplaceBinaryOperation) -> str:
276
+ return (
277
+ f"{self._indent}{op.operation.value}({op.value.name}, {op.target.name});\n"
278
+ )
279
+
280
+ def _visit_pack_expr(self, vars: List[HandleBinding]) -> str:
281
+ if len(vars) == 1:
282
+ return self.visit(vars[0])
283
+
284
+ var_list_str = ", ".join(self.visit(var) for var in vars)
285
+ return f"{{{var_list_str}}}"
286
+
287
+ def visit_Expression(self, expr: Expression) -> str:
288
+ return transform_expression(
289
+ expr.expr, level=self._level, decimal_precision=self._decimal_precision
290
+ )
291
+
292
+ def visit_QuantumLambdaFunction(self, qlambda: QuantumLambdaFunction) -> str:
293
+ assert qlambda.func_decl is not None
294
+ gen_time_args = ", ".join(
295
+ qlambda.rename_params.get(arg_decl.name, arg_decl.name)
296
+ for arg_decl in qlambda.func_decl.get_positional_arg_decls()
297
+ if not isinstance(arg_decl, PortDeclaration)
298
+ )
299
+ quantum_args = ", ".join(
300
+ arg_decl.name
301
+ for arg_decl in qlambda.func_decl.get_positional_arg_decls()
302
+ if isinstance(arg_decl, PortDeclaration)
303
+ )
304
+ gen_time_arg_list = f"<{gen_time_args}>" if gen_time_args else ""
305
+ body = self._visit_body(qlambda.body)
306
+ return f"lambda{gen_time_arg_list}({quantum_args}) {{\n{body}{self._indent}}}"
307
+
308
+ def visit_HandleBinding(self, var_ref: HandleBinding) -> str:
309
+ return var_ref.name
310
+
311
+ def visit_SlicedHandleBinding(self, var_ref: SlicedHandleBinding) -> str:
312
+ return str(var_ref)
313
+
314
+ def visit_SubscriptHandleBinding(self, var_ref: SubscriptHandleBinding) -> str:
315
+ return str(var_ref)
316
+
317
+ def visit_ArithmeticOperation(self, arith_op: ArithmeticOperation) -> str:
318
+ op = "^=" if arith_op.inplace_result else "="
319
+ return f"{self._indent}{self.visit(arith_op.result_var)} {op} {self.visit(arith_op.expression)};\n"
320
+
321
+ def visit_AmplitudeLoadingOperation(
322
+ self, amplitude_loading_op: AmplitudeLoadingOperation
323
+ ) -> str:
324
+ return f"{self._indent}{self.visit(amplitude_loading_op.result_var)} *= {self.visit(amplitude_loading_op.expression)};\n"
325
+
326
+ def _print_bind_handles(self, handles: List[HandleBinding]) -> str:
327
+ if len(handles) == 1:
328
+ return self.visit(handles[0])
329
+
330
+ return "{" + ", ".join(self.visit(handle) for handle in handles) + "}"
331
+
332
+ def visit_BindOperation(self, bind_op: BindOperation) -> str:
333
+ return f"{self._indent}{self._print_bind_handles(bind_op.in_handles)} -> {self._print_bind_handles(bind_op.out_handles)};\n"
334
+
335
+ def visit_list(self, node: list) -> str:
336
+ return "[" + ", ".join(self.visit(elem) for elem in node) + "]"
337
+
338
+ @property
339
+ def _indent(self) -> str:
340
+ return " " * self._level
classiq/qmod/qfunc.py ADDED
@@ -0,0 +1,27 @@
1
+ from typing import Callable, Optional, Union, overload
2
+
3
+ from classiq.qmod.quantum_callable import QCallable
4
+ from classiq.qmod.quantum_function import ExternalQFunc, QFunc
5
+
6
+
7
+ @overload
8
+ def qfunc(func: Callable, *, external: bool = False) -> QFunc: ...
9
+
10
+
11
+ @overload
12
+ def qfunc(func: None = None, *, external: bool) -> Callable[[Callable], QCallable]: ...
13
+
14
+
15
+ def qfunc(
16
+ func: Optional[Callable] = None, *, external: bool = False
17
+ ) -> Union[Callable[[Callable], QCallable], QCallable]:
18
+ def wrapper(func: Callable) -> QCallable:
19
+ if external:
20
+ return ExternalQFunc(func)
21
+
22
+ return QFunc(func)
23
+
24
+ if func is not None:
25
+ return wrapper(func)
26
+
27
+ return wrapper
@@ -0,0 +1,100 @@
1
+ import inspect
2
+ from typing import Any, Optional
3
+
4
+ from classiq.interface.generator.constant import Constant
5
+ from classiq.interface.generator.expressions.expression import Expression
6
+ from classiq.interface.generator.functions.classical_type import (
7
+ ClassicalArray,
8
+ ClassicalList,
9
+ QStructBase,
10
+ )
11
+
12
+ from classiq.exceptions import ClassiqError
13
+ from classiq.qmod.declaration_inferrer import python_type_to_qmod
14
+ from classiq.qmod.model_state_container import ModelStateContainer
15
+ from classiq.qmod.qmod_parameter import QParam, QParamList, QParamStruct
16
+
17
+
18
+ class QConstant:
19
+ CURRENT_QMODULE: Optional[ModelStateContainer] = None
20
+
21
+ def __init__(self, name: str, py_type: type, value: Any) -> None:
22
+ self.name = name
23
+ self._py_type = py_type
24
+ self._value = value
25
+
26
+ @staticmethod
27
+ def set_current_model(qmodule: ModelStateContainer) -> None:
28
+ QConstant.CURRENT_QMODULE = qmodule
29
+
30
+ def add_to_model(self) -> None:
31
+ if QConstant.CURRENT_QMODULE is None:
32
+ raise ClassiqError(
33
+ "Error trying to add a constant to a model without a current QModule."
34
+ )
35
+
36
+ expr = str(self._value)
37
+ if (
38
+ self.name in QConstant.CURRENT_QMODULE.constants
39
+ and expr != QConstant.CURRENT_QMODULE.constants[self.name].value.expr
40
+ ):
41
+ raise ClassiqError(f"Constant {self.name} is already defined in the model")
42
+
43
+ if isinstance(self._value, QConstant):
44
+ QConstant.CURRENT_QMODULE.constants[self.name] = Constant(
45
+ name=self.name,
46
+ const_type=QConstant.CURRENT_QMODULE.constants[
47
+ self._value.name
48
+ ].const_type,
49
+ value=Expression(expr=self._value.name),
50
+ )
51
+ else:
52
+ qmod_type = python_type_to_qmod(
53
+ self._py_type, qmodule=QConstant.CURRENT_QMODULE
54
+ )
55
+ if qmod_type is None:
56
+ raise ClassiqError("Invalid QMOD type")
57
+
58
+ QConstant.CURRENT_QMODULE.constants[self.name] = Constant(
59
+ name=self.name,
60
+ const_type=qmod_type,
61
+ value=Expression(expr=expr),
62
+ )
63
+
64
+ def __getattr__(self, name: str) -> QParam:
65
+ self.add_to_model()
66
+
67
+ py_type = type(self._value)
68
+ if (
69
+ QConstant.CURRENT_QMODULE is None
70
+ or not inspect.isclass(py_type)
71
+ or not issubclass(py_type, QStructBase)
72
+ ):
73
+ return self.__getattribute__(name)
74
+
75
+ return QParamStruct.get_field(
76
+ QConstant.CURRENT_QMODULE, self.name, py_type.__name__, name
77
+ )
78
+
79
+ def __getitem__(self, item: Any) -> QParam:
80
+ self.add_to_model()
81
+
82
+ assert QConstant.CURRENT_QMODULE is not None
83
+
84
+ qmod_type = python_type_to_qmod(
85
+ self._py_type, qmodule=QConstant.CURRENT_QMODULE
86
+ )
87
+ if qmod_type is None:
88
+ raise ClassiqError("Invalid QMOD type")
89
+
90
+ if not isinstance(qmod_type, (ClassicalList, ClassicalArray)):
91
+ raise ClassiqError("Invalid subscript to non-list constant")
92
+
93
+ return QParamList(
94
+ self.name,
95
+ qmod_type,
96
+ QConstant.CURRENT_QMODULE,
97
+ )[item]
98
+
99
+ def __str__(self) -> str:
100
+ return self.name