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.
- classiq/__init__.py +2 -0
- classiq/_internals/authentication/auth0.py +29 -0
- classiq/_internals/authentication/auth_flow_factory.py +43 -0
- classiq/_internals/authentication/machine_credentials_flow.py +26 -0
- classiq/_internals/authentication/password_manager.py +84 -0
- classiq/_internals/authentication/token_manager.py +24 -8
- classiq/analyzer/show_interactive_hack.py +0 -8
- classiq/applications/chemistry/op_utils.py +32 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +1 -1
- classiq/evaluators/qmod_annotated_expression.py +1 -1
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +1 -8
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +1 -1
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +2 -2
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +18 -29
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +1 -6
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +1 -7
- classiq/evaluators/qmod_type_inference/quantum_type_comparison.py +52 -0
- classiq/execution/all_hardware_devices.py +59 -1
- classiq/execution/execution_session.py +1 -1
- classiq/execution/functions/__init__.py +13 -0
- classiq/execution/functions/expectation_value.py +106 -0
- classiq/execution/functions/minimize.py +90 -0
- classiq/execution/functions/sample.py +76 -0
- classiq/execution/functions/state_vector.py +113 -0
- classiq/execution/functions/util/__init__.py +0 -0
- classiq/execution/functions/util/_logging.py +19 -0
- classiq/execution/functions/util/backend_preferences.py +188 -0
- classiq/execution/functions/util/constants.py +9 -0
- classiq/execution/functions/util/parse_provider_backend.py +90 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +81 -0
- classiq/interface/backend/provider_config/providers/aqt.py +1 -1
- classiq/interface/backend/provider_config/providers/azure.py +1 -2
- classiq/interface/backend/provider_config/providers/ibm.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +14 -0
- classiq/interface/exceptions.py +0 -4
- classiq/interface/executor/result.py +9 -5
- classiq/interface/generator/arith/binary_ops.py +62 -2
- classiq/interface/generator/arith/number_utils.py +15 -6
- classiq/interface/generator/compiler_keywords.py +1 -0
- classiq/interface/generator/function_param_list.py +8 -2
- classiq/interface/generator/function_params.py +1 -1
- classiq/interface/generator/functions/builtins/internal_operators.py +5 -9
- classiq/interface/generator/functions/classical_type.py +60 -0
- classiq/interface/generator/functions/type_name.py +36 -0
- classiq/interface/generator/generated_circuit_data.py +0 -2
- classiq/interface/generator/transpiler_basis_gates.py +1 -0
- classiq/interface/generator/types/compilation_metadata.py +18 -0
- classiq/interface/hardware.py +2 -0
- classiq/interface/helpers/model_normalizer.py +42 -6
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/invert.py +8 -0
- classiq/interface/model/model.py +19 -0
- classiq/interface/model/model_visitor.py +4 -2
- classiq/interface/model/quantum_type.py +36 -0
- classiq/interface/model/statement_block.py +0 -4
- classiq/interface/qubits_mapping/__init__.py +4 -0
- classiq/interface/qubits_mapping/path_expr_range.py +69 -0
- classiq/interface/qubits_mapping/qubits_mapping.py +231 -0
- classiq/interface/qubits_mapping/slices.py +112 -0
- classiq/model_expansions/arithmetic.py +6 -0
- classiq/model_expansions/capturing/captured_vars.py +16 -12
- classiq/model_expansions/function_builder.py +9 -1
- classiq/model_expansions/interpreters/base_interpreter.py +9 -8
- classiq/model_expansions/interpreters/generative_interpreter.py +9 -24
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +132 -28
- classiq/model_expansions/quantum_operations/bind.py +4 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +5 -35
- classiq/model_expansions/quantum_operations/emitter.py +1 -4
- classiq/model_expansions/quantum_operations/expression_evaluator.py +0 -3
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +0 -9
- classiq/qmod/builtins/functions/__init__.py +21 -9
- classiq/qmod/builtins/functions/allocation.py +0 -36
- classiq/qmod/builtins/functions/arithmetic.py +183 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -2
- classiq/qmod/builtins/functions/gray_code.py +23 -0
- classiq/qmod/builtins/functions/mcx_func.py +10 -0
- classiq/qmod/builtins/operations.py +2 -38
- classiq/qmod/builtins/structs.py +22 -3
- classiq/qmod/native/pretty_printer.py +1 -12
- classiq/qmod/pretty_print/pretty_printer.py +1 -17
- classiq/qmod/qmod_parameter.py +4 -0
- classiq/qmod/qmod_variable.py +38 -63
- classiq/qmod/quantum_function.py +43 -7
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +7 -4
- classiq/qmod/semantics/validation/model_validation.py +7 -2
- classiq/qmod/symbolic_type.py +4 -2
- classiq/qprog_to_cudaq.py +347 -0
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/METADATA +4 -1
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/RECORD +93 -76
- classiq/interface/generator/amplitude_loading.py +0 -103
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +0 -77
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/WHEEL +0 -0
- {classiq-0.102.0.dist-info → classiq-1.0.0.dist-info}/licenses/LICENSE.txt +0 -0
classiq/qmod/quantum_function.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
358
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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)
|
classiq/qmod/symbolic_type.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from typing import Union, get_args, get_origin
|
|
2
2
|
|
|
3
|
-
from classiq.qmod.symbolic_expr import
|
|
3
|
+
from classiq.qmod.symbolic_expr import Symbolic
|
|
4
4
|
|
|
5
|
-
SymbolicTypes = Union[
|
|
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.
|
|
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
|