classiq 0.68.0__py3-none-any.whl → 0.70.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/_internals/api_wrapper.py +4 -8
- classiq/analyzer/analyzer.py +0 -18
- classiq/analyzer/url_utils.py +9 -4
- classiq/applications/combinatorial_helpers/pyomo_utils.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +8 -11
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/torch_utils.py +1 -1
- classiq/execution/jobs.py +2 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/quantum_backend_providers.py +8 -3
- classiq/interface/chemistry/operator.py +12 -28
- classiq/interface/debug_info/back_ref_util.py +22 -0
- classiq/interface/debug_info/debug_info.py +11 -21
- classiq/interface/executor/optimizer_preferences.py +1 -0
- classiq/interface/executor/quantum_instruction_set.py +1 -0
- classiq/interface/generator/arith/arithmetic.py +21 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +3 -3
- classiq/interface/generator/circuit_code/circuit_code.py +4 -0
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -0
- classiq/interface/generator/expressions/atomic_expression_functions.py +1 -2
- classiq/interface/generator/expressions/expression_types.py +8 -2
- classiq/interface/generator/expressions/proxies/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/__init__.py +0 -0
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +75 -0
- classiq/interface/generator/expressions/proxies/classical/classical_proxy.py +26 -0
- classiq/interface/generator/expressions/proxies/classical/classical_scalar_proxy.py +32 -0
- classiq/interface/generator/expressions/proxies/classical/classical_struct_proxy.py +31 -0
- classiq/interface/generator/expressions/proxies/quantum/__init__.py +0 -0
- classiq/interface/generator/expressions/{qmod_qarray_proxy.py → proxies/quantum/qmod_qarray_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qscalar_proxy.py → proxies/quantum/qmod_qscalar_proxy.py} +3 -1
- classiq/interface/generator/expressions/{qmod_qstruct_proxy.py → proxies/quantum/qmod_qstruct_proxy.py} +3 -1
- classiq/interface/generator/functions/classical_type.py +34 -29
- classiq/interface/generator/functions/type_name.py +26 -2
- classiq/interface/generator/generated_circuit_data.py +84 -27
- classiq/interface/generator/model/preferences/preferences.py +1 -0
- classiq/interface/generator/quantum_program.py +0 -1
- classiq/interface/generator/types/builtin_enum_declarations.py +1 -0
- classiq/interface/generator/types/enum_declaration.py +12 -1
- classiq/interface/ide/visual_model.py +0 -2
- classiq/interface/model/native_function_definition.py +0 -10
- classiq/interface/model/quantum_statement.py +1 -1
- classiq/interface/model/quantum_type.py +15 -3
- classiq/interface/server/routes.py +0 -6
- classiq/model_expansions/atomic_expression_functions_defs.py +9 -3
- classiq/model_expansions/evaluators/arg_type_match.py +4 -2
- classiq/model_expansions/evaluators/classical_expression.py +2 -2
- classiq/model_expansions/evaluators/control.py +1 -1
- classiq/model_expansions/evaluators/parameter_types.py +58 -16
- classiq/model_expansions/evaluators/quantum_type_utils.py +7 -57
- classiq/model_expansions/expression_evaluator.py +3 -1
- classiq/model_expansions/generative_functions.py +67 -7
- classiq/model_expansions/quantum_operations/arithmetic/__init__.py +0 -0
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +60 -0
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +9 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -13
- classiq/model_expansions/quantum_operations/quantum_function_call.py +0 -22
- classiq/model_expansions/scope.py +7 -6
- classiq/model_expansions/scope_initialization.py +20 -33
- classiq/model_expansions/transformers/model_renamer.py +13 -4
- classiq/model_expansions/visitors/variable_references.py +8 -4
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/amplitude_amplification.py +3 -7
- classiq/open_library/functions/discrete_sine_cosine_transform.py +4 -4
- classiq/open_library/functions/grover.py +2 -2
- classiq/open_library/functions/hea.py +3 -3
- classiq/open_library/functions/lookup_table.py +58 -0
- classiq/open_library/functions/modular_exponentiation.py +10 -20
- classiq/open_library/functions/qft_functions.py +2 -2
- classiq/open_library/functions/qsvt.py +8 -8
- classiq/open_library/functions/utility_functions.py +2 -2
- classiq/qmod/builtins/classical_functions.py +24 -7
- classiq/qmod/builtins/enums.py +1 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +26 -11
- classiq/qmod/cparam.py +32 -5
- classiq/qmod/declaration_inferrer.py +3 -1
- classiq/qmod/python_classical_type.py +10 -4
- classiq/qmod/qmod_parameter.py +8 -0
- classiq/qmod/qmod_variable.py +11 -14
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_function.py +3 -2
- classiq/qmod/semantics/annotation/call_annotation.py +0 -28
- classiq/qmod/semantics/annotation/qstruct_annotator.py +21 -1
- classiq/qmod/semantics/error_manager.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -1
- classiq/qmod/semantics/validation/type_hints.py +29 -0
- classiq/qmod/utilities.py +67 -2
- classiq/synthesis.py +9 -6
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/METADATA +10 -12
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/RECORD +95 -84
- {classiq-0.68.0.dist-info → classiq-0.70.0.dist-info}/WHEEL +1 -1
- classiq/interface/execution/jobs.py +0 -31
- /classiq/interface/generator/expressions/{qmod_struct_instance.py → proxies/classical/qmod_struct_instance.py} +0 -0
- /classiq/interface/generator/expressions/{qmod_sized_proxy.py → proxies/quantum/qmod_sized_proxy.py} +0 -0
@@ -22,10 +22,6 @@ from classiq.interface.execution.iqcc import (
|
|
22
22
|
IQCCProbeAuthData,
|
23
23
|
IQCCProbeAuthResponse,
|
24
24
|
)
|
25
|
-
from classiq.interface.execution.jobs import (
|
26
|
-
ExecutionJobDetailsV1,
|
27
|
-
ExecutionJobsQueryResultsV1,
|
28
|
-
)
|
29
25
|
from classiq.interface.execution.primitives import PrimitivesInput
|
30
26
|
from classiq.interface.executor import execution_request
|
31
27
|
from classiq.interface.generator import quantum_program as generator_result
|
@@ -218,7 +214,7 @@ class ApiWrapper:
|
|
218
214
|
job_id: JobID,
|
219
215
|
name: str,
|
220
216
|
http_client: Optional[httpx.AsyncClient] = None,
|
221
|
-
) ->
|
217
|
+
) -> execution_request.ExecutionJobDetails:
|
222
218
|
data = await cls._call_task(
|
223
219
|
http_method=HTTPMethod.PATCH,
|
224
220
|
url=f"{routes.EXECUTION_JOBS_FULL_PATH}/{job_id.job_id}",
|
@@ -227,7 +223,7 @@ class ApiWrapper:
|
|
227
223
|
},
|
228
224
|
http_client=http_client,
|
229
225
|
)
|
230
|
-
return
|
226
|
+
return execution_request.ExecutionJobDetails.model_validate(data)
|
231
227
|
|
232
228
|
@classmethod
|
233
229
|
async def call_cancel_execution_job(
|
@@ -248,7 +244,7 @@ class ApiWrapper:
|
|
248
244
|
offset: int,
|
249
245
|
limit: int,
|
250
246
|
http_client: Optional[httpx.AsyncClient] = None,
|
251
|
-
) ->
|
247
|
+
) -> execution_request.ExecutionJobsQueryResults:
|
252
248
|
data = await cls._call_task(
|
253
249
|
http_method=HTTPMethod.GET,
|
254
250
|
url=f"{routes.EXECUTION_JOBS_FULL_PATH}",
|
@@ -258,7 +254,7 @@ class ApiWrapper:
|
|
258
254
|
},
|
259
255
|
http_client=http_client,
|
260
256
|
)
|
261
|
-
return
|
257
|
+
return execution_request.ExecutionJobsQueryResults.model_validate(data)
|
262
258
|
|
263
259
|
@classmethod
|
264
260
|
async def call_analysis_task(
|
classiq/analyzer/analyzer.py
CHANGED
@@ -5,7 +5,6 @@ import webbrowser
|
|
5
5
|
from collections.abc import Sequence
|
6
6
|
from importlib.util import find_spec
|
7
7
|
from typing import Any, Optional, Union
|
8
|
-
from urllib.parse import urljoin
|
9
8
|
|
10
9
|
import plotly.graph_objects as go
|
11
10
|
|
@@ -21,7 +20,6 @@ from classiq.analyzer.analyzer_utilities import (
|
|
21
20
|
DeviceName,
|
22
21
|
ProviderNameEnum,
|
23
22
|
)
|
24
|
-
from classiq.analyzer.url_utils import circuit_page_uri, client_ide_base_url
|
25
23
|
|
26
24
|
find_ipywidgets = find_spec("ipywidgets")
|
27
25
|
VBox = Any
|
@@ -63,22 +61,6 @@ class Analyzer(AnalyzerUtilities):
|
|
63
61
|
transpilation_option=self.circuit.model.execution_preferences.transpile_to_hardware,
|
64
62
|
)
|
65
63
|
|
66
|
-
def analyzer_app(self) -> None:
|
67
|
-
"""Opens the analyzer app with synthesis interactive results.
|
68
|
-
|
69
|
-
Returns:
|
70
|
-
None.
|
71
|
-
"""
|
72
|
-
result = async_utils.run(ApiWrapper.call_analyzer_app(self.circuit))
|
73
|
-
webbrowser.open_new_tab(
|
74
|
-
urljoin(
|
75
|
-
client_ide_base_url(),
|
76
|
-
circuit_page_uri(
|
77
|
-
circuit_id=result.id, circuit_version=self.circuit.version
|
78
|
-
),
|
79
|
-
)
|
80
|
-
)
|
81
|
-
|
82
64
|
def get_available_devices(
|
83
65
|
self, providers: Optional[list[ProviderNameEnum]] = None
|
84
66
|
) -> dict[ProviderNameEnum, list[DeviceName]]:
|
classiq/analyzer/url_utils.py
CHANGED
@@ -7,6 +7,7 @@ import classiq
|
|
7
7
|
|
8
8
|
QUERY_START_MARK = "?"
|
9
9
|
VERSION_QUERY_PARAM = "version"
|
10
|
+
LOGIN_QUERY_PARAM = "login"
|
10
11
|
|
11
12
|
|
12
13
|
def client_ide_base_url() -> str:
|
@@ -14,13 +15,17 @@ def client_ide_base_url() -> str:
|
|
14
15
|
return str(client.config.ide)
|
15
16
|
|
16
17
|
|
17
|
-
def
|
18
|
-
return
|
19
|
-
{
|
18
|
+
def circuit_page_search_params(circuit_version: str) -> str:
|
19
|
+
return urllib.parse.urlencode(
|
20
|
+
{
|
21
|
+
LOGIN_QUERY_PARAM: True,
|
22
|
+
VERSION_QUERY_PARAM: circuit_version,
|
23
|
+
}
|
20
24
|
)
|
21
25
|
|
22
26
|
|
23
27
|
def circuit_page_uri(circuit_id: str, circuit_version: str) -> str:
|
24
28
|
url = urljoin(f"{routes.ANALYZER_CIRCUIT_PAGE}/", circuit_id)
|
25
|
-
|
29
|
+
query_string = circuit_page_search_params(circuit_version)
|
30
|
+
url += QUERY_START_MARK + query_string
|
26
31
|
return url
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import copy
|
1
2
|
import math
|
2
3
|
import re
|
3
4
|
from collections import defaultdict
|
@@ -209,6 +210,7 @@ def convert_pyomo_to_global_presentation(
|
|
209
210
|
def pyomo2qmod(
|
210
211
|
struct_name: str, pyo_model: ConcreteModel
|
211
212
|
) -> CombinatorialOptimizationStructDeclaration:
|
213
|
+
pyo_model = copy.deepcopy(pyo_model)
|
212
214
|
symbols_map = PyomoSympyBimap()
|
213
215
|
|
214
216
|
variables: list[sympy.Symbol] = []
|
@@ -24,7 +24,6 @@ from classiq.open_library.functions.utility_functions import (
|
|
24
24
|
from classiq.qmod.builtins.functions import RX
|
25
25
|
from classiq.qmod.builtins.operations import allocate, phase, repeat
|
26
26
|
from classiq.qmod.cparam import CReal
|
27
|
-
from classiq.qmod.create_model_function import create_model
|
28
27
|
from classiq.qmod.qfunc import qfunc
|
29
28
|
from classiq.qmod.qmod_parameter import CArray
|
30
29
|
from classiq.qmod.qmod_variable import Output, QVar
|
@@ -75,17 +74,15 @@ class CombinatorialProblem:
|
|
75
74
|
hadamard_transform(v)
|
76
75
|
repeat(
|
77
76
|
self.num_layers_,
|
78
|
-
lambda i: [
|
79
|
-
phase(
|
80
|
-
-self.cost_func(v), params[i]
|
81
|
-
), # type:ignore[func-returns-value]
|
77
|
+
lambda i: [
|
78
|
+
phase(-self.cost_func(v), params[i]),
|
82
79
|
apply_to_all(lambda q: RX(params[self.num_layers_ + i], q), v),
|
83
80
|
],
|
84
81
|
)
|
85
82
|
|
86
|
-
self.model_ = create_model(
|
87
|
-
|
88
|
-
) # type:ignore[assignment]
|
83
|
+
self.model_ = main.create_model(
|
84
|
+
constraints=constraints, preferences=preferences
|
85
|
+
).get_model() # type:ignore[assignment]
|
89
86
|
return self.model_ # type:ignore[return-value]
|
90
87
|
|
91
88
|
def get_qprog(self) -> SerializedQuantumProgram:
|
@@ -199,13 +196,13 @@ def execute_qaoa(
|
|
199
196
|
hadamard_transform(v)
|
200
197
|
repeat(
|
201
198
|
num_layers,
|
202
|
-
lambda i: [
|
203
|
-
phase(-cost_func(v), params[i]),
|
199
|
+
lambda i: [
|
200
|
+
phase(-cost_func(v), params[i]),
|
204
201
|
apply_to_all(lambda q: RX(params[num_layers + i], q), v),
|
205
202
|
],
|
206
203
|
)
|
207
204
|
|
208
|
-
model = create_model(
|
205
|
+
model = main.create_model().get_model()
|
209
206
|
qprog = synthesize(model)
|
210
207
|
|
211
208
|
with ExecutionSession(qprog, execution_preferences) as es:
|
@@ -71,7 +71,7 @@ class SimpleQuantumGradient(QuantumGradient):
|
|
71
71
|
post_process: PostProcessFunction,
|
72
72
|
epsilon: float = EPSILON,
|
73
73
|
*args: Any,
|
74
|
-
**kwargs: Any
|
74
|
+
**kwargs: Any,
|
75
75
|
) -> None:
|
76
76
|
super().__init__(quantum_program, execute, post_process)
|
77
77
|
self._epsilon = epsilon
|
@@ -94,7 +94,7 @@ def iter_inputs_weights(
|
|
94
94
|
post_process: PostProcessFunction,
|
95
95
|
*,
|
96
96
|
expected_shape: Shape = (),
|
97
|
-
requires_grad: Optional[bool] = None
|
97
|
+
requires_grad: Optional[bool] = None,
|
98
98
|
) -> Tensor:
|
99
99
|
if is_single_layer_circuit(weights):
|
100
100
|
iter_weights = torch.reshape(weights, (1, weights.shape[0]))
|
classiq/execution/jobs.py
CHANGED
@@ -9,7 +9,6 @@ from classiq.interface.exceptions import (
|
|
9
9
|
ClassiqAPIError,
|
10
10
|
ClassiqError,
|
11
11
|
)
|
12
|
-
from classiq.interface.execution.jobs import ExecutionJobDetailsV1
|
13
12
|
from classiq.interface.executor.execution_request import ExecutionJobDetails, JobCost
|
14
13
|
from classiq.interface.executor.execution_result import ResultsCollection
|
15
14
|
from classiq.interface.executor.result import (
|
@@ -26,8 +25,6 @@ from classiq._internals.async_utils import syncify_function
|
|
26
25
|
from classiq._internals.client import client
|
27
26
|
from classiq._internals.jobs import JobID, JobPoller
|
28
27
|
|
29
|
-
_JobDetails = Union[ExecutionJobDetails, ExecutionJobDetailsV1]
|
30
|
-
|
31
28
|
|
32
29
|
class ClassiqExecutionResultError(ClassiqError):
|
33
30
|
def __init__(self, primitive: str) -> None:
|
@@ -37,10 +34,10 @@ class ClassiqExecutionResultError(ClassiqError):
|
|
37
34
|
|
38
35
|
|
39
36
|
class ExecutionJob:
|
40
|
-
_details:
|
37
|
+
_details: ExecutionJobDetails
|
41
38
|
_result: Optional[ResultsCollection]
|
42
39
|
|
43
|
-
def __init__(self, details:
|
40
|
+
def __init__(self, details: ExecutionJobDetails) -> None:
|
44
41
|
self._details = details
|
45
42
|
self._result = None
|
46
43
|
|
classiq/interface/_version.py
CHANGED
@@ -172,15 +172,20 @@ class ClassiqNvidiaBackendNames(StrEnum):
|
|
172
172
|
|
173
173
|
SIMULATOR = "nvidia_simulator"
|
174
174
|
SIMULATOR_STATEVECTOR = "nvidia_simulator_statevector"
|
175
|
+
BRAKET_NVIDIA_SIMULATOR = "braket_nvidia_simulator"
|
176
|
+
BRAKET_NVIDIA_SIMULATOR_STATEVECTOR = "braket_nvidia_simulator_statevector"
|
177
|
+
|
178
|
+
def is_braket_nvidia_backend(self) -> bool:
|
179
|
+
return self in (
|
180
|
+
self.BRAKET_NVIDIA_SIMULATOR,
|
181
|
+
self.BRAKET_NVIDIA_SIMULATOR_STATEVECTOR,
|
182
|
+
)
|
175
183
|
|
176
184
|
|
177
185
|
class IntelBackendNames(StrEnum):
|
178
186
|
SIMULATOR = "intel_qsdk_simulator"
|
179
187
|
|
180
188
|
|
181
|
-
AllClassiqBackendNames = Union[ClassiqSimulatorBackendNames, ClassiqNvidiaBackendNames]
|
182
|
-
|
183
|
-
|
184
189
|
class GoogleNvidiaBackendNames(StrEnum):
|
185
190
|
"""
|
186
191
|
Google backend names which Classiq Supports running on.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from collections.abc import Collection
|
2
2
|
from functools import reduce
|
3
|
+
from itertools import combinations
|
3
4
|
from typing import (
|
4
5
|
Any,
|
5
6
|
Optional,
|
@@ -84,31 +85,11 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
84
85
|
raise ClassiqValueError("Pauli strings have incompatible lengths.")
|
85
86
|
return pauli_list
|
86
87
|
|
87
|
-
@staticmethod
|
88
|
-
def check_if_hermitian(pauli_list: PydanticPauliList) -> bool:
|
89
|
-
if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
|
90
|
-
if all(np.isclose(summand[1].imag, 0) for summand in pauli_list): # type: ignore[union-attr]
|
91
|
-
return True
|
92
|
-
|
93
|
-
for pauli_string, coeff in pauli_list:
|
94
|
-
reverse_string = pauli_string[::-1]
|
95
|
-
reverse_found = False
|
96
|
-
for other_string, other_coeff in pauli_list:
|
97
|
-
if other_string == reverse_string and np.isclose(
|
98
|
-
coeff, other_coeff.conjugate() # type: ignore[union-attr]
|
99
|
-
):
|
100
|
-
reverse_found = True
|
101
|
-
break
|
102
|
-
if not reverse_found:
|
103
|
-
return False
|
104
|
-
return True
|
105
|
-
return False
|
106
|
-
|
107
88
|
@pydantic.model_validator(mode="before")
|
108
89
|
@classmethod
|
109
90
|
def _validate_hermitianity(cls, values: dict[str, Any]) -> dict[str, Any]:
|
110
91
|
pauli_list = values.get("pauli_list", [])
|
111
|
-
if
|
92
|
+
if all(isinstance(summand[1], (float, int, complex)) for summand in pauli_list):
|
112
93
|
values["is_hermitian"] = all(
|
113
94
|
np.isclose(complex(summand[1]).real, summand[1])
|
114
95
|
for summand in pauli_list
|
@@ -144,16 +125,19 @@ class PauliOperator(HashablePydanticBaseModel, VersionedModel):
|
|
144
125
|
@property
|
145
126
|
def is_commutative(self) -> bool:
|
146
127
|
return all(
|
147
|
-
self.
|
148
|
-
|
149
|
-
)
|
150
|
-
for qubit_num in range(self.num_qubits)
|
128
|
+
self._do_paulis_commute(first[0], second[0])
|
129
|
+
for first, second in combinations(self.pauli_list, 2)
|
151
130
|
)
|
152
131
|
|
153
132
|
@staticmethod
|
154
|
-
def
|
155
|
-
|
156
|
-
|
133
|
+
def _do_paulis_commute(
|
134
|
+
first: PydanticPauliMonomialStr, second: PydanticPauliMonomialStr
|
135
|
+
) -> bool:
|
136
|
+
commute = True
|
137
|
+
for c1, c2 in zip(first, second):
|
138
|
+
if (c1 != "I") and (c2 != "I") and (c1 != c2):
|
139
|
+
commute = not commute
|
140
|
+
return commute
|
157
141
|
|
158
142
|
@property
|
159
143
|
def num_qubits(self) -> int:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from classiq.interface.model.allocate import Allocate
|
2
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
3
|
+
from classiq.interface.model.statement_block import (
|
4
|
+
ConcreteQuantumStatement,
|
5
|
+
StatementBlock,
|
6
|
+
)
|
7
|
+
|
8
|
+
"""
|
9
|
+
This module contains helper functions to determine if a given quantum statement
|
10
|
+
is an allocation or free statement.
|
11
|
+
"""
|
12
|
+
|
13
|
+
|
14
|
+
def is_allocate_or_free(concrete_quantum_statement: ConcreteQuantumStatement) -> bool:
|
15
|
+
return isinstance(concrete_quantum_statement, Allocate) or (
|
16
|
+
isinstance(concrete_quantum_statement, QuantumFunctionCall)
|
17
|
+
and concrete_quantum_statement.function == "free"
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
def is_allocate_or_free_by_backref(back_refs: StatementBlock) -> bool:
|
22
|
+
return len(back_refs) > 0 and is_allocate_or_free(back_refs[0])
|
@@ -1,34 +1,23 @@
|
|
1
|
-
import json
|
2
1
|
from collections.abc import Mapping
|
3
|
-
from typing import
|
2
|
+
from typing import Optional, Union
|
4
3
|
from uuid import UUID
|
5
4
|
|
6
5
|
from pydantic import BaseModel, Field
|
7
6
|
|
8
|
-
from classiq.interface.
|
7
|
+
from classiq.interface.debug_info import back_ref_util
|
9
8
|
from classiq.interface.generator.generated_circuit_data import (
|
10
9
|
FunctionDebugInfoInterface,
|
11
10
|
OperationLevel,
|
11
|
+
StatementType,
|
12
12
|
)
|
13
13
|
from classiq.interface.model.statement_block import ConcreteQuantumStatement
|
14
14
|
|
15
15
|
ParameterValue = Union[float, int, str, None]
|
16
16
|
|
17
17
|
|
18
|
-
class StatementType(StrEnum):
|
19
|
-
CONTROL = "control"
|
20
|
-
POWER = "power"
|
21
|
-
INVERT = "invert"
|
22
|
-
WITHIN_APPLY = "within_apply"
|
23
|
-
ASSIGNMENT = "assignment"
|
24
|
-
REPEAT = "repeat"
|
25
|
-
|
26
|
-
|
27
18
|
class FunctionDebugInfo(BaseModel):
|
28
19
|
name: str
|
29
|
-
|
30
|
-
parameters: dict[str, str]
|
31
|
-
level: OperationLevel
|
20
|
+
level: OperationLevel = Field(default=OperationLevel.UNKNOWN)
|
32
21
|
statement_type: Union[StatementType, None] = None
|
33
22
|
is_allocate_or_free: bool = Field(default=False)
|
34
23
|
is_inverse: bool = Field(default=False)
|
@@ -36,12 +25,13 @@ class FunctionDebugInfo(BaseModel):
|
|
36
25
|
port_to_passed_variable_map: dict[str, str] = Field(default_factory=dict)
|
37
26
|
node: Optional[ConcreteQuantumStatement] = None
|
38
27
|
|
39
|
-
@
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
@property
|
29
|
+
def is_allocate_or_free_(self) -> bool:
|
30
|
+
return (
|
31
|
+
back_ref_util.is_allocate_or_free(self.node)
|
32
|
+
if self.node is not None
|
33
|
+
else self.is_allocate_or_free
|
34
|
+
)
|
45
35
|
|
46
36
|
def update_map_from_port_mapping(self, port_mapping: Mapping[str, str]) -> None:
|
47
37
|
new_port_to_passed_variable_map = self.port_to_passed_variable_map.copy()
|
@@ -22,6 +22,9 @@ from classiq.interface.generator.arith.arithmetic_result_builder import (
|
|
22
22
|
)
|
23
23
|
from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
|
24
24
|
from classiq.interface.generator.expressions.expression import Expression
|
25
|
+
from classiq.interface.generator.expressions.expression_constants import (
|
26
|
+
BOOLEAN_LITERALS,
|
27
|
+
)
|
25
28
|
from classiq.interface.model.quantum_type import (
|
26
29
|
QuantumNumeric,
|
27
30
|
QuantumType,
|
@@ -40,6 +43,10 @@ def is_zero(expr: str) -> bool:
|
|
40
43
|
return is_constant(expr) and float(expr) == 0
|
41
44
|
|
42
45
|
|
46
|
+
def is_bool(expr: str) -> bool:
|
47
|
+
return expr in BOOLEAN_LITERALS
|
48
|
+
|
49
|
+
|
43
50
|
class Arithmetic(ArithmeticExpressionABC):
|
44
51
|
target: Optional[RegisterArithmeticInfo] = None
|
45
52
|
inputs_to_save: set[str] = pydantic.Field(default_factory=set)
|
@@ -115,7 +122,7 @@ def get_arithmetic_params(
|
|
115
122
|
def compute_arithmetic_result_type(
|
116
123
|
expr_str: str, var_types: dict[str, QuantumType], machine_precision: int
|
117
124
|
) -> QuantumNumeric:
|
118
|
-
if is_zero(expr_str):
|
125
|
+
if is_zero(expr_str) or is_bool(expr_str):
|
119
126
|
return QuantumNumeric(
|
120
127
|
size=Expression(expr="1"),
|
121
128
|
is_signed=Expression(expr="False"),
|
@@ -153,6 +160,17 @@ def aggregate_numeric_types(
|
|
153
160
|
)
|
154
161
|
|
155
162
|
|
163
|
+
def _eval_num(val: ast.AST) -> float:
|
164
|
+
if isinstance(val, ast.Num):
|
165
|
+
return cast(float, val.value)
|
166
|
+
if isinstance(val, ast.UnaryOp) and isinstance(val.op, ast.USub):
|
167
|
+
return -_eval_num(val.operand)
|
168
|
+
raise ClassiqValueError(
|
169
|
+
"Classical lists with quantum subscripts must contain compile-time classical "
|
170
|
+
"real numbers"
|
171
|
+
)
|
172
|
+
|
173
|
+
|
156
174
|
class _QuantumSubscriptRemover(ast.NodeTransformer):
|
157
175
|
def __init__(self, machine_precision: int) -> None:
|
158
176
|
self._machine_precision = machine_precision
|
@@ -161,10 +179,7 @@ class _QuantumSubscriptRemover(ast.NodeTransformer):
|
|
161
179
|
def visit_Call(self, node: ast.Call) -> ast.expr:
|
162
180
|
if not isinstance(node.func, ast.Name) or node.func.id != "Piecewise":
|
163
181
|
return node
|
164
|
-
items = [
|
165
|
-
cast(float, cast(ast.Num, cast(ast.Tuple, arg).elts[0]).value)
|
166
|
-
for arg in node.args
|
167
|
-
]
|
182
|
+
items = [_eval_num(cast(ast.Tuple, arg).elts[0]) for arg in node.args]
|
168
183
|
numeric_types = [
|
169
184
|
compute_arithmetic_result_type(str(num), {}, self._machine_precision)
|
170
185
|
for num in items
|
@@ -172,7 +187,7 @@ class _QuantumSubscriptRemover(ast.NodeTransformer):
|
|
172
187
|
unified_numeric_type = register_info_to_quantum_type(
|
173
188
|
aggregate_numeric_types(numeric_types)
|
174
189
|
)
|
175
|
-
substitution_var_name = f"
|
190
|
+
substitution_var_name = f"lut__{len(self.substitutions_types)}__"
|
176
191
|
self.substitutions_types[substitution_var_name] = unified_numeric_type
|
177
192
|
return ast.Name(id=substitution_var_name)
|
178
193
|
|
@@ -59,7 +59,7 @@ def get_params(
|
|
59
59
|
machine_precision: int,
|
60
60
|
output_size: Optional[int] = None,
|
61
61
|
inplace_arg: Optional[str] = None,
|
62
|
-
target: Optional[RegisterArithmeticInfo] = None
|
62
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
63
63
|
) -> ArithmeticOperationParams:
|
64
64
|
operation = id2op(node_id)
|
65
65
|
if target and not operation_allows_target(operation):
|
@@ -334,7 +334,7 @@ def logical_and_params_getter(
|
|
334
334
|
machine_precision: int,
|
335
335
|
output_size: Optional[int] = None,
|
336
336
|
inplace_arg: Optional[str] = None,
|
337
|
-
target: Optional[RegisterArithmeticInfo] = None
|
337
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
338
338
|
) -> ArithmeticOperationParams:
|
339
339
|
return LogicalAnd(args=arg, target=target, machine_precision=machine_precision)
|
340
340
|
|
@@ -344,7 +344,7 @@ def logical_or_params_getter(
|
|
344
344
|
machine_precision: int,
|
345
345
|
output_size: Optional[int] = None,
|
346
346
|
inplace_arg: Optional[str] = None,
|
347
|
-
target: Optional[RegisterArithmeticInfo] = None
|
347
|
+
target: Optional[RegisterArithmeticInfo] = None,
|
348
348
|
) -> ArithmeticOperationParams:
|
349
349
|
return LogicalOr(args=arg, target=target, machine_precision=machine_precision)
|
350
350
|
|
@@ -49,6 +49,10 @@ class CircuitCodeInterface(pydantic.BaseModel):
|
|
49
49
|
def qasm_cirq_compatible(self) -> Optional[Code]:
|
50
50
|
return self.outputs.get(QuantumFormat.QASM_CIRQ_COMPATIBLE)
|
51
51
|
|
52
|
+
@property
|
53
|
+
def _execution_serialization(self) -> Optional[Code]:
|
54
|
+
return self.outputs.get(QuantumFormat.EXECUTION_SERIALIZATION)
|
55
|
+
|
52
56
|
def get_code(self, instruction_set: QuantumInstructionSet) -> Code:
|
53
57
|
quantum_format: QuantumFormat = INSTRUCTION_SET_TO_FORMAT[instruction_set]
|
54
58
|
code = self.outputs.get(quantum_format)
|
@@ -12,6 +12,7 @@ INSTRUCTION_SET_TO_FORMAT: dict[QuantumInstructionSet, QuantumFormat] = {
|
|
12
12
|
QuantumInstructionSet.QASM: QuantumFormat.QASM,
|
13
13
|
QuantumInstructionSet.QSHARP: QuantumFormat.QSHARP,
|
14
14
|
QuantumInstructionSet.IONQ: QuantumFormat.IONQ,
|
15
|
+
QuantumInstructionSet.INTERNAL: QuantumFormat.EXECUTION_SERIALIZATION,
|
15
16
|
}
|
16
17
|
VENDOR_TO_INSTRUCTION_SET: dict[Provider, QuantumInstructionSet] = {
|
17
18
|
Provider.CLASSIQ: QuantumInstructionSet.QASM,
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from classiq.interface.generator.functions.classical_type import CLASSICAL_ATTRIBUTES
|
2
|
-
|
3
1
|
SUPPORTED_PYTHON_BUILTIN_FUNCTIONS = {"len", "sum", "print"}
|
4
2
|
|
5
3
|
SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
|
@@ -33,6 +31,7 @@ SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
|
|
33
31
|
*SUPPORTED_PYTHON_BUILTIN_FUNCTIONS,
|
34
32
|
}
|
35
33
|
|
34
|
+
CLASSICAL_ATTRIBUTES = {"len", "size", "is_signed", "fraction_digits"}
|
36
35
|
SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS_QMOD = (
|
37
36
|
SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS - CLASSICAL_ATTRIBUTES
|
38
37
|
)
|
@@ -4,10 +4,15 @@ from sympy import Expr
|
|
4
4
|
from sympy.logic.boolalg import Boolean
|
5
5
|
|
6
6
|
from classiq.interface.generator.expressions.handle_identifier import HandleIdentifier
|
7
|
-
from classiq.interface.generator.expressions.
|
8
|
-
|
7
|
+
from classiq.interface.generator.expressions.proxies.classical.classical_proxy import (
|
8
|
+
ClassicalProxy,
|
9
|
+
)
|
10
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
9
11
|
QmodStructInstance,
|
10
12
|
)
|
13
|
+
from classiq.interface.generator.expressions.proxies.quantum.qmod_sized_proxy import (
|
14
|
+
QmodSizedProxy,
|
15
|
+
)
|
11
16
|
from classiq.interface.generator.expressions.type_proxy import TypeProxy
|
12
17
|
|
13
18
|
RuntimeConstant = Union[
|
@@ -19,6 +24,7 @@ RuntimeConstant = Union[
|
|
19
24
|
QmodSizedProxy,
|
20
25
|
TypeProxy,
|
21
26
|
HandleIdentifier,
|
27
|
+
ClassicalProxy,
|
22
28
|
]
|
23
29
|
RuntimeExpression = Union[Expr, Boolean]
|
24
30
|
ExpressionValue = Union[RuntimeConstant, RuntimeExpression]
|
File without changes
|
File without changes
|