classiq 0.86.0__py3-none-any.whl → 0.87.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 +2 -0
- classiq/applications/chemistry/hartree_fock.py +5 -1
- classiq/applications/chemistry/op_utils.py +2 -2
- classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
- classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
- classiq/applications/combinatorial_helpers/memory.py +4 -4
- classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
- classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
- classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
- classiq/applications/hamiltonian/pauli_decomposition.py +33 -1
- classiq/evaluators/argument_types.py +15 -6
- classiq/evaluators/parameter_types.py +43 -39
- classiq/evaluators/qmod_annotated_expression.py +88 -11
- classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +54 -11
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +40 -25
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +29 -59
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +12 -5
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +21 -14
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +9 -5
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +20 -1
- classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
- classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +2 -3
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +48 -21
- classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
- classiq/evaluators/qmod_node_evaluators/utils.py +27 -5
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +292 -0
- classiq/evaluators/quantum_type_utils.py +0 -131
- classiq/execution/execution_session.py +1 -1
- classiq/execution/qnn.py +4 -1
- classiq/execution/user_budgets.py +1 -1
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +10 -30
- classiq/interface/backend/quantum_backend_providers.py +63 -52
- classiq/interface/generator/arith/binary_ops.py +107 -115
- classiq/interface/generator/arith/extremum_operations.py +33 -45
- classiq/interface/generator/arith/number_utils.py +4 -1
- classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
- classiq/interface/generator/compiler_keywords.py +2 -0
- classiq/interface/generator/function_param_list.py +133 -5
- classiq/interface/generator/functions/classical_type.py +59 -2
- classiq/interface/generator/functions/qmod_python_interface.py +15 -0
- classiq/interface/generator/functions/type_name.py +6 -0
- classiq/interface/generator/model/preferences/preferences.py +1 -17
- classiq/interface/generator/quantum_program.py +1 -13
- classiq/interface/helpers/model_normalizer.py +2 -2
- classiq/interface/helpers/text_utils.py +7 -2
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/classical_if.py +40 -0
- classiq/interface/model/handle_binding.py +28 -16
- classiq/interface/model/quantum_type.py +61 -2
- classiq/interface/pretty_print/expression_to_qmod.py +24 -11
- classiq/interface/pyomo_extension/__init__.py +0 -4
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
- classiq/model_expansions/arithmetic.py +43 -1
- classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
- classiq/model_expansions/capturing/captured_vars.py +2 -5
- classiq/model_expansions/quantum_operations/allocate.py +22 -15
- classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
- classiq/model_expansions/quantum_operations/bind.py +15 -7
- classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
- classiq/open_library/functions/__init__.py +3 -0
- classiq/open_library/functions/lcu.py +117 -0
- classiq/qmod/builtins/enums.py +2 -2
- classiq/qmod/builtins/structs.py +33 -18
- classiq/qmod/pretty_print/expression_to_python.py +7 -9
- {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/METADATA +3 -3
- {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/RECORD +83 -89
- classiq/interface/generator/amplitude_estimation.py +0 -34
- classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
- classiq/interface/generator/grover_diffuser.py +0 -93
- classiq/interface/generator/grover_operator.py +0 -106
- classiq/interface/generator/oracles/__init__.py +0 -3
- classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
- classiq/interface/generator/oracles/custom_oracle.py +0 -65
- classiq/interface/generator/oracles/oracle_abc.py +0 -76
- classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
- classiq/interface/generator/qpe.py +0 -169
- classiq/interface/grover/grover_modelling_params.py +0 -13
- classiq/model_expansions/transformers/var_splitter.py +0 -224
- /classiq/{interface/grover → evaluators/qmod_type_inference}/__init__.py +0 -0
- {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,188 @@
|
|
1
|
+
from enum import IntEnum
|
2
|
+
from typing import Any, Optional, Union
|
3
|
+
|
4
|
+
import sympy
|
5
|
+
|
6
|
+
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
9
|
+
QmodStructInstance,
|
10
|
+
)
|
11
|
+
from classiq.interface.generator.functions.classical_type import (
|
12
|
+
Bool,
|
13
|
+
ClassicalArray,
|
14
|
+
ClassicalTuple,
|
15
|
+
ClassicalType,
|
16
|
+
Integer,
|
17
|
+
Real,
|
18
|
+
)
|
19
|
+
from classiq.interface.generator.functions.type_name import Enum, Struct, TypeName
|
20
|
+
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
21
|
+
from classiq.interface.helpers.backward_compatibility import zip_strict
|
22
|
+
|
23
|
+
|
24
|
+
def _copy_generative_flag(
|
25
|
+
from_type: ClassicalType, to_type: Optional[ClassicalType]
|
26
|
+
) -> Optional[ClassicalType]:
|
27
|
+
if to_type is None:
|
28
|
+
return None
|
29
|
+
if from_type.is_generative:
|
30
|
+
return to_type.set_generative()
|
31
|
+
return to_type
|
32
|
+
|
33
|
+
|
34
|
+
def infer_classical_type(value: Any) -> ClassicalType:
|
35
|
+
if isinstance(value, IntEnum):
|
36
|
+
return Enum(name=type(value).__name__)
|
37
|
+
if isinstance(value, bool):
|
38
|
+
return Bool()
|
39
|
+
if isinstance(value, int):
|
40
|
+
return Integer()
|
41
|
+
if isinstance(value, (float, complex)):
|
42
|
+
return Real()
|
43
|
+
if isinstance(value, list):
|
44
|
+
return ClassicalTuple(
|
45
|
+
element_types=[infer_classical_type(item) for item in value]
|
46
|
+
)
|
47
|
+
if isinstance(value, QmodStructInstance):
|
48
|
+
struct_name = value.struct_declaration.name
|
49
|
+
classical_type = Struct(name=struct_name)
|
50
|
+
classical_type.set_classical_struct_decl(
|
51
|
+
StructDeclaration(
|
52
|
+
name=struct_name,
|
53
|
+
variables={
|
54
|
+
field_name: infer_classical_type(field_value)
|
55
|
+
for field_name, field_value in value.fields.items()
|
56
|
+
},
|
57
|
+
)
|
58
|
+
)
|
59
|
+
return classical_type
|
60
|
+
# FIXME: Remove sympy compatibility (CLS-3214)
|
61
|
+
if (
|
62
|
+
isinstance(value, sympy.Basic)
|
63
|
+
and len(value.free_symbols) == 0
|
64
|
+
and value.is_complex
|
65
|
+
):
|
66
|
+
return Real()
|
67
|
+
raise ClassiqInternalExpansionError
|
68
|
+
|
69
|
+
|
70
|
+
def _inject_classical_array_attributes(
|
71
|
+
from_type: ClassicalType, to_type: Union[ClassicalArray, ClassicalTuple]
|
72
|
+
) -> Optional[ClassicalType]:
|
73
|
+
if isinstance(to_type, ClassicalArray):
|
74
|
+
if isinstance(from_type, ClassicalArray):
|
75
|
+
length: Optional[Expression]
|
76
|
+
if from_type.has_length:
|
77
|
+
if (
|
78
|
+
to_type.has_length
|
79
|
+
and from_type.length_value != to_type.length_value
|
80
|
+
):
|
81
|
+
return None
|
82
|
+
length = from_type.length
|
83
|
+
else:
|
84
|
+
length = to_type.length
|
85
|
+
element_type = inject_classical_type_attributes(
|
86
|
+
from_type.element_type, to_type.element_type
|
87
|
+
)
|
88
|
+
if element_type is None:
|
89
|
+
return None
|
90
|
+
return ClassicalArray(element_type=element_type, length=length)
|
91
|
+
if isinstance(from_type, ClassicalTuple):
|
92
|
+
if (
|
93
|
+
to_type.has_length
|
94
|
+
and len(from_type.element_types) != to_type.length_value
|
95
|
+
):
|
96
|
+
return None
|
97
|
+
element_types = [
|
98
|
+
inject_classical_type_attributes(element_type, to_type.element_type)
|
99
|
+
for element_type in from_type.element_types
|
100
|
+
]
|
101
|
+
if None in element_types:
|
102
|
+
return None
|
103
|
+
return ClassicalTuple(element_types=element_types)
|
104
|
+
return None
|
105
|
+
if isinstance(from_type, ClassicalArray):
|
106
|
+
if from_type.has_length and from_type.length_value != len(
|
107
|
+
to_type.element_types
|
108
|
+
):
|
109
|
+
return None
|
110
|
+
element_types = [
|
111
|
+
inject_classical_type_attributes(from_type.element_type, element_type)
|
112
|
+
for element_type in to_type.element_types
|
113
|
+
]
|
114
|
+
if None in element_types:
|
115
|
+
return None
|
116
|
+
return ClassicalTuple(element_types=element_types)
|
117
|
+
if isinstance(from_type, ClassicalTuple):
|
118
|
+
if len(from_type.element_types) != len(to_type.element_types):
|
119
|
+
return None
|
120
|
+
element_types = [
|
121
|
+
inject_classical_type_attributes(from_element_type, to_element_type)
|
122
|
+
for from_element_type, to_element_type in zip_strict(
|
123
|
+
from_type.element_types, to_type.element_types, strict=True
|
124
|
+
)
|
125
|
+
]
|
126
|
+
if None in element_types:
|
127
|
+
return None
|
128
|
+
return ClassicalTuple(element_types=element_types)
|
129
|
+
return None
|
130
|
+
|
131
|
+
|
132
|
+
def _inject_classical_type_name_attributes(
|
133
|
+
from_type: ClassicalType, to_type: TypeName
|
134
|
+
) -> Optional[ClassicalType]:
|
135
|
+
if to_type.is_enum:
|
136
|
+
if isinstance(from_type, Integer) or (
|
137
|
+
isinstance(from_type, TypeName) and from_type.name == to_type.name
|
138
|
+
):
|
139
|
+
return Enum(name=to_type.name)
|
140
|
+
return None
|
141
|
+
if to_type.has_classical_struct_decl:
|
142
|
+
if not isinstance(from_type, TypeName) or from_type.name != to_type.name:
|
143
|
+
return None
|
144
|
+
classical_type = Struct(name=to_type.name)
|
145
|
+
field_types = {
|
146
|
+
field_name: inject_classical_type_attributes(
|
147
|
+
from_type.classical_struct_decl.variables[field_name],
|
148
|
+
to_type.classical_struct_decl.variables[field_name],
|
149
|
+
)
|
150
|
+
for field_name in to_type.classical_struct_decl.variables
|
151
|
+
}
|
152
|
+
if None in field_types.values():
|
153
|
+
return None
|
154
|
+
classical_type.set_classical_struct_decl(
|
155
|
+
StructDeclaration(name=to_type.name, variables=field_types)
|
156
|
+
)
|
157
|
+
return classical_type
|
158
|
+
return None
|
159
|
+
|
160
|
+
|
161
|
+
def inject_classical_type_attributes(
|
162
|
+
from_type: ClassicalType, to_type: ClassicalType
|
163
|
+
) -> Optional[ClassicalType]:
|
164
|
+
if isinstance(to_type, Bool):
|
165
|
+
if isinstance(from_type, Bool):
|
166
|
+
return _copy_generative_flag(to_type, Bool())
|
167
|
+
return None
|
168
|
+
if isinstance(to_type, Integer):
|
169
|
+
if isinstance(from_type, (Integer, Real)) or (
|
170
|
+
isinstance(from_type, TypeName) and from_type.is_enum
|
171
|
+
):
|
172
|
+
return _copy_generative_flag(to_type, Integer())
|
173
|
+
return None
|
174
|
+
if isinstance(to_type, Real):
|
175
|
+
if isinstance(from_type, (Integer, Real)) or (
|
176
|
+
isinstance(from_type, TypeName) and from_type.is_enum
|
177
|
+
):
|
178
|
+
return _copy_generative_flag(to_type, Real())
|
179
|
+
return None
|
180
|
+
if isinstance(to_type, (ClassicalArray, ClassicalTuple)):
|
181
|
+
return _copy_generative_flag(
|
182
|
+
to_type, _inject_classical_array_attributes(from_type, to_type)
|
183
|
+
)
|
184
|
+
if isinstance(to_type, TypeName):
|
185
|
+
return _copy_generative_flag(
|
186
|
+
to_type, _inject_classical_type_name_attributes(from_type, to_type)
|
187
|
+
)
|
188
|
+
return None
|
@@ -0,0 +1,292 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
2
|
+
|
3
|
+
from classiq.interface.exceptions import (
|
4
|
+
ClassiqExpansionError,
|
5
|
+
ClassiqInternalExpansionError,
|
6
|
+
)
|
7
|
+
from classiq.interface.generator.expressions.expression import Expression
|
8
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
9
|
+
from classiq.interface.model.quantum_type import (
|
10
|
+
QuantumBit,
|
11
|
+
QuantumBitvector,
|
12
|
+
QuantumNumeric,
|
13
|
+
QuantumType,
|
14
|
+
)
|
15
|
+
|
16
|
+
from classiq.evaluators.quantum_type_utils import set_bounds
|
17
|
+
|
18
|
+
|
19
|
+
def _normalized_qnum(quantum_type: QuantumType) -> QuantumType:
|
20
|
+
if not isinstance(quantum_type, QuantumNumeric):
|
21
|
+
return quantum_type
|
22
|
+
normalized_qnum = QuantumNumeric(
|
23
|
+
size=quantum_type.size,
|
24
|
+
is_signed=(
|
25
|
+
quantum_type.is_signed
|
26
|
+
if quantum_type.is_signed is not None
|
27
|
+
else Expression(expr="False")
|
28
|
+
),
|
29
|
+
fraction_digits=(
|
30
|
+
quantum_type.fraction_digits
|
31
|
+
if quantum_type.fraction_digits is not None
|
32
|
+
else Expression(expr="0")
|
33
|
+
),
|
34
|
+
)
|
35
|
+
normalized_qnum.set_bounds(quantum_type.get_bounds())
|
36
|
+
return normalized_qnum
|
37
|
+
|
38
|
+
|
39
|
+
def _same_shape(quantum_type_1: QuantumType, quantum_type_2: QuantumType) -> bool:
|
40
|
+
if isinstance(quantum_type_1, QuantumBit) and isinstance(
|
41
|
+
quantum_type_2, QuantumBit
|
42
|
+
):
|
43
|
+
return True
|
44
|
+
if (
|
45
|
+
isinstance(quantum_type_1, QuantumNumeric)
|
46
|
+
and isinstance(quantum_type_2, QuantumNumeric)
|
47
|
+
and (
|
48
|
+
not quantum_type_1.has_size_in_bits
|
49
|
+
or not quantum_type_2.has_size_in_bits
|
50
|
+
or quantum_type_1.size_in_bits == quantum_type_2.size_in_bits
|
51
|
+
)
|
52
|
+
):
|
53
|
+
return True
|
54
|
+
if (
|
55
|
+
isinstance(quantum_type_1, QuantumBitvector)
|
56
|
+
and isinstance(quantum_type_2, QuantumBitvector)
|
57
|
+
and (
|
58
|
+
not quantum_type_1.has_constant_length
|
59
|
+
or not quantum_type_2.has_constant_length
|
60
|
+
or quantum_type_1.length_value == quantum_type_2.length_value
|
61
|
+
)
|
62
|
+
and _same_shape(quantum_type_1.element_type, quantum_type_2.element_type)
|
63
|
+
):
|
64
|
+
return True
|
65
|
+
return (
|
66
|
+
isinstance(quantum_type_1, TypeName)
|
67
|
+
and quantum_type_1.has_fields
|
68
|
+
and isinstance(quantum_type_2, TypeName)
|
69
|
+
and quantum_type_2.has_fields
|
70
|
+
and quantum_type_1.name == quantum_type_2.name
|
71
|
+
and all(
|
72
|
+
_same_shape(
|
73
|
+
quantum_type_1.fields[field_name], quantum_type_2.fields[field_name]
|
74
|
+
)
|
75
|
+
for field_name in quantum_type_1.fields
|
76
|
+
)
|
77
|
+
)
|
78
|
+
|
79
|
+
|
80
|
+
def _inject_qnum_type_attributes(
|
81
|
+
from_type: QuantumType, to_type: QuantumNumeric
|
82
|
+
) -> QuantumNumeric:
|
83
|
+
size: Optional[Expression]
|
84
|
+
if from_type.has_size_in_bits:
|
85
|
+
size = Expression(expr=str(from_type.size_in_bits))
|
86
|
+
else:
|
87
|
+
size = to_type.size
|
88
|
+
if to_type.is_signed is not None:
|
89
|
+
if to_type.is_signed.is_evaluated():
|
90
|
+
is_signed = Expression(expr=str(to_type.sign_value))
|
91
|
+
else:
|
92
|
+
is_signed = Expression(expr="False")
|
93
|
+
else:
|
94
|
+
is_signed = None
|
95
|
+
if to_type.fraction_digits is not None:
|
96
|
+
if to_type.fraction_digits.is_evaluated():
|
97
|
+
fraction_digits = Expression(expr=str(to_type.fraction_digits_value))
|
98
|
+
else:
|
99
|
+
fraction_digits = Expression(expr="0")
|
100
|
+
else:
|
101
|
+
fraction_digits = None
|
102
|
+
if isinstance(from_type, QuantumNumeric) and not to_type.has_size_in_bits:
|
103
|
+
if (
|
104
|
+
is_signed is None
|
105
|
+
and from_type.is_signed is not None
|
106
|
+
and from_type.is_signed.is_evaluated()
|
107
|
+
):
|
108
|
+
is_signed = from_type.is_signed
|
109
|
+
if (
|
110
|
+
fraction_digits is None
|
111
|
+
and from_type.fraction_digits is not None
|
112
|
+
and from_type.fraction_digits.is_evaluated()
|
113
|
+
):
|
114
|
+
fraction_digits = from_type.fraction_digits
|
115
|
+
if size is not None and is_signed is None:
|
116
|
+
is_signed = Expression(expr="False")
|
117
|
+
if size is not None and fraction_digits is None:
|
118
|
+
fraction_digits = Expression(expr="0")
|
119
|
+
updated_type = QuantumNumeric(
|
120
|
+
size=size, is_signed=is_signed, fraction_digits=fraction_digits
|
121
|
+
)
|
122
|
+
updated_type.set_bounds(to_type.get_bounds())
|
123
|
+
set_bounds(_normalized_qnum(from_type), updated_type)
|
124
|
+
return updated_type
|
125
|
+
|
126
|
+
|
127
|
+
def _inject_qarray_type_attributes(
|
128
|
+
from_type: QuantumType, to_type: QuantumBitvector
|
129
|
+
) -> Optional[QuantumBitvector]:
|
130
|
+
if _same_shape(from_type, to_type):
|
131
|
+
if TYPE_CHECKING:
|
132
|
+
assert isinstance(from_type, QuantumBitvector)
|
133
|
+
if to_type.has_length:
|
134
|
+
length = to_type.length
|
135
|
+
elif from_type.has_length:
|
136
|
+
length = from_type.length
|
137
|
+
elif from_type.has_size_in_bits:
|
138
|
+
raise ClassiqExpansionError(
|
139
|
+
f"Could not infer the length attribute of type {to_type.qmod_type_name}"
|
140
|
+
)
|
141
|
+
else:
|
142
|
+
length = None
|
143
|
+
element_type = inject_quantum_type_attributes(
|
144
|
+
from_type.element_type, to_type.element_type
|
145
|
+
)
|
146
|
+
else:
|
147
|
+
if to_type.has_constant_length:
|
148
|
+
if (
|
149
|
+
from_type.has_size_in_bits
|
150
|
+
and from_type.size_in_bits % to_type.length_value != 0
|
151
|
+
):
|
152
|
+
return None
|
153
|
+
length = to_type.length
|
154
|
+
elif from_type.has_size_in_bits:
|
155
|
+
if not to_type.element_type.has_size_in_bits:
|
156
|
+
raise ClassiqExpansionError(
|
157
|
+
f"Could not infer the length attribute of type "
|
158
|
+
f"{to_type.qmod_type_name}"
|
159
|
+
)
|
160
|
+
if from_type.size_in_bits % to_type.element_type.size_in_bits != 0:
|
161
|
+
return None
|
162
|
+
length = Expression(
|
163
|
+
expr=str(from_type.size_in_bits // to_type.element_type.size_in_bits)
|
164
|
+
)
|
165
|
+
else:
|
166
|
+
length = None
|
167
|
+
if length is not None and from_type.has_size_in_bits:
|
168
|
+
element_type = inject_quantum_type_attributes(
|
169
|
+
QuantumBitvector(
|
170
|
+
length=Expression(
|
171
|
+
expr=str(from_type.size_in_bits // length.to_int_value())
|
172
|
+
)
|
173
|
+
),
|
174
|
+
to_type.element_type,
|
175
|
+
)
|
176
|
+
else:
|
177
|
+
element_type = inject_quantum_type_attributes(
|
178
|
+
QuantumBitvector(), to_type.element_type
|
179
|
+
)
|
180
|
+
return QuantumBitvector(element_type=element_type, length=length)
|
181
|
+
|
182
|
+
|
183
|
+
def _inject_qstruct_type_attributes(
|
184
|
+
from_type: QuantumType, to_type: TypeName
|
185
|
+
) -> Optional[TypeName]:
|
186
|
+
if isinstance(from_type, TypeName) and from_type.name == to_type.name:
|
187
|
+
fields = {
|
188
|
+
field_name: inject_quantum_type_attributes(
|
189
|
+
from_type.fields[field_name], to_type.fields[field_name]
|
190
|
+
)
|
191
|
+
for field_name in to_type.fields
|
192
|
+
}
|
193
|
+
if None in fields.values():
|
194
|
+
return None
|
195
|
+
elif not from_type.has_size_in_bits:
|
196
|
+
fields = {
|
197
|
+
field_name: inject_quantum_type_attributes(QuantumBitvector(), field_type)
|
198
|
+
for field_name, field_type in to_type.fields.items()
|
199
|
+
}
|
200
|
+
else:
|
201
|
+
initialized_fields = {
|
202
|
+
field_name: field_type.has_size_in_bits
|
203
|
+
for field_name, field_type in to_type.fields.items()
|
204
|
+
}
|
205
|
+
if sum(initialized_fields.values()) == len(initialized_fields) - 1:
|
206
|
+
flexible_field_name = [
|
207
|
+
field_name
|
208
|
+
for field_name, is_initialized in initialized_fields.items()
|
209
|
+
if not is_initialized
|
210
|
+
][0]
|
211
|
+
flexible_field_size = from_type.size_in_bits - sum(
|
212
|
+
field_type.size_in_bits
|
213
|
+
for field_name, field_type in to_type.fields.items()
|
214
|
+
if initialized_fields[field_name]
|
215
|
+
)
|
216
|
+
flexible_field_type = inject_quantum_type_attributes(
|
217
|
+
QuantumBitvector(length=Expression(expr=str(flexible_field_size))),
|
218
|
+
to_type.fields[flexible_field_name],
|
219
|
+
)
|
220
|
+
if flexible_field_type is None:
|
221
|
+
return None
|
222
|
+
fields = {
|
223
|
+
field_name: (
|
224
|
+
flexible_field_type
|
225
|
+
if field_name == flexible_field_name
|
226
|
+
else inject_quantum_type_attributes(QuantumBitvector(), field_type)
|
227
|
+
)
|
228
|
+
for field_name, field_type in to_type.fields.items()
|
229
|
+
}
|
230
|
+
else:
|
231
|
+
fields = {
|
232
|
+
field_name: inject_quantum_type_attributes(
|
233
|
+
QuantumBitvector(), field_type
|
234
|
+
)
|
235
|
+
for field_name, field_type in to_type.fields.items()
|
236
|
+
}
|
237
|
+
classical_type = TypeName(name=to_type.name)
|
238
|
+
classical_type.set_fields(fields) # type:ignore[arg-type]
|
239
|
+
return classical_type
|
240
|
+
|
241
|
+
|
242
|
+
def inject_quantum_type_attributes(
|
243
|
+
from_type: QuantumType, to_type: QuantumType
|
244
|
+
) -> Optional[QuantumType]:
|
245
|
+
for qmod_type in (from_type, to_type):
|
246
|
+
if isinstance(qmod_type, TypeName) and not qmod_type.has_fields:
|
247
|
+
raise ClassiqInternalExpansionError
|
248
|
+
if to_type.has_size_in_bits and (
|
249
|
+
(from_type.has_size_in_bits and to_type.size_in_bits != from_type.size_in_bits)
|
250
|
+
or (from_type.minimal_size_in_bits > to_type.size_in_bits)
|
251
|
+
):
|
252
|
+
return None
|
253
|
+
if isinstance(to_type, QuantumBit):
|
254
|
+
return QuantumBit()
|
255
|
+
if isinstance(to_type, QuantumNumeric):
|
256
|
+
return _inject_qnum_type_attributes(from_type, to_type)
|
257
|
+
if isinstance(to_type, QuantumBitvector):
|
258
|
+
return _inject_qarray_type_attributes(from_type, to_type)
|
259
|
+
if isinstance(to_type, TypeName):
|
260
|
+
return _inject_qstruct_type_attributes(from_type, to_type)
|
261
|
+
raise ClassiqInternalExpansionError
|
262
|
+
|
263
|
+
|
264
|
+
def inject_quantum_type_attributes_inplace(
|
265
|
+
from_type: QuantumType, to_type: QuantumType
|
266
|
+
) -> bool:
|
267
|
+
updated_type = inject_quantum_type_attributes(from_type, to_type)
|
268
|
+
if updated_type is None:
|
269
|
+
return False
|
270
|
+
if isinstance(to_type, QuantumBit) and isinstance(updated_type, QuantumBit):
|
271
|
+
return True
|
272
|
+
if isinstance(to_type, QuantumNumeric) and isinstance(updated_type, QuantumNumeric):
|
273
|
+
to_type.size = updated_type.size
|
274
|
+
to_type.is_signed = updated_type.is_signed
|
275
|
+
to_type.fraction_digits = updated_type.fraction_digits
|
276
|
+
to_type.set_bounds(updated_type.get_bounds())
|
277
|
+
return True
|
278
|
+
if isinstance(to_type, QuantumBitvector) and isinstance(
|
279
|
+
updated_type, QuantumBitvector
|
280
|
+
):
|
281
|
+
to_type.length = updated_type.length
|
282
|
+
to_type.element_type = updated_type.element_type
|
283
|
+
return True
|
284
|
+
if (
|
285
|
+
isinstance(to_type, TypeName)
|
286
|
+
and to_type.has_fields
|
287
|
+
and isinstance(updated_type, TypeName)
|
288
|
+
and updated_type.has_fields
|
289
|
+
):
|
290
|
+
to_type.set_fields(updated_type.fields)
|
291
|
+
return True
|
292
|
+
raise ClassiqInternalExpansionError
|
@@ -3,15 +3,10 @@ from classiq.interface.exceptions import (
|
|
3
3
|
ClassiqInternalExpansionError,
|
4
4
|
)
|
5
5
|
from classiq.interface.generator.expressions.expression import Expression
|
6
|
-
from classiq.interface.generator.functions.concrete_types import ConcreteQuantumType
|
7
|
-
from classiq.interface.generator.functions.type_name import (
|
8
|
-
TypeName,
|
9
|
-
)
|
10
6
|
from classiq.interface.model.bind_operation import BindOperation
|
11
7
|
from classiq.interface.model.inplace_binary_operation import BinaryOperation
|
12
8
|
from classiq.interface.model.quantum_type import (
|
13
9
|
QuantumBit,
|
14
|
-
QuantumBitvector,
|
15
10
|
QuantumNumeric,
|
16
11
|
QuantumScalar,
|
17
12
|
QuantumType,
|
@@ -20,129 +15,6 @@ from classiq.interface.model.quantum_type import (
|
|
20
15
|
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
21
16
|
|
22
17
|
|
23
|
-
def copy_type_information(
|
24
|
-
from_type: QuantumType,
|
25
|
-
to_type: QuantumType,
|
26
|
-
to_param_name: str,
|
27
|
-
) -> None:
|
28
|
-
if isinstance(to_type, QuantumBit):
|
29
|
-
set_size(to_type, from_type.size_in_bits, to_param_name)
|
30
|
-
elif isinstance(to_type, QuantumNumeric):
|
31
|
-
if to_type.size is None and isinstance(from_type, QuantumNumeric):
|
32
|
-
to_type.is_signed = Expression(expr=str(from_type.sign_value))
|
33
|
-
to_type.fraction_digits = Expression(
|
34
|
-
expr=str(from_type.fraction_digits_value)
|
35
|
-
)
|
36
|
-
set_size(to_type, from_type.size_in_bits, to_param_name)
|
37
|
-
set_bounds(from_type, to_type)
|
38
|
-
elif isinstance(to_type, QuantumBitvector):
|
39
|
-
if isinstance(from_type, QuantumBitvector) and type( # noqa: E721
|
40
|
-
from_type.element_type
|
41
|
-
) == type(to_type.element_type):
|
42
|
-
copy_type_information(
|
43
|
-
from_type.element_type, to_type.element_type, to_param_name
|
44
|
-
)
|
45
|
-
set_size(to_type, from_type.size_in_bits, to_param_name)
|
46
|
-
elif isinstance(to_type, TypeName):
|
47
|
-
if isinstance(from_type, TypeName) and from_type.name == to_type.name:
|
48
|
-
for field in from_type.fields:
|
49
|
-
copy_type_information(
|
50
|
-
from_type.fields[field], to_type.fields[field], to_param_name
|
51
|
-
)
|
52
|
-
set_size(to_type, from_type.size_in_bits, to_param_name)
|
53
|
-
else:
|
54
|
-
raise ClassiqInternalExpansionError
|
55
|
-
|
56
|
-
|
57
|
-
def set_size(quantum_type: QuantumType, size: int, param_name: str) -> None:
|
58
|
-
if size <= 0:
|
59
|
-
raise ClassiqExpansionError(
|
60
|
-
f"Size for {param_name!r} was deduced to be non-positive: {size!r}"
|
61
|
-
)
|
62
|
-
|
63
|
-
if quantum_type.has_size_in_bits and quantum_type.size_in_bits != size:
|
64
|
-
raise ClassiqExpansionError(
|
65
|
-
f"Size mismatch for variable {param_name!r} between declared size {quantum_type.size_in_bits} and assigned size {size}"
|
66
|
-
)
|
67
|
-
|
68
|
-
if isinstance(quantum_type, QuantumNumeric):
|
69
|
-
quantum_type.size = Expression(expr=str(size))
|
70
|
-
if not quantum_type.has_sign or not quantum_type.has_fraction_digits:
|
71
|
-
quantum_type.is_signed = Expression(expr="False")
|
72
|
-
quantum_type.fraction_digits = Expression(expr="0")
|
73
|
-
elif isinstance(quantum_type, QuantumBitvector):
|
74
|
-
if quantum_type.has_length:
|
75
|
-
if size % quantum_type.length_value != 0:
|
76
|
-
raise ClassiqExpansionError(
|
77
|
-
f"Size mismatch for variable {param_name!r}. Cannot fit {size} "
|
78
|
-
f"qubits into an array of {quantum_type.length_value} elements."
|
79
|
-
)
|
80
|
-
set_size(
|
81
|
-
quantum_type.element_type,
|
82
|
-
size // quantum_type.length_value,
|
83
|
-
param_name,
|
84
|
-
)
|
85
|
-
set_length_by_size(quantum_type, size, param_name)
|
86
|
-
elif isinstance(quantum_type, TypeName):
|
87
|
-
fields_without_size = [
|
88
|
-
field_type
|
89
|
-
for field_type in quantum_type.fields.values()
|
90
|
-
if not field_type.has_size_in_bits
|
91
|
-
]
|
92
|
-
if len(fields_without_size) > 1:
|
93
|
-
raise ClassiqInternalExpansionError(
|
94
|
-
f"QuantumStruct should have at most one field without "
|
95
|
-
f"predetermined size. Found {fields_without_size}."
|
96
|
-
)
|
97
|
-
if len(fields_without_size) == 1:
|
98
|
-
predetermined_size_part = sum(
|
99
|
-
field_type.size_in_bits if field_type.has_size_in_bits else 0
|
100
|
-
for field_type in quantum_type.fields.values()
|
101
|
-
)
|
102
|
-
set_size(fields_without_size[0], size - predetermined_size_part, param_name)
|
103
|
-
|
104
|
-
|
105
|
-
def set_element_type(
|
106
|
-
quantum_array: QuantumBitvector, element_type: ConcreteQuantumType
|
107
|
-
) -> None:
|
108
|
-
quantum_array.element_type = element_type
|
109
|
-
|
110
|
-
|
111
|
-
def set_length(quantum_array: QuantumBitvector, length: int) -> None:
|
112
|
-
quantum_array.length = Expression(expr=str(length))
|
113
|
-
|
114
|
-
|
115
|
-
def set_length_by_size(
|
116
|
-
quantum_array: QuantumBitvector, size: int, param_name: str
|
117
|
-
) -> None:
|
118
|
-
if size <= 0:
|
119
|
-
raise ClassiqExpansionError(
|
120
|
-
f"Size for {param_name!r} was deduced to be non-positive: {size!r}"
|
121
|
-
)
|
122
|
-
|
123
|
-
if quantum_array.has_size_in_bits and quantum_array.size_in_bits != size:
|
124
|
-
raise ClassiqExpansionError(
|
125
|
-
f"Size mismatch for variable {param_name!r} between declared size "
|
126
|
-
f"{quantum_array.size_in_bits} ({quantum_array.length_value} elements of "
|
127
|
-
f"size {quantum_array.element_type.size_in_bits}) and assigned size {size}."
|
128
|
-
)
|
129
|
-
|
130
|
-
if not quantum_array.element_type.has_size_in_bits:
|
131
|
-
raise ClassiqExpansionError(
|
132
|
-
f"Could not infer element size for array {param_name!r}."
|
133
|
-
)
|
134
|
-
element_size = quantum_array.element_type.size_in_bits
|
135
|
-
|
136
|
-
if size % element_size != 0:
|
137
|
-
raise ClassiqExpansionError(
|
138
|
-
f"Size mismatch for variable {param_name!r}. Cannot fit elements of type "
|
139
|
-
f"{quantum_array.element_type.qmod_type_name} (size {element_size}) into "
|
140
|
-
f"{size} qubits."
|
141
|
-
)
|
142
|
-
|
143
|
-
quantum_array.length = Expression(expr=str(size // element_size))
|
144
|
-
|
145
|
-
|
146
18
|
def validate_bind_targets(bind: BindOperation, scope: Scope) -> None:
|
147
19
|
illegal_qnum_bind_targets = []
|
148
20
|
for out_handle in bind.out_handles:
|
@@ -152,9 +24,6 @@ def validate_bind_targets(bind: BindOperation, scope: Scope) -> None:
|
|
152
24
|
continue
|
153
25
|
if not out_var_type.has_size_in_bits:
|
154
26
|
illegal_qnum_bind_targets.append(str(out_var.handle))
|
155
|
-
elif not out_var_type.has_sign:
|
156
|
-
assert not out_var_type.has_fraction_digits
|
157
|
-
illegal_qnum_bind_targets.append(str(out_var.handle))
|
158
27
|
if len(illegal_qnum_bind_targets) > 0:
|
159
28
|
raise ClassiqExpansionError(
|
160
29
|
f"QNum bind targets {illegal_qnum_bind_targets!r} must be declared or initialized with size, sign, and fraction digits"
|
@@ -530,7 +530,7 @@ class ExecutionSession:
|
|
530
530
|
return PauliOperator(pauli_list=pauli_list)
|
531
531
|
pauli_list = []
|
532
532
|
for term in cast(list, hamiltonian.terms):
|
533
|
-
paulis = ["I"] *
|
533
|
+
paulis = ["I"] * hamiltonian.num_qubits
|
534
534
|
for indexed_pauli in term.paulis:
|
535
535
|
paulis[len(paulis) - indexed_pauli.index - 1] = indexed_pauli.pauli.name
|
536
536
|
pauli_list.append(("".join(paulis), term.coefficient))
|
classiq/execution/qnn.py
CHANGED
@@ -15,6 +15,7 @@ from classiq.interface.executor.quantum_code import Arguments, MultipleArguments
|
|
15
15
|
|
16
16
|
from classiq import QuantumProgram
|
17
17
|
from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
|
18
|
+
pauli_operator_to_hamiltonian,
|
18
19
|
pauli_operator_to_sparse_hamiltonian,
|
19
20
|
)
|
20
21
|
from classiq.execution.execution_session import ExecutionSession
|
@@ -27,7 +28,9 @@ def _execute_qnn_estimate(
|
|
27
28
|
arguments: list[Arguments],
|
28
29
|
observable: PauliOperator,
|
29
30
|
) -> ResultsCollection:
|
30
|
-
hamiltonian = pauli_operator_to_sparse_hamiltonian(
|
31
|
+
hamiltonian = pauli_operator_to_sparse_hamiltonian(
|
32
|
+
pauli_operator_to_hamiltonian(observable.pauli_list)
|
33
|
+
)
|
31
34
|
return [
|
32
35
|
TaggedEstimationResult(
|
33
36
|
name=DEFAULT_RESULT_NAME,
|
@@ -8,7 +8,7 @@ from classiq._internals.async_utils import syncify_function
|
|
8
8
|
|
9
9
|
PROVIDER_MAPPER = {
|
10
10
|
ProviderVendor.IONQ: "IONQ",
|
11
|
-
ProviderVendor.IBM_QUANTUM: "
|
11
|
+
ProviderVendor.IBM_QUANTUM: "IBM_CLOUD",
|
12
12
|
ProviderVendor.AZURE_QUANTUM: "AZURE",
|
13
13
|
ProviderVendor.AMAZON_BRAKET: "AMAZON",
|
14
14
|
ProviderVendor.GOOGLE: "GOOGLE",
|
classiq/interface/_version.py
CHANGED