classiq 0.36.0__py3-none-any.whl → 0.37.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 +1 -0
- classiq/_internals/api_wrapper.py +24 -6
- classiq/_internals/authentication/device.py +6 -3
- classiq/_internals/authentication/token_manager.py +21 -5
- classiq/_internals/client.py +7 -2
- classiq/_internals/config.py +12 -0
- classiq/_internals/host_checker.py +1 -1
- classiq/_internals/jobs.py +3 -1
- classiq/_internals/type_validation.py +3 -6
- classiq/analyzer/analyzer.py +1 -0
- classiq/analyzer/rb.py +3 -5
- classiq/applications_model_constructors/chemistry_model_constructor.py +42 -67
- classiq/applications_model_constructors/grover_model_constructor.py +27 -18
- classiq/exceptions.py +5 -0
- classiq/execution/jobs.py +13 -4
- classiq/executor.py +3 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +0 -6
- classiq/interface/analyzer/result.py +0 -4
- classiq/interface/backend/backend_preferences.py +2 -2
- classiq/interface/backend/quantum_backend_providers.py +1 -1
- classiq/interface/execution/resource_estimator.py +7 -0
- classiq/interface/execution/result.py +5 -0
- classiq/interface/executor/register_initialization.py +3 -1
- classiq/interface/executor/vqe_result.py +1 -0
- classiq/interface/generator/ansatz_library.py +3 -3
- classiq/interface/generator/arith/argument_utils.py +4 -4
- classiq/interface/generator/arith/arithmetic.py +4 -2
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +11 -5
- classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -7
- classiq/interface/generator/arith/arithmetic_operations.py +7 -0
- classiq/interface/generator/arith/arithmetic_param_getters.py +97 -16
- classiq/interface/generator/arith/arithmetic_result_builder.py +13 -3
- classiq/interface/generator/arith/binary_ops.py +8 -10
- classiq/interface/generator/arith/extremum_operations.py +2 -2
- classiq/interface/generator/arith/number_utils.py +20 -23
- classiq/interface/generator/arith/register_user_input.py +3 -1
- classiq/interface/generator/arith/unary_ops.py +9 -13
- classiq/interface/generator/expressions/atomic_expression_functions.py +2 -0
- classiq/interface/generator/expressions/expression.py +7 -2
- classiq/interface/generator/expressions/qmod_qnum_proxy.py +22 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +2 -12
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +63 -3
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +143 -17
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +41 -16
- classiq/interface/generator/functions/native_function_definition.py +3 -3
- classiq/interface/generator/model/constraints.py +3 -3
- classiq/interface/generator/model/preferences/preferences.py +13 -9
- classiq/interface/generator/noise_properties.py +5 -5
- classiq/interface/generator/qpe.py +5 -5
- classiq/interface/generator/quantum_function_call.py +5 -3
- classiq/interface/generator/randomized_benchmarking.py +5 -3
- classiq/interface/generator/visitor.py +1 -2
- classiq/interface/hardware.py +1 -1
- classiq/interface/helpers/custom_pydantic_types.py +6 -0
- classiq/interface/model/{modular_addition_operation.py → inplace_binary_operation.py} +16 -2
- classiq/interface/model/native_function_definition.py +2 -24
- classiq/interface/model/operator_synthesis_data.py +6 -0
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +8 -4
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +9 -5
- classiq/interface/model/quantum_expressions/control_state.py +38 -0
- classiq/interface/model/quantum_expressions/quantum_expression.py +21 -11
- classiq/interface/model/quantum_function_call.py +81 -6
- classiq/interface/model/quantum_function_declaration.py +3 -3
- classiq/interface/model/quantum_if_operation.py +95 -0
- classiq/interface/model/resolvers/function_call_resolver.py +1 -1
- classiq/interface/model/validations/handles_validator.py +42 -15
- classiq/interface/server/routes.py +10 -6
- classiq/model/function_handler.pyi +86 -86
- classiq/model/model.py +1 -0
- classiq/qmod/__init__.py +6 -1
- classiq/qmod/builtins/__init__.py +13 -1
- classiq/qmod/builtins/classical_execution_primitives.py +109 -0
- classiq/qmod/builtins/classical_functions.py +68 -0
- classiq/qmod/builtins/functions.py +88 -18
- classiq/qmod/builtins/operations.py +60 -35
- classiq/qmod/classical_function.py +40 -0
- classiq/qmod/declaration_inferrer.py +5 -2
- classiq/qmod/qmod_variable.py +17 -10
- classiq/qmod/quantum_callable.py +24 -3
- classiq/qmod/quantum_expandable.py +131 -21
- classiq/qmod/quantum_function.py +12 -2
- classiq/qmod/symbolic.py +182 -107
- classiq/qmod/symbolic_expr.py +11 -10
- classiq/qmod/symbolic_type.py +8 -0
- classiq/quantum_functions/decorators.py +2 -4
- classiq/quantum_functions/function_library.py +1 -0
- {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/METADATA +1 -1
- {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/RECORD +90 -82
- classiq/interface/model/local_variable_declaration.py +0 -7
- {classiq-0.36.0.dist-info → classiq-0.37.0.dist-info}/WHEEL +0 -0
classiq/__init__.py
CHANGED
@@ -24,6 +24,10 @@ from classiq._internals.jobs import JobPoller
|
|
24
24
|
from classiq.exceptions import ClassiqAPIError, ClassiqValueError
|
25
25
|
|
26
26
|
ResultType = TypeVar("ResultType", bound=pydantic.BaseModel)
|
27
|
+
CLASSIQ_ACCEPT_HEADER = "X-Classiq-Accept-Version"
|
28
|
+
|
29
|
+
_ACCEPT_HEADER = "X-Classiq-Accept-Version"
|
30
|
+
_CONTENT_TYPE_HEADER = "X-Classiq-Content-Type-Version"
|
27
31
|
|
28
32
|
|
29
33
|
class HTTPMethod(StrEnum):
|
@@ -72,11 +76,13 @@ class ApiWrapper:
|
|
72
76
|
body: Optional[Dict] = None,
|
73
77
|
params: Optional[Dict] = None,
|
74
78
|
use_versioned_url: bool = True,
|
79
|
+
headers: Optional[Dict[str, str]] = None,
|
75
80
|
) -> dict:
|
76
81
|
res = await client().call_api(
|
77
82
|
http_method=http_method,
|
78
83
|
url=url,
|
79
84
|
body=body,
|
85
|
+
headers=headers,
|
80
86
|
params=params,
|
81
87
|
use_versioned_url=use_versioned_url,
|
82
88
|
)
|
@@ -101,10 +107,16 @@ class ApiWrapper:
|
|
101
107
|
url=routes.CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_FULL,
|
102
108
|
model=circuit,
|
103
109
|
)
|
110
|
+
headers = {
|
111
|
+
_ACCEPT_HEADER: "v1",
|
112
|
+
_CONTENT_TYPE_HEADER: execution_input["version"],
|
113
|
+
}
|
104
114
|
data = await cls._call_task(
|
105
115
|
http_method=HTTPMethod.POST,
|
106
|
-
|
116
|
+
headers=headers,
|
117
|
+
url=routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH,
|
107
118
|
body=execution_input,
|
119
|
+
use_versioned_url=False,
|
108
120
|
)
|
109
121
|
return execution_request.ExecutionJobDetails.parse_obj(data)
|
110
122
|
|
@@ -113,9 +125,12 @@ class ApiWrapper:
|
|
113
125
|
cls,
|
114
126
|
job_id: JobID,
|
115
127
|
) -> execution_request.ExecutionJobDetails:
|
128
|
+
headers = {_CONTENT_TYPE_HEADER: "v1"}
|
116
129
|
data = await cls._call_task(
|
117
130
|
http_method=HTTPMethod.GET,
|
118
|
-
|
131
|
+
headers=headers,
|
132
|
+
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
|
133
|
+
use_versioned_url=False,
|
119
134
|
)
|
120
135
|
return execution_request.ExecutionJobDetails.parse_obj(data)
|
121
136
|
|
@@ -123,11 +138,13 @@ class ApiWrapper:
|
|
123
138
|
async def call_get_execution_job_result(
|
124
139
|
cls,
|
125
140
|
job_id: JobID,
|
141
|
+
version: str,
|
126
142
|
) -> classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults:
|
127
143
|
data = await cls._call_task(
|
128
144
|
http_method=HTTPMethod.GET,
|
129
|
-
url=f"{routes.
|
145
|
+
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}/result",
|
130
146
|
use_versioned_url=False,
|
147
|
+
headers={CLASSIQ_ACCEPT_HEADER: version},
|
131
148
|
)
|
132
149
|
return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.parse_obj(
|
133
150
|
data
|
@@ -141,7 +158,7 @@ class ApiWrapper:
|
|
141
158
|
) -> ExecutionJobDetailsV1:
|
142
159
|
data = await cls._call_task(
|
143
160
|
http_method=HTTPMethod.PATCH,
|
144
|
-
url=f"{routes.
|
161
|
+
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
|
145
162
|
params={
|
146
163
|
"name": name,
|
147
164
|
},
|
@@ -157,7 +174,7 @@ class ApiWrapper:
|
|
157
174
|
) -> ExecutionJobsQueryResultsV1:
|
158
175
|
data = await cls._call_task(
|
159
176
|
http_method=HTTPMethod.GET,
|
160
|
-
url=f"{routes.
|
177
|
+
url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}",
|
161
178
|
params={
|
162
179
|
"offset": offset,
|
163
180
|
"limit": limit,
|
@@ -277,7 +294,8 @@ class ApiWrapper:
|
|
277
294
|
cls, problem: ground_state_problem.CHEMISTRY_PROBLEMS_TYPE
|
278
295
|
) -> operator.PauliOperator:
|
279
296
|
poller = JobPoller(
|
280
|
-
base_url=routes.GENERATE_HAMILTONIAN_FULL_PATH,
|
297
|
+
base_url=routes.GENERATE_HAMILTONIAN_FULL_PATH,
|
298
|
+
use_versioned_url=False,
|
281
299
|
)
|
282
300
|
result = await poller.run_pydantic(problem, timeout_sec=None)
|
283
301
|
return _parse_job_response(result, operator.PauliOperator)
|
@@ -18,7 +18,9 @@ class DeviceRegistrar:
|
|
18
18
|
_TIMEOUT_SEC: float = timedelta(minutes=15).total_seconds()
|
19
19
|
|
20
20
|
@classmethod
|
21
|
-
async def register(
|
21
|
+
async def register(
|
22
|
+
cls, get_refresh_token: bool = True, text_only: bool = False
|
23
|
+
) -> Tokens:
|
22
24
|
auth0_client = Auth0()
|
23
25
|
data: Dict[str, Any] = await auth0_client.get_device_data(
|
24
26
|
get_refresh_token=get_refresh_token
|
@@ -27,9 +29,10 @@ class DeviceRegistrar:
|
|
27
29
|
print(f"Your user code: {data['user_code']}")
|
28
30
|
verification_url = data["verification_uri_complete"]
|
29
31
|
print(
|
30
|
-
f"If a browser doesn't automatically open, please visit
|
32
|
+
f"If a browser doesn't automatically open, please visit this URL from any trusted device: {verification_url}"
|
31
33
|
)
|
32
|
-
|
34
|
+
if not text_only:
|
35
|
+
webbrowser.open(verification_url)
|
33
36
|
timeout = min(data["expires_in"], cls._TIMEOUT_SEC)
|
34
37
|
return await cls._poll_tokens(
|
35
38
|
auth0_client=auth0_client,
|
@@ -7,6 +7,7 @@ from typing import Optional
|
|
7
7
|
from classiq._internals.authentication import password_manager as pm
|
8
8
|
from classiq._internals.authentication.auth0 import Auth0
|
9
9
|
from classiq._internals.authentication.device import DeviceRegistrar, Tokens
|
10
|
+
from classiq._internals.config import Configuration
|
10
11
|
from classiq.exceptions import (
|
11
12
|
ClassiqAuthenticationError,
|
12
13
|
ClassiqPasswordManagerSelectionError,
|
@@ -17,9 +18,14 @@ _logger = logging.getLogger(__name__)
|
|
17
18
|
|
18
19
|
|
19
20
|
class TokenManager:
|
20
|
-
def __init__(
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
config: Configuration,
|
24
|
+
password_manager: Optional[pm.PasswordManager] = None,
|
25
|
+
) -> None:
|
26
|
+
self._config = config
|
21
27
|
if password_manager is None:
|
22
|
-
password_manager = self._make_password_manager()
|
28
|
+
password_manager = self._make_password_manager(self._config)
|
23
29
|
# We use threading.Lock instead of asyncio.Lock because the latter is coupled
|
24
30
|
# to a specific event loop, which is undesirable
|
25
31
|
self._lock = threading.Lock()
|
@@ -32,15 +38,23 @@ class TokenManager:
|
|
32
38
|
)
|
33
39
|
|
34
40
|
@classmethod
|
35
|
-
def
|
41
|
+
def _should_skip_authentication(cls) -> bool:
|
36
42
|
parser = argparse.ArgumentParser()
|
37
43
|
parser.add_argument(
|
38
44
|
"--skip-authentication", action="store_true", required=False
|
39
45
|
)
|
40
46
|
args, _ = parser.parse_known_args()
|
41
47
|
|
42
|
-
|
48
|
+
return args.skip_authentication
|
49
|
+
|
50
|
+
@classmethod
|
51
|
+
def _make_password_manager(cls, config: Configuration) -> pm.PasswordManager:
|
52
|
+
should_skip_authentication = cls._should_skip_authentication()
|
53
|
+
|
54
|
+
if should_skip_authentication:
|
43
55
|
return pm.DummyPasswordManager()
|
56
|
+
if config.text_only:
|
57
|
+
return pm.FilePasswordManager()
|
44
58
|
for password_manager in PASSWORD_MANAGERS:
|
45
59
|
if password_manager.is_supported():
|
46
60
|
return password_manager
|
@@ -108,5 +122,7 @@ class TokenManager:
|
|
108
122
|
async def _authentication_helper(self) -> None:
|
109
123
|
# TODO: consider using refresh token rotation
|
110
124
|
# (https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation)
|
111
|
-
tokens = await DeviceRegistrar.register(
|
125
|
+
tokens = await DeviceRegistrar.register(
|
126
|
+
get_refresh_token=True, text_only=self._config.text_only
|
127
|
+
)
|
112
128
|
self._save_tokens(tokens, force_override_refresh_token=True)
|
classiq/_internals/client.py
CHANGED
@@ -135,7 +135,7 @@ class Client:
|
|
135
135
|
|
136
136
|
def __init__(self, conf: config.Configuration) -> None:
|
137
137
|
self._config = conf
|
138
|
-
self._token_manager = token_manager.TokenManager()
|
138
|
+
self._token_manager = token_manager.TokenManager(config=self._config)
|
139
139
|
self._ssl_context = ssl.create_default_context()
|
140
140
|
self._HTTP_TIMEOUT_SECONDS = (
|
141
141
|
3600 # Needs to be synced with load-balancer timeout
|
@@ -205,6 +205,7 @@ class Client:
|
|
205
205
|
body: Optional[Dict] = None,
|
206
206
|
params: Optional[Dict] = None,
|
207
207
|
use_versioned_url: bool = True,
|
208
|
+
headers: Optional[Dict[str, str]] = None,
|
208
209
|
) -> Union[Dict, str]:
|
209
210
|
if use_versioned_url:
|
210
211
|
url = self.make_versioned_url(url)
|
@@ -214,6 +215,7 @@ class Client:
|
|
214
215
|
url=url,
|
215
216
|
json=body,
|
216
217
|
params=params,
|
218
|
+
headers=headers,
|
217
219
|
)
|
218
220
|
self.handle_response(response)
|
219
221
|
return response.json()
|
@@ -223,12 +225,15 @@ class Client:
|
|
223
225
|
http_method: str,
|
224
226
|
url: str,
|
225
227
|
body: Optional[Dict] = None,
|
228
|
+
headers: Optional[Dict] = None,
|
226
229
|
use_versioned_url: bool = True,
|
227
230
|
) -> Union[Dict, str]:
|
228
231
|
if use_versioned_url:
|
229
232
|
url = self.make_versioned_url(url)
|
230
233
|
with httpx.Client(**self._make_client_args()) as sync_client:
|
231
|
-
response = sync_client.request(
|
234
|
+
response = sync_client.request(
|
235
|
+
method=http_method, url=url, json=body, headers=headers
|
236
|
+
)
|
232
237
|
self.handle_response(response)
|
233
238
|
return response.json()
|
234
239
|
|
classiq/_internals/config.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Configuration of the SDK module."""
|
2
|
+
|
2
3
|
import os
|
3
4
|
import pathlib
|
4
5
|
from typing import List, Optional, Union
|
@@ -32,6 +33,9 @@ class Configuration(BaseModel):
|
|
32
33
|
mode: SDKMode = pydantic.Field(
|
33
34
|
default=SDKMode.PROD, description="The operational mode of the SDK"
|
34
35
|
)
|
36
|
+
text_only: bool = pydantic.Field(
|
37
|
+
default=False, description="Should classiq avoid relying on GUI"
|
38
|
+
)
|
35
39
|
|
36
40
|
|
37
41
|
_DEFAULT_CONFIG_FILES = [str(pathlib.Path("classiq", "config.ini"))]
|
@@ -94,6 +98,13 @@ def init(args: Optional[Union[str, List[str]]] = None) -> Configuration:
|
|
94
98
|
type=SDKMode,
|
95
99
|
default=SDKMode.PROD,
|
96
100
|
)
|
101
|
+
arg_parser.add_argument(
|
102
|
+
"--text-only",
|
103
|
+
dest="classiq_text_only",
|
104
|
+
help="Should classiq avoid relying on GUI",
|
105
|
+
env_var="CLASSIQ_TEXT_ONLY",
|
106
|
+
action="store_true",
|
107
|
+
)
|
97
108
|
|
98
109
|
parsed_args, _ = arg_parser.parse_known_args(args=args)
|
99
110
|
return Configuration(
|
@@ -101,4 +112,5 @@ def init(args: Optional[Union[str, List[str]]] = None) -> Configuration:
|
|
101
112
|
ide=parsed_args.classiq_ide,
|
102
113
|
should_check_host=not parsed_args.classiq_skip_check_host,
|
103
114
|
mode=parsed_args.classiq_mode,
|
115
|
+
text_only=parsed_args.classiq_text_only,
|
104
116
|
)
|
@@ -45,7 +45,7 @@ class HostChecker:
|
|
45
45
|
if lhs_version == cls._UNKNOWN_VERSION or rhs_version == cls._UNKNOWN_VERSION:
|
46
46
|
# In case one of those versions is unknown, they are considered equal
|
47
47
|
_logger.debug(
|
48
|
-
"Either
|
48
|
+
"Either %s or %s is an unknown version. Assuming both versions are equal.",
|
49
49
|
lhs_version,
|
50
50
|
rhs_version,
|
51
51
|
)
|
classiq/_internals/jobs.py
CHANGED
@@ -56,8 +56,10 @@ class JobPoller:
|
|
56
56
|
base_url: str,
|
57
57
|
required_headers: Optional[Set[str]] = None,
|
58
58
|
use_versioned_url: bool = True,
|
59
|
+
additional_headers: Optional[Dict[str, str]] = None,
|
59
60
|
) -> None:
|
60
61
|
self._required_headers = required_headers or set()
|
62
|
+
self._additional_headers = additional_headers
|
61
63
|
client_instance = client()
|
62
64
|
self._base_url = (
|
63
65
|
client_instance.make_versioned_url(base_url)
|
@@ -93,7 +95,7 @@ class JobPoller:
|
|
93
95
|
# Update headers in case they change
|
94
96
|
self._async_client.headers.update(client().get_headers())
|
95
97
|
response = await self._async_client.request(
|
96
|
-
method=http_method, url=url, json=body
|
98
|
+
method=http_method, url=url, json=body, headers=self._additional_headers
|
97
99
|
)
|
98
100
|
client().handle_response(response)
|
99
101
|
return response
|
@@ -11,8 +11,7 @@ U = TypeVar("U")
|
|
11
11
|
@overload
|
12
12
|
def validate_type(
|
13
13
|
obj: Any, expected_type: Type[T], operation: str, exception_type: Type[Exception]
|
14
|
-
) -> T:
|
15
|
-
...
|
14
|
+
) -> T: ...
|
16
15
|
|
17
16
|
|
18
17
|
@overload
|
@@ -21,8 +20,7 @@ def validate_type(
|
|
21
20
|
expected_type: Tuple[Type[T], Type[U]],
|
22
21
|
operation: str,
|
23
22
|
exception_type: Type[Exception],
|
24
|
-
) -> Union[T, U]:
|
25
|
-
...
|
23
|
+
) -> Union[T, U]: ...
|
26
24
|
|
27
25
|
|
28
26
|
@overload
|
@@ -31,8 +29,7 @@ def validate_type(
|
|
31
29
|
expected_type: Tuple[Type[T], ...],
|
32
30
|
operation: str,
|
33
31
|
exception_type: Type[Exception],
|
34
|
-
) -> Any:
|
35
|
-
...
|
32
|
+
) -> Any: ...
|
36
33
|
|
37
34
|
|
38
35
|
def validate_type(
|
classiq/analyzer/analyzer.py
CHANGED
classiq/analyzer/rb.py
CHANGED
@@ -12,7 +12,7 @@ from classiq.interface.analyzer.result import RbResults
|
|
12
12
|
from classiq._internals.api_wrapper import ApiWrapper
|
13
13
|
from classiq._internals.async_utils import Asyncify
|
14
14
|
from classiq.exceptions import ClassiqAnalyzerError
|
15
|
-
from classiq.executor import
|
15
|
+
from classiq.executor import BackendPreferencesAndResult
|
16
16
|
|
17
17
|
|
18
18
|
class RBAnalysis(metaclass=Asyncify):
|
@@ -86,8 +86,7 @@ def _strict_string(arg: Union[Enum, str]) -> str:
|
|
86
86
|
|
87
87
|
|
88
88
|
def order_executor_data_by_hardware(
|
89
|
-
mixed_data: List[
|
90
|
-
clifford_numbers_per_program: Dict[str, int],
|
89
|
+
mixed_data: List[BackendPreferencesAndResult],
|
91
90
|
) -> List[AnalysisRBParams]:
|
92
91
|
hardware_names: Set[str] = {
|
93
92
|
_strict_string(hardware.backend_name) for hardware, _, _ in mixed_data
|
@@ -96,9 +95,8 @@ def order_executor_data_by_hardware(
|
|
96
95
|
name: list() for name in hardware_names
|
97
96
|
}
|
98
97
|
cliffords_dicts: Dict[str, List[int]] = {name: list() for name in hardware_names}
|
99
|
-
for hardware,
|
98
|
+
for hardware, num_clifford, result in mixed_data:
|
100
99
|
hw_name: str = _strict_string(hardware.backend_name)
|
101
|
-
num_clifford: int = clifford_numbers_per_program[program.code] # type: ignore[index]
|
102
100
|
counts_dicts[hw_name].append(result.counts) # type: ignore[union-attr]
|
103
101
|
cliffords_dicts[hw_name].append(num_clifford)
|
104
102
|
|
@@ -27,7 +27,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
27
27
|
PortDeclarationDirection,
|
28
28
|
)
|
29
29
|
from classiq.interface.model.handle_binding import HandleBinding
|
30
|
-
from classiq.interface.model.local_variable_declaration import LocalVariableDeclaration
|
31
30
|
from classiq.interface.model.model import Model, SerializedModel
|
32
31
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
33
32
|
from classiq.interface.model.port_declaration import PortDeclaration
|
@@ -325,70 +324,49 @@ def _get_hartree_fock(
|
|
325
324
|
)
|
326
325
|
|
327
326
|
|
328
|
-
def _get_hea_function(
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
)
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
"reps": Expression(expr=f"{hea_parameters.reps}"),
|
354
|
-
"angle_params": Expression(expr="t"),
|
355
|
-
},
|
356
|
-
operands={
|
357
|
-
"operands_1qubit": [
|
358
|
-
QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
|
359
|
-
for gate in hea_parameters.one_qubit_gates
|
360
|
-
],
|
361
|
-
"operands_2qubit": [
|
362
|
-
QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
|
363
|
-
for gate in hea_parameters.two_qubit_gates
|
364
|
-
],
|
365
|
-
},
|
366
|
-
inouts={"x": HandleBinding(name="qbv")}
|
367
|
-
if use_hartree_fock
|
368
|
-
else {"x": HandleBinding(name="x")},
|
369
|
-
)
|
327
|
+
def _get_hea_function(hea_parameters: HEAParameters) -> QuantumFunctionCall:
|
328
|
+
return QuantumFunctionCall(
|
329
|
+
function="full_hea",
|
330
|
+
params={
|
331
|
+
"num_qubits": Expression(expr=f"{hea_parameters.num_qubits}"),
|
332
|
+
"is_parametrized": Expression(
|
333
|
+
expr=f"{[int(_is_parametric_gate(_HAE_GATE_MAPPING[gate])) for gate in hea_parameters.one_qubit_gates+hea_parameters.two_qubit_gates]}"
|
334
|
+
),
|
335
|
+
"connectivity_map": Expression(
|
336
|
+
expr=f"{[list(connectivity_pair) for connectivity_pair in hea_parameters.connectivity_map]}"
|
337
|
+
),
|
338
|
+
"reps": Expression(expr=f"{hea_parameters.reps}"),
|
339
|
+
"angle_params": Expression(expr="t"),
|
340
|
+
},
|
341
|
+
operands={
|
342
|
+
"operands_1qubit": [
|
343
|
+
QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
|
344
|
+
for gate in hea_parameters.one_qubit_gates
|
345
|
+
],
|
346
|
+
"operands_2qubit": [
|
347
|
+
QuantumLambdaFunction(body=[_HAE_GATE_MAPPING[gate]])
|
348
|
+
for gate in hea_parameters.two_qubit_gates
|
349
|
+
],
|
350
|
+
},
|
351
|
+
inouts={"x": HandleBinding(name="qbv")},
|
370
352
|
)
|
371
|
-
return result
|
372
353
|
|
373
354
|
|
374
355
|
def _get_ansatz(
|
375
356
|
chemistry_problem: CHEMISTRY_PROBLEMS_TYPE,
|
376
|
-
use_hartree_fock: bool,
|
377
357
|
ansatz_parameters: AnsatzParameters,
|
378
|
-
) ->
|
358
|
+
) -> QuantumFunctionCall:
|
379
359
|
if isinstance(ansatz_parameters, HEAParameters):
|
380
|
-
return _get_hea_function(ansatz_parameters
|
381
|
-
return
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
)
|
391
|
-
]
|
360
|
+
return _get_hea_function(ansatz_parameters)
|
361
|
+
return _get_chemistry_function(
|
362
|
+
chemistry_problem,
|
363
|
+
_ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING[type(ansatz_parameters)],
|
364
|
+
{"qbv": HandleBinding(name="qbv")},
|
365
|
+
{
|
366
|
+
param_name: Expression(expr=str(param_value))
|
367
|
+
for param_name, param_value in ansatz_parameters.__dict__.items()
|
368
|
+
},
|
369
|
+
)
|
392
370
|
|
393
371
|
|
394
372
|
def _get_chemistry_vqe_additional_params(
|
@@ -485,20 +463,17 @@ def _get_chemistry_quantum_main(
|
|
485
463
|
if use_hartree_fock:
|
486
464
|
body.append(_get_hartree_fock(chemistry_problem))
|
487
465
|
|
488
|
-
body
|
466
|
+
body.append(_get_ansatz(chemistry_problem, ansatz_parameters))
|
489
467
|
|
490
468
|
return NativeFunctionDefinition(
|
491
469
|
name="main",
|
492
470
|
param_decls=_get_chemistry_quantum_main_params(ansatz_parameters),
|
493
471
|
port_declarations=(
|
494
|
-
{
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
[
|
500
|
-
LocalVariableDeclaration(name="qbv"),
|
501
|
-
]
|
472
|
+
{
|
473
|
+
"qbv": PortDeclaration(
|
474
|
+
name="qbv", direction=PortDeclarationDirection.Output
|
475
|
+
)
|
476
|
+
}
|
502
477
|
),
|
503
478
|
body=body,
|
504
479
|
)
|
@@ -6,9 +6,11 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
6
6
|
)
|
7
7
|
from classiq.interface.model.bind_operation import BindOperation
|
8
8
|
from classiq.interface.model.handle_binding import HandleBinding, SlicedHandleBinding
|
9
|
-
from classiq.interface.model.local_variable_declaration import LocalVariableDeclaration
|
10
9
|
from classiq.interface.model.model import Model, SerializedModel
|
11
10
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
11
|
+
from classiq.interface.model.numeric_reinterpretation import (
|
12
|
+
NumericReinterpretationOperation,
|
13
|
+
)
|
12
14
|
from classiq.interface.model.port_declaration import PortDeclaration
|
13
15
|
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
14
16
|
ArithmeticOperation,
|
@@ -18,10 +20,9 @@ from classiq.interface.model.quantum_function_call import (
|
|
18
20
|
QuantumLambdaFunction,
|
19
21
|
)
|
20
22
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
21
|
-
from classiq.interface.model.quantum_type import
|
22
|
-
|
23
|
-
|
24
|
-
QuantumType,
|
23
|
+
from classiq.interface.model.quantum_type import QuantumNumeric
|
24
|
+
from classiq.interface.model.variable_declaration_statement import (
|
25
|
+
VariableDeclarationStatement,
|
25
26
|
)
|
26
27
|
|
27
28
|
from classiq import RegisterUserInput
|
@@ -108,13 +109,6 @@ def _construct_arithmetic_oracle(
|
|
108
109
|
)
|
109
110
|
|
110
111
|
|
111
|
-
def get_quantum_type(fraction_places: int) -> QuantumType:
|
112
|
-
if fraction_places > 0:
|
113
|
-
return QuantumFixedReal(fraction_places=Expression(expr=f"{fraction_places}"))
|
114
|
-
|
115
|
-
return QuantumInteger()
|
116
|
-
|
117
|
-
|
118
112
|
def grover_main_port_declarations(
|
119
113
|
definitions: List[Tuple[str, RegisterUserInput]],
|
120
114
|
direction: PortDeclarationDirection,
|
@@ -123,25 +117,38 @@ def grover_main_port_declarations(
|
|
123
117
|
name: PortDeclaration(
|
124
118
|
name=name,
|
125
119
|
size=Expression(expr=f"{reg.size}"),
|
126
|
-
quantum_type=
|
120
|
+
quantum_type=QuantumNumeric(),
|
127
121
|
direction=direction,
|
128
122
|
)
|
129
123
|
for name, reg in definitions
|
130
124
|
}
|
131
125
|
|
132
126
|
|
133
|
-
def
|
127
|
+
def _generate_variable_declaration_statements(
|
134
128
|
definitions: List[Tuple[str, RegisterUserInput]]
|
135
|
-
) -> List[
|
136
|
-
ret = [
|
129
|
+
) -> List[VariableDeclarationStatement]:
|
130
|
+
ret = [VariableDeclarationStatement(name="gsq")]
|
137
131
|
if len(definitions) >= 2:
|
138
132
|
ret += [
|
139
|
-
|
133
|
+
VariableDeclarationStatement(name=f"split{i}")
|
140
134
|
for i in range(len(definitions) - 2)
|
141
135
|
]
|
142
136
|
return ret
|
143
137
|
|
144
138
|
|
139
|
+
def reinterpret_registers(
|
140
|
+
definitions: List[Tuple[str, RegisterUserInput]]
|
141
|
+
) -> List[QuantumStatement]:
|
142
|
+
return [
|
143
|
+
NumericReinterpretationOperation(
|
144
|
+
target=HandleBinding(name=name),
|
145
|
+
fraction_digits=Expression(expr=f"{definition.fraction_places}"),
|
146
|
+
is_signed=Expression(expr=f"{definition.is_signed}"),
|
147
|
+
)
|
148
|
+
for name, definition in definitions
|
149
|
+
]
|
150
|
+
|
151
|
+
|
145
152
|
def construct_grover_model(
|
146
153
|
definitions: List[Tuple[str, RegisterUserInput]],
|
147
154
|
expression: str,
|
@@ -163,6 +170,7 @@ def construct_grover_model(
|
|
163
170
|
name=_PREDICATE_FUNCTION_NAME,
|
164
171
|
port_declarations=predicate_port_decls,
|
165
172
|
body=[
|
173
|
+
*reinterpret_registers(definitions),
|
166
174
|
ArithmeticOperation(
|
167
175
|
expression=Expression(expr=expression),
|
168
176
|
result_var=HandleBinding(name="res"),
|
@@ -175,8 +183,8 @@ def construct_grover_model(
|
|
175
183
|
port_declarations=grover_main_port_declarations(
|
176
184
|
definitions, PortDeclarationDirection.Output
|
177
185
|
),
|
178
|
-
local_handles=_generate_local_variable_declarations(definitions),
|
179
186
|
body=[
|
187
|
+
*_generate_variable_declaration_statements(definitions),
|
180
188
|
QuantumFunctionCall(
|
181
189
|
function="allocate",
|
182
190
|
positional_args=[
|
@@ -207,6 +215,7 @@ def construct_grover_model(
|
|
207
215
|
[reg.size for _, reg in definitions],
|
208
216
|
"gsq",
|
209
217
|
),
|
218
|
+
*reinterpret_registers(definitions),
|
210
219
|
],
|
211
220
|
),
|
212
221
|
],
|
classiq/exceptions.py
CHANGED
@@ -13,6 +13,11 @@ class ClassiqError(Exception):
|
|
13
13
|
def __init__(self, message: str) -> None:
|
14
14
|
message_with_link = message + CLASSIQ_SLACK_COMMUNITY_LINK
|
15
15
|
super().__init__(message_with_link)
|
16
|
+
self._raw_message = message
|
17
|
+
|
18
|
+
@property
|
19
|
+
def raw_message(self) -> str:
|
20
|
+
return self._raw_message
|
16
21
|
|
17
22
|
|
18
23
|
class ClassiqExecutionError(ClassiqError):
|