classiq 0.43.3__py3-none-any.whl → 0.44.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 +7 -1
- classiq/_internals/client.py +4 -7
- classiq/_internals/host_checker.py +34 -12
- classiq/_internals/jobs.py +2 -2
- classiq/applications/chemistry/chemistry_model_constructor.py +12 -6
- classiq/applications/combinatorial_helpers/allowed_constraints.py +4 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +1 -1
- classiq/applications/finance/finance_model_constructor.py +3 -2
- classiq/applications/grover/grover_model_constructor.py +7 -5
- classiq/applications/hamiltonian/__init__.py +0 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
- classiq/applications/qnn/qlayer.py +1 -1
- classiq/exceptions.py +4 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/ast_node.py +1 -18
- classiq/interface/backend/backend_preferences.py +10 -16
- classiq/interface/backend/ionq/ionq_quantum_program.py +1 -1
- classiq/interface/backend/pydantic_backend.py +0 -5
- classiq/interface/backend/quantum_backend_providers.py +3 -2
- classiq/interface/chemistry/operator.py +5 -1
- classiq/interface/debug_info/__init__.py +0 -0
- classiq/interface/debug_info/debug_info.py +32 -0
- classiq/interface/executor/execution_preferences.py +1 -45
- classiq/interface/executor/result.py +25 -12
- classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
- classiq/interface/generator/application_apis/chemistry_declarations.py +78 -60
- classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +19 -10
- classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
- classiq/interface/generator/application_apis/finance_declarations.py +36 -22
- classiq/interface/generator/application_apis/qsvm_declarations.py +21 -15
- classiq/interface/generator/arith/arithmetic_expression_abc.py +21 -1
- classiq/interface/generator/arith/binary_ops.py +5 -4
- classiq/interface/generator/arith/extremum_operations.py +43 -19
- classiq/interface/generator/constant.py +1 -1
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -0
- classiq/interface/generator/expressions/expression_constants.py +3 -1
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +52 -66
- classiq/interface/generator/expressions/qmod_qstruct_proxy.py +35 -0
- classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
- classiq/interface/generator/functions/builtins/core_library/__init__.py +4 -2
- classiq/interface/generator/functions/builtins/core_library/atomic_quantum_functions.py +41 -41
- classiq/interface/generator/functions/builtins/core_library/exponentiation_functions.py +52 -42
- classiq/interface/generator/functions/builtins/open_lib_functions.py +1095 -3347
- classiq/interface/generator/functions/builtins/quantum_operators.py +9 -22
- classiq/interface/generator/functions/classical_function_declaration.py +14 -6
- classiq/interface/generator/functions/classical_type.py +7 -76
- classiq/interface/generator/functions/concrete_types.py +55 -0
- classiq/interface/generator/functions/function_declaration.py +10 -10
- classiq/interface/generator/functions/type_name.py +104 -0
- classiq/interface/generator/generated_circuit_data.py +3 -3
- classiq/interface/generator/model/model.py +11 -0
- classiq/interface/generator/model/preferences/preferences.py +5 -0
- classiq/interface/generator/quantum_function_call.py +3 -0
- classiq/interface/generator/quantum_program.py +2 -2
- classiq/interface/generator/register_role.py +7 -1
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +1 -3
- classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +1 -2
- classiq/interface/generator/types/qstruct_declaration.py +17 -0
- classiq/interface/generator/types/struct_declaration.py +1 -1
- classiq/interface/helpers/validation_helpers.py +1 -17
- classiq/interface/ide/visual_model.py +9 -2
- classiq/interface/interface_version.py +1 -0
- classiq/interface/model/bind_operation.py +25 -5
- classiq/interface/model/classical_parameter_declaration.py +8 -5
- classiq/interface/model/control.py +5 -5
- classiq/interface/model/handle_binding.py +185 -12
- classiq/interface/model/inplace_binary_operation.py +16 -4
- classiq/interface/model/model.py +28 -5
- classiq/interface/model/native_function_definition.py +8 -4
- classiq/interface/model/parameter.py +14 -0
- classiq/interface/model/port_declaration.py +20 -2
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +21 -6
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +30 -6
- classiq/interface/model/quantum_expressions/quantum_expression.py +4 -9
- classiq/interface/model/quantum_function_call.py +135 -192
- classiq/interface/model/quantum_function_declaration.py +147 -165
- classiq/interface/model/quantum_lambda_function.py +24 -6
- classiq/interface/model/quantum_statement.py +34 -8
- classiq/interface/model/quantum_type.py +61 -10
- classiq/interface/model/quantum_variable_declaration.py +1 -1
- classiq/interface/model/statement_block.py +2 -0
- classiq/interface/model/validation_handle.py +7 -0
- classiq/interface/server/global_versions.py +4 -4
- classiq/interface/server/routes.py +2 -0
- classiq/interface/source_reference.py +59 -0
- classiq/qmod/__init__.py +2 -3
- classiq/qmod/builtins/functions.py +39 -11
- classiq/qmod/builtins/operations.py +171 -40
- classiq/qmod/declaration_inferrer.py +99 -56
- classiq/qmod/expression_query.py +1 -1
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/pretty_printer.py +71 -53
- classiq/qmod/pretty_print/pretty_printer.py +98 -52
- classiq/qmod/qfunc.py +11 -5
- classiq/qmod/qmod_parameter.py +1 -2
- classiq/qmod/qmod_variable.py +364 -172
- classiq/qmod/quantum_callable.py +3 -3
- classiq/qmod/quantum_expandable.py +119 -65
- classiq/qmod/quantum_function.py +15 -3
- classiq/qmod/semantics/annotation.py +12 -13
- classiq/qmod/semantics/error_manager.py +36 -10
- classiq/qmod/semantics/static_semantics_visitor.py +163 -75
- classiq/qmod/semantics/validation/func_call_validation.py +42 -96
- classiq/qmod/semantics/validation/handle_validation.py +85 -0
- classiq/qmod/semantics/validation/types_validation.py +108 -1
- classiq/qmod/type_attribute_remover.py +32 -0
- classiq/qmod/utilities.py +26 -5
- {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/METADATA +3 -3
- {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/RECORD +111 -99
- classiq/qmod/qmod_struct.py +0 -13
- /classiq/{interface/ide/show.py → show.py} +0 -0
- {classiq-0.43.3.dist-info → classiq-0.44.0.dist-info}/WHEEL +0 -0
classiq/__init__.py
CHANGED
@@ -14,7 +14,6 @@ from classiq.interface.generator.model import * # noqa: F403
|
|
14
14
|
from classiq.interface.generator.model import __all__ as _md_all
|
15
15
|
from classiq.interface.generator.quantum_program import QuantumProgram
|
16
16
|
from classiq.interface.generator.types.builtin_enum_declarations import * # noqa: F403
|
17
|
-
from classiq.interface.ide.show import show
|
18
17
|
|
19
18
|
from classiq import applications, exceptions, execution, synthesis
|
20
19
|
from classiq._internals import logger
|
@@ -38,6 +37,10 @@ from classiq.applications.combinatorial_optimization import (
|
|
38
37
|
)
|
39
38
|
from classiq.applications.finance import construct_finance_model
|
40
39
|
from classiq.applications.grover import construct_grover_model
|
40
|
+
from classiq.applications.hamiltonian.pauli_decomposition import (
|
41
|
+
hamiltonian_to_matrix,
|
42
|
+
matrix_to_hamiltonian,
|
43
|
+
)
|
41
44
|
from classiq.applications.qsvm import construct_qsvm_model
|
42
45
|
from classiq.executor import (
|
43
46
|
execute,
|
@@ -46,6 +49,7 @@ from classiq.executor import (
|
|
46
49
|
)
|
47
50
|
from classiq.qmod import * # noqa: F403
|
48
51
|
from classiq.qmod import __all__ as _qmod_all
|
52
|
+
from classiq.show import show
|
49
53
|
from classiq.synthesis import (
|
50
54
|
set_constraints,
|
51
55
|
set_execution_preferences,
|
@@ -95,6 +99,8 @@ __all__ = (
|
|
95
99
|
"set_execution_preferences",
|
96
100
|
"set_quantum_program_execution_preferences",
|
97
101
|
"show",
|
102
|
+
"hamiltonian_to_matrix",
|
103
|
+
"matrix_to_hamiltonian",
|
98
104
|
]
|
99
105
|
+ _md_all
|
100
106
|
+ _sub_modules
|
classiq/_internals/client.py
CHANGED
@@ -19,10 +19,10 @@ from typing import (
|
|
19
19
|
)
|
20
20
|
|
21
21
|
import httpx
|
22
|
-
from packaging.version import Version
|
23
22
|
from typing_extensions import ParamSpec
|
24
23
|
|
25
24
|
from classiq.interface._version import VERSION as _VERSION
|
25
|
+
from classiq.interface.interface_version import INTERFACE_VERSION
|
26
26
|
|
27
27
|
from classiq._internals import config
|
28
28
|
from classiq._internals.authentication import token_manager
|
@@ -161,12 +161,9 @@ class Client:
|
|
161
161
|
self._api_prefix = self._make_api_prefix()
|
162
162
|
self._session_id: Optional[str] = None
|
163
163
|
|
164
|
-
@
|
165
|
-
def _make_api_prefix(
|
166
|
-
|
167
|
-
return cls._LATEST_VERSION_API_PREFIX
|
168
|
-
parsed_version = Version(_VERSION)
|
169
|
-
return f"/api/v{parsed_version.major}-{parsed_version.minor}"
|
164
|
+
@staticmethod
|
165
|
+
def _make_api_prefix() -> str:
|
166
|
+
return f"/api/v{INTERFACE_VERSION}"
|
170
167
|
|
171
168
|
def make_versioned_url(self, url_postfix: str) -> str:
|
172
169
|
return self._api_prefix + url_postfix
|
@@ -1,6 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import logging
|
4
|
+
import warnings
|
5
|
+
from datetime import datetime
|
4
6
|
from typing import TYPE_CHECKING, Optional
|
5
7
|
|
6
8
|
import httpx
|
@@ -8,9 +10,10 @@ import pydantic
|
|
8
10
|
from packaging.version import Version
|
9
11
|
from pydantic import BaseModel
|
10
12
|
|
13
|
+
from classiq.interface.interface_version import INTERFACE_VERSION
|
11
14
|
from classiq.interface.server.global_versions import DeprecationInfo, GlobalVersions
|
12
15
|
|
13
|
-
from classiq.exceptions import ClassiqAPIError
|
16
|
+
from classiq.exceptions import ClassiqAPIError, ClassiqDeprecationWarning
|
14
17
|
|
15
18
|
if TYPE_CHECKING:
|
16
19
|
from classiq._internals.client import Client
|
@@ -26,9 +29,23 @@ class HostVersions(BaseModel):
|
|
26
29
|
class HostChecker:
|
27
30
|
_UNKNOWN_VERSION = "0.0.0"
|
28
31
|
|
29
|
-
def __init__(
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
client: Client,
|
35
|
+
client_version: str,
|
36
|
+
interface_version: str = INTERFACE_VERSION,
|
37
|
+
) -> None:
|
30
38
|
self._client = client
|
31
39
|
self._client_version = client_version
|
40
|
+
self._interface_version = interface_version
|
41
|
+
|
42
|
+
def _get_interface_version(self) -> Optional[str]:
|
43
|
+
global_interfaces = GlobalVersions.parse_obj(
|
44
|
+
self._client.sync_call_api(
|
45
|
+
"get", "/interface_versions", use_versioned_url=False
|
46
|
+
)
|
47
|
+
)
|
48
|
+
return global_interfaces.deployed.get(self._interface_version, None)
|
32
49
|
|
33
50
|
def _get_host_version(self) -> str:
|
34
51
|
host = HostVersions.parse_obj(self._client.sync_call_api("get", "/versions"))
|
@@ -56,18 +73,16 @@ class HostChecker:
|
|
56
73
|
|
57
74
|
def check_host_version(self) -> None:
|
58
75
|
try:
|
59
|
-
|
76
|
+
interface_version = self._get_interface_version()
|
60
77
|
except httpx.ConnectError:
|
61
78
|
_logger.warning(
|
62
79
|
"Version check failed - host unavailable.",
|
63
80
|
)
|
64
81
|
else:
|
65
|
-
if
|
66
|
-
raw_host_version, self._client_version
|
67
|
-
):
|
82
|
+
if interface_version is None:
|
68
83
|
raise ClassiqAPIError(
|
69
|
-
f"
|
70
|
-
f"{
|
84
|
+
f"You are using an unsupported version of Classiq SDK - {self._client_version}. "
|
85
|
+
f"{_VERSION_UPDATE_SUGGESTION}"
|
71
86
|
)
|
72
87
|
|
73
88
|
def check_deprecated_version(self) -> None:
|
@@ -80,8 +95,15 @@ class HostChecker:
|
|
80
95
|
else:
|
81
96
|
if deprecation_info is None:
|
82
97
|
return
|
83
|
-
|
84
|
-
|
85
|
-
deprecation_info.removal_date
|
86
|
-
|
98
|
+
removal_date = (
|
99
|
+
deprecation_info.removal_date.date()
|
100
|
+
if isinstance(deprecation_info.removal_date, datetime)
|
101
|
+
else deprecation_info.removal_date
|
102
|
+
)
|
103
|
+
warnings.warn(
|
104
|
+
f"The current version of 'classiq' has been deprecated, and"
|
105
|
+
f" will not be supported as of {removal_date}. "
|
106
|
+
f"{_VERSION_UPDATE_SUGGESTION}",
|
107
|
+
ClassiqDeprecationWarning,
|
108
|
+
stacklevel=2,
|
87
109
|
)
|
classiq/_internals/jobs.py
CHANGED
@@ -169,7 +169,7 @@ class JobPoller:
|
|
169
169
|
self, model: pydantic.BaseModel, timeout_sec: Optional[float]
|
170
170
|
) -> GeneralJobDescription:
|
171
171
|
# TODO: we can't use model.dict() - it doesn't serialize complex class.
|
172
|
-
# This was added because JSON serializer doesn't serialize complex
|
173
|
-
# We should add support for smarter json serialization.
|
172
|
+
# This was added because JSON serializer doesn't serialize complex and UUID,
|
173
|
+
# while pydantic does. We should add support for smarter json serialization.
|
174
174
|
body = json.loads(model.json())
|
175
175
|
return await self.run(body, timeout_sec)
|
@@ -154,7 +154,6 @@ _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
|
|
154
154
|
),
|
155
155
|
"crx": QuantumFunctionCall(
|
156
156
|
function="CRX",
|
157
|
-
designated_params={"theta": Expression(expr="angle")},
|
158
157
|
positional_args=[
|
159
158
|
Expression(expr="angle"),
|
160
159
|
HandleBinding(name="q1"),
|
@@ -325,11 +324,17 @@ def _get_hea_function(hea_parameters: HEAParameters) -> QuantumFunctionCall:
|
|
325
324
|
),
|
326
325
|
Expression(expr=f"{hea_parameters.reps}"),
|
327
326
|
[
|
328
|
-
QuantumLambdaFunction(
|
327
|
+
QuantumLambdaFunction(
|
328
|
+
pos_rename_params=["angle", "q"],
|
329
|
+
body=[_HAE_GATE_MAPPING[gate]],
|
330
|
+
)
|
329
331
|
for gate in hea_parameters.one_qubit_gates
|
330
332
|
],
|
331
333
|
[
|
332
|
-
QuantumLambdaFunction(
|
334
|
+
QuantumLambdaFunction(
|
335
|
+
pos_rename_params=["angle", "q1", "q2"],
|
336
|
+
body=[_HAE_GATE_MAPPING[gate]],
|
337
|
+
)
|
333
338
|
for gate in hea_parameters.two_qubit_gates
|
334
339
|
],
|
335
340
|
HandleBinding(name="qbv"),
|
@@ -378,9 +383,10 @@ save({{{_MOLECULE_PROBLEM_RESULT!r}: {_MOLECULE_PROBLEM_RESULT}}})
|
|
378
383
|
|
379
384
|
|
380
385
|
def _is_parametric_gate(call: QuantumFunctionCall) -> bool:
|
381
|
-
|
382
|
-
|
383
|
-
|
386
|
+
# FIXME: call call.params instead (CAD-21568)
|
387
|
+
return any(
|
388
|
+
arg for arg in call.positional_args if isinstance(arg, Expression)
|
389
|
+
) or any(isinstance(arg, Expression) for arg in call.positional_args)
|
384
390
|
|
385
391
|
|
386
392
|
def _get_execution_result_post_processing_statements(
|
@@ -15,6 +15,9 @@ def is_constraint_sum_less_than_one(
|
|
15
15
|
isinstance(expression, LessThan)
|
16
16
|
and isinstance(expression.args[0], Add)
|
17
17
|
and all(isinstance(arg, Symbol) for arg in expression.args[0].args)
|
18
|
-
and
|
18
|
+
and (
|
19
|
+
expression.args[1] == _INEQUALITY_UPPER_LIMIT
|
20
|
+
or expression.args[1] == float(_INEQUALITY_UPPER_LIMIT)
|
21
|
+
)
|
19
22
|
and encoding_type is None
|
20
23
|
)
|
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -9,7 +9,6 @@ from classiq.interface.generator.functions.classical_type import (
|
|
9
9
|
ClassicalArray,
|
10
10
|
ClassicalList,
|
11
11
|
Real,
|
12
|
-
Struct,
|
13
12
|
)
|
14
13
|
from classiq.interface.generator.functions.port_declaration import (
|
15
14
|
PortDeclarationDirection,
|
@@ -24,6 +23,7 @@ from classiq.interface.model.port_declaration import PortDeclaration
|
|
24
23
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
25
24
|
from classiq.interface.model.quantum_type import QuantumBitvector
|
26
25
|
|
26
|
+
from classiq import Struct
|
27
27
|
from classiq.applications.combinatorial_helpers.combinatorial_problem_utils import (
|
28
28
|
compute_qaoa_initial_point,
|
29
29
|
convert_pyomo_to_global_presentation,
|
@@ -96,14 +96,15 @@ def construct_finance_model(
|
|
96
96
|
function="qmci",
|
97
97
|
positional_args=[
|
98
98
|
QuantumLambdaFunction(
|
99
|
+
pos_rename_params=["state", "ind"],
|
99
100
|
body=[
|
100
101
|
QuantumFunctionCall(
|
101
102
|
function=finance_function,
|
102
103
|
positional_args=[
|
103
104
|
Expression(expr=finance_model),
|
104
105
|
Expression(expr=finance_function_object),
|
105
|
-
HandleBinding(name="
|
106
|
-
HandleBinding(name="
|
106
|
+
HandleBinding(name="state"),
|
107
|
+
HandleBinding(name="ind"),
|
107
108
|
],
|
108
109
|
),
|
109
110
|
],
|
@@ -34,7 +34,7 @@ def _arithmetic_oracle_ios(
|
|
34
34
|
for _, reg in definitions:
|
35
35
|
ios.append(
|
36
36
|
SlicedHandleBinding(
|
37
|
-
name=handle_name,
|
37
|
+
base_handle=HandleBinding(name=handle_name),
|
38
38
|
start=Expression(expr=f"{cursor}"),
|
39
39
|
end=Expression(expr=f"{cursor + reg.size}"),
|
40
40
|
)
|
@@ -47,12 +47,13 @@ def _construct_arithmetic_oracle(
|
|
47
47
|
predicate_function: str,
|
48
48
|
definitions: List[Tuple[str, RegisterUserInput]],
|
49
49
|
) -> QuantumFunctionCall:
|
50
|
-
predicate_var_binding = _arithmetic_oracle_ios(definitions, "
|
51
|
-
predicate_var_binding.append(HandleBinding(name="
|
50
|
+
predicate_var_binding = _arithmetic_oracle_ios(definitions, "state")
|
51
|
+
predicate_var_binding.append(HandleBinding(name="oracle"))
|
52
52
|
return QuantumFunctionCall(
|
53
53
|
function="phase_oracle",
|
54
54
|
positional_args=[
|
55
55
|
QuantumLambdaFunction(
|
56
|
+
pos_rename_params=["state", "oracle"],
|
56
57
|
body=[
|
57
58
|
QuantumFunctionCall(
|
58
59
|
function=predicate_function,
|
@@ -60,7 +61,7 @@ def _construct_arithmetic_oracle(
|
|
60
61
|
),
|
61
62
|
],
|
62
63
|
),
|
63
|
-
HandleBinding(name="
|
64
|
+
HandleBinding(name="packed_vars"),
|
64
65
|
],
|
65
66
|
)
|
66
67
|
|
@@ -132,12 +133,13 @@ def construct_grover_model(
|
|
132
133
|
positional_args=[
|
133
134
|
Expression(expr=f"{num_reps}"),
|
134
135
|
QuantumLambdaFunction(
|
136
|
+
pos_rename_params=["packed_vars"],
|
135
137
|
body=[
|
136
138
|
_construct_arithmetic_oracle(
|
137
139
|
_PREDICATE_FUNCTION_NAME,
|
138
140
|
definitions,
|
139
141
|
)
|
140
|
-
]
|
142
|
+
],
|
141
143
|
),
|
142
144
|
HandleBinding(name="packed_vars"),
|
143
145
|
],
|
File without changes
|
@@ -0,0 +1,113 @@
|
|
1
|
+
from typing import List, Tuple, Union
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
from sympy import fwht
|
5
|
+
|
6
|
+
from classiq.qmod import ( # type:ignore[attr-defined]
|
7
|
+
Pauli,
|
8
|
+
PauliTerm,
|
9
|
+
)
|
10
|
+
|
11
|
+
ATOL = 1e-12
|
12
|
+
PAULI_MATRICES_DICT = {
|
13
|
+
Pauli.I: np.array([[1, 0], [0, 1]], dtype=np.complex128),
|
14
|
+
Pauli.Z: np.array([[1, 0], [0, -1]], dtype=np.complex128),
|
15
|
+
Pauli.X: np.array([[0, 1], [1, 0]], dtype=np.complex128),
|
16
|
+
Pauli.Y: np.array([[0, -1j], [1j, 0]], dtype=np.complex128),
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
def _get_pauli_string(set_index: int, term_index: int, num_qubits: int) -> List[Pauli]:
|
21
|
+
"""
|
22
|
+
The basis of 4^N Pauli strings on N qubits can be partitioned to 2^N sets, each contains 2^N Pauli strings.
|
23
|
+
In the k-th set we have Pauli strings of the form s_1s_2...s_N, where s_j is in {I,Z} if k_j is 0,
|
24
|
+
and in {X,iY} if k_j=1. The function get_pauli_string returns the m-th Pauli string in the k-th set of Pauli strings
|
25
|
+
"""
|
26
|
+
|
27
|
+
# returns the Pauli (I,Z) or (iY, X) appearing in the pauli_index position for a given set
|
28
|
+
def _get_paulis_for_set(set_index: int, pauli_index: int) -> Tuple[Pauli, Pauli]:
|
29
|
+
if (set_index >> pauli_index) & 1:
|
30
|
+
return Pauli.Y, Pauli.X
|
31
|
+
else:
|
32
|
+
return Pauli.Z, Pauli.I
|
33
|
+
|
34
|
+
return [
|
35
|
+
(
|
36
|
+
_get_paulis_for_set(set_index, s)[0]
|
37
|
+
if (term_index >> s) & 1
|
38
|
+
else _get_paulis_for_set(set_index, s)[1]
|
39
|
+
)
|
40
|
+
for s in range(num_qubits)
|
41
|
+
][::-1]
|
42
|
+
|
43
|
+
|
44
|
+
def _coefficents_for_set(mat: np.ndarray, set_index: int) -> list:
|
45
|
+
"""
|
46
|
+
The 2^N coefficients in a 2^N x 2^N matrix that are decomposed to the elements
|
47
|
+
in the k-th set are the indices [i,j] such that i^j=k
|
48
|
+
The function coefficents_for_set returns the matrix entries that are decomposed to the same Pauli strigs set
|
49
|
+
"""
|
50
|
+
return [mat[k, k ^ set_index] / len(mat) for k in range(len(mat))]
|
51
|
+
|
52
|
+
|
53
|
+
def _get_signed_coefficient(
|
54
|
+
c: complex, k: int, i: int, is_hermitian: bool
|
55
|
+
) -> Union[complex, float]:
|
56
|
+
# correct from iY to Y
|
57
|
+
coef = complex((1j) ** ((i & k).bit_count()) * c)
|
58
|
+
if is_hermitian:
|
59
|
+
return coef.real
|
60
|
+
else:
|
61
|
+
return coef
|
62
|
+
|
63
|
+
|
64
|
+
def matrix_to_hamiltonian(
|
65
|
+
mat: np.ndarray, tol: float = ATOL, is_hermitian: bool = True
|
66
|
+
) -> List[PauliTerm]:
|
67
|
+
"""
|
68
|
+
The decomposition per set is done by the Walsh-Hadamard transform,
|
69
|
+
since the transformation between {e_0,e_3} ({e_1,e_2}) to {I,Z} ({X,iY}) is the Hadamard matrix.
|
70
|
+
"""
|
71
|
+
mat.shape[0] != 0, "matrix is of size 0"
|
72
|
+
if is_hermitian:
|
73
|
+
assert np.allclose(
|
74
|
+
mat, np.conjugate(mat.T)
|
75
|
+
), "Matrix is not hermitian, please pass is_hermitian=False"
|
76
|
+
assert mat.shape[0] == mat.shape[1], "Matrix is not square"
|
77
|
+
mat_dimension = mat.shape[0]
|
78
|
+
assert mat_dimension.bit_count() == 1, "Matrix dimension is not a power of 2"
|
79
|
+
num_qubits = (mat_dimension - 1).bit_length()
|
80
|
+
hamiltonian = []
|
81
|
+
for k in range(2**num_qubits):
|
82
|
+
coef = fwht(
|
83
|
+
_coefficents_for_set(mat, k)
|
84
|
+
) # the transformation per set is given by the Walsh-Hadamard transform
|
85
|
+
hamiltonian += [
|
86
|
+
PauliTerm(
|
87
|
+
pauli=_get_pauli_string(k, i, num_qubits),
|
88
|
+
coefficient=_get_signed_coefficient(coef[i], k, i, is_hermitian),
|
89
|
+
)
|
90
|
+
for i in range(2**num_qubits)
|
91
|
+
if abs(coef[i]) > tol
|
92
|
+
]
|
93
|
+
return hamiltonian
|
94
|
+
|
95
|
+
|
96
|
+
# convert a single puali string of length N to 2**N X 2**N matrix
|
97
|
+
def pauli_string_to_mat(seq: List[Pauli]) -> np.ndarray:
|
98
|
+
real_matrix = PAULI_MATRICES_DICT[seq[0]]
|
99
|
+
for p in seq[1:]:
|
100
|
+
real_matrix = np.kron(real_matrix, PAULI_MATRICES_DICT[p])
|
101
|
+
return real_matrix
|
102
|
+
|
103
|
+
|
104
|
+
# return matrix from hamiltonian
|
105
|
+
def hamiltonian_to_matrix(hamiltonian: List[PauliTerm]) -> np.ndarray:
|
106
|
+
matrix = np.zeros(
|
107
|
+
[2 ** len(hamiltonian[0].pauli), 2 ** len(hamiltonian[0].pauli)],
|
108
|
+
dtype=np.complex_,
|
109
|
+
)
|
110
|
+
for p in hamiltonian:
|
111
|
+
matrix += p.coefficient * pauli_string_to_mat(p.pauli)
|
112
|
+
|
113
|
+
return matrix
|
@@ -181,6 +181,6 @@ class QLayer(nn.Module):
|
|
181
181
|
self.weight = Parameter(value)
|
182
182
|
|
183
183
|
def forward(self, x: Tensor) -> Tensor:
|
184
|
-
return QLayerFunction.apply(
|
184
|
+
return QLayerFunction.apply(
|
185
185
|
x, self.weight, self.quantum_program, self._execute, self._post_process
|
186
186
|
)
|
classiq/exceptions.py
CHANGED
classiq/interface/_version.py
CHANGED
classiq/interface/ast_node.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from typing import Optional
|
3
2
|
|
4
3
|
import pydantic
|
@@ -6,23 +5,7 @@ import pydantic
|
|
6
5
|
from classiq.interface.helpers.hashable_pydantic_base_model import (
|
7
6
|
HashablePydanticBaseModel,
|
8
7
|
)
|
9
|
-
|
10
|
-
|
11
|
-
class SourceReference(HashablePydanticBaseModel):
|
12
|
-
start_line: int
|
13
|
-
start_column: int
|
14
|
-
end_line: int
|
15
|
-
end_column: int
|
16
|
-
file_name: Optional[str] = pydantic.Field(default=None)
|
17
|
-
|
18
|
-
def __str__(self) -> str:
|
19
|
-
file_string = (
|
20
|
-
f"file {os.path.basename(self.file_name)} " if self.file_name else ""
|
21
|
-
)
|
22
|
-
start_character_string = (
|
23
|
-
f" character {self.start_column + 1}" if self.start_column > 0 else ""
|
24
|
-
)
|
25
|
-
return f"{file_string}line {self.start_line + 1}{start_character_string}"
|
8
|
+
from classiq.interface.source_reference import SourceReference
|
26
9
|
|
27
10
|
|
28
11
|
class ASTNode(HashablePydanticBaseModel):
|
@@ -1,10 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from datetime import timedelta
|
4
3
|
from typing import Any, Dict, Iterable, List, Optional, Union
|
5
4
|
|
6
5
|
import pydantic
|
7
|
-
from pydantic import BaseModel,
|
6
|
+
from pydantic import BaseModel, validator
|
8
7
|
|
9
8
|
from classiq.interface.backend import pydantic_backend
|
10
9
|
from classiq.interface.backend.quantum_backend_providers import (
|
@@ -56,9 +55,6 @@ class BackendPreferences(BaseModel):
|
|
56
55
|
return False
|
57
56
|
|
58
57
|
|
59
|
-
AWS_DEFAULT_JOB_TIMEOUT_SECONDS = int(timedelta(minutes=240).total_seconds())
|
60
|
-
|
61
|
-
|
62
58
|
class AliceBobBackendPreferences(BackendPreferences):
|
63
59
|
backend_service_provider: ProviderTypeVendor.ALICE_BOB
|
64
60
|
distance: Optional[int] = pydantic.Field(
|
@@ -76,7 +72,6 @@ class AliceBobBackendPreferences(BackendPreferences):
|
|
76
72
|
api_key: pydantic_backend.PydanticAliceBobApiKeyType = pydantic.Field(
|
77
73
|
..., description="AliceBob API key"
|
78
74
|
)
|
79
|
-
_parameters: Dict[str, Any] = PrivateAttr(default_factory=dict)
|
80
75
|
|
81
76
|
@pydantic.root_validator(pre=True)
|
82
77
|
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
@@ -86,14 +81,13 @@ class AliceBobBackendPreferences(BackendPreferences):
|
|
86
81
|
|
87
82
|
@property
|
88
83
|
def parameters(self) -> Dict[str, Any]:
|
89
|
-
|
84
|
+
parameters = {
|
90
85
|
"distance": self.distance,
|
91
|
-
"
|
92
|
-
"
|
93
|
-
"
|
86
|
+
"kappa1": self.kappa_1,
|
87
|
+
"kappa2": self.kappa_2,
|
88
|
+
"averageNbPhotons": self.average_nb_photons,
|
94
89
|
}
|
95
|
-
|
96
|
-
return self._parameters
|
90
|
+
return {k: v for k, v in parameters.items() if v is not None}
|
97
91
|
|
98
92
|
|
99
93
|
class ClassiqBackendPreferences(BackendPreferences):
|
@@ -118,10 +112,6 @@ class AwsBackendPreferences(BackendPreferences):
|
|
118
112
|
s3_folder: pydantic_backend.PydanticS3BucketKey = pydantic.Field(
|
119
113
|
description="S3 Folder Path Within The S3 Bucket"
|
120
114
|
)
|
121
|
-
job_timeout: pydantic_backend.PydanticExecutionTimeout = pydantic.Field(
|
122
|
-
description="Timeout for Jobs sent for execution in seconds.",
|
123
|
-
default=AWS_DEFAULT_JOB_TIMEOUT_SECONDS,
|
124
|
-
)
|
125
115
|
|
126
116
|
@validator("s3_bucket_name")
|
127
117
|
def _validate_s3_bucket_name(
|
@@ -156,6 +146,10 @@ class IBMBackendPreferences(BackendPreferences):
|
|
156
146
|
default_factory=IBMBackendProvider,
|
157
147
|
description="Provider specs. for identifying a single IBM Quantum provider.",
|
158
148
|
)
|
149
|
+
qctrl_api_key: Optional[str] = pydantic.Field(
|
150
|
+
default=None,
|
151
|
+
description="QCTRL API key to access QCTRL optimization abilities",
|
152
|
+
)
|
159
153
|
|
160
154
|
@pydantic.root_validator(pre=True)
|
161
155
|
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
@@ -37,7 +37,7 @@ class IonqQuantumCircuit(BaseModel):
|
|
37
37
|
circuit: List[Gate]
|
38
38
|
|
39
39
|
# Ionq changes format sometimes.
|
40
|
-
# One example is that `
|
40
|
+
# One example is that `IonqQuantumCircuit` got a field name "gateset" with the value "qis"
|
41
41
|
# Another is that `Gate` got a field named "rotation"
|
42
42
|
class Config:
|
43
43
|
extra = pydantic.Extra.allow
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from datetime import timedelta
|
2
1
|
from typing import TYPE_CHECKING
|
3
2
|
|
4
3
|
import pydantic
|
@@ -11,12 +10,10 @@ INVALID_API_KEY: str = _IONQ_API_KEY_LENGTH * "a"
|
|
11
10
|
INVALID_API_KEY_ALICE_BOB: str = _ALICE_BOB_API_KEY_LENGTH * "a"
|
12
11
|
INVALID_EMAIL_OQC: str = "aa@aa.aa"
|
13
12
|
INVALID_PASSWORD_OQC: str = "Aa1!Aa1!"
|
14
|
-
MAX_EXECUTION_TIMEOUT_SECONDS = timedelta(hours=4).total_seconds()
|
15
13
|
|
16
14
|
EXECUTION_PARAMETER_PATTERN = "[_a-z][_a-z0-9]*"
|
17
15
|
|
18
16
|
if TYPE_CHECKING:
|
19
|
-
PydanticExecutionTimeout = int
|
20
17
|
PydanticAwsRoleArn = str
|
21
18
|
PydanticS3BucketKey = str
|
22
19
|
PydanticS3BucketName = str
|
@@ -42,8 +39,6 @@ else:
|
|
42
39
|
|
43
40
|
PydanticAliceBobApiKeyType = pydantic.constr(min_length=1, strip_whitespace=True)
|
44
41
|
|
45
|
-
PydanticExecutionTimeout = pydantic.conint(gt=0, le=MAX_EXECUTION_TIMEOUT_SECONDS)
|
46
|
-
|
47
42
|
PydanticArgumentNameType = pydantic.constr(regex="[_a-zA-Z][_a-zA-Z0-9]*")
|
48
43
|
|
49
44
|
PydanticExecutionParameter = pydantic.constr(regex=EXECUTION_PARAMETER_PATTERN)
|
@@ -41,8 +41,9 @@ class ClassiqSimulatorBackendNames(StrEnum):
|
|
41
41
|
class IonqBackendNames(StrEnum):
|
42
42
|
SIMULATOR = "simulator"
|
43
43
|
HARMONY = "qpu.harmony"
|
44
|
-
|
45
|
-
|
44
|
+
ARIA_1 = "qpu.aria-1"
|
45
|
+
ARIA_2 = "qpu.aria-2"
|
46
|
+
FORTE_1 = "qpu.forte-1"
|
46
47
|
|
47
48
|
|
48
49
|
class AzureQuantumBackendNames(StrEnum):
|
@@ -140,8 +140,12 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
140
140
|
def num_qubits(self) -> int:
|
141
141
|
return len(self.pauli_list[0][0])
|
142
142
|
|
143
|
+
@property
|
144
|
+
def all_coefficients_numeric(self) -> bool:
|
145
|
+
return all(isinstance(summand[1], complex) for summand in self.pauli_list)
|
146
|
+
|
143
147
|
def to_matrix(self) -> np.ndarray:
|
144
|
-
if not
|
148
|
+
if not self.all_coefficients_numeric:
|
145
149
|
raise ClassiqValueError(
|
146
150
|
"Supporting only Hamiltonian with numeric coefficients."
|
147
151
|
)
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from typing import Dict, Optional, Union
|
2
|
+
from uuid import UUID
|
3
|
+
|
4
|
+
from pydantic import BaseModel, Field
|
5
|
+
|
6
|
+
from classiq.interface.ide.visual_model import OperationLevel
|
7
|
+
|
8
|
+
|
9
|
+
class FunctionDebugInfo(BaseModel):
|
10
|
+
name: str
|
11
|
+
parameters: Dict[str, Union[int, float, None]]
|
12
|
+
level: OperationLevel
|
13
|
+
is_allocate_or_free: bool = Field(default=False)
|
14
|
+
|
15
|
+
|
16
|
+
class DebugInfoCollection(BaseModel):
|
17
|
+
# Pydantic only started supporting UUID as keys in Pydantic V2
|
18
|
+
# See https://github.com/pydantic/pydantic/issues/2096#issuecomment-814860206
|
19
|
+
# For now, we use strings as keys in the raw data and use UUID in the wrapper logic
|
20
|
+
data: Dict[str, FunctionDebugInfo] = Field(default_factory=dict)
|
21
|
+
|
22
|
+
def __setitem__(self, key: UUID, value: FunctionDebugInfo) -> None:
|
23
|
+
self.data[str(key)] = value
|
24
|
+
|
25
|
+
def get(self, key: UUID) -> Optional[FunctionDebugInfo]:
|
26
|
+
return self.data.get(str(key))
|
27
|
+
|
28
|
+
def __getitem__(self, key: UUID) -> FunctionDebugInfo:
|
29
|
+
return self.data[str(key)]
|
30
|
+
|
31
|
+
def __contains__(self, key: UUID) -> bool:
|
32
|
+
return str(key) in self.data
|