classiq 0.91.1__py3-none-any.whl → 0.93.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 +13 -0
- classiq/_internals/config.py +1 -1
- classiq/analyzer/show_interactive_hack.py +1 -1
- classiq/applications/__init__.py +2 -6
- classiq/applications/qsp/__init__.py +7 -0
- classiq/applications/qsp/qsp.py +366 -0
- classiq/evaluators/parameter_types.py +13 -7
- classiq/execution/jobs.py +18 -8
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +8 -8
- classiq/interface/exceptions.py +4 -0
- classiq/interface/executor/result.py +4 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +1 -0
- classiq/interface/generator/generated_circuit_data.py +5 -17
- classiq/interface/generator/transpiler_basis_gates.py +1 -1
- classiq/interface/helpers/versioned_model.py +0 -2
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/bind_operation.py +0 -12
- classiq/interface/model/handle_binding.py +3 -0
- classiq/interface/model/skip_control.py +11 -0
- classiq/interface/model/statement_block.py +3 -0
- classiq/interface/server/routes.py +0 -3
- classiq/model_expansions/interpreters/generative_interpreter.py +18 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +6 -0
- classiq/model_expansions/quantum_operations/bind.py +14 -0
- classiq/model_expansions/quantum_operations/skip_control_verifier.py +20 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +59 -27
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/discrete_sine_cosine_transform.py +15 -10
- classiq/open_library/functions/qsvt.py +60 -6
- classiq/qmod/builtins/operations.py +24 -0
- classiq/qmod/classical_variable.py +4 -2
- classiq/qmod/native/pretty_printer.py +8 -0
- classiq/qmod/pretty_print/pretty_printer.py +5 -0
- classiq/qmod/quantum_expandable.py +31 -15
- classiq/qmod/symbolic_expr.py +12 -4
- classiq/synthesis.py +1 -1
- {classiq-0.91.1.dist-info → classiq-0.93.0.dist-info}/METADATA +39 -34
- {classiq-0.91.1.dist-info → classiq-0.93.0.dist-info}/RECORD +41 -37
- classiq-0.93.0.dist-info/WHEEL +4 -0
- classiq-0.93.0.dist-info/licenses/LICENSE.txt +27 -0
- classiq/interface/ide/ide_data.py +0 -102
- classiq-0.91.1.dist-info/WHEEL +0 -4
|
@@ -148,6 +148,7 @@ class StatementType(StrEnum):
|
|
|
148
148
|
REPEAT = "repeat"
|
|
149
149
|
BLOCK = "block"
|
|
150
150
|
IF = "if"
|
|
151
|
+
SKIP_CONTROL = "skip control"
|
|
151
152
|
|
|
152
153
|
|
|
153
154
|
# Mapping between statement kind (or sub-kind) and statement type (visualization name)
|
|
@@ -170,6 +171,7 @@ STATEMENTS_NAME: dict[str, StatementType] = {
|
|
|
170
171
|
"Repeat": StatementType.REPEAT,
|
|
171
172
|
"Block": StatementType.BLOCK,
|
|
172
173
|
"ClassicalIf": StatementType.IF,
|
|
174
|
+
"SkipControl": StatementType.SKIP_CONTROL,
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
|
|
@@ -197,9 +199,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
|
197
199
|
@property
|
|
198
200
|
def name(self) -> str:
|
|
199
201
|
generated_name = self.generated_function.name if self.generated_function else ""
|
|
200
|
-
# Temp fix for remaining old "supported" statements - power
|
|
201
|
-
if generated_name == StatementType.POWER:
|
|
202
|
-
return generated_name
|
|
203
202
|
|
|
204
203
|
back_ref = self.first_back_ref
|
|
205
204
|
if back_ref is None:
|
|
@@ -235,10 +234,6 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
|
235
234
|
|
|
236
235
|
@property
|
|
237
236
|
def level(self) -> OperationLevel:
|
|
238
|
-
# Temp fix for remaining old "supported" statements - power
|
|
239
|
-
if self.name == StatementType.POWER:
|
|
240
|
-
return OperationLevel.QMOD_STATEMENT
|
|
241
|
-
|
|
242
237
|
if self.first_back_ref is None:
|
|
243
238
|
# we use ENGINE_FUNCTION_CALL in case where there's not back ref
|
|
244
239
|
return OperationLevel.ENGINE_FUNCTION_CALL
|
|
@@ -300,15 +295,8 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
|
300
295
|
|
|
301
296
|
updated_children: list[FunctionDebugInfoInterface] = []
|
|
302
297
|
for child in self.children:
|
|
303
|
-
updated_child = child.
|
|
304
|
-
|
|
305
|
-
updated_child = updated_child.propagate_absolute_qubits()
|
|
306
|
-
else:
|
|
307
|
-
updated_child.override_debug_info = (
|
|
308
|
-
updated_child.override_debug_info.white_new_absolute_qubits(
|
|
309
|
-
absolute_qubits=self.absolute_qubits
|
|
310
|
-
).propagate_absolute_qubits()
|
|
311
|
-
)
|
|
298
|
+
updated_child = child._write_new_absolute_qubits(self.absolute_qubits)
|
|
299
|
+
updated_child = updated_child.propagate_absolute_qubits()
|
|
312
300
|
updated_children.append(updated_child)
|
|
313
301
|
|
|
314
302
|
return self.model_copy(
|
|
@@ -318,7 +306,7 @@ class FunctionDebugInfoInterface(pydantic.BaseModel):
|
|
|
318
306
|
)
|
|
319
307
|
)
|
|
320
308
|
|
|
321
|
-
def
|
|
309
|
+
def _write_new_absolute_qubits(
|
|
322
310
|
self, absolute_qubits: tuple[int, ...]
|
|
323
311
|
) -> "FunctionDebugInfoInterface":
|
|
324
312
|
return self.model_copy(
|
|
@@ -61,7 +61,7 @@ NON_UNITARY_GATES: BasisGates = frozenset(("if_else",))
|
|
|
61
61
|
|
|
62
62
|
TWO_QUBIT_GATES = BASIC_TWO_QUBIT_GATES | EXTRA_TWO_QUBIT_GATES
|
|
63
63
|
|
|
64
|
-
THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap"))
|
|
64
|
+
THREE_QUBIT_GATES: BasisGates = frozenset(("ccx", "cswap", "ccz"))
|
|
65
65
|
DEFAULT_BASIS_GATES: BasisGates = SINGLE_QUBIT_GATES | BASIC_TWO_QUBIT_GATES
|
|
66
66
|
ALL_GATES: BasisGates = (
|
|
67
67
|
SINGLE_QUBIT_GATES | TWO_QUBIT_GATES | THREE_QUBIT_GATES | NON_UNITARY_GATES
|
|
@@ -2,12 +2,10 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
import pydantic
|
|
4
4
|
|
|
5
|
-
from classiq.interface._version import VERSION
|
|
6
5
|
from classiq.interface.interface_version import INTERFACE_VERSION
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class VersionedModel(pydantic.BaseModel):
|
|
10
|
-
version: str = pydantic.Field(default=VERSION)
|
|
11
9
|
interface_version: str = pydantic.Field(default="0")
|
|
12
10
|
|
|
13
11
|
@pydantic.model_validator(mode="before")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
INTERFACE_VERSION = "
|
|
1
|
+
INTERFACE_VERSION = "13"
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
from collections.abc import Mapping, Sequence
|
|
2
2
|
from typing import Literal
|
|
3
3
|
|
|
4
|
-
import pydantic
|
|
5
|
-
|
|
6
|
-
from classiq.interface.exceptions import ClassiqValueError
|
|
7
4
|
from classiq.interface.model.handle_binding import ConcreteHandleBinding, HandleBinding
|
|
8
5
|
from classiq.interface.model.quantum_statement import HandleMetadata, QuantumOperation
|
|
9
6
|
|
|
@@ -49,12 +46,3 @@ class BindOperation(QuantumOperation):
|
|
|
49
46
|
)
|
|
50
47
|
for handle in self.out_handles
|
|
51
48
|
]
|
|
52
|
-
|
|
53
|
-
@pydantic.field_validator("in_handles", "out_handles")
|
|
54
|
-
@classmethod
|
|
55
|
-
def validate_handle(cls, handles: list[HandleBinding]) -> list[HandleBinding]:
|
|
56
|
-
for handle in handles:
|
|
57
|
-
if not handle.is_bindable():
|
|
58
|
-
raise ClassiqValueError(f"Cannot bind '{handle}'")
|
|
59
|
-
|
|
60
|
-
return handles
|
|
@@ -382,6 +382,9 @@ FieldHandleBinding.model_rebuild()
|
|
|
382
382
|
class HandlesList(ASTNode):
|
|
383
383
|
handles: list["GeneralHandle"]
|
|
384
384
|
|
|
385
|
+
def __str__(self) -> str:
|
|
386
|
+
return f"[{', '.join(map(str, self.handles))}]"
|
|
387
|
+
|
|
385
388
|
|
|
386
389
|
GeneralHandle = Union[ConcreteHandleBinding, HandlesList]
|
|
387
390
|
HandlesList.model_rebuild()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Literal
|
|
2
|
+
|
|
3
|
+
from classiq.interface.model.quantum_statement import QuantumOperation
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from classiq.interface.model.statement_block import StatementBlock
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SkipControl(QuantumOperation):
|
|
10
|
+
kind: Literal["SkipControl"]
|
|
11
|
+
body: "StatementBlock"
|
|
@@ -22,6 +22,7 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
|
22
22
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
23
23
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
|
24
24
|
from classiq.interface.model.repeat import Repeat
|
|
25
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
25
26
|
from classiq.interface.model.variable_declaration_statement import (
|
|
26
27
|
VariableDeclarationStatement,
|
|
27
28
|
)
|
|
@@ -53,6 +54,7 @@ ConcreteQuantumStatement = Annotated[
|
|
|
53
54
|
Action,
|
|
54
55
|
Uncompute,
|
|
55
56
|
SetBoundsStatement,
|
|
57
|
+
SkipControl,
|
|
56
58
|
],
|
|
57
59
|
Field(..., discriminator="kind"),
|
|
58
60
|
]
|
|
@@ -69,3 +71,4 @@ WithinApply.model_rebuild()
|
|
|
69
71
|
ClassicalIf.model_rebuild()
|
|
70
72
|
NativeFunctionDefinition.model_rebuild()
|
|
71
73
|
PhaseOperation.model_rebuild()
|
|
74
|
+
SkipControl.model_rebuild()
|
|
@@ -25,7 +25,6 @@ RB = "/rb"
|
|
|
25
25
|
ANALYZER_DATA_TASK = f"{TASKS_SUFFIX}/data"
|
|
26
26
|
ANALYZER_QASM_TASK = f"{TASKS_SUFFIX}/qasm"
|
|
27
27
|
ANALYZER_GET_VISUAL_MODEL = "/get_visual_model"
|
|
28
|
-
ANALYZER_GET_IDE_DATA = "/get_ide_data"
|
|
29
28
|
IDE_EVENT_TASK = f"{TASKS_SUFFIX}/event"
|
|
30
29
|
DATA_DOG_EVENT_TASK = f"{TASKS_SUFFIX}/data_dog_event"
|
|
31
30
|
|
|
@@ -33,14 +32,12 @@ ANALYZER_DATA_TASK_UPLOAD_FILE = f"{TASKS_SUFFIX}/data/file_upload"
|
|
|
33
32
|
ANALYZER_DATA_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_DATA_TASK}"
|
|
34
33
|
ANALYZER_QASM_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_QASM_TASK}"
|
|
35
34
|
ANALYZER_GET_VISUAL_MODEL_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_GET_VISUAL_MODEL}"
|
|
36
|
-
ANALYZER_GET_IDE_DATA_FULL_PATH = f"{ANALYZER_PREFIX}{ANALYZER_GET_IDE_DATA}"
|
|
37
35
|
IDE_EVENT_TASK_FULL_PATH = f"{ANALYZER_PREFIX}{IDE_EVENT_TASK}"
|
|
38
36
|
DATA_DOG_EVENT_TASK_FULL_PATH = f"{ANALYZER_PREFIX}{DATA_DOG_EVENT_TASK}"
|
|
39
37
|
|
|
40
38
|
IDE_QASM_TASK = f"{TASKS_SUFFIX}/generated_circuit_from_qasm"
|
|
41
39
|
IDE_QASM_FULL_PATH = f"{ANALYZER_PREFIX}{IDE_QASM_TASK}"
|
|
42
40
|
TASKS_GENERATE_SUFFIX = TASKS_SUFFIX + "/generate"
|
|
43
|
-
TASKS_VISUALIZE_SUFFIX = TASKS_SUFFIX + "/visualize"
|
|
44
41
|
TASKS_VISUAL_MODEL_SUFFIX = TASKS_SUFFIX + "/visual_model"
|
|
45
42
|
TASKS_SOLVE_SUFFIX = "/tasks/solve"
|
|
46
43
|
|
|
@@ -13,6 +13,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
|
|
|
13
13
|
INVERT_OPERATOR_NAME,
|
|
14
14
|
POWER_OPERATOR_NAME,
|
|
15
15
|
REPEAT_OPERATOR_NAME,
|
|
16
|
+
SKIP_CONTROL_OPERATOR_NAME,
|
|
16
17
|
WITHIN_APPLY_NAME,
|
|
17
18
|
)
|
|
18
19
|
from classiq.interface.model.allocate import Allocate
|
|
@@ -43,6 +44,7 @@ from classiq.interface.model.quantum_lambda_function import (
|
|
|
43
44
|
)
|
|
44
45
|
from classiq.interface.model.quantum_statement import QuantumStatement
|
|
45
46
|
from classiq.interface.model.repeat import Repeat
|
|
47
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
46
48
|
from classiq.interface.model.variable_declaration_statement import (
|
|
47
49
|
VariableDeclarationStatement,
|
|
48
50
|
)
|
|
@@ -84,6 +86,9 @@ from classiq.model_expansions.quantum_operations.handle_evaluator import HandleE
|
|
|
84
86
|
from classiq.model_expansions.quantum_operations.repeat_block_evaluator import (
|
|
85
87
|
RepeatBlockEvaluator,
|
|
86
88
|
)
|
|
89
|
+
from classiq.model_expansions.quantum_operations.skip_control_verifier import (
|
|
90
|
+
SkipControlVerifier,
|
|
91
|
+
)
|
|
87
92
|
from classiq.model_expansions.scope import Evaluated, Scope
|
|
88
93
|
from classiq.model_expansions.scope_initialization import (
|
|
89
94
|
add_constants_to_scope,
|
|
@@ -240,7 +245,9 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
240
245
|
def emit_variable_declaration(
|
|
241
246
|
self, variable_declaration: VariableDeclarationStatement
|
|
242
247
|
) -> None:
|
|
243
|
-
VariableDeclarationStatementEmitter(
|
|
248
|
+
VariableDeclarationStatementEmitter(
|
|
249
|
+
self, allow_symbolic_vars=self._symbolic_parameters_switch
|
|
250
|
+
).emit(variable_declaration)
|
|
244
251
|
|
|
245
252
|
@emit.register
|
|
246
253
|
def emit_classical_if(self, classical_if: ClassicalIf) -> None:
|
|
@@ -278,6 +285,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
278
285
|
def emit_invert(self, invert: Invert) -> None:
|
|
279
286
|
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
|
280
287
|
|
|
288
|
+
@emit.register
|
|
289
|
+
def emit_skip_control(self, skip_control: SkipControl) -> None:
|
|
290
|
+
CompositeEmitter[SkipControl](
|
|
291
|
+
self,
|
|
292
|
+
[
|
|
293
|
+
SkipControlVerifier(self),
|
|
294
|
+
BlockEvaluator(self, SKIP_CONTROL_OPERATOR_NAME, "body"),
|
|
295
|
+
],
|
|
296
|
+
).emit(skip_control)
|
|
297
|
+
|
|
281
298
|
@emit.register
|
|
282
299
|
def _emit_repeat(self, repeat: Repeat) -> None:
|
|
283
300
|
self.emit_repeat(repeat)
|
|
@@ -62,6 +62,12 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
|
62
62
|
if isinstance(result_symbol, ClassicalSymbol):
|
|
63
63
|
return False
|
|
64
64
|
result_type = result_symbol.quantum_type
|
|
65
|
+
if not isinstance(result_type, QuantumScalar):
|
|
66
|
+
raise ClassiqExpansionError(
|
|
67
|
+
f"Cannot assign into a non-scalar quantum variable "
|
|
68
|
+
f"{str(result_symbol.handle)!r} of type "
|
|
69
|
+
f"{result_type.raw_qmod_type_name}"
|
|
70
|
+
)
|
|
65
71
|
|
|
66
72
|
if not (
|
|
67
73
|
isinstance(op, ArithmeticOperation)
|
|
@@ -25,6 +25,12 @@ if TYPE_CHECKING:
|
|
|
25
25
|
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
BIND_PATH_EXPR_MESSAGE = (
|
|
29
|
+
"Cannot use variable part (subscript, slice, or field access) in the source or "
|
|
30
|
+
"destination of a 'bind' statement"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
28
34
|
class BindEmitter(Emitter[BindOperation]):
|
|
29
35
|
def __init__(
|
|
30
36
|
self, interpreter: "BaseInterpreter", allow_symbolic_size: bool = False
|
|
@@ -60,6 +66,7 @@ class BindEmitter(Emitter[BindOperation]):
|
|
|
60
66
|
evaluated_outputs: list[Evaluated] = [
|
|
61
67
|
self._interpreter.evaluate(arg) for arg in bind.out_handles
|
|
62
68
|
]
|
|
69
|
+
self._validate_var_types(evaluated_inputs + evaluated_outputs)
|
|
63
70
|
self._validate_handle_states(evaluated_inputs, evaluated_outputs)
|
|
64
71
|
inputs: list[QuantumSymbol] = [
|
|
65
72
|
input.as_type(QuantumSymbol) for input in evaluated_inputs
|
|
@@ -71,6 +78,13 @@ class BindEmitter(Emitter[BindOperation]):
|
|
|
71
78
|
outputs = evaluate_types_in_quantum_symbols(outputs, self._current_scope)
|
|
72
79
|
return inputs, outputs
|
|
73
80
|
|
|
81
|
+
def _validate_var_types(self, vars: list[Evaluated]) -> None:
|
|
82
|
+
path_expr_vars = [
|
|
83
|
+
var.value for var in vars if not var.value.handle.is_bindable()
|
|
84
|
+
]
|
|
85
|
+
if len(path_expr_vars) > 0:
|
|
86
|
+
raise ClassiqExpansionError(BIND_PATH_EXPR_MESSAGE)
|
|
87
|
+
|
|
74
88
|
def _validate_handle_states(
|
|
75
89
|
self, inputs: list[Evaluated], outputs: list[Evaluated]
|
|
76
90
|
) -> None:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
|
2
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
3
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
4
|
+
|
|
5
|
+
from classiq.model_expansions.function_builder import FunctionContext
|
|
6
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SkipControlVerifier(Emitter[SkipControl]):
|
|
10
|
+
def emit(self, skip_control: SkipControl, /) -> bool:
|
|
11
|
+
for op, block in list(
|
|
12
|
+
zip_strict(self._builder._operations, self._builder._blocks, strict=True)
|
|
13
|
+
)[::-1]:
|
|
14
|
+
if isinstance(op, FunctionContext):
|
|
15
|
+
break
|
|
16
|
+
if block in ("action", "apply"):
|
|
17
|
+
raise ClassiqExpansionError(
|
|
18
|
+
"skip_control cannot be used under within-apply's 'apply' block"
|
|
19
|
+
)
|
|
20
|
+
return False
|
|
@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Union, cast
|
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
|
4
4
|
from classiq.interface.generator.functions.classical_type import ClassicalType
|
|
5
5
|
from classiq.interface.generator.functions.concrete_types import ConcreteType
|
|
6
|
+
from classiq.interface.helpers.text_utils import readable_list, s
|
|
6
7
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
7
8
|
from classiq.interface.model.quantum_type import QuantumType
|
|
8
9
|
from classiq.interface.model.variable_declaration_statement import (
|
|
@@ -13,11 +14,21 @@ from classiq.evaluators.parameter_types import (
|
|
|
13
14
|
evaluate_type_in_classical_symbol,
|
|
14
15
|
evaluate_type_in_quantum_symbol,
|
|
15
16
|
)
|
|
17
|
+
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
16
18
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
|
17
19
|
from classiq.model_expansions.scope import ClassicalSymbol, Evaluated, QuantumSymbol
|
|
18
20
|
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
|
23
|
+
|
|
19
24
|
|
|
20
25
|
class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
|
|
26
|
+
def __init__(
|
|
27
|
+
self, interpreter: "BaseInterpreter", allow_symbolic_vars: bool = False
|
|
28
|
+
) -> None:
|
|
29
|
+
super().__init__(interpreter)
|
|
30
|
+
self._allow_symbolic_vars = allow_symbolic_vars
|
|
31
|
+
|
|
21
32
|
def emit(self, variable_declaration: VariableDeclarationStatement, /) -> bool:
|
|
22
33
|
var_decl = variable_declaration.model_copy(
|
|
23
34
|
update=dict(back_ref=variable_declaration.uuid)
|
|
@@ -29,36 +40,57 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
|
|
|
29
40
|
)
|
|
30
41
|
var_value: Union[QuantumSymbol, ClassicalSymbol]
|
|
31
42
|
if variable_declaration.is_quantum:
|
|
32
|
-
|
|
33
|
-
assert isinstance(var_decl.qmod_type, QuantumType)
|
|
34
|
-
updated_quantum_type = evaluate_type_in_quantum_symbol(
|
|
35
|
-
var_decl.qmod_type,
|
|
36
|
-
self._current_scope,
|
|
37
|
-
var_decl.name,
|
|
38
|
-
)
|
|
39
|
-
var_decl.qmod_type = updated_quantum_type
|
|
40
|
-
var_value = QuantumSymbol(
|
|
41
|
-
handle=HandleBinding(name=var_decl.name),
|
|
42
|
-
quantum_type=updated_quantum_type,
|
|
43
|
-
)
|
|
44
|
-
self._builder.current_block.captured_vars.init_var(
|
|
45
|
-
var_decl.name, self._builder.current_function
|
|
46
|
-
)
|
|
43
|
+
var_value = self._get_quantum_var(var_decl)
|
|
47
44
|
else:
|
|
48
|
-
|
|
49
|
-
assert isinstance(var_decl.qmod_type, ClassicalType)
|
|
50
|
-
updated_classical_type = evaluate_type_in_classical_symbol(
|
|
51
|
-
var_decl.qmod_type,
|
|
52
|
-
self._current_scope,
|
|
53
|
-
var_decl.name,
|
|
54
|
-
)
|
|
55
|
-
var_decl.qmod_type = cast(ConcreteType, updated_classical_type)
|
|
56
|
-
var_value = ClassicalSymbol(
|
|
57
|
-
handle=HandleBinding(name=var_decl.name),
|
|
58
|
-
classical_type=updated_classical_type,
|
|
59
|
-
)
|
|
45
|
+
var_value = self._get_classical_var(var_decl)
|
|
60
46
|
self._current_scope[variable_declaration.name] = Evaluated(
|
|
61
47
|
value=var_value, defining_function=self._builder.current_function
|
|
62
48
|
)
|
|
63
49
|
self.emit_statement(var_decl)
|
|
64
50
|
return True
|
|
51
|
+
|
|
52
|
+
def _get_quantum_var(self, var_decl: VariableDeclarationStatement) -> QuantumSymbol:
|
|
53
|
+
updated_quantum_type = evaluate_type_in_quantum_symbol(
|
|
54
|
+
cast(QuantumType, var_decl.qmod_type),
|
|
55
|
+
self._current_scope,
|
|
56
|
+
var_decl.name,
|
|
57
|
+
)
|
|
58
|
+
if not self._allow_symbolic_vars:
|
|
59
|
+
symbolic_variables = list(
|
|
60
|
+
dict.fromkeys(
|
|
61
|
+
classical_var.name
|
|
62
|
+
for expr in updated_quantum_type.expressions
|
|
63
|
+
if isinstance(expr_val := expr.value.value, QmodAnnotatedExpression)
|
|
64
|
+
for classical_var in expr_val.get_classical_vars().values()
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
if len(symbolic_variables) > 0:
|
|
68
|
+
raise ClassiqExpansionError(
|
|
69
|
+
f"Variable type is instantiated with non-compile-time "
|
|
70
|
+
f"variable{s(symbolic_variables)} "
|
|
71
|
+
f"{readable_list(symbolic_variables, quote=True)}"
|
|
72
|
+
)
|
|
73
|
+
var_decl.qmod_type = updated_quantum_type
|
|
74
|
+
var_value = QuantumSymbol(
|
|
75
|
+
handle=HandleBinding(name=var_decl.name),
|
|
76
|
+
quantum_type=updated_quantum_type,
|
|
77
|
+
)
|
|
78
|
+
self._builder.current_block.captured_vars.init_var(
|
|
79
|
+
var_decl.name, self._builder.current_function
|
|
80
|
+
)
|
|
81
|
+
return var_value
|
|
82
|
+
|
|
83
|
+
def _get_classical_var(
|
|
84
|
+
self, var_decl: VariableDeclarationStatement
|
|
85
|
+
) -> ClassicalSymbol:
|
|
86
|
+
updated_classical_type = evaluate_type_in_classical_symbol(
|
|
87
|
+
cast(ClassicalType, var_decl.qmod_type),
|
|
88
|
+
self._current_scope,
|
|
89
|
+
var_decl.name,
|
|
90
|
+
)
|
|
91
|
+
var_decl.qmod_type = cast(ConcreteType, updated_classical_type)
|
|
92
|
+
var_value = ClassicalSymbol(
|
|
93
|
+
handle=HandleBinding(name=var_decl.name),
|
|
94
|
+
classical_type=updated_classical_type,
|
|
95
|
+
)
|
|
96
|
+
return var_value
|
|
@@ -53,6 +53,7 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
|
53
53
|
qsvt_inversion,
|
|
54
54
|
qsvt_lcu,
|
|
55
55
|
qsvt_lcu_step,
|
|
56
|
+
gqsp,
|
|
56
57
|
qaoa_mixer_layer,
|
|
57
58
|
qaoa_cost_layer,
|
|
58
59
|
qaoa_layer,
|
|
@@ -94,6 +95,7 @@ __all__ = [
|
|
|
94
95
|
"encode_on_bloch",
|
|
95
96
|
"exact_amplitude_amplification",
|
|
96
97
|
"full_hea",
|
|
98
|
+
"gqsp",
|
|
97
99
|
"grover_diffuser",
|
|
98
100
|
"grover_operator",
|
|
99
101
|
"grover_search",
|
|
@@ -13,6 +13,7 @@ from classiq.qmod.builtins.operations import (
|
|
|
13
13
|
from classiq.qmod.qfunc import qfunc
|
|
14
14
|
from classiq.qmod.qmod_variable import Const, Permutable, QArray, QBit, QNum
|
|
15
15
|
from classiq.qmod.symbolic import pi
|
|
16
|
+
from classiq.qmod.utilities import suppress_return_value
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def _b_operator(q: QBit) -> None:
|
|
@@ -27,7 +28,7 @@ def _qct_d_operator(x: Const[QNum], q: QBit) -> None:
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
@qfunc
|
|
30
|
-
def _qct_pi_operator(x: Permutable[
|
|
31
|
+
def _qct_pi_operator(x: Permutable[QNum], q: Const[QBit]) -> None:
|
|
31
32
|
control(
|
|
32
33
|
q == 1,
|
|
33
34
|
lambda: [
|
|
@@ -65,8 +66,8 @@ def _d1_operator(x: QArray[QBit], q: QBit) -> None:
|
|
|
65
66
|
PHASE(-omega_exp, q)
|
|
66
67
|
|
|
67
68
|
|
|
68
|
-
def _pi2_operator(x:
|
|
69
|
-
control(q == 1, lambda: inplace_add(1, x)) # type:ignore[arg-type]
|
|
69
|
+
def _pi2_operator(x: QNum, q: QBit) -> None:
|
|
70
|
+
control(q == 1, lambda: inplace_add(1, x)), # type:ignore[arg-type]
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
def _j_operator(q: QBit) -> None:
|
|
@@ -78,19 +79,23 @@ def _b_t_operator(q: QBit) -> None:
|
|
|
78
79
|
S(q)
|
|
79
80
|
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
bind(x, x_num)
|
|
82
|
+
@suppress_return_value
|
|
83
|
+
def _d0dt_operator(x: QNum, q: QBit) -> None:
|
|
84
84
|
_b_t_operator(q)
|
|
85
|
-
control(
|
|
86
|
-
bind(x_num, x)
|
|
85
|
+
control(x == 0, lambda: _j_operator(q))
|
|
87
86
|
|
|
88
87
|
|
|
89
88
|
def _un_dag_operator(x: QArray[QBit], q: QBit) -> None:
|
|
90
89
|
_d1_operator(x, q)
|
|
91
90
|
invert(lambda: _qct_pi_operator(x, q))
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
x_num: QNum = QNum(size=x.len)
|
|
92
|
+
within_apply(
|
|
93
|
+
lambda: bind(x, x_num),
|
|
94
|
+
lambda: [
|
|
95
|
+
_d0dt_operator(x_num, q),
|
|
96
|
+
invert(lambda: _pi2_operator(x_num, q)),
|
|
97
|
+
],
|
|
98
|
+
)
|
|
94
99
|
|
|
95
100
|
|
|
96
101
|
@qfunc
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from classiq.qmod.builtins.functions.standard_gates import IDENTITY, RZ, H
|
|
1
|
+
from classiq.qmod.builtins.functions.standard_gates import IDENTITY, RZ, H, U, X, Z
|
|
2
2
|
from classiq.qmod.builtins.operations import control, if_, invert, repeat, within_apply
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
|
4
|
-
from classiq.qmod.qmod_parameter import CArray, CReal
|
|
4
|
+
from classiq.qmod.qmod_parameter import CArray, CInt, CReal
|
|
5
5
|
from classiq.qmod.qmod_variable import QArray, QBit
|
|
6
6
|
from classiq.qmod.quantum_callable import QCallable
|
|
7
7
|
from classiq.qmod.symbolic import floor, min as qmin
|
|
@@ -267,8 +267,8 @@ def qsvt_lcu(
|
|
|
267
267
|
Note: the two polynomials should have the same degree up to a difference of 1.
|
|
268
268
|
|
|
269
269
|
Args:
|
|
270
|
-
phase_seq_odd: A sequence of phase angles of length d+
|
|
271
|
-
phase_seq_even: A sequence of phase angles of length d+1 for the even polynomial.
|
|
270
|
+
phase_seq_odd: A sequence of phase angles of length d+(d%2) for the odd polynomial.
|
|
271
|
+
phase_seq_even: A sequence of phase angles of length d+(d+1)%2 for the even polynomial.
|
|
272
272
|
proj_cnot_1: Projector-controlled-not unitary that locates the encoded matrix columns within U. Accepts a quantum variable of the same size as qvar, and a qubit that is set to |1> when the state is in the block.
|
|
273
273
|
proj_cnot_2: Projector-controlled-not unitary that locates the encoded matrix rows within U. Accepts a quantum variable of the same size as qvar, and a qubit that is set to |1> when the state is in the block.
|
|
274
274
|
u: A block encoded unitary matrix.
|
|
@@ -281,7 +281,7 @@ def qsvt_lcu(
|
|
|
281
281
|
phase_seq_even[0], phase_seq_odd[0], proj_cnot_1, qvar, aux, lcu
|
|
282
282
|
)
|
|
283
283
|
repeat(
|
|
284
|
-
count=floor((qmin(phase_seq_odd.len, phase_seq_even.len)) / 2),
|
|
284
|
+
count=floor((qmin(phase_seq_odd.len - 1, phase_seq_even.len - 1)) / 2),
|
|
285
285
|
iteration=lambda index: qsvt_lcu_step(
|
|
286
286
|
phase_seq_even[2 * index + 1 : 2 * index + 3],
|
|
287
287
|
phase_seq_odd[2 * index + 1 : 2 * index + 3],
|
|
@@ -310,7 +310,7 @@ def qsvt_lcu(
|
|
|
310
310
|
then=lambda: (
|
|
311
311
|
u(qvar),
|
|
312
312
|
projector_controlled_double_phase(
|
|
313
|
-
phase_seq_even[phase_seq_even.len -
|
|
313
|
+
phase_seq_even[phase_seq_even.len - 2],
|
|
314
314
|
phase_seq_odd[phase_seq_odd.len - 1],
|
|
315
315
|
proj_cnot_2,
|
|
316
316
|
qvar,
|
|
@@ -329,3 +329,57 @@ def qsvt_lcu(
|
|
|
329
329
|
),
|
|
330
330
|
)
|
|
331
331
|
H(aux)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@qfunc
|
|
335
|
+
def _gqsp_r_gate(theta: CReal, phi: CReal, _lambda: CReal, q: QBit) -> None:
|
|
336
|
+
"""
|
|
337
|
+
Implements the R gate from the paper https://arxiv.org/abs/2308.01501 using the U gate.
|
|
338
|
+
"""
|
|
339
|
+
within_apply(lambda: X(q), lambda: U(2 * theta, phi, _lambda, 0, q))
|
|
340
|
+
Z(q)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@qfunc
|
|
344
|
+
def gqsp(
|
|
345
|
+
u: QCallable, aux: QBit, phases: CArray[CArray[CReal], 3], negative_power: CInt # type: ignore[valid-type]
|
|
346
|
+
) -> None:
|
|
347
|
+
"""
|
|
348
|
+
Implements Generalized Quantum Signal Processing (GQSP), which realizes a
|
|
349
|
+
(Laurent) polynomial transformation of degree d on the eigenvalues of the given
|
|
350
|
+
signal unitary `u`. The protocol is according to https://arxiv.org/abs/2308.01501
|
|
351
|
+
Fig.2.
|
|
352
|
+
|
|
353
|
+
Notes:
|
|
354
|
+
- The user is encouraged to use the function `gqsp_phases` to find `phases` that
|
|
355
|
+
correspond to the wanted polynomial transformation.
|
|
356
|
+
- Feasibility: the target polynomial must satisfy |P(e^{i*theta})| <= 1 for all
|
|
357
|
+
theta in [0, 2*pi). This ensures a unitary completion exists.
|
|
358
|
+
- Using `negative_power = m` (m >= 0) you can realize Laurent polynomials with
|
|
359
|
+
negative exponents: the implemented transform is equivalent to applying
|
|
360
|
+
z^{-m} * P(z) (i.e., shift the minimal degree to -m).
|
|
361
|
+
For ordinary (non-Laurent) polynomials, set `negative_power = 0`.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
u: The signal unitary.
|
|
365
|
+
aux: Auxiliary qubit used for the phase rotations. Should start in |0>.
|
|
366
|
+
phases: 3 x (d+1) real array of angles: phases[0] = thetas, phases[1] = phis,
|
|
367
|
+
phases[2] = lambdas.
|
|
368
|
+
negative_power: Integer m in [0, d]. Encodes the minimal Laurent power -m of
|
|
369
|
+
the realized transformation.
|
|
370
|
+
"""
|
|
371
|
+
degree = phases[0].len - 1
|
|
372
|
+
_gqsp_r_gate(phases[0][0], phases[1][0], phases[2][0], aux)
|
|
373
|
+
repeat(
|
|
374
|
+
degree,
|
|
375
|
+
lambda index: [
|
|
376
|
+
if_(
|
|
377
|
+
index + 1 <= degree - negative_power,
|
|
378
|
+
lambda: control(aux == 0, lambda: u()),
|
|
379
|
+
lambda: control(aux == 1, lambda: invert(u)),
|
|
380
|
+
),
|
|
381
|
+
_gqsp_r_gate(
|
|
382
|
+
phases[0][index + 1], phases[1][index + 1], phases[2][index + 1], aux
|
|
383
|
+
),
|
|
384
|
+
],
|
|
385
|
+
)
|
|
@@ -45,6 +45,7 @@ from classiq.interface.model.quantum_function_declaration import (
|
|
|
45
45
|
)
|
|
46
46
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
|
47
47
|
from classiq.interface.model.repeat import Repeat
|
|
48
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
48
49
|
from classiq.interface.model.statement_block import StatementBlock
|
|
49
50
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
50
51
|
|
|
@@ -254,6 +255,20 @@ def control(
|
|
|
254
255
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(control_stmt)
|
|
255
256
|
|
|
256
257
|
|
|
258
|
+
@suppress_return_value
|
|
259
|
+
def skip_control(stmt_block: Union[QCallable, Callable[[], Statements]]) -> None:
|
|
260
|
+
_validate_operand(stmt_block)
|
|
261
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
|
262
|
+
source_ref = get_source_ref(sys._getframe(1))
|
|
263
|
+
sc_stmt = SkipControl(
|
|
264
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
|
265
|
+
source_ref=source_ref,
|
|
266
|
+
)
|
|
267
|
+
if is_generative_mode():
|
|
268
|
+
sc_stmt.set_generative_block("body", stmt_block)
|
|
269
|
+
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(sc_stmt)
|
|
270
|
+
|
|
271
|
+
|
|
257
272
|
@suppress_return_value
|
|
258
273
|
def assign(expression: SymbolicExpr, target_var: QScalar) -> None:
|
|
259
274
|
"""
|
|
@@ -645,6 +660,14 @@ def _validate_operand(stmt_block: Any, num_params: int = 0) -> None:
|
|
|
645
660
|
)
|
|
646
661
|
if isinstance(stmt_block, QCallable):
|
|
647
662
|
return
|
|
663
|
+
if not callable(stmt_block):
|
|
664
|
+
_raise_operand_error(
|
|
665
|
+
lambda operation_name, operand_arg_name: (
|
|
666
|
+
f"Argument {operand_arg_name!r} to {operation_name!r} must be a "
|
|
667
|
+
f"callable object"
|
|
668
|
+
),
|
|
669
|
+
num_params,
|
|
670
|
+
)
|
|
648
671
|
op_spec = inspect.getfullargspec(stmt_block)
|
|
649
672
|
params = op_spec.args[: len(op_spec.args) - len(op_spec.defaults or ())]
|
|
650
673
|
if len(params) > num_params or (
|
|
@@ -748,6 +771,7 @@ __all__ = [
|
|
|
748
771
|
"power",
|
|
749
772
|
"repeat",
|
|
750
773
|
"reset_bounds",
|
|
774
|
+
"skip_control",
|
|
751
775
|
"within_apply",
|
|
752
776
|
]
|
|
753
777
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from typing import TYPE_CHECKING, Any
|
|
3
3
|
|
|
4
|
-
from classiq.interface.exceptions import ClassiqInternalError
|
|
4
|
+
from classiq.interface.exceptions import ClassiqInternalError, ClassiqTypeError
|
|
5
5
|
from classiq.interface.generator.expressions.expression import Expression
|
|
6
6
|
from classiq.interface.generator.functions.classical_type import Bool, ClassicalType
|
|
7
7
|
from classiq.interface.model.handle_binding import HandleBinding
|
|
@@ -37,7 +37,9 @@ def declare_classical_variable(
|
|
|
37
37
|
|
|
38
38
|
def assign_classical_variable(target: CParam, value: Any, frame_depth: int) -> None:
|
|
39
39
|
if not isinstance(value, SYMBOLIC_TYPES):
|
|
40
|
-
raise
|
|
40
|
+
raise ClassiqTypeError(
|
|
41
|
+
f"Invalid argument {value!r} for classical variable assignment"
|
|
42
|
+
)
|
|
41
43
|
|
|
42
44
|
if TYPE_CHECKING:
|
|
43
45
|
assert QCallable.CURRENT_EXPANDABLE is not None
|