classiq 0.91.0__py3-none-any.whl → 0.92.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/execution/jobs.py +18 -8
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +8 -8
- 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 +15 -0
- classiq/model_expansions/quantum_operations/bind.py +14 -0
- classiq/model_expansions/quantum_operations/skip_control_verifier.py +20 -0
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/qsvt.py +60 -6
- classiq/qmod/builtins/operations.py +16 -0
- classiq/qmod/native/pretty_printer.py +8 -0
- classiq/qmod/pretty_print/pretty_printer.py +5 -0
- classiq/qmod/quantum_expandable.py +29 -15
- classiq/synthesis.py +1 -1
- {classiq-0.91.0.dist-info → classiq-0.92.0.dist-info}/METADATA +4 -1
- {classiq-0.91.0.dist-info → classiq-0.92.0.dist-info}/RECORD +33 -30
- classiq/interface/ide/ide_data.py +0 -102
- {classiq-0.91.0.dist-info → classiq-0.92.0.dist-info}/WHEEL +0 -0
|
@@ -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,
|
|
@@ -278,6 +283,16 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
|
278
283
|
def emit_invert(self, invert: Invert) -> None:
|
|
279
284
|
BlockEvaluator(self, INVERT_OPERATOR_NAME, "body").emit(invert)
|
|
280
285
|
|
|
286
|
+
@emit.register
|
|
287
|
+
def emit_skip_control(self, skip_control: SkipControl) -> None:
|
|
288
|
+
CompositeEmitter[SkipControl](
|
|
289
|
+
self,
|
|
290
|
+
[
|
|
291
|
+
SkipControlVerifier(self),
|
|
292
|
+
BlockEvaluator(self, SKIP_CONTROL_OPERATOR_NAME, "body"),
|
|
293
|
+
],
|
|
294
|
+
).emit(skip_control)
|
|
295
|
+
|
|
281
296
|
@emit.register
|
|
282
297
|
def _emit_repeat(self, repeat: Repeat) -> None:
|
|
283
298
|
self.emit_repeat(repeat)
|
|
@@ -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
|
|
@@ -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",
|
|
@@ -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
|
"""
|
|
@@ -748,6 +763,7 @@ __all__ = [
|
|
|
748
763
|
"power",
|
|
749
764
|
"repeat",
|
|
750
765
|
"reset_bounds",
|
|
766
|
+
"skip_control",
|
|
751
767
|
"within_apply",
|
|
752
768
|
]
|
|
753
769
|
|
|
@@ -78,6 +78,7 @@ from classiq.interface.model.quantum_type import (
|
|
|
78
78
|
QuantumNumeric,
|
|
79
79
|
)
|
|
80
80
|
from classiq.interface.model.repeat import Repeat
|
|
81
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
81
82
|
from classiq.interface.model.statement_block import StatementBlock
|
|
82
83
|
from classiq.interface.model.variable_declaration_statement import (
|
|
83
84
|
VariableDeclarationStatement,
|
|
@@ -311,6 +312,13 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
|
311
312
|
control += "\n"
|
|
312
313
|
return control
|
|
313
314
|
|
|
315
|
+
def visit_SkipControl(self, op: SkipControl) -> str:
|
|
316
|
+
sc = f"{self._indent}skip_control {{\n"
|
|
317
|
+
sc += self._visit_body(op.body)
|
|
318
|
+
sc += f"{self._indent}}}"
|
|
319
|
+
sc += "\n"
|
|
320
|
+
return sc
|
|
321
|
+
|
|
314
322
|
def visit_PhaseOperation(self, op: PhaseOperation) -> str:
|
|
315
323
|
theta = f", {self.visit(op.theta)}" if op.theta.expr != "1.0" else ""
|
|
316
324
|
phase = f"{self._indent}phase ({self.visit(op.expression)}{theta});\n"
|
|
@@ -78,6 +78,7 @@ from classiq.interface.model.quantum_type import (
|
|
|
78
78
|
QuantumNumeric,
|
|
79
79
|
)
|
|
80
80
|
from classiq.interface.model.repeat import Repeat
|
|
81
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
81
82
|
from classiq.interface.model.statement_block import StatementBlock
|
|
82
83
|
from classiq.interface.model.variable_declaration_statement import (
|
|
83
84
|
VariableDeclarationStatement,
|
|
@@ -459,6 +460,10 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
|
459
460
|
)
|
|
460
461
|
return f"{self._indent}control({self.visit(op.expression)}, {self._visit_body(op.body)}{control_else})\n"
|
|
461
462
|
|
|
463
|
+
def visit_SkipControl(self, op: SkipControl) -> str:
|
|
464
|
+
self._imports["skip_control"] = 1
|
|
465
|
+
return f"{self._indent}skip_control({self._visit_body(op.body)})\n"
|
|
466
|
+
|
|
462
467
|
def visit_PhaseOperation(self, op: PhaseOperation) -> str:
|
|
463
468
|
self._imports["phase"] = 1
|
|
464
469
|
theta = f", {self.visit(op.theta)}" if op.theta.expr != "1.0" else ""
|
|
@@ -472,6 +472,34 @@ def _prepare_args(
|
|
|
472
472
|
return result
|
|
473
473
|
|
|
474
474
|
|
|
475
|
+
def _validate_argument_names(
|
|
476
|
+
decl: QuantumFunctionDeclaration, arg_list: list[Any], kwargs: dict[str, Any]
|
|
477
|
+
) -> None:
|
|
478
|
+
params = decl.positional_arg_declarations
|
|
479
|
+
param_names = {
|
|
480
|
+
mangle_keyword(param.name) for param in params if param.name is not None
|
|
481
|
+
}
|
|
482
|
+
pos_arg_names = {
|
|
483
|
+
mangle_keyword(param.name)
|
|
484
|
+
for param in params[: len(arg_list)]
|
|
485
|
+
if param.name is not None
|
|
486
|
+
}
|
|
487
|
+
for kwarg_name in kwargs:
|
|
488
|
+
if kwarg_name not in param_names:
|
|
489
|
+
raise ClassiqValueError(
|
|
490
|
+
f"{decl.name}() got an unexpected keyword argument {kwarg_name!r}"
|
|
491
|
+
)
|
|
492
|
+
if kwarg_name in pos_arg_names:
|
|
493
|
+
raise ClassiqValueError(
|
|
494
|
+
f"{decl.name}() got multiple values for argument {kwarg_name!r}"
|
|
495
|
+
)
|
|
496
|
+
total_args = len(arg_list) + len(kwargs)
|
|
497
|
+
if total_args != len(params):
|
|
498
|
+
raise ClassiqValueError(
|
|
499
|
+
f"{decl.name}() takes {len(params)} arguments but {total_args} were given"
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
|
|
475
503
|
def _create_quantum_function_call(
|
|
476
504
|
decl_: QuantumFunctionDeclaration,
|
|
477
505
|
index_: Optional[Union[CParamScalar, int]] = None,
|
|
@@ -479,24 +507,10 @@ def _create_quantum_function_call(
|
|
|
479
507
|
*args: Any,
|
|
480
508
|
**kwargs: Any,
|
|
481
509
|
) -> QuantumFunctionCall:
|
|
482
|
-
arg_decls = decl_.positional_arg_declarations
|
|
483
510
|
arg_list = list(args)
|
|
511
|
+
_validate_argument_names(decl_, arg_list, kwargs)
|
|
484
512
|
prepared_args = _prepare_args(decl_, arg_list, kwargs)
|
|
485
513
|
|
|
486
|
-
if kwargs:
|
|
487
|
-
bad_kwarg = next(iter(kwargs))
|
|
488
|
-
if not all(arg_decl.name == bad_kwarg for arg_decl in arg_decls):
|
|
489
|
-
raise ClassiqValueError(
|
|
490
|
-
f"{decl_.name}() got an unexpected keyword argument {bad_kwarg!r}"
|
|
491
|
-
)
|
|
492
|
-
else:
|
|
493
|
-
raise ClassiqValueError(
|
|
494
|
-
f"{decl_.name}() got multiple values for argument {bad_kwarg!r}"
|
|
495
|
-
)
|
|
496
|
-
if arg_list:
|
|
497
|
-
raise ClassiqValueError(
|
|
498
|
-
f"{decl_.name}() takes {len(arg_decls)} arguments but {len(args)} were given"
|
|
499
|
-
)
|
|
500
514
|
function_ident: Union[str, OperandIdentifier] = decl_.name
|
|
501
515
|
if index_ is not None:
|
|
502
516
|
function_ident = OperandIdentifier(
|
classiq/synthesis.py
CHANGED
|
@@ -69,7 +69,7 @@ def synthesize(
|
|
|
69
69
|
) -> QuantumProgram:
|
|
70
70
|
"""
|
|
71
71
|
Synthesize a model with the Classiq engine to receive a quantum program.
|
|
72
|
-
[More details](https://docs.classiq.io/latest/reference
|
|
72
|
+
[More details](https://docs.classiq.io/latest/sdk-reference/synthesis/#classiq.synthesize)
|
|
73
73
|
|
|
74
74
|
Args:
|
|
75
75
|
model: The entry point of the Qmod model - a qfunc named 'main' (or alternatively the output of 'create_model').
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: classiq
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.92.0
|
|
4
4
|
Summary: Classiq's Python SDK for quantum computing
|
|
5
5
|
License: Proprietary
|
|
6
6
|
Keywords: quantum computing,quantum circuits,quantum algorithms,QAD,QDL
|
|
@@ -29,9 +29,11 @@ Classifier: Typing :: Typed
|
|
|
29
29
|
Provides-Extra: analyzer-sdk
|
|
30
30
|
Provides-Extra: chemistry
|
|
31
31
|
Provides-Extra: qml
|
|
32
|
+
Provides-Extra: qsp
|
|
32
33
|
Requires-Dist: ConfigArgParse (>=1.5.3,<2.0.0)
|
|
33
34
|
Requires-Dist: Pyomo (>=6.9,<6.10)
|
|
34
35
|
Requires-Dist: black (>=24.0,<25.0)
|
|
36
|
+
Requires-Dist: cvxpy ; extra == "qsp"
|
|
35
37
|
Requires-Dist: httpx (>=0.23.0,<1)
|
|
36
38
|
Requires-Dist: ipywidgets ; extra == "analyzer-sdk"
|
|
37
39
|
Requires-Dist: jupyterlab ; extra == "analyzer-sdk"
|
|
@@ -49,6 +51,7 @@ Requires-Dist: pandas (>=1.4.0,<3.0.0)
|
|
|
49
51
|
Requires-Dist: plotly (>=5.7.0,<6.0.0)
|
|
50
52
|
Requires-Dist: pydantic (>=2.10.4,<3.0.0)
|
|
51
53
|
Requires-Dist: pydantic-settings (>=2.4.0,<3.0.0)
|
|
54
|
+
Requires-Dist: pyqsp ; extra == "qsp"
|
|
52
55
|
Requires-Dist: scipy (>=1.10.0,<2.0.0) ; python_version < "3.12"
|
|
53
56
|
Requires-Dist: scipy (>=1.11.0,<2.0.0) ; python_version >= "3.12"
|
|
54
57
|
Requires-Dist: sympy (>=1.13.0,<2.0.0)
|