classiq 0.102.0__py3-none-any.whl → 1.0.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 (95) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/_internals/authentication/auth0.py +29 -0
  3. classiq/_internals/authentication/auth_flow_factory.py +43 -0
  4. classiq/_internals/authentication/machine_credentials_flow.py +26 -0
  5. classiq/_internals/authentication/password_manager.py +84 -0
  6. classiq/_internals/authentication/token_manager.py +24 -8
  7. classiq/analyzer/show_interactive_hack.py +0 -8
  8. classiq/applications/chemistry/op_utils.py +32 -0
  9. classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
  10. classiq/evaluators/qmod_annotated_expression.py +1 -1
  11. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
  12. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
  13. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
  14. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
  15. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
  16. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
  17. classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
  18. classiq/execution/all_hardware_devices.py +59 -1
  19. classiq/execution/execution_session.py +1 -1
  20. classiq/execution/functions/__init__.py +13 -0
  21. classiq/execution/functions/expectation_value.py +106 -0
  22. classiq/execution/functions/minimize.py +90 -0
  23. classiq/execution/functions/sample.py +76 -0
  24. classiq/execution/functions/state_vector.py +113 -0
  25. classiq/execution/functions/util/__init__.py +0 -0
  26. classiq/execution/functions/util/_logging.py +19 -0
  27. classiq/execution/functions/util/backend_preferences.py +188 -0
  28. classiq/execution/functions/util/constants.py +9 -0
  29. classiq/execution/functions/util/parse_provider_backend.py +90 -0
  30. classiq/interface/_version.py +1 -1
  31. classiq/interface/backend/backend_preferences.py +81 -0
  32. classiq/interface/backend/provider_config/providers/aqt.py +1 -1
  33. classiq/interface/backend/provider_config/providers/azure.py +1 -2
  34. classiq/interface/backend/provider_config/providers/ibm.py +1 -1
  35. classiq/interface/backend/quantum_backend_providers.py +14 -0
  36. classiq/interface/exceptions.py +0 -4
  37. classiq/interface/executor/result.py +9 -5
  38. classiq/interface/generator/arith/binary_ops.py +62 -2
  39. classiq/interface/generator/arith/number_utils.py +15 -6
  40. classiq/interface/generator/compiler_keywords.py +1 -0
  41. classiq/interface/generator/function_param_list.py +8 -2
  42. classiq/interface/generator/function_params.py +1 -1
  43. classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
  44. classiq/interface/generator/functions/classical_type.py +60 -0
  45. classiq/interface/generator/functions/type_name.py +36 -0
  46. classiq/interface/generator/generated_circuit_data.py +0 -2
  47. classiq/interface/generator/transpiler_basis_gates.py +1 -0
  48. classiq/interface/generator/types/compilation_metadata.py +18 -0
  49. classiq/interface/hardware.py +2 -0
  50. classiq/interface/helpers/model_normalizer.py +42 -6
  51. classiq/interface/interface_version.py +1 -1
  52. classiq/interface/model/invert.py +8 -0
  53. classiq/interface/model/model.py +19 -0
  54. classiq/interface/model/model_visitor.py +4 -2
  55. classiq/interface/model/quantum_type.py +36 -0
  56. classiq/interface/model/statement_block.py +0 -4
  57. classiq/interface/qubits_mapping/__init__.py +4 -0
  58. classiq/interface/qubits_mapping/path_expr_range.py +69 -0
  59. classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
  60. classiq/interface/qubits_mapping/slices.py +112 -0
  61. classiq/model_expansions/arithmetic.py +6 -0
  62. classiq/model_expansions/capturing/captured_vars.py +16 -12
  63. classiq/model_expansions/function_builder.py +9 -1
  64. classiq/model_expansions/interpreters/base_interpreter.py +9 -8
  65. classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
  66. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
  67. classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
  68. classiq/model_expansions/quantum_operations/bind.py +4 -0
  69. classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
  70. classiq/model_expansions/quantum_operations/emitter.py +1 -4
  71. classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
  72. classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
  73. classiq/qmod/builtins/functions/__init__.py +21 -9
  74. classiq/qmod/builtins/functions/allocation.py +0 -36
  75. classiq/qmod/builtins/functions/arithmetic.py +183 -0
  76. classiq/qmod/builtins/functions/exponentiation.py +32 -2
  77. classiq/qmod/builtins/functions/gray_code.py +23 -0
  78. classiq/qmod/builtins/functions/mcx_func.py +10 -0
  79. classiq/qmod/builtins/operations.py +2 -38
  80. classiq/qmod/builtins/structs.py +22 -3
  81. classiq/qmod/native/pretty_printer.py +1 -12
  82. classiq/qmod/pretty_print/pretty_printer.py +1 -17
  83. classiq/qmod/qmod_parameter.py +4 -0
  84. classiq/qmod/qmod_variable.py +38 -63
  85. classiq/qmod/quantum_function.py +43 -7
  86. classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
  87. classiq/qmod/semantics/validation/model_validation.py +7 -2
  88. classiq/qmod/symbolic_type.py +4 -2
  89. classiq/qprog_to_cudaq.py +347 -0
  90. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
  91. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
  92. classiq/interface/generator/amplitude_loading.py +0 -103
  93. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
  94. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
  95. {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  import ast
2
2
  import functools
3
+ import inspect
3
4
  import warnings
4
5
  from abc import abstractmethod
5
6
  from collections.abc import Callable
@@ -8,7 +9,11 @@ from enum import EnumMeta
8
9
  from inspect import isclass
9
10
  from typing import Any, get_origin
10
11
 
11
- from classiq.interface.exceptions import ClassiqDeprecationWarning, ClassiqError
12
+ from classiq.interface.exceptions import (
13
+ ClassiqDeprecationWarning,
14
+ ClassiqError,
15
+ ClassiqExpansionError,
16
+ )
12
17
  from classiq.interface.executor.execution_preferences import ExecutionPreferences
13
18
  from classiq.interface.generator.functions.port_declaration import (
14
19
  PortDeclarationDirection,
@@ -276,10 +281,16 @@ class ExternalQFunc(QTerminalCallable):
276
281
  ClassiqDeprecationWarning,
277
282
  stacklevel=2,
278
283
  )
279
- if (
280
- self._py_callable.__name__ == "suzuki_trotter"
281
- and len(args) > 0
282
- and isinstance(args[0], (list, CParamList))
284
+ if self._py_callable.__name__ == "suzuki_trotter" and (
285
+ (
286
+ "pauli_operator" not in kwargs
287
+ and len(args) > 0
288
+ and isinstance(args[0], (list, CParamList))
289
+ )
290
+ or (
291
+ "pauli_operator" in kwargs
292
+ and isinstance(kwargs["pauli_operator"], (list, CParamList))
293
+ )
283
294
  ):
284
295
  warnings.warn(
285
296
  (
@@ -320,6 +331,19 @@ class ExternalQFunc(QTerminalCallable):
320
331
  ClassiqDeprecationWarning,
321
332
  stacklevel=2,
322
333
  )
334
+ if (
335
+ self._py_callable.__name__ == "unscheduled_suzuki_trotter"
336
+ ): # FIXME: remove (CLS-5391)
337
+ warnings.warn(
338
+ (
339
+ "Function 'unscheduled_suzuki_trotter' was renamed to "
340
+ "'sequential_suzuki_trotter'. 'unscheduled_suzuki_trotter' is "
341
+ "deprecated and will no longer be supported starting on 2026-02-02 "
342
+ "at the earliest."
343
+ ),
344
+ ClassiqDeprecationWarning,
345
+ stacklevel=2,
346
+ )
323
347
  super().__call__(*args, **kwargs)
324
348
 
325
349
 
@@ -348,14 +372,26 @@ class GenerativeQFunc(BaseQFunc):
348
372
  return self._inferred_func_decl
349
373
 
350
374
  def __call__(self, *args: Any, **kwargs: Any) -> None:
375
+ from classiq.qmod.builtins.functions import BUILTIN_FUNCTION_DECLARATIONS
376
+
351
377
  if get_global_declarative_switch():
352
378
  return QFunc(
353
379
  self._py_callable,
354
380
  self.compilation_metadata,
355
381
  permutation=self.permutation,
356
382
  )(*args, **kwargs)
357
- if self.func_decl.name not in self._qmodule.generative_functions:
358
- self._qmodule.generative_functions[self.func_decl.name] = self
383
+ frame = inspect.currentframe()
384
+ caller_frame = frame.f_back if frame is not None else None
385
+ module = inspect.getmodule(caller_frame)
386
+ func_name = self.func_decl.name
387
+ if func_name in BUILTIN_FUNCTION_DECLARATIONS and (
388
+ module is None or not module.__name__.startswith("model.function_library")
389
+ ):
390
+ raise ClassiqExpansionError(
391
+ f"Cannot redefine built-in function {func_name!r}"
392
+ )
393
+ if func_name not in self._qmodule.generative_functions:
394
+ self._qmodule.generative_functions[func_name] = self
359
395
  if self._func_decl is None:
360
396
  self._inferred_func_decl = infer_func_decl(
361
397
  self._py_callable, self._qmodule, permutation=self.permutation
@@ -1,13 +1,16 @@
1
1
  from classiq.interface.exceptions import ClassiqExpansionError
2
2
  from classiq.interface.model.model import Model
3
+ from classiq.interface.model.quantum_function_declaration import (
4
+ NamedParamsQuantumFunctionDeclaration,
5
+ )
3
6
 
4
- from classiq.qmod.builtins.functions import CORE_LIB_DECLS
5
7
 
6
-
7
- def check_function_name_collisions(model: Model) -> None:
8
+ def check_function_name_collisions(
9
+ model: Model, builtin_functions: list[NamedParamsQuantumFunctionDeclaration]
10
+ ) -> None:
8
11
  redefined_functions = [
9
12
  function.name
10
- for function in CORE_LIB_DECLS
13
+ for function in builtin_functions
11
14
  if function.name in model.function_dict
12
15
  ]
13
16
  if len(redefined_functions) == 1:
@@ -1,4 +1,7 @@
1
1
  from classiq.interface.model.model import Model
2
+ from classiq.interface.model.quantum_function_declaration import (
3
+ NamedParamsQuantumFunctionDeclaration,
4
+ )
2
5
 
3
6
  from classiq.qmod.semantics.validation.constants_validation import (
4
7
  check_duplicate_constants,
@@ -14,7 +17,9 @@ from classiq.qmod.semantics.validation.types_validation import (
14
17
  )
15
18
 
16
19
 
17
- def validate_model(model: Model) -> None:
20
+ def validate_model(
21
+ model: Model, builtin_functions: list[NamedParamsQuantumFunctionDeclaration]
22
+ ) -> None:
18
23
  check_duplicate_types([*model.enums, *model.types, *model.qstructs])
19
24
  check_duplicate_constants(model.constants)
20
25
  for qstruct in model.qstructs:
@@ -22,4 +27,4 @@ def validate_model(model: Model) -> None:
22
27
  for cstruct in model.types:
23
28
  validate_cstruct(cstruct)
24
29
  validate_main_function(model.main_func)
25
- check_function_name_collisions(model)
30
+ check_function_name_collisions(model, builtin_functions)
@@ -1,6 +1,8 @@
1
1
  from typing import Union, get_args, get_origin
2
2
 
3
- from classiq.qmod.symbolic_expr import SymbolicExpr
3
+ from classiq.qmod.symbolic_expr import Symbolic
4
4
 
5
- SymbolicTypes = Union[SymbolicExpr, int, float, bool, tuple["SymbolicTypes", ...]]
5
+ SymbolicTypes = Union[
6
+ Symbolic, int, float, bool, tuple["SymbolicTypes", ...], list["SymbolicTypes"]
7
+ ]
6
8
  SYMBOLIC_TYPES = tuple(get_origin(t) or t for t in get_args(SymbolicTypes))
@@ -0,0 +1,347 @@
1
+ import importlib.util
2
+ from typing import TYPE_CHECKING, Any
3
+
4
+ from classiq.interface.exceptions import ClassiqError
5
+ from classiq.interface.generator.quantum_program import QuantumProgram
6
+ from classiq.interface.helpers.text_utils import readable_list
7
+
8
+ if TYPE_CHECKING:
9
+ import cudaq
10
+ import openqasm3
11
+
12
+ _CONVERSION_ERROR_PREFIX = "Cannot convert quantum program to cudaq: "
13
+
14
+
15
+ def _require_cudaq() -> None:
16
+ missing = [m for m in ("cudaq", "openqasm3") if importlib.util.find_spec(m) is None]
17
+ if missing:
18
+ raise ClassiqError(
19
+ "This feature needs the 'cudaq' extra. "
20
+ "Install with: pip install classiq[cudaq] "
21
+ f"(missing: {', '.join(missing)}).\n"
22
+ f"Note: cudaq is only supported on Linux operating systems "
23
+ f"https://nvidia.github.io/cuda-quantum/latest/using/quick_start.html\n"
24
+ f"If you are using a different operating system, consider running on the "
25
+ f"Classiq Studio https://docs.classiq.io/latest/user-guide/studio/Studio-Guide/ "
26
+ f"or a Linux Docker container"
27
+ )
28
+
29
+
30
+ def _get_qasm_ast(quantum_program: QuantumProgram) -> "openqasm3.ast.Program":
31
+ import openqasm3
32
+
33
+ if quantum_program.qasm is None:
34
+ raise ClassiqError(_CONVERSION_ERROR_PREFIX + "missing QASM output format")
35
+ try:
36
+ return openqasm3.parser.parse(quantum_program.qasm)
37
+ except Exception as e:
38
+ raise ClassiqError(
39
+ _CONVERSION_ERROR_PREFIX + "the provided QASM is not supported"
40
+ ) from e
41
+
42
+
43
+ def _get_main_kernel(
44
+ qasm_ast: "openqasm3.ast.Program",
45
+ ) -> tuple["cudaq.PyKernel", dict[str, "cudaq.QuakeValue"]]:
46
+ import cudaq
47
+ import openqasm3
48
+
49
+ classical_inputs: list[str] = []
50
+ for statement in qasm_ast.statements:
51
+ if isinstance(statement, openqasm3.ast.IODeclaration):
52
+ if statement.io_identifier != openqasm3.ast.IOKeyword.input:
53
+ raise ClassiqError(
54
+ _CONVERSION_ERROR_PREFIX + "classical outputs are not supported"
55
+ )
56
+ if not isinstance(statement.type, openqasm3.ast.FloatType):
57
+ raise ClassiqError(
58
+ _CONVERSION_ERROR_PREFIX
59
+ + "only float classical inputs are supported"
60
+ )
61
+ classical_inputs.append(statement.identifier.name)
62
+
63
+ if len(classical_inputs) == 0:
64
+ return cudaq.make_kernel(), {}
65
+ kernel_and_params = cudaq.make_kernel(*((float,) * len(classical_inputs)))
66
+ kernel = kernel_and_params[0]
67
+ params = dict(zip(classical_inputs, kernel_and_params[1:], strict=True))
68
+ return kernel, params
69
+
70
+
71
+ def qprog_to_cudaq_kernel(quantum_program: QuantumProgram) -> "cudaq.PyKernel":
72
+ _require_cudaq()
73
+
74
+ qasm_ast = _get_qasm_ast(quantum_program)
75
+ kernel, params = _get_main_kernel(qasm_ast)
76
+ gates: dict[str, "cudaq.PyKernel"] = {}
77
+ qubits: dict[str, "cudaq.QuakeValue"] = {}
78
+
79
+ for statement in qasm_ast.statements:
80
+ _process_main_statement(kernel, gates, qubits, params, statement)
81
+ return kernel
82
+
83
+
84
+ def _process_main_statement(
85
+ kernel: "cudaq.PyKernel",
86
+ gates: dict[str, "cudaq.PyKernel"],
87
+ qubits: dict[str, "cudaq.QuakeValue"],
88
+ params: dict[str, "cudaq.QuakeValue"],
89
+ statement: "openqasm3.ast.Statement | openqasm3.ast.Pragma",
90
+ ) -> None:
91
+ import cudaq
92
+ import openqasm3
93
+
94
+ if isinstance(statement, (openqasm3.ast.Include, openqasm3.ast.IODeclaration)):
95
+ pass
96
+ elif isinstance(
97
+ statement,
98
+ (
99
+ openqasm3.ast.ClassicalDeclaration,
100
+ openqasm3.ast.BranchingStatement,
101
+ openqasm3.ast.QuantumMeasurementStatement,
102
+ ),
103
+ ):
104
+ raise ClassiqError(
105
+ _CONVERSION_ERROR_PREFIX + "mid-circuit measurements are not supported"
106
+ )
107
+ elif isinstance(statement, openqasm3.ast.QuantumReset):
108
+ raise ClassiqError(
109
+ _CONVERSION_ERROR_PREFIX + "reset instructions are not supported"
110
+ )
111
+ elif isinstance(statement, openqasm3.ast.QubitDeclaration):
112
+ if statement.size is None:
113
+ raise ClassiqError(
114
+ _CONVERSION_ERROR_PREFIX
115
+ + f"qubit declaration {statement.qubit.name!r} has no size"
116
+ )
117
+ if not isinstance(statement.size, openqasm3.ast.IntegerLiteral):
118
+ raise ClassiqError(
119
+ _CONVERSION_ERROR_PREFIX
120
+ + f"the size of qubit declaration {statement.qubit.name!r} must be an integer literal"
121
+ )
122
+ qubits[statement.qubit.name] = kernel.qalloc(statement.size.value)
123
+ elif isinstance(statement, openqasm3.ast.QuantumGateDefinition):
124
+ angle_names = [param.name for param in statement.arguments]
125
+ qubit_names = [param.name for param in statement.qubits]
126
+ kernel_and_params = cudaq.make_kernel(
127
+ *((float,) * len(angle_names)), *((cudaq.qubit,) * len(qubit_names))
128
+ )
129
+ func_kernel = kernel_and_params[0]
130
+ func_params = dict(
131
+ zip(angle_names, kernel_and_params[1 : len(angle_names) + 1], strict=True)
132
+ )
133
+ func_qubits = dict(
134
+ zip(qubit_names, kernel_and_params[len(angle_names) + 1 :], strict=True)
135
+ )
136
+ for gate_statement in statement.body:
137
+ _process_statement(
138
+ func_kernel, gates, func_qubits, func_params, gate_statement
139
+ )
140
+ gates[statement.name.name] = func_kernel
141
+ else:
142
+ _process_statement(kernel, gates, qubits, params, statement)
143
+
144
+
145
+ def _eval_expr(
146
+ params: dict[str, "cudaq.QuakeValue"], expr: "openqasm3.ast.Expression"
147
+ ) -> Any:
148
+ import openqasm3
149
+
150
+ if isinstance(expr, openqasm3.ast.Identifier):
151
+ if expr.name not in params:
152
+ raise ClassiqError(
153
+ _CONVERSION_ERROR_PREFIX + f"name {expr.name!r} is not defined"
154
+ )
155
+ return params[expr.name]
156
+ if isinstance(expr, openqasm3.ast.UnaryExpression):
157
+ target = _eval_expr(params, expr.expression)
158
+ if expr.op == openqasm3.ast.UnaryOperator["~"]:
159
+ return ~target
160
+ if expr.op == openqasm3.ast.UnaryOperator["-"]:
161
+ return -target
162
+ raise ClassiqError(
163
+ _CONVERSION_ERROR_PREFIX + f"operation {str(expr.op)!r} is not supported"
164
+ )
165
+ if isinstance(expr, openqasm3.ast.BinaryExpression):
166
+ left = _eval_expr(params, expr.lhs)
167
+ right = _eval_expr(params, expr.rhs)
168
+ if expr.op == openqasm3.ast.BinaryOperator["|"]:
169
+ return left | right
170
+ if expr.op == openqasm3.ast.BinaryOperator["&"]:
171
+ return left & right
172
+ if expr.op == openqasm3.ast.BinaryOperator["<<"]:
173
+ return left << right
174
+ if expr.op == openqasm3.ast.BinaryOperator[">>"]:
175
+ return left >> right
176
+ if expr.op == openqasm3.ast.BinaryOperator["+"]:
177
+ return left + right
178
+ if expr.op == openqasm3.ast.BinaryOperator["-"]:
179
+ return left - right
180
+ if expr.op == openqasm3.ast.BinaryOperator["*"]:
181
+ return left * right
182
+ if expr.op == openqasm3.ast.BinaryOperator["/"]:
183
+ return left / right
184
+ raise ClassiqError(
185
+ _CONVERSION_ERROR_PREFIX + f"operation {str(expr.op)!r} is not supported"
186
+ )
187
+ if isinstance(
188
+ expr,
189
+ (
190
+ openqasm3.ast.IntegerLiteral,
191
+ openqasm3.ast.FloatLiteral,
192
+ openqasm3.ast.ImaginaryLiteral,
193
+ openqasm3.ast.BooleanLiteral,
194
+ ),
195
+ ):
196
+ return expr.value
197
+ raise ClassiqError(
198
+ _CONVERSION_ERROR_PREFIX
199
+ + f"expression type {type(expr).__name__!r} is not supported"
200
+ )
201
+
202
+
203
+ def _eval_var(
204
+ qubits: dict[str, "cudaq.QuakeValue"],
205
+ expr: "openqasm3.ast.IndexedIdentifier | openqasm3.ast.Identifier",
206
+ ) -> "cudaq.QuakeValue":
207
+ import openqasm3
208
+
209
+ if isinstance(expr, openqasm3.ast.Identifier):
210
+ if expr.name not in qubits:
211
+ raise ClassiqError(
212
+ _CONVERSION_ERROR_PREFIX + f"name {expr.name!r} is not defined"
213
+ )
214
+ return qubits[expr.name]
215
+ if isinstance(expr, openqasm3.ast.IndexedIdentifier):
216
+ if expr.name.name not in qubits:
217
+ raise ClassiqError(
218
+ _CONVERSION_ERROR_PREFIX + f"name {expr.name.name!r} is not defined"
219
+ )
220
+ if (
221
+ len(expr.indices) != 1
222
+ or not isinstance(accessor := expr.indices[0], list)
223
+ or len(accessor) != 1
224
+ or not isinstance(index := accessor[0], openqasm3.ast.IntegerLiteral)
225
+ ):
226
+ raise ClassiqError(
227
+ _CONVERSION_ERROR_PREFIX
228
+ + "only simple subscript expressions are supported (for example, q[0])"
229
+ )
230
+ return qubits[expr.name.name][index.value]
231
+ raise ClassiqError(
232
+ _CONVERSION_ERROR_PREFIX
233
+ + f"expression type {type(expr).__name__!r} is not supported"
234
+ )
235
+
236
+
237
+ def _get_expr_vars(
238
+ params: dict[str, "cudaq.QuakeValue"], expr: "openqasm3.ast.Expression"
239
+ ) -> set[str]:
240
+ import openqasm3
241
+
242
+ if isinstance(expr, openqasm3.ast.Identifier):
243
+ if expr.name not in params:
244
+ raise ClassiqError(
245
+ _CONVERSION_ERROR_PREFIX + f"name {expr.name!r} is not defined"
246
+ )
247
+ return {expr.name}
248
+ if isinstance(expr, openqasm3.ast.UnaryExpression):
249
+ return _get_expr_vars(params, expr.expression)
250
+ if isinstance(expr, openqasm3.ast.BinaryExpression):
251
+ return _get_expr_vars(params, expr.lhs) | _get_expr_vars(params, expr.rhs)
252
+ if isinstance(
253
+ expr,
254
+ (
255
+ openqasm3.ast.IntegerLiteral,
256
+ openqasm3.ast.FloatLiteral,
257
+ openqasm3.ast.ImaginaryLiteral,
258
+ openqasm3.ast.BooleanLiteral,
259
+ ),
260
+ ):
261
+ return set()
262
+ raise ClassiqError(
263
+ _CONVERSION_ERROR_PREFIX
264
+ + f"expression type {type(expr).__name__!r} is not supported"
265
+ )
266
+
267
+
268
+ def _eval_single_var(
269
+ params: dict[str, "cudaq.QuakeValue"], expr: "openqasm3.ast.Expression"
270
+ ) -> "cudaq.QuakeValue":
271
+ expr_vars = _get_expr_vars(params, expr)
272
+ if len(expr_vars) != 1:
273
+ if len(expr_vars) == 0:
274
+ suffix = "got none"
275
+ else:
276
+ suffix = f"got {readable_list(list(expr_vars), quote=True)}"
277
+ raise ClassiqError(
278
+ _CONVERSION_ERROR_PREFIX
279
+ + f"gate argument must contain exactly one angle variable, {suffix}"
280
+ )
281
+ return params[list(expr_vars)[0]]
282
+
283
+
284
+ def _process_statement(
285
+ kernel: "cudaq.PyKernel",
286
+ gates: dict[str, "cudaq.PyKernel"],
287
+ qubits: dict[str, "cudaq.QuakeValue"],
288
+ params: dict[str, "cudaq.QuakeValue"],
289
+ statement: "openqasm3.ast.Statement | openqasm3.ast.Pragma",
290
+ ) -> None:
291
+ import openqasm3
292
+
293
+ if isinstance(statement, openqasm3.ast.QuantumGate):
294
+ if len(statement.modifiers) != 0:
295
+ raise ClassiqError(
296
+ _CONVERSION_ERROR_PREFIX + "gate modifiers are not supported"
297
+ )
298
+ if statement.duration:
299
+ raise ClassiqError(
300
+ _CONVERSION_ERROR_PREFIX + "gate duration is not supported"
301
+ )
302
+ qubit_args = [_eval_var(qubits, var) for var in statement.qubits]
303
+ gate_name = statement.name.name
304
+ if gate_name in gates:
305
+ angle_args = [
306
+ _eval_single_var(params, angle_expr)
307
+ for angle_expr in statement.arguments
308
+ ]
309
+ kernel.apply_call(gates[gate_name], *angle_args, *qubit_args)
310
+ elif gate_name in {"i", "id"}:
311
+ pass
312
+ elif gate_name in {
313
+ "x",
314
+ "y",
315
+ "z",
316
+ "h",
317
+ "s",
318
+ "t",
319
+ "sdg",
320
+ "tdg",
321
+ "rx",
322
+ "ry",
323
+ "rz",
324
+ "u3",
325
+ "cx",
326
+ "cy",
327
+ "cz",
328
+ "ch",
329
+ "cs",
330
+ "ct",
331
+ "crx",
332
+ "cry",
333
+ "crz",
334
+ }:
335
+ angle_args = [
336
+ _eval_expr(params, angle_expr) for angle_expr in statement.arguments
337
+ ]
338
+ getattr(kernel, gate_name)(*angle_args, *qubit_args)
339
+ else:
340
+ raise ClassiqError(
341
+ _CONVERSION_ERROR_PREFIX + f"gate {gate_name!r} is not defined"
342
+ )
343
+ else:
344
+ raise ClassiqError(
345
+ _CONVERSION_ERROR_PREFIX
346
+ + f"QASM statement {type(statement).__name__} is not supported"
347
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classiq
3
- Version: 0.102.0
3
+ Version: 1.0.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL
6
6
  Author: Classiq Technologies
@@ -50,6 +50,8 @@ Requires-Dist: notebook>=7.2.2,<8 ; extra == 'analyzer-sdk'
50
50
  Requires-Dist: openfermion==1.6.1 ; python_full_version < '3.10' and extra == 'chemistry'
51
51
  Requires-Dist: openfermion==1.7.1 ; python_full_version >= '3.10' and extra == 'chemistry'
52
52
  Requires-Dist: openfermionpyscf>=0.5 ; extra == 'chemistry'
53
+ Requires-Dist: cudaq>=0.12.0,<1 ; sys_platform == 'linux' and extra == 'cudaq'
54
+ Requires-Dist: openqasm3[parser]>=1.0.1,<2 ; extra == 'cudaq'
53
55
  Requires-Dist: torch~=2.3 ; extra == 'qml'
54
56
  Requires-Dist: torchvision>=0.18,<1.0 ; extra == 'qml'
55
57
  Requires-Dist: cvxpy>=1.7.1,<2 ; extra == 'qsp'
@@ -60,6 +62,7 @@ Project-URL: examples, https://github.com/Classiq/classiq-library
60
62
  Project-URL: homepage, https://classiq.io
61
63
  Provides-Extra: analyzer-sdk
62
64
  Provides-Extra: chemistry
65
+ Provides-Extra: cudaq
63
66
  Provides-Extra: qml
64
67
  Provides-Extra: qsp
65
68
  Description-Content-Type: text/markdown