classiq 0.99.0__py3-none-any.whl → 0.102.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 +3 -0
- classiq/_internals/api_wrapper.py +29 -4
- classiq/applications/chemistry/op_utils.py +31 -1
- classiq/applications/chemistry/problems.py +18 -6
- classiq/applications/chemistry/ucc.py +2 -2
- classiq/evaluators/parameter_types.py +1 -4
- classiq/evaluators/qmod_node_evaluators/utils.py +6 -3
- classiq/execution/__init__.py +11 -1
- classiq/execution/jobs.py +122 -5
- classiq/interface/_version.py +1 -1
- classiq/interface/exceptions.py +0 -42
- classiq/interface/executor/execution_request.py +1 -0
- classiq/interface/executor/quantum_code.py +0 -6
- classiq/interface/executor/user_budget.py +2 -6
- classiq/interface/generator/generation_request.py +40 -0
- classiq/interface/generator/quantum_program.py +8 -36
- classiq/interface/generator/transpiler_basis_gates.py +1 -3
- classiq/interface/generator/types/compilation_metadata.py +1 -1
- classiq/interface/helpers/model_normalizer.py +24 -0
- classiq/interface/helpers/text_utils.py +20 -5
- classiq/interface/model/bind_operation.py +3 -0
- classiq/interface/model/invert.py +7 -0
- classiq/interface/model/model.py +42 -3
- classiq/interface/model/quantum_function_call.py +17 -5
- classiq/model_expansions/arithmetic_compute_result_attrs.py +10 -1
- classiq/model_expansions/interpreters/base_interpreter.py +3 -2
- classiq/model_expansions/quantum_operations/call_emitter.py +0 -3
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +15 -38
- classiq/open_library/functions/__init__.py +55 -27
- classiq/open_library/functions/bit_operations.py +30 -0
- classiq/open_library/functions/encodings.py +182 -0
- classiq/open_library/functions/modular_arithmetics.py +597 -0
- classiq/open_library/functions/qft_space_arithmetics.py +81 -0
- classiq/open_library/functions/state_preparation.py +13 -7
- classiq/open_library/functions/utility_functions.py +22 -3
- classiq/qmod/builtins/functions/exponentiation.py +2 -2
- classiq/qmod/builtins/operations.py +29 -4
- classiq/qmod/native/pretty_printer.py +15 -4
- classiq/qmod/pretty_print/pretty_printer.py +14 -2
- classiq/qmod/qmod_variable.py +1 -1
- classiq/qmod/quantum_callable.py +8 -2
- classiq/qmod/quantum_expandable.py +3 -1
- classiq/qmod/quantum_function.py +2 -1
- classiq/qmod/semantics/error_manager.py +11 -1
- classiq/qmod/utilities.py +7 -4
- classiq/synthesis_action/__init__.py +20 -0
- classiq/synthesis_action/actions.py +106 -0
- {classiq-0.99.0.dist-info → classiq-0.102.0.dist-info}/METADATA +1 -1
- {classiq-0.99.0.dist-info → classiq-0.102.0.dist-info}/RECORD +51 -47
- classiq/interface/executor/register_initialization.py +0 -36
- classiq/open_library/functions/modular_exponentiation.py +0 -272
- classiq/open_library/functions/qsvt_temp.py +0 -536
- {classiq-0.99.0.dist-info → classiq-0.102.0.dist-info}/WHEEL +0 -0
- {classiq-0.99.0.dist-info → classiq-0.102.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -13,8 +13,8 @@ from classiq.open_library.functions.utility_functions import (
|
|
|
13
13
|
from classiq.qmod.builtins.functions import (
|
|
14
14
|
CX,
|
|
15
15
|
IDENTITY,
|
|
16
|
-
PHASE,
|
|
17
16
|
RY,
|
|
17
|
+
RZ,
|
|
18
18
|
H,
|
|
19
19
|
X,
|
|
20
20
|
free,
|
|
@@ -28,6 +28,7 @@ from classiq.qmod.builtins.operations import (
|
|
|
28
28
|
inplace_add,
|
|
29
29
|
inplace_xor,
|
|
30
30
|
invert,
|
|
31
|
+
phase,
|
|
31
32
|
repeat,
|
|
32
33
|
within_apply,
|
|
33
34
|
)
|
|
@@ -337,10 +338,12 @@ def apply_phase_table(
|
|
|
337
338
|
for i in range(1, len(alphas) - 1):
|
|
338
339
|
gray = _graycode(i)
|
|
339
340
|
next_gray = _graycode(i + 1)
|
|
340
|
-
|
|
341
|
+
RZ(alphas[gray], target[_msb(gray)])
|
|
341
342
|
CX(target[_control_qubit(i)], target[_msb(next_gray)])
|
|
342
343
|
|
|
343
|
-
|
|
344
|
+
RZ(alphas[_graycode(len(phases) - 1)], target[target.len - 1])
|
|
345
|
+
# fix the global phase:
|
|
346
|
+
phase(-0.5 * alphas[0])
|
|
344
347
|
|
|
345
348
|
|
|
346
349
|
@qfunc
|
|
@@ -393,7 +396,7 @@ def _dicke_split_cycle_shift(k: int, qvar: QArray[QBit]) -> None:
|
|
|
393
396
|
internal function, assumes the input is in the form |11..100..0> with up to k ones.
|
|
394
397
|
transforms the state to: sqrt(1/n)*|11..100..0> + sqrt((n-1)/n)*|01..110..0>.
|
|
395
398
|
"""
|
|
396
|
-
for i in range(k):
|
|
399
|
+
for i in range(min(k, qvar.len - 1)):
|
|
397
400
|
within_apply(
|
|
398
401
|
lambda i=i: CX(qvar[i + 1], qvar[0]), # type: ignore[misc]
|
|
399
402
|
lambda i=i: ( # type: ignore[misc]
|
|
@@ -415,7 +418,7 @@ def prepare_dicke_state_unary_input(max_k: int, qvar: QArray[QBit]) -> None:
|
|
|
415
418
|
"""
|
|
416
419
|
[Qmod Classiq-library function]
|
|
417
420
|
|
|
418
|
-
Prepares a Dicke state with a variable number of excitations based on
|
|
421
|
+
Prepares a Dicke state with a variable number of excitations based on a unary-encoded input.
|
|
419
422
|
|
|
420
423
|
The Dicke state is defined to be:
|
|
421
424
|
|
|
@@ -430,9 +433,12 @@ def prepare_dicke_state_unary_input(max_k: int, qvar: QArray[QBit]) -> None:
|
|
|
430
433
|
max_k: The maximum number of allowed excitations (upper bound for k).
|
|
431
434
|
qvar: Unary-encoded quantum input register of length >= max_k. Must be pre-initialized.
|
|
432
435
|
"""
|
|
433
|
-
if qvar.len
|
|
436
|
+
if qvar.len >= max(1, max_k):
|
|
434
437
|
_dicke_split_cycle_shift(max_k, qvar)
|
|
435
|
-
|
|
438
|
+
if qvar.len > 2:
|
|
439
|
+
prepare_dicke_state_unary_input(
|
|
440
|
+
min(max_k, qvar.len - 2), qvar[1 : qvar.len]
|
|
441
|
+
)
|
|
436
442
|
|
|
437
443
|
|
|
438
444
|
@qfunc
|
|
@@ -4,13 +4,13 @@ from typing import Annotated
|
|
|
4
4
|
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
|
5
5
|
|
|
6
6
|
from classiq.open_library.functions.qft_functions import qft
|
|
7
|
-
from classiq.qmod.builtins.functions.standard_gates import PHASE, H
|
|
7
|
+
from classiq.qmod.builtins.functions.standard_gates import PHASE, SWAP, H
|
|
8
8
|
from classiq.qmod.builtins.operations import bind, repeat, within_apply
|
|
9
9
|
from classiq.qmod.cparam import CInt
|
|
10
|
-
from classiq.qmod.qfunc import qfunc
|
|
10
|
+
from classiq.qmod.qfunc import qfunc, qperm
|
|
11
11
|
from classiq.qmod.qmod_variable import QArray, QBit, QCallable, QNum
|
|
12
12
|
from classiq.qmod.quantum_callable import QCallableList
|
|
13
|
-
from classiq.qmod.symbolic import pi
|
|
13
|
+
from classiq.qmod.symbolic import min, pi
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@qfunc
|
|
@@ -50,6 +50,25 @@ def hadamard_transform(target: QArray[QBit]) -> None:
|
|
|
50
50
|
repeat(target.len, lambda index: H(target[index]))
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
@qperm
|
|
54
|
+
def multiswap(x: QArray[QBit], y: QArray[QBit]) -> None:
|
|
55
|
+
"""
|
|
56
|
+
[Qmod Classiq-library function]
|
|
57
|
+
|
|
58
|
+
Swaps the qubit states between two arrays.
|
|
59
|
+
Qubits of respective indices are swapped, and additional qubits in the longer array are left unchanged.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
x: The first array
|
|
63
|
+
y: The second array
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
repeat(
|
|
67
|
+
count=min(x.len, y.len),
|
|
68
|
+
iteration=lambda index: SWAP(x[index], y[index]),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
53
72
|
@qfunc
|
|
54
73
|
def switch(selector: CInt, cases: QCallableList) -> None:
|
|
55
74
|
cases[selector]()
|
|
@@ -218,10 +218,10 @@ def sparse_suzuki_trotter(
|
|
|
218
218
|
|
|
219
219
|
@qfunc(external=True)
|
|
220
220
|
def qdrift(
|
|
221
|
-
pauli_operator: SparsePauliOp,
|
|
221
|
+
pauli_operator: SparsePauliOp,
|
|
222
222
|
evolution_coefficient: CReal,
|
|
223
223
|
num_qdrift: CInt,
|
|
224
|
-
qbv: QArray[QBit],
|
|
224
|
+
qbv: QArray[QBit, Literal["pauli_operator.num_qubits"]],
|
|
225
225
|
) -> None:
|
|
226
226
|
"""
|
|
227
227
|
[Qmod core-library function]
|
|
@@ -30,7 +30,7 @@ from classiq.interface.model.classical_parameter_declaration import (
|
|
|
30
30
|
ClassicalParameterDeclaration,
|
|
31
31
|
)
|
|
32
32
|
from classiq.interface.model.control import Control
|
|
33
|
-
from classiq.interface.model.invert import Invert
|
|
33
|
+
from classiq.interface.model.invert import BlockKind, Invert
|
|
34
34
|
from classiq.interface.model.phase_operation import PhaseOperation
|
|
35
35
|
from classiq.interface.model.power import Power
|
|
36
36
|
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
|
@@ -49,6 +49,7 @@ from classiq.interface.model.repeat import Repeat
|
|
|
49
49
|
from classiq.interface.model.skip_control import SkipControl
|
|
50
50
|
from classiq.interface.model.statement_block import StatementBlock
|
|
51
51
|
from classiq.interface.model.within_apply_operation import WithinApply
|
|
52
|
+
from classiq.interface.source_reference import SourceReference
|
|
52
53
|
|
|
53
54
|
from classiq.qmod.builtins.functions import H, S
|
|
54
55
|
from classiq.qmod.generative import is_generative_mode
|
|
@@ -552,7 +553,7 @@ def power(
|
|
|
552
553
|
|
|
553
554
|
@suppress_return_value
|
|
554
555
|
@qmod_statement
|
|
555
|
-
def invert(stmt_block: QCallable | Callable[[], Statements]) -> None:
|
|
556
|
+
def invert(stmt_block: QCallable | Callable[[], Statements]) -> Callable | None:
|
|
556
557
|
"""
|
|
557
558
|
Apply the inverse of a quantum gate.
|
|
558
559
|
|
|
@@ -574,11 +575,35 @@ def invert(stmt_block: QCallable | Callable[[], Statements]) -> None:
|
|
|
574
575
|
invert(qft(x))
|
|
575
576
|
```
|
|
576
577
|
"""
|
|
577
|
-
_validate_operand(stmt_block)
|
|
578
578
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
|
579
579
|
source_ref = get_source_ref(sys._getframe(2))
|
|
580
|
+
|
|
581
|
+
if (
|
|
582
|
+
isinstance(stmt_block, QCallable)
|
|
583
|
+
and len(stmt_block.func_decl.positional_arg_declarations) > 0
|
|
584
|
+
):
|
|
585
|
+
return lambda *args, **kwargs: _invert(
|
|
586
|
+
lambda: stmt_block( # type:ignore[call-arg]
|
|
587
|
+
*args, **kwargs, _source_ref=source_ref
|
|
588
|
+
),
|
|
589
|
+
source_ref,
|
|
590
|
+
BlockKind.SingleCall,
|
|
591
|
+
)
|
|
592
|
+
_invert(stmt_block, source_ref, BlockKind.Compound)
|
|
593
|
+
return None
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
def _invert(
|
|
597
|
+
stmt_block: Callable[[], Statements],
|
|
598
|
+
source_ref: SourceReference,
|
|
599
|
+
block_kind: BlockKind,
|
|
600
|
+
) -> None:
|
|
601
|
+
assert QCallable.CURRENT_EXPANDABLE is not None
|
|
602
|
+
_validate_operand(stmt_block)
|
|
580
603
|
invert_stmt = Invert(
|
|
581
|
-
body=_operand_to_body(stmt_block, "stmt_block"),
|
|
604
|
+
body=_operand_to_body(stmt_block, "stmt_block"),
|
|
605
|
+
block_kind=block_kind,
|
|
606
|
+
source_ref=source_ref,
|
|
582
607
|
)
|
|
583
608
|
if is_generative_mode():
|
|
584
609
|
invert_stmt.set_generative_block("body", stmt_block)
|
|
@@ -42,7 +42,7 @@ from classiq.interface.model.handle_binding import (
|
|
|
42
42
|
SubscriptHandleBinding,
|
|
43
43
|
)
|
|
44
44
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
|
45
|
-
from classiq.interface.model.invert import Invert
|
|
45
|
+
from classiq.interface.model.invert import BlockKind, Invert
|
|
46
46
|
from classiq.interface.model.model import Model
|
|
47
47
|
from classiq.interface.model.model_visitor import ModelVisitor
|
|
48
48
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
|
@@ -367,9 +367,20 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
|
367
367
|
return power_code
|
|
368
368
|
|
|
369
369
|
def visit_Invert(self, invert: Invert) -> str:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
370
|
+
match invert.block_kind:
|
|
371
|
+
case BlockKind.SingleCall:
|
|
372
|
+
if len(invert.body) != 1 or not isinstance(
|
|
373
|
+
invert.body[0], QuantumFunctionCall
|
|
374
|
+
):
|
|
375
|
+
raise ClassiqInternalError("Malformed single-call invert")
|
|
376
|
+
invert_code = f"{self._indent}invert "
|
|
377
|
+
invert_code += self.visit(invert.body[0]).lstrip()
|
|
378
|
+
case BlockKind.Compound:
|
|
379
|
+
invert_code = f"{self._indent}invert {{\n"
|
|
380
|
+
invert_code += self._visit_body(invert.body)
|
|
381
|
+
invert_code += f"{self._indent}}}\n"
|
|
382
|
+
case _:
|
|
383
|
+
raise ClassiqInternalError("Unknown block type")
|
|
373
384
|
return invert_code
|
|
374
385
|
|
|
375
386
|
def visit_Block(self, block: Block) -> str:
|
|
@@ -45,7 +45,7 @@ from classiq.interface.model.handle_binding import (
|
|
|
45
45
|
SubscriptHandleBinding,
|
|
46
46
|
)
|
|
47
47
|
from classiq.interface.model.inplace_binary_operation import InplaceBinaryOperation
|
|
48
|
-
from classiq.interface.model.invert import Invert
|
|
48
|
+
from classiq.interface.model.invert import BlockKind, Invert
|
|
49
49
|
from classiq.interface.model.model import Model
|
|
50
50
|
from classiq.interface.model.model_visitor import ModelVisitor
|
|
51
51
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
|
@@ -509,7 +509,19 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
|
509
509
|
|
|
510
510
|
def visit_Invert(self, invert: Invert) -> str:
|
|
511
511
|
self._imports["invert"] = 1
|
|
512
|
-
|
|
512
|
+
match invert.block_kind:
|
|
513
|
+
case BlockKind.SingleCall:
|
|
514
|
+
if len(invert.body) != 1 or not isinstance(
|
|
515
|
+
invert.body[0], QuantumFunctionCall
|
|
516
|
+
):
|
|
517
|
+
raise ClassiqInternalError("Malformed single-call invert")
|
|
518
|
+
call_str = self.visit(invert.body[0])
|
|
519
|
+
call_str = call_str.replace("(", ")(", 1)
|
|
520
|
+
return f"{self._indent}invert({call_str}\n"
|
|
521
|
+
case BlockKind.Compound:
|
|
522
|
+
return f"{self._indent}invert({self._visit_body(invert.body)})\n"
|
|
523
|
+
case _:
|
|
524
|
+
raise ClassiqInternalError("Unknown block type")
|
|
513
525
|
|
|
514
526
|
def visit_Block(self, block: Block) -> str:
|
|
515
527
|
self._imports["block"] = 1
|
classiq/qmod/qmod_variable.py
CHANGED
|
@@ -274,7 +274,7 @@ class QScalar(QVar, SymbolicExpr):
|
|
|
274
274
|
|
|
275
275
|
def __iand__(self, other: Any) -> NoReturn:
|
|
276
276
|
raise ClassiqNotImplementedError(
|
|
277
|
-
f"{self.get_qmod_type().raw_qmod_type_name} does not support '
|
|
277
|
+
f"{self.get_qmod_type().raw_qmod_type_name} does not support '&='"
|
|
278
278
|
)
|
|
279
279
|
|
|
280
280
|
def __ifloordiv__(self, other: Any) -> NoReturn:
|
classiq/qmod/quantum_callable.py
CHANGED
|
@@ -46,9 +46,15 @@ class QCallable(Generic[P], ABC):
|
|
|
46
46
|
FRAME_DEPTH = 1
|
|
47
47
|
|
|
48
48
|
@suppress_return_value
|
|
49
|
-
def __call__(
|
|
49
|
+
def __call__(
|
|
50
|
+
self, *args: Any, _source_ref: SourceReference | None = None, **kwargs: Any
|
|
51
|
+
) -> None:
|
|
50
52
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
|
51
|
-
source_ref =
|
|
53
|
+
source_ref = (
|
|
54
|
+
get_source_ref(sys._getframe(self.FRAME_DEPTH))
|
|
55
|
+
if _source_ref is None
|
|
56
|
+
else _source_ref
|
|
57
|
+
)
|
|
52
58
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
|
53
59
|
self.create_quantum_function_call(source_ref, *args, **kwargs)
|
|
54
60
|
)
|
|
@@ -388,7 +388,9 @@ def prepare_arg(
|
|
|
388
388
|
qlambda.set_py_callable(val._py_callable)
|
|
389
389
|
return qlambda
|
|
390
390
|
|
|
391
|
-
if isinstance(val, QExpandable)
|
|
391
|
+
if isinstance(val, QExpandable) and (
|
|
392
|
+
get_global_declarative_switch() or not is_generative_mode()
|
|
393
|
+
):
|
|
392
394
|
val.expand()
|
|
393
395
|
elif isinstance(val, QTerminalCallable):
|
|
394
396
|
return val.get_arg()
|
classiq/qmod/quantum_function.py
CHANGED
|
@@ -162,7 +162,8 @@ class QFunc(BaseQFunc):
|
|
|
162
162
|
not get_global_declarative_switch()
|
|
163
163
|
and len(self._qmodule.generative_functions) > 0
|
|
164
164
|
):
|
|
165
|
-
|
|
165
|
+
model = self._create_generative_model(model)
|
|
166
|
+
model.compress_debug_info()
|
|
166
167
|
return model
|
|
167
168
|
|
|
168
169
|
def _create_generative_model(self, model_stub: Model) -> Model:
|
|
@@ -20,6 +20,7 @@ class ErrorManager:
|
|
|
20
20
|
self._current_refs_stack: list[SourceReference | None] = []
|
|
21
21
|
self._call_stack: list[str] = []
|
|
22
22
|
self._ignore_errors: bool = False
|
|
23
|
+
self._treat_warnings_as_errors: bool = False
|
|
23
24
|
|
|
24
25
|
@property
|
|
25
26
|
def _current_source_ref(self) -> SourceReference | None:
|
|
@@ -36,6 +37,15 @@ class ErrorManager:
|
|
|
36
37
|
finally:
|
|
37
38
|
self._ignore_errors = previous
|
|
38
39
|
|
|
40
|
+
@contextmanager
|
|
41
|
+
def treat_warnings_as_errors_context(self, value: bool) -> Iterator[None]:
|
|
42
|
+
previous = self._treat_warnings_as_errors
|
|
43
|
+
self._treat_warnings_as_errors = value
|
|
44
|
+
try:
|
|
45
|
+
yield
|
|
46
|
+
finally:
|
|
47
|
+
self._treat_warnings_as_errors = previous
|
|
48
|
+
|
|
39
49
|
@property
|
|
40
50
|
def annotated_errors(self) -> list[str]:
|
|
41
51
|
return [str(error) for error in self._errors]
|
|
@@ -62,7 +72,7 @@ class ErrorManager:
|
|
|
62
72
|
),
|
|
63
73
|
function=(function if function is not None else self.current_function),
|
|
64
74
|
)
|
|
65
|
-
if warning:
|
|
75
|
+
if warning and not self._treat_warnings_as_errors:
|
|
66
76
|
self._warnings.append(source_ref_error)
|
|
67
77
|
else:
|
|
68
78
|
self._errors.append(source_ref_error)
|
classiq/qmod/utilities.py
CHANGED
|
@@ -11,6 +11,7 @@ from typing import (
|
|
|
11
11
|
Any,
|
|
12
12
|
ForwardRef,
|
|
13
13
|
Literal,
|
|
14
|
+
TypeVar,
|
|
14
15
|
Union,
|
|
15
16
|
get_args,
|
|
16
17
|
get_origin,
|
|
@@ -156,18 +157,20 @@ def varname(depth: int) -> str | None:
|
|
|
156
157
|
return var_name
|
|
157
158
|
|
|
158
159
|
|
|
160
|
+
ReturnType = TypeVar("ReturnType")
|
|
159
161
|
Params = ParamSpec("Params")
|
|
160
162
|
|
|
161
163
|
|
|
162
|
-
def suppress_return_value(
|
|
164
|
+
def suppress_return_value(
|
|
165
|
+
func: Callable[Params, ReturnType],
|
|
166
|
+
) -> Callable[Params, ReturnType]:
|
|
163
167
|
# An empty decorator suppresses mypy's func-returns-value error when assigning the
|
|
164
168
|
# return value of a None-returning function
|
|
165
169
|
return func
|
|
166
170
|
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
]
|
|
172
|
+
Statement = Union[None, Callable, "QVar", "CParam"]
|
|
173
|
+
Statements = Union[Statement, list[Statement], tuple[Statement, ...]]
|
|
171
174
|
|
|
172
175
|
|
|
173
176
|
def _eval_qnum(val: int, size: int, is_signed: bool, fraction_digits: int) -> float:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from classiq.interface.generator.generation_request import (
|
|
2
|
+
SynthesisActionDetails,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
from .actions import (
|
|
6
|
+
SynthesisActionFilters,
|
|
7
|
+
get_synthesis_actions,
|
|
8
|
+
get_synthesis_actions_async,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"SynthesisActionDetails",
|
|
13
|
+
"SynthesisActionFilters",
|
|
14
|
+
"get_synthesis_actions",
|
|
15
|
+
"get_synthesis_actions_async",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def __dir__() -> list[str]:
|
|
20
|
+
return __all__
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from dataclasses import asdict, dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from classiq.interface.jobs import JobStatus
|
|
6
|
+
|
|
7
|
+
from classiq._internals.api_wrapper import ApiWrapper
|
|
8
|
+
from classiq._internals.async_utils import syncify_function
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class SynthesisActionFilters:
|
|
16
|
+
"""
|
|
17
|
+
Filter parameters for querying synthesis actions.
|
|
18
|
+
|
|
19
|
+
All filters are combined using AND logic: only actions matching all specified filters are returned.
|
|
20
|
+
Range filters (with _min/_max suffixes) are inclusive.
|
|
21
|
+
Datetime filters are compared against the job's timestamps.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
status: JobStatus | None = None
|
|
25
|
+
target_backend: str | None = None
|
|
26
|
+
optimization_level: str | None = None
|
|
27
|
+
program_id: str | None = None
|
|
28
|
+
backend_name: str | None = None
|
|
29
|
+
optimization_parameter: str | None = None
|
|
30
|
+
random_seed: int | None = None
|
|
31
|
+
max_width: int | None = None
|
|
32
|
+
max_gate_count: int | None = None
|
|
33
|
+
total_cost_min: float | None = None
|
|
34
|
+
total_cost_max: float | None = None
|
|
35
|
+
start_time_min: datetime | None = None
|
|
36
|
+
start_time_max: datetime | None = None
|
|
37
|
+
end_time_min: datetime | None = None
|
|
38
|
+
end_time_max: datetime | None = None
|
|
39
|
+
|
|
40
|
+
def format_filters(self) -> dict[str, Any]:
|
|
41
|
+
"""Convert filter fields to API kwargs, excluding None values and converting datetimes."""
|
|
42
|
+
filter_dict = asdict(self)
|
|
43
|
+
return {
|
|
44
|
+
k: (v.isoformat() if isinstance(v, datetime) else v)
|
|
45
|
+
for k, v in filter_dict.items()
|
|
46
|
+
if v is not None
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def get_synthesis_actions_async(
|
|
51
|
+
offset: int = 0,
|
|
52
|
+
limit: int = 50,
|
|
53
|
+
filters: SynthesisActionFilters | None = None,
|
|
54
|
+
) -> "pd.DataFrame":
|
|
55
|
+
"""Query synthesis actions with optional filters.
|
|
56
|
+
Args:
|
|
57
|
+
offset: Number of results to skip (default: 0)
|
|
58
|
+
limit: Maximum number of results to return (default: 50)
|
|
59
|
+
filters: Optional SynthesisActionFilters object containing filter parameters.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
A pandas DataFrame containing synthesis actions matching the filters.
|
|
63
|
+
Each row represents a synthesis action with columns for all fields
|
|
64
|
+
from SynthesisActionDetails (id, name, start_time, end_time, status, etc.).
|
|
65
|
+
"""
|
|
66
|
+
import pandas as pd
|
|
67
|
+
|
|
68
|
+
api_kwargs = filters.format_filters() if filters is not None else {}
|
|
69
|
+
|
|
70
|
+
result = await ApiWrapper().call_query_synthesis_actions(
|
|
71
|
+
offset, limit, http_client=None, **api_kwargs
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if not result.results:
|
|
75
|
+
return pd.DataFrame()
|
|
76
|
+
|
|
77
|
+
return pd.DataFrame(action.model_dump() for action in result.results)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_synthesis_actions(
|
|
81
|
+
offset: int = 0,
|
|
82
|
+
limit: int = 50,
|
|
83
|
+
filters: SynthesisActionFilters | None = None,
|
|
84
|
+
) -> "pd.DataFrame":
|
|
85
|
+
"""Query synthesis actions with optional filters.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
offset: Number of results to skip (default: 0)
|
|
89
|
+
limit: Maximum number of results to return (default: 50)
|
|
90
|
+
filters: Optional SynthesisActionFilters object containing filter parameters.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
A pandas DataFrame containing synthesis actions matching the filters.
|
|
94
|
+
Each row represents a synthesis action with columns for all fields
|
|
95
|
+
from SynthesisActionDetails (id, name, start_time, end_time, status, etc.).
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
# Query all actions:
|
|
99
|
+
df = get_synthesis_actions(limit=10)
|
|
100
|
+
|
|
101
|
+
# Query with filters:
|
|
102
|
+
filters = SynthesisActionFilters(status="COMPLETED", target_backend="ibm")
|
|
103
|
+
df = get_synthesis_actions(filters=filters, limit=10)
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
return syncify_function(get_synthesis_actions_async)(offset, limit, filters)
|