classiq 0.66.0__py3-none-any.whl → 0.67.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/applications/finance/finance_model_constructor.py +9 -0
- classiq/applications/grover/grover_model_constructor.py +10 -0
- classiq/applications/qnn/qlayer.py +8 -2
- classiq/applications/qsvm/qsvm_model_constructor.py +9 -0
- classiq/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +12 -0
- classiq/interface/exceptions.py +2 -5
- classiq/interface/generator/arith/argument_utils.py +1 -1
- classiq/interface/generator/arith/arithmetic.py +3 -1
- classiq/interface/generator/arith/binary_ops.py +3 -0
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/functions/type_name.py +2 -2
- classiq/interface/generator/generated_circuit_data.py +34 -1
- classiq/interface/generator/hardware_efficient_ansatz.py +1 -1
- classiq/interface/generator/hva.py +1 -1
- classiq/interface/generator/model/preferences/preferences.py +8 -1
- classiq/interface/generator/reset.py +14 -0
- classiq/interface/generator/ucc.py +1 -1
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/quantum_statement.py +13 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +2 -1
- classiq/model_expansions/capturing/captured_vars.py +184 -54
- classiq/model_expansions/closure.py +6 -3
- classiq/model_expansions/evaluators/control.py +14 -38
- classiq/model_expansions/function_builder.py +19 -14
- classiq/model_expansions/generative_functions.py +7 -11
- classiq/model_expansions/interpreters/base_interpreter.py +14 -5
- classiq/model_expansions/interpreters/generative_interpreter.py +9 -8
- classiq/model_expansions/quantum_operations/allocate.py +6 -2
- classiq/model_expansions/quantum_operations/bind.py +65 -13
- classiq/model_expansions/quantum_operations/call_emitter.py +79 -10
- classiq/model_expansions/quantum_operations/classicalif.py +5 -2
- classiq/model_expansions/quantum_operations/emitter.py +8 -1
- classiq/model_expansions/quantum_operations/repeat.py +7 -2
- classiq/model_expansions/quantum_operations/shallow_emitter.py +1 -1
- classiq/model_expansions/quantum_operations/variable_decleration.py +11 -1
- classiq/open_library/functions/__init__.py +8 -0
- classiq/open_library/functions/amplitude_amplification.py +92 -0
- classiq/open_library/functions/grover.py +5 -5
- classiq/qmod/builtins/functions/__init__.py +3 -0
- classiq/qmod/builtins/functions/mid_circuit_measurement.py +15 -0
- classiq/qmod/quantum_function.py +4 -0
- classiq/qmod/semantics/annotation/call_annotation.py +8 -2
- classiq/qmod/semantics/annotation/model_annotation.py +9 -0
- classiq/qmod/semantics/error_manager.py +0 -6
- classiq/qmod/semantics/static_semantics_visitor.py +0 -347
- {classiq-0.66.0.dist-info → classiq-0.67.0.dist-info}/METADATA +1 -1
- {classiq-0.66.0.dist-info → classiq-0.67.0.dist-info}/RECORD +49 -47
- classiq/qmod/semantics/validation/func_call_validation.py +0 -99
- classiq/qmod/semantics/validation/handle_validation.py +0 -85
- {classiq-0.66.0.dist-info → classiq-0.67.0.dist-info}/WHEEL +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import warnings
|
1
2
|
from math import floor, log
|
2
3
|
from typing import Union
|
3
4
|
|
@@ -32,6 +33,14 @@ def construct_finance_model(
|
|
32
33
|
finance_function_input: FinanceFunctionInput,
|
33
34
|
phase_port_size: int,
|
34
35
|
) -> SerializedModel:
|
36
|
+
warnings.warn(
|
37
|
+
"Function 'construct_finance_model' has been deprecated and will no longer"
|
38
|
+
"be supported starting on 03/02/2025 the earliest\nHint: It is now possible to "
|
39
|
+
"implement Option Pricing in pure Qmod. For example, see the Option Pricing notebook on the "
|
40
|
+
"Classiq library at https://github.com/Classiq/classiq-library/blob/main/applications/finance/option_pricing/option_pricing.ipynb",
|
41
|
+
category=DeprecationWarning,
|
42
|
+
stacklevel=2,
|
43
|
+
)
|
35
44
|
if isinstance(finance_model_input, LogNormalModelInput):
|
36
45
|
finance_model = f"struct_literal(LogNormalModel, num_qubits={finance_model_input.num_qubits}, mu={finance_model_input.mu}, sigma={finance_model_input.sigma})"
|
37
46
|
finance_function = "log_normal_finance"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import warnings
|
2
|
+
|
1
3
|
from classiq.interface.generator.expressions.expression import Expression
|
2
4
|
from classiq.interface.generator.functions.port_declaration import (
|
3
5
|
PortDeclarationDirection,
|
@@ -90,6 +92,14 @@ def construct_grover_model(
|
|
90
92
|
expression: str,
|
91
93
|
num_reps: int = 1,
|
92
94
|
) -> SerializedModel:
|
95
|
+
warnings.warn(
|
96
|
+
"Function 'construct_grover_model' has been deprecated and will no longer"
|
97
|
+
"be supported starting on 03/02/2025 the earliest\nHint: It is now possible to "
|
98
|
+
"implement the Grover algorithm in pure Qmod. For example, see the Grover notebook on the "
|
99
|
+
"Classiq library at https://github.com/Classiq/classiq-library/blob/main/algorithms/grover/3_sat_grover/3_sat_grover.ipynb",
|
100
|
+
category=DeprecationWarning,
|
101
|
+
stacklevel=2,
|
102
|
+
)
|
93
103
|
predicate_port_decls = grover_main_port_declarations(
|
94
104
|
definitions, PortDeclarationDirection.Inout
|
95
105
|
)
|
@@ -244,9 +244,11 @@ class QLayer(nn.Module):
|
|
244
244
|
|
245
245
|
self.weight = Parameter(value)
|
246
246
|
|
247
|
-
|
248
|
-
|
247
|
+
def _make_execute(
|
248
|
+
self, quantum_program: SerializedQuantumProgram
|
249
|
+
) -> ExecuteFunction:
|
249
250
|
session = ExecutionSession(quantum_program)
|
251
|
+
self._session = session
|
250
252
|
|
251
253
|
def execute(_ignored: Any, arguments: MultipleArguments) -> ResultsCollection:
|
252
254
|
result: ResultsCollection = []
|
@@ -266,3 +268,7 @@ class QLayer(nn.Module):
|
|
266
268
|
self._post_process,
|
267
269
|
self._epsilon,
|
268
270
|
)
|
271
|
+
|
272
|
+
def _cleanup(self) -> None:
|
273
|
+
if hasattr(self, "_session"):
|
274
|
+
self._session.close()
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import warnings
|
1
2
|
from typing import Any
|
2
3
|
|
3
4
|
from classiq.interface.applications.qsvm import DataList, LabelsInt
|
@@ -92,6 +93,14 @@ def construct_qsvm_model(
|
|
92
93
|
feature_map_function_name: str,
|
93
94
|
**kwargs: Any,
|
94
95
|
) -> SerializedModel:
|
96
|
+
warnings.warn(
|
97
|
+
"Function 'construct_qsvm_model' has been deprecated and will no longer"
|
98
|
+
"be supported starting on 03/02/2025 the earliest\nHint: It is now possible to "
|
99
|
+
"implement QSVM in pure Qmod. For example, see the QSVM notebook on the "
|
100
|
+
"Classiq library at https://github.com/Classiq/classiq-library/blob/main/algorithms/qml/qsvm/qsvm.ipynb",
|
101
|
+
category=DeprecationWarning,
|
102
|
+
stacklevel=2,
|
103
|
+
)
|
95
104
|
qsvm_qmod = Model(
|
96
105
|
functions=[
|
97
106
|
NativeFunctionDefinition(
|
classiq/interface/_version.py
CHANGED
@@ -32,6 +32,7 @@ class FunctionDebugInfo(BaseModel):
|
|
32
32
|
statement_type: Union[StatementType, None] = None
|
33
33
|
is_allocate_or_free: bool = Field(default=False)
|
34
34
|
is_inverse: bool = Field(default=False)
|
35
|
+
release_by_inverse: bool = Field(default=False)
|
35
36
|
port_to_passed_variable_map: dict[str, str] = Field(default_factory=dict)
|
36
37
|
node: Optional[ConcreteQuantumStatement] = None
|
37
38
|
|
@@ -86,3 +87,14 @@ class DebugInfoCollection(BaseModel):
|
|
86
87
|
if (debug_info := self.get(key)) is None:
|
87
88
|
return None
|
88
89
|
return self.blackbox_data.get(debug_info.name)
|
90
|
+
|
91
|
+
|
92
|
+
def new_function_debug_info_by_node(
|
93
|
+
node: ConcreteQuantumStatement,
|
94
|
+
) -> FunctionDebugInfo:
|
95
|
+
return FunctionDebugInfo(
|
96
|
+
name="",
|
97
|
+
parameters=dict(),
|
98
|
+
level=OperationLevel.QMOD_STATEMENT,
|
99
|
+
node=node._as_back_ref(),
|
100
|
+
)
|
classiq/interface/exceptions.py
CHANGED
@@ -6,7 +6,8 @@ _logger = logging.getLogger(__name__)
|
|
6
6
|
|
7
7
|
CLASSIQ_SLACK_COMMUNITY_LINK = (
|
8
8
|
"\nIf you need further assistance, please reach out on our Community Slack channel "
|
9
|
-
"at: https://short.classiq.io/join-slack"
|
9
|
+
"at: https://short.classiq.io/join-slack or open a support ticket at: "
|
10
|
+
"https://classiq-community.freshdesk.com/support/tickets/new"
|
10
11
|
)
|
11
12
|
|
12
13
|
|
@@ -177,10 +178,6 @@ class ClassiqExecutorInvalidHamiltonianError(ClassiqCombOptError):
|
|
177
178
|
super().__init__("Invalid hamiltonian")
|
178
179
|
|
179
180
|
|
180
|
-
class ClassiqSemanticError(ClassiqError):
|
181
|
-
pass
|
182
|
-
|
183
|
-
|
184
181
|
class ClassiqDeprecationWarning(FutureWarning):
|
185
182
|
pass
|
186
183
|
|
@@ -91,7 +91,7 @@ def unsigned_integer_interpretation(
|
|
91
91
|
int_val <<= fraction_digits_diff
|
92
92
|
|
93
93
|
# extend sign bit
|
94
|
-
if
|
94
|
+
if value < 0:
|
95
95
|
bin_val = number_utils.binary_string(int_val)
|
96
96
|
bin_val += "1" * (register.size - len(bin_val))
|
97
97
|
int_val = number_utils.binary_to_int(bin_val[::-1])
|
@@ -32,6 +32,8 @@ ARITHMETIC_EXPRESSION_TARGET_NAME: Final[str] = "arithmetic_target"
|
|
32
32
|
ARITHMETIC_EXPRESSION_RESULT_NAME: Final[str] = "expression_result"
|
33
33
|
ARITHMETIC_EXPRESSION_GARBAGE_NAME: Final[str] = "expression_garbage"
|
34
34
|
|
35
|
+
TARGET_ASSIGNMENT_ERROR = "Expression does not support target assignment"
|
36
|
+
|
35
37
|
|
36
38
|
def is_zero(expr: str) -> bool:
|
37
39
|
return is_constant(expr) and float(expr) == 0
|
@@ -60,7 +62,7 @@ class Arithmetic(ArithmeticExpressionABC):
|
|
60
62
|
degree or operation_allows_target(id2op(node))
|
61
63
|
for node, degree in graph.out_degree
|
62
64
|
):
|
63
|
-
raise ClassiqValueError(
|
65
|
+
raise ClassiqValueError(TARGET_ASSIGNMENT_ERROR)
|
64
66
|
|
65
67
|
def _create_ios(self) -> None:
|
66
68
|
self._inputs = {
|
@@ -398,6 +398,7 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
398
398
|
right_arg=-self.effective_right_arg,
|
399
399
|
output_size=self.output_size,
|
400
400
|
inplace_arg=self.inplace_arg,
|
401
|
+
machine_precision=self.machine_precision,
|
401
402
|
)
|
402
403
|
return adder_params.garbage_output_size()
|
403
404
|
|
@@ -406,6 +407,7 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
406
407
|
output_size=self.negation_output_size,
|
407
408
|
inplace=self.should_inplace_negation,
|
408
409
|
bypass_bounds_validation=True,
|
410
|
+
machine_precision=self.machine_precision,
|
409
411
|
)
|
410
412
|
negation_result = negation_params.result_register
|
411
413
|
if self.output_size is None and max(self.effective_right_arg.bounds) > 0:
|
@@ -425,6 +427,7 @@ class Subtractor(InplacableBinaryOpParams[RegisterOrConst, RegisterOrConst]):
|
|
425
427
|
right_arg=negation_result,
|
426
428
|
output_size=self.output_size,
|
427
429
|
inplace_arg=self.arg_to_inplace_adder,
|
430
|
+
machine_precision=self.machine_precision,
|
428
431
|
)
|
429
432
|
negation_garbage_size = negation_params.garbage_output_size() * int(
|
430
433
|
not self.should_uncompute_negation
|
@@ -65,6 +65,7 @@ from classiq.interface.generator.piecewise_linear_amplitude_loading import (
|
|
65
65
|
from classiq.interface.generator.qft import QFT
|
66
66
|
from classiq.interface.generator.qsvm import QSVMFeatureMap
|
67
67
|
from classiq.interface.generator.randomized_benchmarking import RandomizedBenchmarking
|
68
|
+
from classiq.interface.generator.reset import Reset
|
68
69
|
from classiq.interface.generator.standard_gates.standard_gates_param_list import (
|
69
70
|
standard_gate_function_param_library,
|
70
71
|
)
|
@@ -150,6 +151,7 @@ function_param_library_without_self_reference: FunctionParamLibrary = (
|
|
150
151
|
PiecewiseLinearRotationAmplitudeLoading,
|
151
152
|
HadamardTransform,
|
152
153
|
Copy,
|
154
|
+
Reset,
|
153
155
|
},
|
154
156
|
standard_gate_function_param_library.param_list,
|
155
157
|
oracle_function_param_library.param_list,
|
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
|
6
|
-
from classiq.interface.exceptions import
|
6
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
7
7
|
from classiq.interface.generator.expressions.qmod_qstruct_proxy import QmodQStructProxy
|
8
8
|
from classiq.interface.generator.functions.classical_type import (
|
9
9
|
ClassicalType,
|
@@ -59,7 +59,7 @@ class TypeName(ClassicalType, QuantumType):
|
|
59
59
|
@property
|
60
60
|
def fields(self) -> Mapping[str, "ConcreteQuantumType"]:
|
61
61
|
if self._assigned_fields is None:
|
62
|
-
raise
|
62
|
+
raise ClassiqExpansionError(f"Type {self.name!r} is undefined")
|
63
63
|
return self._assigned_fields
|
64
64
|
|
65
65
|
@property
|
@@ -135,6 +135,7 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
135
135
|
level: OperationLevel = pydantic.Field(default=OperationLevel.UNKNOWN)
|
136
136
|
parameters: list[OperationParameter] = list()
|
137
137
|
port_to_passed_variable_map: dict[str, str] = pydantic.Field(default={})
|
138
|
+
release_by_inverse: bool = pydantic.Field(default=False)
|
138
139
|
|
139
140
|
model_config = ConfigDict(extra="allow")
|
140
141
|
# Temporary field to store the override debug info for parallel old/new visualization
|
@@ -227,14 +228,46 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
227
228
|
)
|
228
229
|
|
229
230
|
def inverse(self) -> "FunctionDebugInfoInterface":
|
230
|
-
|
231
|
+
if self.override_debug_info is not None:
|
232
|
+
self.override_debug_info = self.override_debug_info.inverse()
|
233
|
+
return self
|
234
|
+
inverse_generated_function = (
|
235
|
+
self.generated_function.model_copy(
|
236
|
+
update=dict(registers=self._inverse_registers)
|
237
|
+
)
|
238
|
+
if self.generated_function
|
239
|
+
else None
|
240
|
+
)
|
241
|
+
inverted_children = [child.inverse() for child in reversed(self.children)]
|
231
242
|
return self.model_copy(
|
232
243
|
update=dict(
|
233
244
|
is_inverse=not self.is_inverse,
|
234
245
|
children=inverted_children,
|
246
|
+
generated_function=inverse_generated_function,
|
235
247
|
)
|
236
248
|
)
|
237
249
|
|
250
|
+
@property
|
251
|
+
def _inverse_registers(self) -> list[GeneratedRegister]:
|
252
|
+
return [
|
253
|
+
reg.model_copy(update=dict(role=self._inverse_register_role(reg.role)))
|
254
|
+
for reg in self.registers
|
255
|
+
]
|
256
|
+
|
257
|
+
def _inverse_register_role(self, role: RegisterRole) -> RegisterRole:
|
258
|
+
if role is RegisterRole.INPUT:
|
259
|
+
return RegisterRole.OUTPUT
|
260
|
+
if role is RegisterRole.EXPLICIT_ZERO_INPUT or role is RegisterRole.ZERO_INPUT:
|
261
|
+
if self.release_by_inverse:
|
262
|
+
return RegisterRole.ZERO_OUTPUT
|
263
|
+
return RegisterRole.OUTPUT
|
264
|
+
if role is RegisterRole.AUXILIARY:
|
265
|
+
return RegisterRole.AUXILIARY
|
266
|
+
if role is RegisterRole.OUTPUT or role is RegisterRole.GARBAGE_OUTPUT:
|
267
|
+
return RegisterRole.INPUT
|
268
|
+
if role is RegisterRole.ZERO_OUTPUT:
|
269
|
+
return RegisterRole.ZERO_INPUT
|
270
|
+
|
238
271
|
|
239
272
|
def _get_absolute_from_relative(
|
240
273
|
absolute_qubits: tuple[int, ...], relative_qubits: tuple[int, ...]
|
@@ -60,7 +60,7 @@ class HardwareEfficientAnsatz(function_params.FunctionParams):
|
|
60
60
|
description='List of gates for the two qubit gates entangling layer, e.g. ["cx", "cry"]',
|
61
61
|
)
|
62
62
|
parameter_prefix: str = pydantic.Field(
|
63
|
-
default="
|
63
|
+
default="hea_param_",
|
64
64
|
description="Prefix for the generated parameters",
|
65
65
|
)
|
66
66
|
|
@@ -36,7 +36,7 @@ if TYPE_CHECKING:
|
|
36
36
|
PydanticBackendName = str
|
37
37
|
else:
|
38
38
|
PydanticBackendName = Annotated[
|
39
|
-
str, Field(strict=True,
|
39
|
+
str, Field(strict=True, pattern="^([.A-Za-z0-9_-][ .A-Za-z0-9_-]*)$")
|
40
40
|
]
|
41
41
|
|
42
42
|
|
@@ -262,6 +262,13 @@ class Preferences(pydantic.BaseModel, extra="forbid"):
|
|
262
262
|
|
263
263
|
return output_format
|
264
264
|
|
265
|
+
@pydantic.field_validator("backend_name")
|
266
|
+
@classmethod
|
267
|
+
def validate_backend_name(cls, backend_name: Optional[str]) -> Optional[str]:
|
268
|
+
if backend_name is None:
|
269
|
+
return backend_name
|
270
|
+
return backend_name.rstrip()
|
271
|
+
|
265
272
|
@pydantic.model_validator(mode="after")
|
266
273
|
def validate_backend(self) -> Self:
|
267
274
|
backend_name = self.backend_name
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from classiq.interface.generator.arith.register_user_input import (
|
2
|
+
RegisterArithmeticInfo,
|
3
|
+
RegisterUserInput,
|
4
|
+
)
|
5
|
+
from classiq.interface.generator.function_params import FunctionParams
|
6
|
+
|
7
|
+
|
8
|
+
class Reset(FunctionParams):
|
9
|
+
target: RegisterUserInput
|
10
|
+
|
11
|
+
def _create_ios(self) -> None:
|
12
|
+
mapping: dict[str, RegisterArithmeticInfo] = {self.target.name: self.target}
|
13
|
+
self._inputs = mapping
|
14
|
+
self._outputs = mapping
|
@@ -38,7 +38,7 @@ class UCC(ChemistryFunctionParams):
|
|
38
38
|
description="Maximum depth of the generated quantum circuit ansatz",
|
39
39
|
)
|
40
40
|
parameter_prefix: str = pydantic.Field(
|
41
|
-
default="
|
41
|
+
default="ucc_param_",
|
42
42
|
description="Prefix for the generated parameters",
|
43
43
|
)
|
44
44
|
|
@@ -1 +1 @@
|
|
1
|
-
INTERFACE_VERSION = "
|
1
|
+
INTERFACE_VERSION = "8"
|
@@ -5,6 +5,7 @@ from uuid import UUID, uuid4
|
|
5
5
|
|
6
6
|
import pydantic
|
7
7
|
from pydantic import ConfigDict
|
8
|
+
from typing_extensions import Self
|
8
9
|
|
9
10
|
from classiq.interface.ast_node import ASTNode
|
10
11
|
from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
|
@@ -21,6 +22,18 @@ class QuantumStatement(ASTNode):
|
|
21
22
|
description="A unique identifier for this operation", default_factory=uuid4
|
22
23
|
)
|
23
24
|
|
25
|
+
def model_copy(
|
26
|
+
self,
|
27
|
+
*,
|
28
|
+
update: Optional[dict[str, Any]] = None,
|
29
|
+
deep: bool = False,
|
30
|
+
keep_uuid: bool = False
|
31
|
+
) -> Self:
|
32
|
+
if not keep_uuid:
|
33
|
+
update = update or dict()
|
34
|
+
update.setdefault("uuid", uuid4())
|
35
|
+
return super().model_copy(update=update, deep=deep)
|
36
|
+
|
24
37
|
@pydantic.model_validator(mode="before")
|
25
38
|
@classmethod
|
26
39
|
def _set_kind(cls, values: Any) -> dict[str, Any]:
|
@@ -21,6 +21,7 @@ from classiq.interface.generator.functions.classical_function_declaration import
|
|
21
21
|
)
|
22
22
|
from classiq.interface.generator.functions.classical_type import (
|
23
23
|
Bool,
|
24
|
+
ClassicalArray,
|
24
25
|
ClassicalList,
|
25
26
|
ClassicalType,
|
26
27
|
OpaqueHandle,
|
@@ -64,7 +65,7 @@ def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
|
64
65
|
if isinstance(val, (Enum, int)):
|
65
66
|
return val
|
66
67
|
|
67
|
-
elif isinstance(qmod_type, ClassicalList):
|
68
|
+
elif isinstance(qmod_type, (ClassicalArray, ClassicalList)):
|
68
69
|
if isinstance(val, list):
|
69
70
|
return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
|
70
71
|
|