classiq 0.40.0__py3-none-any.whl → 0.41.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 +4 -2
- classiq/_internals/api_wrapper.py +3 -21
- classiq/applications/chemistry/chemistry_model_constructor.py +86 -100
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +6 -24
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +33 -45
- classiq/applications/combinatorial_optimization/__init__.py +2 -0
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +29 -26
- classiq/applications/finance/finance_model_constructor.py +23 -26
- classiq/applications/grover/grover_model_constructor.py +37 -38
- classiq/applications/qsvm/qsvm.py +1 -2
- classiq/applications/qsvm/qsvm_model_constructor.py +15 -16
- classiq/execution/__init__.py +4 -0
- classiq/execution/execution_session.py +151 -0
- classiq/execution/qnn.py +80 -0
- classiq/executor.py +2 -109
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +11 -0
- classiq/interface/applications/qsvm.py +0 -8
- classiq/interface/ast_node.py +12 -2
- classiq/interface/backend/backend_preferences.py +25 -1
- classiq/interface/backend/quantum_backend_providers.py +4 -4
- classiq/interface/executor/execution_preferences.py +4 -59
- classiq/interface/executor/execution_result.py +22 -1
- classiq/interface/generator/arith/arithmetic_expression_validator.py +0 -2
- classiq/interface/generator/arith/binary_ops.py +88 -25
- classiq/interface/generator/arith/unary_ops.py +28 -19
- classiq/interface/generator/expressions/atomic_expression_functions.py +6 -2
- classiq/interface/generator/expressions/enums/__init__.py +10 -0
- classiq/interface/generator/expressions/enums/classical_enum.py +5 -1
- classiq/interface/generator/expressions/expression.py +9 -2
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +7 -0
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +0 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +10 -1
- classiq/interface/generator/functions/builtins/internal_operators.py +7 -62
- classiq/interface/generator/functions/builtins/open_lib_functions.py +810 -2
- classiq/interface/generator/functions/classical_type.py +1 -3
- classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
- classiq/interface/model/bind_operation.py +3 -1
- classiq/interface/model/call_synthesis_data.py +2 -13
- classiq/interface/model/classical_if.py +3 -1
- classiq/interface/model/classical_parameter_declaration.py +13 -0
- classiq/interface/model/control.py +3 -101
- classiq/interface/model/inplace_binary_operation.py +3 -1
- classiq/interface/model/invert.py +3 -1
- classiq/interface/model/port_declaration.py +8 -1
- classiq/interface/model/power.py +3 -1
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +4 -2
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
- classiq/interface/model/quantum_expressions/quantum_expression.py +11 -1
- classiq/interface/model/quantum_function_call.py +4 -10
- classiq/interface/model/quantum_function_declaration.py +26 -4
- classiq/interface/model/quantum_lambda_function.py +1 -20
- classiq/interface/model/quantum_statement.py +9 -2
- classiq/interface/model/repeat.py +3 -1
- classiq/interface/model/statement_block.py +19 -13
- classiq/interface/model/validations/handles_validator.py +8 -2
- classiq/interface/model/variable_declaration_statement.py +3 -1
- classiq/interface/model/within_apply_operation.py +3 -1
- classiq/interface/server/routes.py +0 -5
- classiq/qmod/__init__.py +1 -2
- classiq/qmod/builtins/classical_execution_primitives.py +22 -2
- classiq/qmod/builtins/functions.py +51 -1
- classiq/qmod/builtins/operations.py +6 -36
- classiq/qmod/declaration_inferrer.py +8 -15
- classiq/qmod/native/__init__.py +9 -0
- classiq/qmod/native/expression_to_qmod.py +12 -9
- classiq/qmod/native/pretty_printer.py +4 -4
- classiq/qmod/pretty_print/__init__.py +9 -0
- classiq/qmod/pretty_print/expression_to_python.py +221 -0
- classiq/qmod/pretty_print/pretty_printer.py +421 -0
- classiq/qmod/qmod_parameter.py +7 -4
- classiq/qmod/quantum_callable.py +2 -1
- classiq/qmod/quantum_expandable.py +4 -3
- classiq/qmod/quantum_function.py +4 -16
- classiq/qmod/symbolic.py +1 -6
- classiq/synthesis.py +15 -16
- {classiq-0.40.0.dist-info → classiq-0.41.0.dist-info}/METADATA +5 -4
- {classiq-0.40.0.dist-info → classiq-0.41.0.dist-info}/RECORD +79 -76
- classiq/interface/model/common_model_types.py +0 -23
- classiq/interface/model/quantum_expressions/control_state.py +0 -38
- {classiq-0.40.0.dist-info → classiq-0.41.0.dist-info}/WHEEL +0 -0
classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py
CHANGED
@@ -14,20 +14,23 @@ from classiq.interface.generator.functions.classical_type import (
|
|
14
14
|
from classiq.interface.generator.functions.port_declaration import (
|
15
15
|
PortDeclarationDirection,
|
16
16
|
)
|
17
|
+
from classiq.interface.model.classical_parameter_declaration import (
|
18
|
+
ClassicalParameterDeclaration,
|
19
|
+
)
|
17
20
|
from classiq.interface.model.handle_binding import HandleBinding
|
18
21
|
from classiq.interface.model.model import Model, SerializedModel
|
19
22
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
20
23
|
from classiq.interface.model.port_declaration import PortDeclaration
|
21
24
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
25
|
+
from classiq.interface.model.quantum_type import QuantumBitvector
|
22
26
|
|
23
27
|
from classiq.applications.combinatorial_helpers.combinatorial_problem_utils import (
|
24
|
-
_internal_pyo_model_to_hamiltonian,
|
25
28
|
compute_qaoa_initial_point,
|
26
29
|
convert_pyomo_to_global_presentation,
|
30
|
+
pyo_model_to_hamiltonian,
|
27
31
|
)
|
28
32
|
from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
|
29
|
-
|
30
|
-
get_pauli_operator,
|
33
|
+
_pauli_terms_to_qmod,
|
31
34
|
)
|
32
35
|
from classiq.applications.combinatorial_optimization import OptimizerConfig, QAOAConfig
|
33
36
|
|
@@ -47,13 +50,10 @@ def construct_combi_opt_py_model(
|
|
47
50
|
if optimizer_config.max_iteration is not None:
|
48
51
|
max_iteration = optimizer_config.max_iteration
|
49
52
|
|
50
|
-
hamiltonian =
|
51
|
-
|
52
|
-
)
|
53
|
+
hamiltonian = pyo_model_to_hamiltonian(pyo_model, qaoa_config.penalty_energy)
|
54
|
+
len_hamiltonian = len(hamiltonian[0].pauli) # type: ignore[arg-type]
|
53
55
|
qaoa_initial_point = compute_qaoa_initial_point(hamiltonian, qaoa_config.num_layers)
|
54
|
-
|
55
|
-
pauli_oper = get_pauli_operator(hamiltonian)
|
56
|
-
pauli_qmod = _pauli_operator_to_qmod(pauli_oper)
|
56
|
+
pauli_qmod = _pauli_terms_to_qmod(hamiltonian)
|
57
57
|
|
58
58
|
initial_point_expression = (
|
59
59
|
f"{optimizer_config.initial_point}"
|
@@ -72,34 +72,37 @@ def construct_combi_opt_py_model(
|
|
72
72
|
functions=[
|
73
73
|
NativeFunctionDefinition(
|
74
74
|
name="main",
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
75
|
+
positional_arg_declarations=[
|
76
|
+
ClassicalParameterDeclaration(
|
77
|
+
name="params_list",
|
78
|
+
classical_type=ClassicalArray(
|
79
|
+
element_type=Real(), size=qaoa_config.num_layers * 2
|
80
|
+
),
|
81
|
+
),
|
82
|
+
PortDeclaration(
|
82
83
|
name="target",
|
83
|
-
|
84
|
+
quantum_type=QuantumBitvector(
|
85
|
+
length=Expression(expr=f"{len_hamiltonian}"),
|
86
|
+
),
|
84
87
|
direction=PortDeclarationDirection.Output,
|
85
88
|
),
|
86
|
-
|
89
|
+
],
|
87
90
|
body=[
|
88
91
|
QuantumFunctionCall(
|
89
92
|
function="allocate",
|
90
93
|
positional_args=[
|
91
|
-
Expression(expr="target
|
94
|
+
Expression(expr="get_field(target, 'len')"),
|
92
95
|
HandleBinding(name="target"),
|
93
96
|
],
|
94
97
|
),
|
95
98
|
QuantumFunctionCall(
|
96
99
|
function="qaoa_penalty",
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
positional_args=[
|
101
|
+
Expression(expr="get_field(target, 'len')"),
|
102
|
+
Expression(expr="params_list"),
|
103
|
+
Expression(expr="hamiltonian"),
|
104
|
+
HandleBinding(name="target"),
|
105
|
+
],
|
103
106
|
),
|
104
107
|
],
|
105
108
|
),
|
@@ -118,7 +121,7 @@ alpha_cvar={optimizer_config.alpha_cvar}
|
|
118
121
|
)
|
119
122
|
|
120
123
|
save({{"vqe_result": vqe_result, "hamiltonian": hamiltonian}})
|
121
|
-
""",
|
124
|
+
""".strip(),
|
122
125
|
)
|
123
126
|
|
124
127
|
|
@@ -14,6 +14,7 @@ from classiq.interface.model.native_function_definition import NativeFunctionDef
|
|
14
14
|
from classiq.interface.model.port_declaration import PortDeclaration
|
15
15
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
16
16
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
17
|
+
from classiq.interface.model.quantum_type import QuantumBitvector
|
17
18
|
from classiq.interface.model.variable_declaration_statement import (
|
18
19
|
VariableDeclarationStatement,
|
19
20
|
)
|
@@ -66,13 +67,15 @@ def construct_finance_model(
|
|
66
67
|
*QMCI_LIBRARY,
|
67
68
|
NativeFunctionDefinition(
|
68
69
|
name="main",
|
69
|
-
|
70
|
-
|
70
|
+
positional_arg_declarations=[
|
71
|
+
PortDeclaration(
|
71
72
|
name="phase_port",
|
72
|
-
|
73
|
+
quantum_type=QuantumBitvector(
|
74
|
+
length=Expression(expr=f"{phase_port_size}")
|
75
|
+
),
|
73
76
|
direction=PortDeclarationDirection.Output,
|
74
77
|
),
|
75
|
-
|
78
|
+
],
|
76
79
|
body=[
|
77
80
|
VariableDeclarationStatement(name="unitary_port"),
|
78
81
|
QuantumFunctionCall(
|
@@ -93,40 +96,34 @@ def construct_finance_model(
|
|
93
96
|
),
|
94
97
|
QuantumFunctionCall(
|
95
98
|
function="qmci",
|
96
|
-
|
97
|
-
|
99
|
+
positional_args=[
|
100
|
+
QuantumLambdaFunction(
|
98
101
|
body=[
|
99
102
|
QuantumFunctionCall(
|
100
103
|
function=finance_function,
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
),
|
105
|
-
"
|
106
|
-
|
107
|
-
),
|
108
|
-
},
|
109
|
-
inouts={
|
110
|
-
"func_port": HandleBinding(name="arg0"),
|
111
|
-
"obj_port": HandleBinding(name="arg1"),
|
112
|
-
},
|
104
|
+
positional_args=[
|
105
|
+
Expression(expr=finance_model),
|
106
|
+
Expression(expr=finance_function_object),
|
107
|
+
HandleBinding(name="arg0"),
|
108
|
+
HandleBinding(name="arg1"),
|
109
|
+
],
|
113
110
|
),
|
114
111
|
],
|
115
112
|
),
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
"packed_vars": HandleBinding(name="unitary_port"),
|
120
|
-
},
|
113
|
+
HandleBinding(name="phase_port"),
|
114
|
+
HandleBinding(name="unitary_port"),
|
115
|
+
],
|
121
116
|
),
|
122
117
|
],
|
123
118
|
),
|
124
119
|
],
|
125
|
-
classical_execution_code=
|
126
|
-
|
120
|
+
classical_execution_code=(
|
121
|
+
AE_CLASSICAL_LIBRARY
|
122
|
+
+ f"""
|
127
123
|
estimation = execute_amplitude_estimation({phase_port_size})
|
128
124
|
{_OUTPUT_VARIABLE_NAME} = {post_process_function}({finance_model}, {finance_function_object}, estimation)
|
129
125
|
save({{{_OUTPUT_VARIABLE_NAME!r}: {_OUTPUT_VARIABLE_NAME}}})
|
130
|
-
"""
|
126
|
+
"""
|
127
|
+
).strip(),
|
131
128
|
)
|
132
129
|
return model.get_model()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import List, Tuple
|
2
2
|
|
3
3
|
from classiq.interface.generator.expressions.expression import Expression
|
4
4
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -14,7 +14,7 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
14
14
|
)
|
15
15
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
16
16
|
from classiq.interface.model.quantum_lambda_function import QuantumLambdaFunction
|
17
|
-
from classiq.interface.model.quantum_type import QuantumNumeric
|
17
|
+
from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
|
18
18
|
from classiq.interface.model.variable_declaration_statement import (
|
19
19
|
VariableDeclarationStatement,
|
20
20
|
)
|
@@ -26,16 +26,18 @@ _OUTPUT_VARIABLE_NAME = "result"
|
|
26
26
|
_PREDICATE_FUNCTION_NAME = "expr_predicate"
|
27
27
|
|
28
28
|
|
29
|
-
def
|
29
|
+
def _arithmetic_oracle_ios(
|
30
30
|
definitions: List[Tuple[str, RegisterUserInput]], handle_name: str
|
31
|
-
) ->
|
31
|
+
) -> List[HandleBinding]:
|
32
32
|
cursor = 0
|
33
|
-
ios:
|
34
|
-
for
|
35
|
-
ios
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
ios: List[HandleBinding] = []
|
34
|
+
for _, reg in definitions:
|
35
|
+
ios.append(
|
36
|
+
SlicedHandleBinding(
|
37
|
+
name=handle_name,
|
38
|
+
start=Expression(expr=f"{cursor}"),
|
39
|
+
end=Expression(expr=f"{cursor + reg.size}"),
|
40
|
+
)
|
39
41
|
)
|
40
42
|
cursor += reg.size
|
41
43
|
return ios
|
@@ -45,34 +47,31 @@ def _construct_arithmetic_oracle(
|
|
45
47
|
predicate_function: str,
|
46
48
|
definitions: List[Tuple[str, RegisterUserInput]],
|
47
49
|
) -> QuantumFunctionCall:
|
48
|
-
predicate_var_binding =
|
49
|
-
predicate_var_binding
|
50
|
+
predicate_var_binding = _arithmetic_oracle_ios(definitions, "arg0")
|
51
|
+
predicate_var_binding.append(HandleBinding(name="arg1"))
|
50
52
|
return QuantumFunctionCall(
|
51
53
|
function="phase_oracle",
|
52
|
-
|
53
|
-
|
54
|
-
},
|
55
|
-
operands={
|
56
|
-
"predicate": QuantumLambdaFunction(
|
54
|
+
positional_args=[
|
55
|
+
QuantumLambdaFunction(
|
57
56
|
body=[
|
58
57
|
QuantumFunctionCall(
|
59
58
|
function=predicate_function,
|
60
|
-
|
59
|
+
positional_args=predicate_var_binding,
|
61
60
|
),
|
62
61
|
],
|
63
62
|
),
|
64
|
-
|
63
|
+
HandleBinding(name="arg0"),
|
64
|
+
],
|
65
65
|
)
|
66
66
|
|
67
67
|
|
68
68
|
def grover_main_port_declarations(
|
69
69
|
definitions: List[Tuple[str, RegisterUserInput]],
|
70
70
|
direction: PortDeclarationDirection,
|
71
|
-
) ->
|
72
|
-
return
|
73
|
-
|
71
|
+
) -> List[PortDeclaration]:
|
72
|
+
return [
|
73
|
+
PortDeclaration(
|
74
74
|
name=name,
|
75
|
-
size=Expression(expr=f"{reg.size}"),
|
76
75
|
quantum_type=QuantumNumeric(
|
77
76
|
size=Expression(expr=f"{reg.size}"),
|
78
77
|
is_signed=Expression(expr=f"{reg.is_signed}"),
|
@@ -81,7 +80,7 @@ def grover_main_port_declarations(
|
|
81
80
|
direction=direction,
|
82
81
|
)
|
83
82
|
for name, reg in definitions
|
84
|
-
|
83
|
+
]
|
85
84
|
|
86
85
|
|
87
86
|
def construct_grover_model(
|
@@ -92,10 +91,12 @@ def construct_grover_model(
|
|
92
91
|
predicate_port_decls = grover_main_port_declarations(
|
93
92
|
definitions, PortDeclarationDirection.Inout
|
94
93
|
)
|
95
|
-
predicate_port_decls
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
predicate_port_decls.append(
|
95
|
+
PortDeclaration(
|
96
|
+
name="res",
|
97
|
+
quantum_type=QuantumBitvector(length=Expression(expr="1")),
|
98
|
+
direction=PortDeclarationDirection.Inout,
|
99
|
+
)
|
99
100
|
)
|
100
101
|
num_qubits = sum(reg.size for _, reg in definitions)
|
101
102
|
|
@@ -103,7 +104,7 @@ def construct_grover_model(
|
|
103
104
|
functions=[
|
104
105
|
NativeFunctionDefinition(
|
105
106
|
name=_PREDICATE_FUNCTION_NAME,
|
106
|
-
|
107
|
+
positional_arg_declarations=predicate_port_decls,
|
107
108
|
body=[
|
108
109
|
ArithmeticOperation(
|
109
110
|
expression=Expression(expr=expression),
|
@@ -114,7 +115,7 @@ def construct_grover_model(
|
|
114
115
|
),
|
115
116
|
NativeFunctionDefinition(
|
116
117
|
name="main",
|
117
|
-
|
118
|
+
positional_arg_declarations=grover_main_port_declarations(
|
118
119
|
definitions, PortDeclarationDirection.Output
|
119
120
|
),
|
120
121
|
body=[
|
@@ -128,20 +129,18 @@ def construct_grover_model(
|
|
128
129
|
),
|
129
130
|
QuantumFunctionCall(
|
130
131
|
function="grover_search",
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
inouts={"packed_vars": HandleBinding(name="packed_vars")},
|
135
|
-
operands={
|
136
|
-
"oracle": QuantumLambdaFunction(
|
132
|
+
positional_args=[
|
133
|
+
Expression(expr=f"{num_reps}"),
|
134
|
+
QuantumLambdaFunction(
|
137
135
|
body=[
|
138
136
|
_construct_arithmetic_oracle(
|
139
137
|
_PREDICATE_FUNCTION_NAME,
|
140
138
|
definitions,
|
141
139
|
)
|
142
140
|
]
|
143
|
-
)
|
144
|
-
|
141
|
+
),
|
142
|
+
HandleBinding(name="packed_vars"),
|
143
|
+
],
|
145
144
|
),
|
146
145
|
BindOperation(
|
147
146
|
in_handles=[HandleBinding(name="packed_vars")],
|
@@ -1,10 +1,9 @@
|
|
1
1
|
from typing import List
|
2
2
|
|
3
|
-
from classiq.interface.applications.qsvm import Data, Labels, QSVMData
|
3
|
+
from classiq.interface.applications.qsvm import Data, Labels, QSVMData
|
4
4
|
|
5
5
|
__all__ = [
|
6
6
|
"QSVMData",
|
7
|
-
"QSVMPreferences",
|
8
7
|
"Data",
|
9
8
|
"Labels",
|
10
9
|
]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any,
|
1
|
+
from typing import Any, List, Tuple
|
2
2
|
|
3
3
|
from classiq.interface.applications.qsvm import DataList, LabelsInt
|
4
4
|
from classiq.interface.generator.expressions.enums.pauli import Pauli
|
@@ -24,10 +24,10 @@ _OUTPUT_VARIABLE_NAME = "qsvm_results"
|
|
24
24
|
|
25
25
|
def _bloch_sphere_feature_map_function_params(
|
26
26
|
bloch_feature_dimension: int,
|
27
|
-
) -> Tuple[
|
28
|
-
return
|
29
|
-
|
30
|
-
|
27
|
+
) -> Tuple[List[Expression], str]:
|
28
|
+
return [
|
29
|
+
Expression(expr=f"{bloch_feature_dimension}")
|
30
|
+
], f"ceiling({bloch_feature_dimension}/2)"
|
31
31
|
|
32
32
|
|
33
33
|
def _pauli_feature_map_function_params(
|
@@ -36,7 +36,7 @@ def _pauli_feature_map_function_params(
|
|
36
36
|
alpha: int,
|
37
37
|
reps: int,
|
38
38
|
feature_dimension: int,
|
39
|
-
) -> Tuple[
|
39
|
+
) -> Tuple[List[Expression], str]:
|
40
40
|
paulis_str = (
|
41
41
|
"["
|
42
42
|
+ ",".join(
|
@@ -51,11 +51,11 @@ def _pauli_feature_map_function_params(
|
|
51
51
|
f"reps={reps}, "
|
52
52
|
f"feature_dimension={feature_dimension}"
|
53
53
|
)
|
54
|
-
return
|
55
|
-
|
54
|
+
return [
|
55
|
+
Expression(
|
56
56
|
expr=f"struct_literal(QSVMFeatureMapPauli, {pauli_feature_map_params})"
|
57
57
|
)
|
58
|
-
|
58
|
+
], f"{feature_dimension}"
|
59
59
|
|
60
60
|
|
61
61
|
def get_qsvm_qmain_body(
|
@@ -75,8 +75,7 @@ def get_qsvm_qmain_body(
|
|
75
75
|
),
|
76
76
|
QuantumFunctionCall(
|
77
77
|
function=feature_map_function_name,
|
78
|
-
|
79
|
-
inouts={"qbv": HandleBinding(name="qbv")},
|
78
|
+
positional_args=[*params, HandleBinding(name="qbv")],
|
80
79
|
),
|
81
80
|
]
|
82
81
|
|
@@ -94,12 +93,12 @@ def construct_qsvm_model(
|
|
94
93
|
functions=[
|
95
94
|
NativeFunctionDefinition(
|
96
95
|
name="main",
|
97
|
-
|
98
|
-
|
96
|
+
positional_arg_declarations=[
|
97
|
+
PortDeclaration(
|
99
98
|
name="qbv",
|
100
99
|
direction=PortDeclarationDirection.Output,
|
101
|
-
)
|
102
|
-
|
100
|
+
),
|
101
|
+
],
|
103
102
|
body=get_qsvm_qmain_body(
|
104
103
|
feature_map_function_name=feature_map_function_name, **kwargs
|
105
104
|
),
|
@@ -114,7 +113,7 @@ def construct_qsvm_model(
|
|
114
113
|
predict_data={predict_data}
|
115
114
|
)
|
116
115
|
save({{{_OUTPUT_VARIABLE_NAME!r}: {_OUTPUT_VARIABLE_NAME}}})
|
117
|
-
""",
|
116
|
+
""".strip(),
|
118
117
|
)
|
119
118
|
|
120
119
|
return qsvm_qmod.get_model()
|
classiq/execution/__init__.py
CHANGED
@@ -9,7 +9,9 @@ from ..interface.executor.execution_preferences import __all__ as _ep_all
|
|
9
9
|
from ..interface.executor.iqae_result import IQAEResult
|
10
10
|
from ..interface.executor.result import ExecutionDetails
|
11
11
|
from ..interface.executor.vqe_result import VQESolverResult
|
12
|
+
from .execution_session import ExecutionSession
|
12
13
|
from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
|
14
|
+
from .qnn import execute_qnn
|
13
15
|
|
14
16
|
__all__ = (
|
15
17
|
_be_all
|
@@ -22,6 +24,8 @@ __all__ = (
|
|
22
24
|
"ExecutionJob",
|
23
25
|
"get_execution_jobs",
|
24
26
|
"get_execution_jobs_async",
|
27
|
+
"ExecutionSession",
|
28
|
+
"execute_qnn",
|
25
29
|
]
|
26
30
|
)
|
27
31
|
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any, Callable, Dict, List, Optional, Union, cast
|
3
|
+
|
4
|
+
from classiq.interface.executor.execution_preferences import ExecutionPreferences
|
5
|
+
from classiq.interface.executor.execution_result import ResultsCollection
|
6
|
+
from classiq.interface.executor.result import (
|
7
|
+
EstimationResult,
|
8
|
+
EstimationResults,
|
9
|
+
ExecutionDetails,
|
10
|
+
MultipleExecutionDetails,
|
11
|
+
)
|
12
|
+
from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
|
13
|
+
from classiq.interface.generator.quantum_program import QuantumProgram
|
14
|
+
|
15
|
+
from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
|
16
|
+
_pauli_dict_to_str,
|
17
|
+
_pauli_terms_to_qmod,
|
18
|
+
)
|
19
|
+
from classiq.exceptions import ClassiqValueError
|
20
|
+
from classiq.executor import execute
|
21
|
+
from classiq.qmod.builtins import PauliTerm
|
22
|
+
from classiq.qmod.builtins.classical_execution_primitives import ExecutionParams
|
23
|
+
from classiq.synthesis import SerializedQuantumProgram
|
24
|
+
|
25
|
+
Hamiltonian = Union[List[QmodPyStruct], List[PauliTerm]]
|
26
|
+
Program = Union[SerializedQuantumProgram, QuantumProgram]
|
27
|
+
ExecutionParameters = Union[None, ExecutionParams, List[ExecutionParams]]
|
28
|
+
|
29
|
+
SAVE_RESULT = "\nsave({'result': result})\n"
|
30
|
+
|
31
|
+
|
32
|
+
class SupportedPrimitives:
|
33
|
+
SAMPLE = "sample"
|
34
|
+
BATCH_SAMPLE = "batch_sample"
|
35
|
+
ESTIMATE = "estimate"
|
36
|
+
BATCH_ESTIMATE = "batch_estimate"
|
37
|
+
|
38
|
+
|
39
|
+
def _deserialize_program(program: Program) -> QuantumProgram:
|
40
|
+
return (
|
41
|
+
program
|
42
|
+
if isinstance(program, QuantumProgram)
|
43
|
+
else QuantumProgram.parse_obj(json.loads(program))
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
def to_hamiltonian_str(hamiltonian: Hamiltonian) -> str:
|
48
|
+
return (
|
49
|
+
_pauli_terms_to_qmod(cast(List[PauliTerm], hamiltonian))
|
50
|
+
if isinstance(hamiltonian[0], PauliTerm)
|
51
|
+
else _pauli_dict_to_str(cast(List[QmodPyStruct], hamiltonian))
|
52
|
+
)
|
53
|
+
|
54
|
+
|
55
|
+
def format_parameters(execution_params: ExecutionParameters) -> str:
|
56
|
+
return json.dumps(execution_params, default=str) if execution_params else ""
|
57
|
+
|
58
|
+
|
59
|
+
def create_estimate_execution_code(operation: str, **kwargs: Any) -> str:
|
60
|
+
hamiltonian = kwargs.get("hamiltonian", "")
|
61
|
+
parameters = kwargs.get("parameters", "")
|
62
|
+
return f"\nresult = {operation}([{hamiltonian}], {parameters})" + SAVE_RESULT
|
63
|
+
|
64
|
+
|
65
|
+
def create_sample_execution_code(operation: str, **kwargs: Any) -> str:
|
66
|
+
parameters = kwargs.get("parameters", "")
|
67
|
+
return f"\nresult = {operation}({parameters})" + SAVE_RESULT
|
68
|
+
|
69
|
+
|
70
|
+
operation_handlers: Dict[str, Callable[[str], str]] = {
|
71
|
+
"estimate": create_estimate_execution_code,
|
72
|
+
"batch_estimate": create_estimate_execution_code,
|
73
|
+
"sample": create_sample_execution_code,
|
74
|
+
"batch_sample": create_sample_execution_code,
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
def generate_code_snippet(operation: str, **kwargs: Any) -> str:
|
79
|
+
handler = operation_handlers.get(operation)
|
80
|
+
if handler:
|
81
|
+
return handler(operation, **kwargs)
|
82
|
+
raise ClassiqValueError(f"Unsupported operation type: {operation}")
|
83
|
+
|
84
|
+
|
85
|
+
class ExecutionSession:
|
86
|
+
def __init__(
|
87
|
+
self,
|
88
|
+
quantum_program: Program,
|
89
|
+
execution_preferences: Optional[ExecutionPreferences] = None,
|
90
|
+
):
|
91
|
+
self.program: QuantumProgram = _deserialize_program(quantum_program)
|
92
|
+
self.update_execution_preferences(execution_preferences)
|
93
|
+
|
94
|
+
@property
|
95
|
+
def qprog(self) -> str:
|
96
|
+
return SerializedQuantumProgram(self.program.json(indent=2))
|
97
|
+
|
98
|
+
def update_execution_preferences(
|
99
|
+
self, execution_preferences: Optional[ExecutionPreferences]
|
100
|
+
) -> None:
|
101
|
+
if execution_preferences is not None:
|
102
|
+
self.program.model.execution_preferences = execution_preferences
|
103
|
+
|
104
|
+
def execute_quantum_program(
|
105
|
+
self, operation: str, **kwargs: Any
|
106
|
+
) -> ResultsCollection:
|
107
|
+
self.program.model.classical_execution_code = generate_code_snippet(
|
108
|
+
operation, **kwargs
|
109
|
+
)
|
110
|
+
return execute(self.qprog).result()
|
111
|
+
|
112
|
+
def sample(self, parameters: Optional[ExecutionParams] = None) -> ExecutionDetails:
|
113
|
+
return cast(
|
114
|
+
ExecutionDetails,
|
115
|
+
self.execute_quantum_program(
|
116
|
+
SupportedPrimitives.SAMPLE, parameters=format_parameters(parameters)
|
117
|
+
)[0].value,
|
118
|
+
)
|
119
|
+
|
120
|
+
def batch_sample(self, parameters: List[ExecutionParams]) -> List[ExecutionDetails]:
|
121
|
+
return cast(
|
122
|
+
MultipleExecutionDetails,
|
123
|
+
self.execute_quantum_program(
|
124
|
+
SupportedPrimitives.BATCH_SAMPLE,
|
125
|
+
parameters=format_parameters(parameters),
|
126
|
+
)[0].value,
|
127
|
+
).details
|
128
|
+
|
129
|
+
def estimate(
|
130
|
+
self, hamiltonian: Hamiltonian, parameters: Optional[ExecutionParams] = None
|
131
|
+
) -> EstimationResult:
|
132
|
+
return cast(
|
133
|
+
EstimationResult,
|
134
|
+
self.execute_quantum_program(
|
135
|
+
SupportedPrimitives.ESTIMATE,
|
136
|
+
parameters=format_parameters(parameters),
|
137
|
+
hamiltonian=to_hamiltonian_str(hamiltonian),
|
138
|
+
)[0].value,
|
139
|
+
)
|
140
|
+
|
141
|
+
def batch_estimate(
|
142
|
+
self, hamiltonian: Hamiltonian, parameters: List[ExecutionParams]
|
143
|
+
) -> List[EstimationResult]:
|
144
|
+
return cast(
|
145
|
+
EstimationResults,
|
146
|
+
self.execute_quantum_program(
|
147
|
+
SupportedPrimitives.BATCH_ESTIMATE,
|
148
|
+
parameters=format_parameters(parameters),
|
149
|
+
hamiltonian=to_hamiltonian_str(hamiltonian),
|
150
|
+
)[0].value,
|
151
|
+
).results
|