classiq 0.83.0__py3-none-any.whl → 0.85.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 +27 -0
- classiq/applications/chemistry/chemistry_model_constructor.py +0 -2
- classiq/applications/chemistry/hartree_fock.py +68 -0
- classiq/applications/chemistry/mapping.py +85 -0
- classiq/applications/chemistry/op_utils.py +79 -0
- classiq/applications/chemistry/problems.py +195 -0
- classiq/applications/chemistry/ucc.py +109 -0
- classiq/applications/chemistry/z2_symmetries.py +368 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +30 -1
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +20 -42
- classiq/{model_expansions/evaluators → evaluators}/arg_type_match.py +12 -4
- classiq/{model_expansions/evaluators → evaluators}/argument_types.py +1 -1
- classiq/evaluators/classical_expression.py +53 -0
- classiq/{model_expansions/evaluators → evaluators}/classical_type_inference.py +3 -4
- classiq/{model_expansions/evaluators → evaluators}/parameter_types.py +17 -15
- classiq/execution/__init__.py +12 -1
- classiq/execution/execution_session.py +238 -49
- classiq/execution/jobs.py +26 -1
- classiq/execution/qnn.py +2 -2
- classiq/execution/user_budgets.py +39 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/constants.py +1 -0
- classiq/interface/debug_info/debug_info.py +0 -4
- classiq/interface/execution/primitives.py +29 -1
- classiq/interface/executor/estimate_cost.py +35 -0
- classiq/interface/executor/execution_result.py +13 -0
- classiq/interface/executor/result.py +116 -1
- classiq/interface/executor/user_budget.py +26 -33
- classiq/interface/generator/expressions/atomic_expression_functions.py +10 -1
- classiq/interface/generator/expressions/proxies/classical/any_classical_value.py +0 -6
- classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
- classiq/interface/generator/functions/classical_type.py +2 -35
- classiq/interface/generator/functions/concrete_types.py +20 -3
- classiq/interface/generator/functions/type_modifier.py +0 -19
- classiq/interface/generator/generated_circuit_data.py +5 -18
- classiq/interface/generator/types/compilation_metadata.py +0 -3
- classiq/interface/ide/operation_registry.py +45 -0
- classiq/interface/ide/visual_model.py +68 -3
- classiq/interface/model/bounds.py +12 -2
- classiq/interface/model/model.py +12 -7
- classiq/interface/model/port_declaration.py +2 -24
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
- classiq/interface/model/variable_declaration_statement.py +33 -6
- classiq/interface/pretty_print/__init__.py +0 -0
- classiq/{qmod/native → interface/pretty_print}/expression_to_qmod.py +18 -11
- classiq/interface/server/routes.py +4 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +47 -6
- classiq/model_expansions/function_builder.py +4 -1
- classiq/model_expansions/interpreters/base_interpreter.py +3 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +16 -1
- classiq/model_expansions/quantum_operations/allocate.py +1 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +64 -22
- classiq/model_expansions/quantum_operations/bind.py +2 -2
- classiq/model_expansions/quantum_operations/bounds.py +7 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +26 -20
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +31 -11
- classiq/model_expansions/scope.py +7 -0
- classiq/model_expansions/scope_initialization.py +3 -3
- classiq/model_expansions/transformers/model_renamer.py +6 -4
- classiq/model_expansions/transformers/type_modifier_inference.py +81 -43
- classiq/model_expansions/transformers/var_splitter.py +1 -1
- classiq/model_expansions/visitors/symbolic_param_inference.py +2 -3
- classiq/open_library/functions/__init__.py +3 -2
- classiq/open_library/functions/amplitude_amplification.py +10 -18
- classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
- classiq/open_library/functions/grover.py +14 -6
- classiq/open_library/functions/modular_exponentiation.py +22 -20
- classiq/open_library/functions/qaoa_penalty.py +8 -1
- classiq/open_library/functions/state_preparation.py +18 -32
- classiq/qmod/__init__.py +2 -0
- classiq/qmod/builtins/enums.py +23 -0
- classiq/qmod/builtins/functions/__init__.py +2 -0
- classiq/qmod/builtins/functions/exponentiation.py +32 -4
- classiq/qmod/builtins/operations.py +65 -1
- classiq/qmod/builtins/structs.py +55 -3
- classiq/qmod/classical_variable.py +74 -0
- classiq/qmod/declaration_inferrer.py +3 -2
- classiq/qmod/native/pretty_printer.py +20 -20
- classiq/qmod/pretty_print/expression_to_python.py +2 -1
- classiq/qmod/pretty_print/pretty_printer.py +35 -21
- classiq/qmod/python_classical_type.py +12 -5
- classiq/qmod/qfunc.py +2 -19
- classiq/qmod/qmod_constant.py +2 -5
- classiq/qmod/qmod_parameter.py +2 -5
- classiq/qmod/qmod_variable.py +61 -23
- classiq/qmod/quantum_expandable.py +5 -3
- classiq/qmod/quantum_function.py +49 -4
- classiq/qmod/semantics/annotation/qstruct_annotator.py +1 -1
- classiq/qmod/semantics/validation/main_validation.py +1 -9
- classiq/qmod/symbolic_type.py +2 -1
- classiq/qmod/utilities.py +0 -2
- classiq/qmod/write_qmod.py +1 -1
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/METADATA +4 -1
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/RECORD +101 -90
- classiq/interface/model/quantum_variable_declaration.py +0 -7
- classiq/model_expansions/evaluators/classical_expression.py +0 -36
- /classiq/{model_expansions/evaluators → evaluators}/__init__.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/control.py +0 -0
- /classiq/{model_expansions → evaluators}/expression_evaluator.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/quantum_type_utils.py +0 -0
- /classiq/{model_expansions/evaluators → evaluators}/type_type_match.py +0 -0
- {classiq-0.83.0.dist-info → classiq-0.85.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
from typing import Callable
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
from classiq.interface.exceptions import ClassiqValueError
|
6
|
+
from classiq.interface.executor.result import ParsedCounts, ParsedState
|
7
|
+
|
8
|
+
|
9
|
+
def estimate_cost(
|
10
|
+
cost_func: Callable[[ParsedState], float],
|
11
|
+
parsed_counts: ParsedCounts,
|
12
|
+
quantile: float = 1.0,
|
13
|
+
) -> float:
|
14
|
+
if quantile < 0 or quantile > 1:
|
15
|
+
raise ClassiqValueError("'quantile' must be between 0 and 1")
|
16
|
+
costs = np.fromiter((cost_func(sample.state) for sample in parsed_counts), float)
|
17
|
+
shots = np.fromiter((sample.shots for sample in parsed_counts), int)
|
18
|
+
|
19
|
+
if quantile == 1:
|
20
|
+
return float(np.average(costs, weights=shots))
|
21
|
+
return float(estimate_quantile_cost(costs, shots, quantile=quantile))
|
22
|
+
|
23
|
+
|
24
|
+
def estimate_quantile_cost(
|
25
|
+
costs: np.ndarray,
|
26
|
+
shots: np.ndarray,
|
27
|
+
quantile: float,
|
28
|
+
) -> np.floating:
|
29
|
+
repeated_costs = np.repeat(costs, shots)
|
30
|
+
sort_idx = repeated_costs.argsort()
|
31
|
+
cutoff_idx = sort_idx[: int(quantile * len(repeated_costs))]
|
32
|
+
sorted_costs = repeated_costs[cutoff_idx]
|
33
|
+
if sorted_costs.size == 0:
|
34
|
+
sorted_costs = repeated_costs[sort_idx[0]]
|
35
|
+
return np.average(sorted_costs)
|
@@ -25,6 +25,7 @@ class SavedResultValueType(StrEnum):
|
|
25
25
|
EstimationResult = "EstimationResult"
|
26
26
|
EstimationResults = "EstimationResults"
|
27
27
|
IQAEResult = "IQAEResult"
|
28
|
+
MinimizeResult = "MinimizeResult"
|
28
29
|
Unstructured = "Unstructured"
|
29
30
|
|
30
31
|
|
@@ -88,6 +89,17 @@ class TaggedUnstructured(BaseModel):
|
|
88
89
|
value: Any = None
|
89
90
|
|
90
91
|
|
92
|
+
class SingleMinimizeResult(BaseModel):
|
93
|
+
expectation_value: float
|
94
|
+
parameters: list[float]
|
95
|
+
|
96
|
+
|
97
|
+
class TaggedMinimizeResult(BaseModel):
|
98
|
+
value_type: Literal[SavedResultValueType.MinimizeResult]
|
99
|
+
name: str
|
100
|
+
value: list[SingleMinimizeResult]
|
101
|
+
|
102
|
+
|
91
103
|
SavedResult = Annotated[
|
92
104
|
Union[
|
93
105
|
TaggedInteger,
|
@@ -100,6 +112,7 @@ SavedResult = Annotated[
|
|
100
112
|
TaggedEstimationResults,
|
101
113
|
TaggedIQAEResult,
|
102
114
|
TaggedUnstructured,
|
115
|
+
TaggedMinimizeResult,
|
103
116
|
],
|
104
117
|
Field(..., discriminator="value_type"),
|
105
118
|
]
|
@@ -10,11 +10,16 @@ from typing import (
|
|
10
10
|
Union,
|
11
11
|
)
|
12
12
|
|
13
|
+
import pandas as pd
|
13
14
|
import pydantic
|
14
15
|
from pydantic import BaseModel
|
15
16
|
from typing_extensions import Self, TypeAlias
|
16
17
|
|
17
|
-
from classiq.interface.exceptions import
|
18
|
+
from classiq.interface.exceptions import (
|
19
|
+
ClassiqError,
|
20
|
+
ClassiqInternalError,
|
21
|
+
ClassiqValueError,
|
22
|
+
)
|
18
23
|
from classiq.interface.executor.quantum_code import OutputQubitsMap, Qubits
|
19
24
|
from classiq.interface.generator.arith import number_utils
|
20
25
|
from classiq.interface.generator.complex_type import Complex
|
@@ -22,6 +27,7 @@ from classiq.interface.generator.functions.classical_type import QmodPyObject
|
|
22
27
|
from classiq.interface.helpers.custom_pydantic_types import PydanticNonNegIntTuple
|
23
28
|
from classiq.interface.helpers.datastructures import get_sdk_compatible_python_object
|
24
29
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
30
|
+
from classiq.interface.model.quantum_type import RegisterQuantumTypeDict
|
25
31
|
|
26
32
|
_ILLEGAL_QUBIT_ERROR_MSG: str = "Illegal qubit index requested"
|
27
33
|
_REPEATED_QUBIT_ERROR_MSG: str = "Requested a qubit more than once"
|
@@ -36,6 +42,11 @@ ParsedStates: TypeAlias = Mapping[State, ParsedState]
|
|
36
42
|
Counts: TypeAlias = dict[State, MeasuredShots]
|
37
43
|
StateVector: TypeAlias = Optional[dict[str, Complex]]
|
38
44
|
|
45
|
+
BITSTRING = "bitstring"
|
46
|
+
PROBABILITY = "probability"
|
47
|
+
AMPLITUDE = "amplitude"
|
48
|
+
COUNT = "count"
|
49
|
+
|
39
50
|
if TYPE_CHECKING:
|
40
51
|
DotAccessParsedState = Mapping[Name, Any]
|
41
52
|
else:
|
@@ -150,6 +161,36 @@ def prepare_parsed_state_vector(
|
|
150
161
|
return sorted(parsed_state_vector, key=lambda k: abs(k.amplitude), reverse=True)
|
151
162
|
|
152
163
|
|
164
|
+
def _flatten_columns(df: pd.DataFrame, columns_to_flatten: list[str]) -> pd.DataFrame:
|
165
|
+
if len(df.columns) == 0:
|
166
|
+
return df
|
167
|
+
|
168
|
+
flattened_data = {}
|
169
|
+
|
170
|
+
for col in columns_to_flatten:
|
171
|
+
if col not in df.columns:
|
172
|
+
continue
|
173
|
+
|
174
|
+
flat_df = pd.json_normalize(df[col]).add_prefix(f"{col}.")
|
175
|
+
flat_df.index = df.index
|
176
|
+
flattened_data[col] = flat_df
|
177
|
+
|
178
|
+
new_df_columns = []
|
179
|
+
dfs_to_concat = []
|
180
|
+
|
181
|
+
for col_name in df.columns:
|
182
|
+
if col_name in flattened_data:
|
183
|
+
new_df_columns.extend(flattened_data[col_name].columns)
|
184
|
+
dfs_to_concat.append(flattened_data[col_name])
|
185
|
+
elif col_name not in columns_to_flatten:
|
186
|
+
new_df_columns.append(col_name)
|
187
|
+
dfs_to_concat.append(df[[col_name]])
|
188
|
+
|
189
|
+
final_df = pd.concat(dfs_to_concat, axis=1)
|
190
|
+
valid_final_columns = [c for c in new_df_columns if c in final_df.columns]
|
191
|
+
return final_df[valid_final_columns]
|
192
|
+
|
193
|
+
|
153
194
|
class ExecutionDetails(BaseModel, QmodPyObject):
|
154
195
|
vendor_format_result: dict[str, Any] = pydantic.Field(
|
155
196
|
..., description="Result in proprietary vendor format"
|
@@ -192,6 +233,8 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
192
233
|
default=None, description="The total number of shots the circuit was executed"
|
193
234
|
)
|
194
235
|
|
236
|
+
output_type_map: RegisterQuantumTypeDict = pydantic.Field(default_factory=dict)
|
237
|
+
|
195
238
|
@pydantic.field_validator("counts", mode="after")
|
196
239
|
@classmethod
|
197
240
|
def _clean_spaces_from_counts_keys(cls, v: Counts) -> Counts:
|
@@ -302,6 +345,78 @@ class ExecutionDetails(BaseModel, QmodPyObject):
|
|
302
345
|
)[::-1]
|
303
346
|
return number_utils.binary_to_float_or_int(bin_rep=register_binary_string)
|
304
347
|
|
348
|
+
def _counts_df(self) -> pd.DataFrame:
|
349
|
+
data: dict[str, Any] = defaultdict(list)
|
350
|
+
|
351
|
+
for bitstring, count in self.counts.items():
|
352
|
+
data[BITSTRING].append(bitstring)
|
353
|
+
data[COUNT].append(count)
|
354
|
+
if self.probabilities:
|
355
|
+
data[PROBABILITY].append(self.probabilities[bitstring])
|
356
|
+
elif self.num_shots:
|
357
|
+
data[PROBABILITY].append(count / self.num_shots)
|
358
|
+
|
359
|
+
for name, value in self.parsed_states[bitstring].items():
|
360
|
+
data[name].append(value)
|
361
|
+
|
362
|
+
final_columns = [COUNT, PROBABILITY, BITSTRING]
|
363
|
+
columns = [
|
364
|
+
col for col in data.keys() if col not in final_columns
|
365
|
+
] + final_columns
|
366
|
+
|
367
|
+
return pd.DataFrame(data, columns=columns)
|
368
|
+
|
369
|
+
def _state_vector_df(self) -> pd.DataFrame:
|
370
|
+
data: dict[str, Any] = defaultdict(list)
|
371
|
+
|
372
|
+
if not self.state_vector:
|
373
|
+
raise ClassiqInternalError("No state vector")
|
374
|
+
if not self.parsed_state_vector_states:
|
375
|
+
raise ClassiqInternalError("No parsed state vector states")
|
376
|
+
|
377
|
+
for bitstring, amplitude in self.state_vector.items():
|
378
|
+
data[BITSTRING].append(bitstring)
|
379
|
+
data[AMPLITUDE].append(amplitude)
|
380
|
+
data[PROBABILITY].append(abs(amplitude) ** 2)
|
381
|
+
for name, value in self.parsed_state_vector_states[bitstring].items():
|
382
|
+
data[name].append(value)
|
383
|
+
|
384
|
+
final_columns = [AMPLITUDE, PROBABILITY, BITSTRING]
|
385
|
+
columns = [
|
386
|
+
col for col in data.keys() if col not in final_columns
|
387
|
+
] + final_columns
|
388
|
+
|
389
|
+
return pd.DataFrame(data, columns=columns)
|
390
|
+
|
391
|
+
@functools.cached_property
|
392
|
+
def dataframe(self) -> pd.DataFrame:
|
393
|
+
reserved_words = frozenset([BITSTRING, PROBABILITY, COUNT, AMPLITUDE])
|
394
|
+
_invalid_output_names = reserved_words.intersection(
|
395
|
+
self.output_qubits_map.keys()
|
396
|
+
)
|
397
|
+
if _invalid_output_names:
|
398
|
+
raise ClassiqValueError(f"Invalid output names: {_invalid_output_names}")
|
399
|
+
|
400
|
+
if self.state_vector:
|
401
|
+
df = self._state_vector_df()
|
402
|
+
else:
|
403
|
+
df = self._counts_df()
|
404
|
+
|
405
|
+
df.sort_values(
|
406
|
+
by=[AMPLITUDE if self.state_vector else COUNT, BITSTRING],
|
407
|
+
inplace=True,
|
408
|
+
ascending=[False, True],
|
409
|
+
ignore_index=True,
|
410
|
+
)
|
411
|
+
|
412
|
+
outputs_to_flatten = [
|
413
|
+
output
|
414
|
+
for output, type in self.output_type_map.items()
|
415
|
+
if type.quantum_types.kind == "struct_instance"
|
416
|
+
]
|
417
|
+
df = _flatten_columns(df, outputs_to_flatten)
|
418
|
+
return df
|
419
|
+
|
305
420
|
|
306
421
|
class MultipleExecutionDetails(VersionedModel):
|
307
422
|
details: list[ExecutionDetails]
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import datetime
|
2
|
-
from collections import defaultdict
|
3
2
|
from typing import Optional
|
4
3
|
|
5
4
|
import pydantic
|
6
5
|
from pydantic import ConfigDict, Field
|
6
|
+
from tabulate import tabulate
|
7
7
|
|
8
8
|
from classiq.interface.helpers.versioned_model import VersionedModel
|
9
9
|
|
@@ -15,6 +15,7 @@ class UserBudget(VersionedModel):
|
|
15
15
|
available_budget: float
|
16
16
|
used_budget: float
|
17
17
|
last_allocation_date: datetime.datetime
|
18
|
+
budget_limit: Optional[float] = Field(default=None)
|
18
19
|
|
19
20
|
model_config = ConfigDict(extra="ignore")
|
20
21
|
|
@@ -22,35 +23,27 @@ class UserBudget(VersionedModel):
|
|
22
23
|
class UserBudgets(VersionedModel):
|
23
24
|
budgets: list[UserBudget] = pydantic.Field(default=[])
|
24
25
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
for provider, values in table_data.items():
|
50
|
-
print( # noqa: T201
|
51
|
-
format_row(
|
52
|
-
provider, values["available"], values["used"], values["currency"]
|
53
|
-
)
|
54
|
-
)
|
55
|
-
|
56
|
-
print(line) # noqa: T201
|
26
|
+
def __str__(self) -> str:
|
27
|
+
rows = [
|
28
|
+
[
|
29
|
+
budget.provider,
|
30
|
+
f"{budget.used_budget:.3f}",
|
31
|
+
f"{budget.available_budget:.3f}",
|
32
|
+
(
|
33
|
+
f"{budget.budget_limit:.3f}"
|
34
|
+
if budget.budget_limit is not None
|
35
|
+
else "NOT SET"
|
36
|
+
),
|
37
|
+
budget.currency_code,
|
38
|
+
]
|
39
|
+
for budget in self.budgets
|
40
|
+
]
|
41
|
+
|
42
|
+
headers = [
|
43
|
+
"Provider",
|
44
|
+
"Used Budget",
|
45
|
+
"Remaining Budget",
|
46
|
+
"Budget Limit",
|
47
|
+
"Currency",
|
48
|
+
]
|
49
|
+
return tabulate(rows, headers=headers, tablefmt="grid")
|
@@ -20,10 +20,14 @@ CLASSIQ_EXPR_FUNCTIONS = {
|
|
20
20
|
"get_field",
|
21
21
|
}
|
22
22
|
|
23
|
+
MEASUREMENT_FUNCTIONS = {
|
24
|
+
"measure",
|
25
|
+
}
|
26
|
+
|
23
27
|
SUPPORTED_CLASSIQ_BUILTIN_FUNCTIONS = {
|
24
28
|
*CLASSIQ_BUILTIN_CLASSICAL_FUNCTIONS,
|
25
29
|
*CLASSIQ_EXPR_FUNCTIONS,
|
26
|
-
|
30
|
+
*MEASUREMENT_FUNCTIONS,
|
27
31
|
}
|
28
32
|
|
29
33
|
SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
@@ -34,6 +38,11 @@ SUPPORTED_CLASSIQ_SYMPY_WRAPPERS = {
|
|
34
38
|
"LogicalXor",
|
35
39
|
"RShift",
|
36
40
|
"LShift",
|
41
|
+
"mod_inverse",
|
42
|
+
"min",
|
43
|
+
"Min",
|
44
|
+
"max",
|
45
|
+
"Max",
|
37
46
|
}
|
38
47
|
|
39
48
|
SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS = {
|
@@ -21,12 +21,6 @@ def subscript_to_str(index: Any) -> str:
|
|
21
21
|
|
22
22
|
|
23
23
|
class AnyClassicalValue(sympy.Symbol):
|
24
|
-
|
25
|
-
is_commutative = None
|
26
|
-
is_infinite = None
|
27
|
-
is_finite = None
|
28
|
-
is_extended_real = None
|
29
|
-
|
30
24
|
def __getitem__(self, item: Any) -> "AnyClassicalValue":
|
31
25
|
if isinstance(item, slice):
|
32
26
|
return AnyClassicalValue(f"{self}[{subscript_to_str(item)}]")
|
@@ -6,6 +6,7 @@ CLASSICAL_IF_OPERATOR_NAME = "classical_if"
|
|
6
6
|
POWER_OPERATOR_NAME = "power"
|
7
7
|
UNCOMPUTE_OPERATOR_NAME = "uncompute"
|
8
8
|
WITHIN_APPLY_NAME = "within_apply"
|
9
|
+
BLOCK_OPERATOR_NAME = "block"
|
9
10
|
|
10
11
|
All_BUILTINS_OPERATORS = {
|
11
12
|
CONTROL_OPERATOR_NAME,
|
@@ -14,4 +15,5 @@ All_BUILTINS_OPERATORS = {
|
|
14
15
|
POWER_OPERATOR_NAME,
|
15
16
|
UNCOMPUTE_OPERATOR_NAME,
|
16
17
|
WITHIN_APPLY_NAME,
|
18
|
+
BLOCK_OPERATOR_NAME,
|
17
19
|
}
|
@@ -98,39 +98,6 @@ class Bool(ClassicalType):
|
|
98
98
|
return values_with_discriminator(values, "kind", "bool")
|
99
99
|
|
100
100
|
|
101
|
-
class ClassicalList(ClassicalType):
|
102
|
-
kind: Literal["list"]
|
103
|
-
element_type: "ConcreteClassicalType"
|
104
|
-
|
105
|
-
@pydantic.model_validator(mode="before")
|
106
|
-
@classmethod
|
107
|
-
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
108
|
-
return values_with_discriminator(values, "kind", "list")
|
109
|
-
|
110
|
-
def get_classical_proxy(self, handle: HandleBinding) -> ClassicalProxy:
|
111
|
-
return ClassicalArrayProxy(
|
112
|
-
handle, self.element_type, AnyClassicalValue(f"get_field({handle}, 'len')")
|
113
|
-
)
|
114
|
-
|
115
|
-
@property
|
116
|
-
def expressions(self) -> list[Expression]:
|
117
|
-
return self.element_type.expressions
|
118
|
-
|
119
|
-
@property
|
120
|
-
def is_purely_declarative(self) -> bool:
|
121
|
-
return super().is_purely_declarative and self.element_type.is_purely_declarative
|
122
|
-
|
123
|
-
@property
|
124
|
-
def is_purely_generative(self) -> bool:
|
125
|
-
return super().is_purely_generative and self.element_type.is_purely_generative
|
126
|
-
|
127
|
-
def get_raw_type(self) -> "ConcreteClassicalType":
|
128
|
-
raw_type = ClassicalArray(element_type=self.element_type.get_raw_type())
|
129
|
-
if self._is_generative:
|
130
|
-
raw_type.set_generative()
|
131
|
-
return raw_type
|
132
|
-
|
133
|
-
|
134
101
|
class StructMetaType(ClassicalType):
|
135
102
|
kind: Literal["type_proxy"]
|
136
103
|
|
@@ -146,8 +113,8 @@ class StructMetaType(ClassicalType):
|
|
146
113
|
class ClassicalArray(ClassicalType):
|
147
114
|
kind: Literal["array"]
|
148
115
|
element_type: "ConcreteClassicalType"
|
149
|
-
size: Optional[int] = None
|
150
|
-
length: Optional[Expression] =
|
116
|
+
size: Optional[int] = pydantic.Field(exclude=True, default=None)
|
117
|
+
length: Optional[Expression] = None
|
151
118
|
|
152
119
|
@pydantic.model_validator(mode="before")
|
153
120
|
@classmethod
|
@@ -5,7 +5,6 @@ from pydantic import Field
|
|
5
5
|
from classiq.interface.generator.functions.classical_type import (
|
6
6
|
Bool,
|
7
7
|
ClassicalArray,
|
8
|
-
ClassicalList,
|
9
8
|
ClassicalTuple,
|
10
9
|
Estimation,
|
11
10
|
Histogram,
|
@@ -29,7 +28,6 @@ ConcreteClassicalType = Annotated[
|
|
29
28
|
Integer,
|
30
29
|
Real,
|
31
30
|
Bool,
|
32
|
-
ClassicalList,
|
33
31
|
StructMetaType,
|
34
32
|
TypeName,
|
35
33
|
ClassicalArray,
|
@@ -41,7 +39,6 @@ ConcreteClassicalType = Annotated[
|
|
41
39
|
],
|
42
40
|
Field(discriminator="kind"),
|
43
41
|
]
|
44
|
-
ClassicalList.model_rebuild()
|
45
42
|
ClassicalArray.model_rebuild()
|
46
43
|
ClassicalTuple.model_rebuild()
|
47
44
|
|
@@ -56,3 +53,23 @@ QuantumBitvector.model_rebuild()
|
|
56
53
|
TypeName.model_rebuild()
|
57
54
|
QStructDeclaration.model_rebuild()
|
58
55
|
RegisterQuantumType.model_rebuild()
|
56
|
+
|
57
|
+
ConcreteType = Annotated[
|
58
|
+
Union[
|
59
|
+
Integer,
|
60
|
+
Real,
|
61
|
+
Bool,
|
62
|
+
StructMetaType,
|
63
|
+
TypeName,
|
64
|
+
ClassicalArray,
|
65
|
+
ClassicalTuple,
|
66
|
+
VQEResult,
|
67
|
+
Histogram,
|
68
|
+
Estimation,
|
69
|
+
IQAERes,
|
70
|
+
QuantumBit,
|
71
|
+
QuantumBitvector,
|
72
|
+
QuantumNumeric,
|
73
|
+
],
|
74
|
+
Field(discriminator="kind"),
|
75
|
+
]
|
@@ -2,25 +2,6 @@ from classiq.interface.enum_utils import StrEnum
|
|
2
2
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
3
3
|
|
4
4
|
|
5
|
-
class TypeQualifier(StrEnum):
|
6
|
-
Const = "const"
|
7
|
-
QFree = "qfree"
|
8
|
-
Quantum = "quantum"
|
9
|
-
Inferred = "inferred"
|
10
|
-
|
11
|
-
def to_modifier(self) -> "TypeModifier":
|
12
|
-
if self is TypeQualifier.Const:
|
13
|
-
return TypeModifier.Const
|
14
|
-
elif self is TypeQualifier.QFree:
|
15
|
-
return TypeModifier.Permutable
|
16
|
-
elif self is TypeQualifier.Quantum:
|
17
|
-
return TypeModifier.Mutable
|
18
|
-
elif self is TypeQualifier.Inferred:
|
19
|
-
return TypeModifier.Inferred
|
20
|
-
else:
|
21
|
-
raise ClassiqInternalExpansionError(f"Unexpected type qualifier: {self}")
|
22
|
-
|
23
|
-
|
24
5
|
class TypeModifier(StrEnum):
|
25
6
|
Const = "const"
|
26
7
|
Permutable = "permutable"
|
@@ -28,8 +28,6 @@ from classiq.interface.model.statement_block import (
|
|
28
28
|
)
|
29
29
|
|
30
30
|
from classiq.model_expansions.capturing.mangling_utils import (
|
31
|
-
demangle_capture_name,
|
32
|
-
demangle_name,
|
33
31
|
is_captured_var_name,
|
34
32
|
)
|
35
33
|
|
@@ -54,8 +52,6 @@ VISUALIZATION_HIDE_LIST = [
|
|
54
52
|
"stmt_block",
|
55
53
|
]
|
56
54
|
|
57
|
-
CONTROLLED_PREFIX = "c_"
|
58
|
-
|
59
55
|
|
60
56
|
def last_name_in_call_hierarchy(name: str) -> str:
|
61
57
|
return name.split(CLASSIQ_HIERARCHY_SEPARATOR)[-1]
|
@@ -85,12 +81,6 @@ class GeneratedRegister(pydantic.BaseModel):
|
|
85
81
|
def is_captured(self) -> bool:
|
86
82
|
return is_captured_var_name(self.name)
|
87
83
|
|
88
|
-
@staticmethod
|
89
|
-
def demangle_name(name: str) -> str:
|
90
|
-
if is_captured_var_name(name):
|
91
|
-
name = demangle_capture_name(name)
|
92
|
-
return demangle_name(name)
|
93
|
-
|
94
84
|
|
95
85
|
class GeneratedFunction(pydantic.BaseModel):
|
96
86
|
name: str
|
@@ -155,6 +145,7 @@ class StatementType(StrEnum):
|
|
155
145
|
INPLACE_XOR = "inplace xor"
|
156
146
|
INPLACE_ADD = "inplace add"
|
157
147
|
REPEAT = "repeat"
|
148
|
+
BLOCK = "block"
|
158
149
|
|
159
150
|
|
160
151
|
# Mapping between statement kind (or sub-kind) and statement type (visualization name)
|
@@ -175,6 +166,7 @@ STATEMENTS_NAME: dict[str, StatementType] = {
|
|
175
166
|
ArithmeticOperationKind.InplaceXor.value: StatementType.INPLACE_XOR,
|
176
167
|
ArithmeticOperationKind.InplaceAdd.value: StatementType.INPLACE_ADD,
|
177
168
|
"Repeat": StatementType.REPEAT,
|
169
|
+
"Block": StatementType.BLOCK,
|
178
170
|
}
|
179
171
|
|
180
172
|
|
@@ -215,8 +207,7 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
215
207
|
ARITH_ENGINE_PREFIX
|
216
208
|
)
|
217
209
|
name_with_suffix = self.add_suffix_from_generated_name(generated_name, name)
|
218
|
-
|
219
|
-
return modified_name
|
210
|
+
return name_with_suffix
|
220
211
|
|
221
212
|
statement_kind: str = back_ref.kind
|
222
213
|
if isinstance(back_ref, ArithmeticOperation):
|
@@ -225,11 +216,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
225
216
|
generated_name, STATEMENTS_NAME[statement_kind]
|
226
217
|
)
|
227
218
|
|
228
|
-
def modify_name_for_controlled_qfunc(self, generated_name: str) -> str:
|
229
|
-
if self.control_variable is None:
|
230
|
-
return generated_name
|
231
|
-
return f"{CONTROLLED_PREFIX}{generated_name}"
|
232
|
-
|
233
219
|
def add_suffix_from_generated_name(self, generated_name: str, name: str) -> str:
|
234
220
|
if part_match := PART_SUFFIX_REGEX.match(generated_name):
|
235
221
|
suffix = f" [{part_match.group(1)}]"
|
@@ -280,7 +266,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
280
266
|
for register in self.registers
|
281
267
|
for qubit in register.qubit_indexes_absolute
|
282
268
|
if register.role is RegisterRole.INPUT
|
283
|
-
and register.name
|
269
|
+
and self.port_to_passed_variable_map.get(register.name, register.name)
|
270
|
+
== self.control_variable
|
284
271
|
)
|
285
272
|
|
286
273
|
def propagate_absolute_qubits(self) -> "FunctionDebugInfoInterface":
|
@@ -6,9 +6,6 @@ class CompilationMetadata(BaseModel):
|
|
6
6
|
occurrences_number: NonNegativeInt = Field(default=1)
|
7
7
|
_occupation_number: NonNegativeInt = PrivateAttr(default=0)
|
8
8
|
unchecked: list[str] = Field(default_factory=list)
|
9
|
-
atomic_qualifiers: list[str] = Field(
|
10
|
-
default_factory=list, exclude=True
|
11
|
-
) # TODO remove after deprecation https://classiq.atlassian.net/browse/CLS-2671
|
12
9
|
|
13
10
|
@property
|
14
11
|
def occupation_number(self) -> NonNegativeInt:
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from classiq.interface.ide.visual_model import Operation
|
4
|
+
|
5
|
+
|
6
|
+
class OperationRegistry:
|
7
|
+
def __init__(self) -> None:
|
8
|
+
self._operation_hash_to_op_id: dict[int, int] = {}
|
9
|
+
self._id_to_operations: dict[int, Operation] = {}
|
10
|
+
self._unique_op_counter = 0
|
11
|
+
self._deduped_op_counter = 0
|
12
|
+
|
13
|
+
def build_operation(self, **kwargs: Any) -> Operation:
|
14
|
+
operation = Operation(**kwargs)
|
15
|
+
return self.add_operation(operation)
|
16
|
+
|
17
|
+
def add_operation(self, op: Operation) -> Operation:
|
18
|
+
"""
|
19
|
+
Adds an operation to the global dictionaries for operations.
|
20
|
+
if operation already exist in the registry, it returns the existing operation.
|
21
|
+
"""
|
22
|
+
op_hash = hash(op)
|
23
|
+
if op_hash not in self._operation_hash_to_op_id:
|
24
|
+
self._operation_hash_to_op_id[op_hash] = op.id
|
25
|
+
self._id_to_operations[op.id] = op
|
26
|
+
self._unique_op_counter += 1
|
27
|
+
else:
|
28
|
+
self._deduped_op_counter += 1
|
29
|
+
op = self._id_to_operations[self._operation_hash_to_op_id[op_hash]]
|
30
|
+
return op
|
31
|
+
|
32
|
+
def get_operation_mapping(self) -> dict[int, Operation]:
|
33
|
+
return self._id_to_operations
|
34
|
+
|
35
|
+
def get_operations(self, op_ids: list[int]) -> list[Operation]:
|
36
|
+
"""
|
37
|
+
Returns a list of operations based on their IDs.
|
38
|
+
"""
|
39
|
+
return [self._id_to_operations[op_id] for op_id in op_ids]
|
40
|
+
|
41
|
+
def get_unique_op_number(self) -> int:
|
42
|
+
return self._unique_op_counter
|
43
|
+
|
44
|
+
def get_deduped_op_number(self) -> int:
|
45
|
+
return self._deduped_op_counter
|