classiq 0.79.1__py3-none-any.whl → 0.80.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 +7 -0
- classiq/_internals/api_wrapper.py +95 -19
- classiq/analyzer/show_interactive_hack.py +63 -48
- classiq/applications/chemistry/chemistry_model_constructor.py +1 -1
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +3 -3
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/result.py +1 -1
- classiq/interface/chemistry/operator.py +3 -8
- classiq/interface/executor/quantum_program_params.py +18 -0
- classiq/interface/generator/application_apis/chemistry_declarations.py +3 -3
- classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +3 -3
- classiq/interface/generator/application_apis/entangler_declarations.py +3 -3
- classiq/interface/generator/arith/number_utils.py +8 -0
- classiq/interface/generator/expressions/proxies/classical/utils.py +8 -3
- classiq/interface/generator/functions/classical_type.py +63 -7
- classiq/interface/generator/generated_circuit_data.py +10 -1
- classiq/interface/helpers/custom_pydantic_types.py +2 -3
- classiq/interface/model/allocate.py +6 -0
- classiq/interface/model/quantum_type.py +26 -5
- classiq/interface/server/routes.py +6 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +9 -1
- classiq/model_expansions/capturing/captured_vars.py +1 -1
- classiq/model_expansions/evaluators/classical_type_inference.py +39 -27
- classiq/model_expansions/evaluators/parameter_types.py +65 -3
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +1 -1
- classiq/model_expansions/quantum_operations/allocate.py +121 -34
- classiq/model_expansions/quantum_operations/call_emitter.py +1 -1
- classiq/model_expansions/scope.py +1 -2
- classiq/open_library/functions/__init__.py +2 -0
- classiq/open_library/functions/state_preparation.py +90 -3
- classiq/qmod/builtins/classical_execution_primitives.py +2 -4
- classiq/qmod/builtins/functions/__init__.py +3 -0
- classiq/qmod/builtins/functions/arithmetic.py +21 -1
- classiq/qmod/builtins/functions/exponentiation.py +24 -0
- classiq/qmod/builtins/operations.py +32 -2
- classiq/qmod/builtins/structs.py +47 -1
- classiq/qmod/native/pretty_printer.py +15 -6
- classiq/qmod/pretty_print/pretty_printer.py +15 -6
- classiq/qmod/python_classical_type.py +4 -4
- classiq/qmod/qmod_parameter.py +5 -1
- classiq/qmod/semantics/validation/main_validation.py +5 -0
- classiq/quantum_program.py +69 -0
- {classiq-0.79.1.dist-info → classiq-0.80.0.dist-info}/METADATA +1 -1
- {classiq-0.79.1.dist-info → classiq-0.80.0.dist-info}/RECORD +46 -44
- {classiq-0.79.1.dist-info → classiq-0.80.0.dist-info}/WHEEL +1 -1
- /classiq/{model_expansions/utils → interface/helpers}/text_utils.py +0 -0
@@ -30,6 +30,7 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
30
30
|
)
|
31
31
|
from classiq.interface.generator.functions.type_qualifier import TypeQualifier
|
32
32
|
from classiq.interface.helpers.backward_compatibility import zip_strict
|
33
|
+
from classiq.interface.helpers.text_utils import are, readable_list, s
|
33
34
|
from classiq.interface.model.classical_parameter_declaration import (
|
34
35
|
ClassicalParameterDeclaration,
|
35
36
|
)
|
@@ -82,7 +83,6 @@ from classiq.model_expansions.transformers.type_qualifier_inference import (
|
|
82
83
|
TypeQualifierInference,
|
83
84
|
)
|
84
85
|
from classiq.model_expansions.transformers.var_splitter import VarSplitter
|
85
|
-
from classiq.model_expansions.utils.text_utils import are, readable_list, s
|
86
86
|
from classiq.qmod.pretty_print.expression_to_python import transform_expression
|
87
87
|
from classiq.qmod.semantics.validation.signature_validation import (
|
88
88
|
validate_function_signature,
|
@@ -22,6 +22,7 @@ from classiq.interface.generator.expressions.proxies.classical.qmod_struct_insta
|
|
22
22
|
QmodStructInstance,
|
23
23
|
)
|
24
24
|
from classiq.interface.generator.functions.type_name import TypeName
|
25
|
+
from classiq.interface.helpers.text_utils import readable_list, s
|
25
26
|
from classiq.interface.model.handle_binding import (
|
26
27
|
FieldHandleBinding,
|
27
28
|
GeneralHandle,
|
@@ -41,8 +42,6 @@ from classiq.interface.model.quantum_type import (
|
|
41
42
|
QuantumType,
|
42
43
|
)
|
43
44
|
|
44
|
-
from classiq.model_expansions.utils.text_utils import readable_list, s
|
45
|
-
|
46
45
|
if TYPE_CHECKING:
|
47
46
|
from classiq.model_expansions.closure import FunctionClosure
|
48
47
|
|
@@ -6,7 +6,10 @@ import sympy
|
|
6
6
|
|
7
7
|
from classiq.interface.exceptions import ClassiqDeprecationWarning
|
8
8
|
|
9
|
-
from classiq.open_library.functions.utility_functions import
|
9
|
+
from classiq.open_library.functions.utility_functions import (
|
10
|
+
apply_to_all,
|
11
|
+
hadamard_transform,
|
12
|
+
)
|
10
13
|
from classiq.qmod.builtins.functions import (
|
11
14
|
CX,
|
12
15
|
IDENTITY,
|
@@ -16,11 +19,19 @@ from classiq.qmod.builtins.functions import (
|
|
16
19
|
X,
|
17
20
|
inplace_prepare_amplitudes,
|
18
21
|
)
|
19
|
-
from classiq.qmod.builtins.operations import
|
22
|
+
from classiq.qmod.builtins.operations import (
|
23
|
+
allocate,
|
24
|
+
control,
|
25
|
+
if_,
|
26
|
+
inplace_add,
|
27
|
+
repeat,
|
28
|
+
within_apply,
|
29
|
+
)
|
20
30
|
from classiq.qmod.cparam import CArray, CBool, CInt, CReal
|
21
31
|
from classiq.qmod.qfunc import qfunc
|
22
32
|
from classiq.qmod.qmod_variable import Output, QArray, QBit, QNum
|
23
33
|
from classiq.qmod.symbolic import (
|
34
|
+
acos,
|
24
35
|
asin,
|
25
36
|
atan,
|
26
37
|
exp,
|
@@ -375,7 +386,7 @@ def inplace_prepare_complex_amplitudes(
|
|
375
386
|
@qfunc
|
376
387
|
def prepare_complex_amplitudes(
|
377
388
|
magnitudes: CArray[CReal],
|
378
|
-
phases:
|
389
|
+
phases: list[float],
|
379
390
|
out: Output[QArray[QBit, Literal["log(get_field(magnitudes, 'len'), 2)"]]],
|
380
391
|
) -> None:
|
381
392
|
"""
|
@@ -391,3 +402,79 @@ def prepare_complex_amplitudes(
|
|
391
402
|
"""
|
392
403
|
allocate(out)
|
393
404
|
inplace_prepare_complex_amplitudes(magnitudes, phases, out)
|
405
|
+
|
406
|
+
|
407
|
+
@qfunc
|
408
|
+
def _dicke_split_cycle_shift(k: int, qvar: QArray[QBit]) -> None:
|
409
|
+
"""
|
410
|
+
internal function, assumes the input is in the form |11..100..0> with up to k ones.
|
411
|
+
transforms the state to: sqrt(1/n)*|11..100..0> + sqrt((n-1)/n)*|01..110..0>.
|
412
|
+
"""
|
413
|
+
for i in range(k):
|
414
|
+
within_apply(
|
415
|
+
lambda i=i: CX(qvar[i + 1], qvar[0]), # type: ignore[misc]
|
416
|
+
lambda i=i: ( # type: ignore[misc]
|
417
|
+
control(
|
418
|
+
qvar[0],
|
419
|
+
lambda i=i: RY(2 * acos(sqrt((i + 1) / qvar.len)), qvar[i + 1]), # type: ignore[misc]
|
420
|
+
)
|
421
|
+
if i == 0
|
422
|
+
else control(
|
423
|
+
qvar[0] & qvar[i],
|
424
|
+
lambda i=i: RY(2 * acos(sqrt((i + 1) / qvar.len)), qvar[i + 1]), # type: ignore[misc]
|
425
|
+
)
|
426
|
+
),
|
427
|
+
)
|
428
|
+
|
429
|
+
|
430
|
+
@qfunc
|
431
|
+
def prepare_dicke_state_unary_input(max_k: int, qvar: QArray[QBit]) -> None:
|
432
|
+
"""
|
433
|
+
assumes the input is encoded in qvar in unary encoding. should work for every value
|
434
|
+
smaller than max_k
|
435
|
+
"""
|
436
|
+
"""
|
437
|
+
[Qmod Classiq-library function]
|
438
|
+
|
439
|
+
Prepares a Dicke state with a variable number of excitations based on an unary-encoded input.
|
440
|
+
|
441
|
+
The Dicke state is defined to be:
|
442
|
+
$$
|
443
|
+
\\mathrm{Dicke}(n, k) = \frac{1}{\\sqrt{\binom{n}{k}}} \\sum_{x \\in \\{0,1\\}^n,\\, |x| = k} |x\rangle
|
444
|
+
$$
|
445
|
+
|
446
|
+
The input register `qvar` is expected to already be initialized in a unary encoding:
|
447
|
+
the value k is represented by a string of k ones followed by zeros, e.g., k = 3 -> |11100...0>.
|
448
|
+
The function generates a Dicke state with k excitations over a new quantum register,
|
449
|
+
where 0 <= k < max_k.
|
450
|
+
|
451
|
+
Args:
|
452
|
+
max_k: The maximum number of allowed excitations (upper bound for k).
|
453
|
+
qvar: Unary-encoded quantum input register of length >= max_k. Must be pre-initialized.
|
454
|
+
"""
|
455
|
+
if qvar.len > max(1, max_k):
|
456
|
+
_dicke_split_cycle_shift(max_k, qvar)
|
457
|
+
prepare_dicke_state_unary_input(qmin(max_k, qvar.len - 2), qvar[1 : qvar.len])
|
458
|
+
|
459
|
+
|
460
|
+
@qfunc
|
461
|
+
def prepare_dicke_state(k: int, qvar: QArray[QBit]) -> None:
|
462
|
+
"""
|
463
|
+
[Qmod Classiq-library function]
|
464
|
+
|
465
|
+
Prepares a Dicke state with k excitations over the provided quantum register.
|
466
|
+
|
467
|
+
A Dicke state of n qubits with k excitations is an equal superposition of all basis states
|
468
|
+
with exactly k qubits in the |1> state and (n - k) qubits in the |0? state.
|
469
|
+
For example, Dicke(2, 1) = (|01> + |10>) / sqrt(2). In the general case it is define to be:
|
470
|
+
$$
|
471
|
+
\\mathrm{Dicke}(n, k) = \frac{1}{\\sqrt{\binom{n}{k}}} \\sum_{x \\in \\{0,1\\}^n,\\, |x| = k} |x\rangle
|
472
|
+
$$
|
473
|
+
|
474
|
+
Args:
|
475
|
+
k: The number of excitations (i.e., number of qubits in state |1>).
|
476
|
+
qvar: The quantum register (array of qubits) to initialize. Must be uninitialized and have length >= k.
|
477
|
+
"""
|
478
|
+
if k > 0:
|
479
|
+
apply_to_all(X, qvar[0:k])
|
480
|
+
prepare_dicke_state_unary_input(k, qvar)
|
@@ -1,8 +1,9 @@
|
|
1
|
-
from typing import Final, Optional
|
1
|
+
from typing import Final, Optional
|
2
2
|
|
3
3
|
from classiq.interface.applications.iqae.iqae_result import IQAEResult
|
4
4
|
from classiq.interface.exceptions import ClassiqError
|
5
5
|
from classiq.interface.executor.execution_preferences import QaeWithQpeEstimationMethod
|
6
|
+
from classiq.interface.executor.quantum_program_params import ExecutionParams
|
6
7
|
from classiq.interface.executor.result import (
|
7
8
|
EstimationResult,
|
8
9
|
EstimationResults,
|
@@ -15,8 +16,6 @@ from classiq.interface.generator.functions.qmod_python_interface import QmodPySt
|
|
15
16
|
from classiq.applications.qsvm.qsvm import Data, Labels
|
16
17
|
from classiq.qmod.builtins.enums import Optimizer
|
17
18
|
|
18
|
-
ExecutionParams = dict[str, Union[float, int, list[int], list[float]]]
|
19
|
-
|
20
19
|
_CALL_IN_QFUNC_ERROR = (
|
21
20
|
'Cannot call "{}" in a quantum context. "{}" is a classical execution primitive.'
|
22
21
|
)
|
@@ -104,7 +103,6 @@ def molecule_ground_state_solution_post_process( # type: ignore[return]
|
|
104
103
|
|
105
104
|
|
106
105
|
__all__ = [
|
107
|
-
"ExecutionParams",
|
108
106
|
"batch_estimate",
|
109
107
|
"batch_sample",
|
110
108
|
"estimate",
|
@@ -55,6 +55,7 @@ CORE_LIB_DECLS = [
|
|
55
55
|
prepare_amplitudes_approx,
|
56
56
|
unitary,
|
57
57
|
add,
|
58
|
+
add_inplace_right,
|
58
59
|
modular_add,
|
59
60
|
integer_xor,
|
60
61
|
modular_add_constant,
|
@@ -69,6 +70,7 @@ CORE_LIB_DECLS = [
|
|
69
70
|
inplace_prepare_amplitudes_approx,
|
70
71
|
single_pauli_exponent,
|
71
72
|
commuting_paulis_exponent,
|
73
|
+
sparse_suzuki_trotter,
|
72
74
|
suzuki_trotter,
|
73
75
|
qdrift,
|
74
76
|
exponentiation_with_depth_constraint,
|
@@ -109,6 +111,7 @@ __all__ = [ # noqa: RUF022
|
|
109
111
|
"Y",
|
110
112
|
"Z",
|
111
113
|
"add",
|
114
|
+
"add_inplace_right",
|
112
115
|
"apply",
|
113
116
|
"bloch_sphere_feature_map",
|
114
117
|
"exponentiation_with_depth_constraint",
|
@@ -2,7 +2,7 @@ from typing import Literal
|
|
2
2
|
|
3
3
|
from classiq.qmod.qfunc import qfunc
|
4
4
|
from classiq.qmod.qmod_parameter import CArray, CBool, CReal
|
5
|
-
from classiq.qmod.qmod_variable import Const, Output, QArray, QBit, QFree, QNum
|
5
|
+
from classiq.qmod.qmod_variable import Const, Input, Output, QArray, QBit, QFree, QNum
|
6
6
|
|
7
7
|
|
8
8
|
@qfunc(external=True)
|
@@ -42,6 +42,26 @@ def add(
|
|
42
42
|
pass
|
43
43
|
|
44
44
|
|
45
|
+
@qfunc(external=True)
|
46
|
+
def add_inplace_right(
|
47
|
+
left: Const[QNum],
|
48
|
+
right: QFree[Input[QNum]],
|
49
|
+
result: QFree[
|
50
|
+
Output[
|
51
|
+
QNum[
|
52
|
+
Literal["result_size"],
|
53
|
+
Literal["result_is_signed"],
|
54
|
+
Literal["result_fraction_places"],
|
55
|
+
]
|
56
|
+
]
|
57
|
+
],
|
58
|
+
result_size: CReal,
|
59
|
+
result_is_signed: CBool,
|
60
|
+
result_fraction_places: CReal,
|
61
|
+
) -> None:
|
62
|
+
pass
|
63
|
+
|
64
|
+
|
45
65
|
@qfunc(external=True)
|
46
66
|
def modular_add(left: Const[QArray[QBit]], right: QFree[QArray[QBit]]) -> None:
|
47
67
|
pass
|
@@ -3,6 +3,7 @@ from typing import Literal
|
|
3
3
|
from classiq.qmod.builtins.enums import Pauli
|
4
4
|
from classiq.qmod.builtins.structs import (
|
5
5
|
PauliTerm,
|
6
|
+
SparsePauliOp,
|
6
7
|
)
|
7
8
|
from classiq.qmod.qfunc import qfunc
|
8
9
|
from classiq.qmod.qmod_parameter import CArray, CInt, CReal
|
@@ -79,6 +80,29 @@ def suzuki_trotter(
|
|
79
80
|
pass
|
80
81
|
|
81
82
|
|
83
|
+
@qfunc(external=True)
|
84
|
+
def sparse_suzuki_trotter(
|
85
|
+
pauli_operator: SparsePauliOp,
|
86
|
+
evolution_coefficient: CReal,
|
87
|
+
order: CInt,
|
88
|
+
repetitions: CInt,
|
89
|
+
qbv: QArray[QBit, Literal["get_field(pauli_operator, 'num_qubits')"]],
|
90
|
+
) -> None:
|
91
|
+
"""
|
92
|
+
Applies the Suzuki-Trotter decomposition to a sparse Pauli operator. For more details,
|
93
|
+
See about Suzuki-Trotter decomposition in `suzuki_trotter` `qfunc`.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
pauli_operator: The Pauli operator to be exponentiated, in sparse representation (See: SparsePauliOp).
|
97
|
+
evolution_coefficient: A global evolution coefficient multiplying the Pauli operator.
|
98
|
+
order: The order of the Suzuki-Trotter decomposition.
|
99
|
+
repetitions: The number of repetitions of the Suzuki-Trotter decomposition.
|
100
|
+
qbv: The target quantum variable of the exponentiation.
|
101
|
+
"""
|
102
|
+
|
103
|
+
pass
|
104
|
+
|
105
|
+
|
82
106
|
@qfunc(external=True)
|
83
107
|
def qdrift(
|
84
108
|
pauli_operator: CArray[PauliTerm],
|
@@ -63,6 +63,16 @@ def allocate(out: Output[QVar]) -> None:
|
|
63
63
|
pass
|
64
64
|
|
65
65
|
|
66
|
+
@overload
|
67
|
+
def allocate(
|
68
|
+
num_qubits: Union[int, SymbolicExpr],
|
69
|
+
is_signed: Union[bool, SymbolicExpr],
|
70
|
+
fraction_digits: Union[int, SymbolicExpr],
|
71
|
+
out: Output[QVar],
|
72
|
+
) -> None:
|
73
|
+
pass
|
74
|
+
|
75
|
+
|
66
76
|
@suppress_return_value
|
67
77
|
def allocate(*args: Any, **kwargs: Any) -> None:
|
68
78
|
"""
|
@@ -73,34 +83,54 @@ def allocate(*args: Any, **kwargs: Any) -> None:
|
|
73
83
|
$$
|
74
84
|
|
75
85
|
If 'num_qubits' is not specified, it will be inferred according to the type of 'out'.
|
86
|
+
In case the quantum variable is of type `QNum`, its numeric attributes can be specified as
|
87
|
+
well.
|
76
88
|
|
77
89
|
Args:
|
78
90
|
num_qubits: The number of qubits to allocate (positive integer, optional).
|
79
91
|
out: The quantum variable that will receive the allocated qubits. Must be uninitialized before allocation.
|
92
|
+
is_signed: The sign of the allocated variable, valid only for `QNum` (boolean, optional).
|
93
|
+
fraction_digits: The number of fraction digits in the allocated variable, valid only for `QNum` (positive integer, optional).
|
80
94
|
|
81
95
|
Notes:
|
82
|
-
1. If the output variable has been declared with a specific number of qubits, the
|
96
|
+
1. If the output variable has been declared with a specific number of qubits or numeric attributes, the passed values must match the declared values.
|
83
97
|
2. The synthesis engine automatically handles the allocation, either by drawing new qubits from the available pool or by reusing existing ones.
|
84
98
|
"""
|
85
99
|
assert QCallable.CURRENT_EXPANDABLE is not None
|
86
100
|
source_ref = get_source_ref(sys._getframe(1))
|
87
101
|
if len(args) == 0:
|
88
102
|
size = kwargs.get("num_qubits", None)
|
103
|
+
is_signed = kwargs.get("is_signed", None)
|
104
|
+
fraction_digits = kwargs.get("fraction_digits", None)
|
89
105
|
target = kwargs["out"]
|
90
106
|
elif len(args) == 1:
|
91
107
|
if "out" in kwargs:
|
92
108
|
size = args[0]
|
109
|
+
is_signed = kwargs.get("is_signed", None)
|
110
|
+
fraction_digits = kwargs.get("fraction_digits", None)
|
93
111
|
target = kwargs["out"]
|
94
112
|
else:
|
95
113
|
size = None
|
114
|
+
is_signed = None
|
115
|
+
fraction_digits = None
|
96
116
|
target = args[0]
|
97
|
-
|
117
|
+
elif len(args) == 2:
|
98
118
|
size, target = args
|
119
|
+
is_signed = kwargs.get("is_signed", None)
|
120
|
+
fraction_digits = kwargs.get("fraction_digits", None)
|
121
|
+
else:
|
122
|
+
size, is_signed, fraction_digits, target = args
|
99
123
|
if isinstance(size, QConstant):
|
100
124
|
size.add_to_model()
|
101
125
|
QCallable.CURRENT_EXPANDABLE.append_statement_to_body(
|
102
126
|
Allocate(
|
103
127
|
size=None if size is None else Expression(expr=str(size)),
|
128
|
+
is_signed=None if is_signed is None else Expression(expr=str(is_signed)),
|
129
|
+
fraction_digits=(
|
130
|
+
None
|
131
|
+
if fraction_digits is None
|
132
|
+
else Expression(expr=str(fraction_digits))
|
133
|
+
),
|
104
134
|
target=target.get_handle_binding(),
|
105
135
|
source_ref=source_ref,
|
106
136
|
)
|
classiq/qmod/builtins/structs.py
CHANGED
@@ -10,7 +10,7 @@ from classiq.qmod.python_classical_type import PythonClassicalType
|
|
10
10
|
@dataclass
|
11
11
|
class PauliTerm:
|
12
12
|
"""
|
13
|
-
A term in a Hamiltonian, represented as a product of Pauli
|
13
|
+
A term in a Hamiltonian, represented as a product of single-qubit Pauli matrices.
|
14
14
|
|
15
15
|
Attributes:
|
16
16
|
pauli (CArray[Pauli]): The list of the chosen Pauli operators in the term, corresponds to a product of them.
|
@@ -21,6 +21,49 @@ class PauliTerm:
|
|
21
21
|
coefficient: CReal
|
22
22
|
|
23
23
|
|
24
|
+
@dataclass
|
25
|
+
class IndexedPauli:
|
26
|
+
"""
|
27
|
+
A single-qubit Pauli matrix on a specific qubit given by its index.
|
28
|
+
|
29
|
+
Attributes:
|
30
|
+
pauli (Pauli): The Pauli operator.
|
31
|
+
index (CInt): The index of the qubit being operated on.
|
32
|
+
"""
|
33
|
+
|
34
|
+
pauli: Pauli
|
35
|
+
index: CInt
|
36
|
+
|
37
|
+
|
38
|
+
@dataclass
|
39
|
+
class SparsePauliTerm:
|
40
|
+
"""
|
41
|
+
A term in the Hamiltonian, represented as a sparse product of single-qubit Pauli
|
42
|
+
matrices.
|
43
|
+
|
44
|
+
Attributes:
|
45
|
+
paulis (CArray[IndexedPauli]): The list of chosen sparse Pauli operators in the term corresponds to a product of them. (See IndexedPauli)
|
46
|
+
coefficient (CReal): The coefficient of the term (floating number).
|
47
|
+
"""
|
48
|
+
|
49
|
+
paulis: CArray[IndexedPauli]
|
50
|
+
coefficient: CReal
|
51
|
+
|
52
|
+
|
53
|
+
@dataclass
|
54
|
+
class SparsePauliOp:
|
55
|
+
"""
|
56
|
+
Represents a collection of sparse Pauli operators.
|
57
|
+
|
58
|
+
Attributes:
|
59
|
+
paulis (CArray[SparsePauliTerm]): The list of chosen sparse Pauli operators in the term, corresponds to a product of them. (See: SparsePauliTerm)
|
60
|
+
num_qubits (CInt): The number of qubits in the Hamiltonian.
|
61
|
+
"""
|
62
|
+
|
63
|
+
paulis: CArray[SparsePauliTerm]
|
64
|
+
num_qubits: CInt
|
65
|
+
|
66
|
+
|
24
67
|
@dataclass
|
25
68
|
class Position:
|
26
69
|
x: CReal
|
@@ -139,6 +182,7 @@ __all__ = [
|
|
139
182
|
"FinanceFunction",
|
140
183
|
"FockHamiltonianProblem",
|
141
184
|
"GaussianModel",
|
185
|
+
"IndexedPauli",
|
142
186
|
"LadderOp",
|
143
187
|
"LadderTerm",
|
144
188
|
"LogNormalModel",
|
@@ -148,4 +192,6 @@ __all__ = [
|
|
148
192
|
"Position",
|
149
193
|
"QSVMFeatureMapPauli",
|
150
194
|
"QsvmResult",
|
195
|
+
"SparsePauliOp",
|
196
|
+
"SparsePauliTerm",
|
151
197
|
]
|
@@ -250,7 +250,10 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
250
250
|
return f"{self.visit(ctlist.element_type)}[]"
|
251
251
|
|
252
252
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
253
|
-
|
253
|
+
element_type = self.visit(ctarray.element_type)
|
254
|
+
if ctarray.length is not None:
|
255
|
+
return f"{element_type}[{self.visit(ctarray.length)}]"
|
256
|
+
return f"{element_type}[]"
|
254
257
|
|
255
258
|
def visit_ClassicalTuple(self, classical_tuple: ClassicalTuple) -> str:
|
256
259
|
raw_type = classical_tuple.get_raw_type()
|
@@ -288,11 +291,17 @@ class DSLPrettyPrinter(ModelVisitor):
|
|
288
291
|
return f"{self.visit_QuantumFunctionDeclaration(func_def)} {{\n{body}}}\n"
|
289
292
|
|
290
293
|
def visit_Allocate(self, allocate: Allocate) -> str:
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
294
|
+
params = ", ".join(
|
295
|
+
self.visit(param)
|
296
|
+
for param in [
|
297
|
+
allocate.size,
|
298
|
+
allocate.is_signed,
|
299
|
+
allocate.fraction_digits,
|
300
|
+
allocate.target,
|
301
|
+
]
|
302
|
+
if param is not None
|
303
|
+
)
|
304
|
+
return f"{self._indent}allocate({params});\n"
|
296
305
|
|
297
306
|
def visit_QuantumFunctionCall(self, func_call: QuantumFunctionCall) -> str:
|
298
307
|
positional_args = ", ".join(
|
@@ -344,7 +344,10 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
344
344
|
|
345
345
|
def visit_ClassicalArray(self, ctarray: ClassicalArray) -> str:
|
346
346
|
self._imports["CArray"] = 1
|
347
|
-
|
347
|
+
element_type = self.visit(ctarray.element_type)
|
348
|
+
if ctarray.length is not None:
|
349
|
+
return f"CArray[{element_type}, {_add_quotes(self.visit(ctarray.length))}]"
|
350
|
+
return f"CArray[{element_type}]"
|
348
351
|
|
349
352
|
def visit_ClassicalTuple(self, classical_tuple: ClassicalTuple) -> str:
|
350
353
|
raw_type = classical_tuple.get_raw_type()
|
@@ -434,11 +437,17 @@ class PythonPrettyPrinter(ModelVisitor):
|
|
434
437
|
|
435
438
|
def visit_Allocate(self, allocate: Allocate) -> str:
|
436
439
|
self._imports["allocate"] = 1
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
440
|
+
params = ", ".join(
|
441
|
+
self.visit(param)
|
442
|
+
for param in [
|
443
|
+
allocate.size,
|
444
|
+
allocate.is_signed,
|
445
|
+
allocate.fraction_digits,
|
446
|
+
allocate.target,
|
447
|
+
]
|
448
|
+
if param is not None
|
449
|
+
)
|
450
|
+
return f"{self._indent}allocate({params})\n"
|
442
451
|
|
443
452
|
def visit_Control(self, op: Control) -> str:
|
444
453
|
self._imports["control"] = 1
|
@@ -11,10 +11,10 @@ from typing import (
|
|
11
11
|
)
|
12
12
|
|
13
13
|
from classiq.interface.exceptions import ClassiqValueError
|
14
|
+
from classiq.interface.generator.expressions.expression import Expression
|
14
15
|
from classiq.interface.generator.functions.classical_type import (
|
15
16
|
Bool,
|
16
17
|
ClassicalArray,
|
17
|
-
ClassicalList,
|
18
18
|
Integer,
|
19
19
|
Real,
|
20
20
|
)
|
@@ -47,15 +47,15 @@ class PythonClassicalType:
|
|
47
47
|
elif get_origin(py_type) is list:
|
48
48
|
element_type = self.convert(get_args(py_type)[0])
|
49
49
|
if element_type is not None:
|
50
|
-
return
|
50
|
+
return ClassicalArray(element_type=element_type).set_generative()
|
51
51
|
elif get_origin(py_type) is CArray:
|
52
52
|
array_args = version_portable_get_args(py_type)
|
53
53
|
if len(array_args) == 1:
|
54
|
-
return
|
54
|
+
return ClassicalArray(element_type=self.convert(array_args[0]))
|
55
55
|
elif len(array_args) == 2:
|
56
56
|
return ClassicalArray(
|
57
57
|
element_type=self.convert(array_args[0]),
|
58
|
-
|
58
|
+
length=Expression(expr=get_type_hint_expr(array_args[1])),
|
59
59
|
)
|
60
60
|
raise ClassiqValueError(CARRAY_ERROR_MESSAGE)
|
61
61
|
elif inspect.isclass(py_type) and dataclasses.is_dataclass(py_type):
|
classiq/qmod/qmod_parameter.py
CHANGED
@@ -167,7 +167,11 @@ def get_qmod_type(ctype: ClassicalType) -> type:
|
|
167
167
|
elif isinstance(ctype, ClassicalList):
|
168
168
|
return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
|
169
169
|
elif isinstance(ctype, ClassicalArray):
|
170
|
-
|
170
|
+
if ctype.length is None:
|
171
|
+
return CArray[get_qmod_type(ctype.element_type)] # type: ignore[misc]
|
172
|
+
if ctype.has_length and isinstance(ctype.length.value.value, int):
|
173
|
+
return CArray[get_qmod_type(ctype.element_type), ctype.length.value.value] # type: ignore[misc]
|
174
|
+
return CArray[get_qmod_type(ctype.element_type), ctype.length.expr] # type: ignore[misc]
|
171
175
|
elif isinstance(ctype, ClassicalTuple):
|
172
176
|
raw_type = ctype.get_raw_type()
|
173
177
|
if isinstance(raw_type, ClassicalTuple):
|
@@ -37,6 +37,11 @@ def _validate_main_classical_param_type(
|
|
37
37
|
f"specify array length",
|
38
38
|
)
|
39
39
|
if isinstance(param, ClassicalArray):
|
40
|
+
if param.length is None:
|
41
|
+
raise ClassiqExpansionError(
|
42
|
+
f"Classical array parameter {param_name!r} of function 'main' must "
|
43
|
+
f"specify array length",
|
44
|
+
)
|
40
45
|
_validate_main_classical_param_type(param.element_type, param_name)
|
41
46
|
|
42
47
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from classiq.interface.executor.quantum_program_params import (
|
4
|
+
ParameterAssignmentsParams,
|
5
|
+
TranspilationParams,
|
6
|
+
)
|
7
|
+
from classiq.interface.generator.model.preferences.preferences import Preferences
|
8
|
+
from classiq.interface.generator.quantum_program import (
|
9
|
+
QuantumProgram,
|
10
|
+
)
|
11
|
+
|
12
|
+
from classiq._internals import async_utils
|
13
|
+
from classiq._internals.api_wrapper import ApiWrapper
|
14
|
+
from classiq.qmod.builtins.classical_execution_primitives import ExecutionParams
|
15
|
+
|
16
|
+
|
17
|
+
async def transpile_async(params: TranspilationParams) -> QuantumProgram:
|
18
|
+
return await ApiWrapper.call_transpilation_task(params)
|
19
|
+
|
20
|
+
|
21
|
+
def transpile(
|
22
|
+
quantum_program: QuantumProgram, preferences: Optional[Preferences] = None
|
23
|
+
) -> QuantumProgram:
|
24
|
+
"""
|
25
|
+
Transpiles a quantum program.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
quantum_program: The quantum program to transpile. This is the result of the synthesize method.
|
29
|
+
preferences: The transpilation preferences.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
QuantumProgram: The result of the transpilation (Optional).
|
33
|
+
"""
|
34
|
+
if preferences is None:
|
35
|
+
preferences = Preferences()
|
36
|
+
return async_utils.run(
|
37
|
+
transpile_async(
|
38
|
+
TranspilationParams(
|
39
|
+
quantum_program=quantum_program, preferences=preferences
|
40
|
+
)
|
41
|
+
)
|
42
|
+
)
|
43
|
+
|
44
|
+
|
45
|
+
async def assign_parameters_async(params: ParameterAssignmentsParams) -> QuantumProgram:
|
46
|
+
return await ApiWrapper.call_assign_parameters_task(params)
|
47
|
+
|
48
|
+
|
49
|
+
def assign_parameters(
|
50
|
+
quantum_program: QuantumProgram, parameters: ExecutionParams
|
51
|
+
) -> QuantumProgram:
|
52
|
+
"""
|
53
|
+
Assign parameters to a parametric quantum program.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
quantum_program: The quantum program to be assigned. This is the result of the synthesize method.
|
57
|
+
parameters: The parameter assignments.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
QuantumProgram: The quantum program after assigning parameters.
|
61
|
+
"""
|
62
|
+
|
63
|
+
return async_utils.run(
|
64
|
+
assign_parameters_async(
|
65
|
+
ParameterAssignmentsParams(
|
66
|
+
quantum_program=quantum_program, parameters=parameters
|
67
|
+
)
|
68
|
+
)
|
69
|
+
)
|