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.
Files changed (96) hide show
  1. classiq/__init__.py +2 -0
  2. classiq/applications/chemistry/hartree_fock.py +5 -1
  3. classiq/applications/chemistry/op_utils.py +2 -2
  4. classiq/applications/combinatorial_helpers/encoding_mapping.py +11 -15
  5. classiq/applications/combinatorial_helpers/encoding_utils.py +6 -6
  6. classiq/applications/combinatorial_helpers/memory.py +4 -4
  7. classiq/applications/combinatorial_helpers/optimization_model.py +5 -5
  8. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +6 -10
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +27 -26
  10. classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
  11. classiq/applications/combinatorial_helpers/transformations/encoding.py +4 -6
  12. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +4 -4
  13. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +2 -2
  14. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +3 -3
  15. classiq/applications/combinatorial_optimization/combinatorial_problem.py +4 -0
  16. classiq/applications/hamiltonian/pauli_decomposition.py +33 -1
  17. classiq/evaluators/argument_types.py +15 -6
  18. classiq/evaluators/parameter_types.py +43 -39
  19. classiq/evaluators/qmod_annotated_expression.py +88 -11
  20. classiq/evaluators/qmod_expression_visitors/out_of_place_node_transformer.py +19 -0
  21. classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +54 -11
  22. classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +40 -25
  23. classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +29 -59
  24. classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +12 -5
  25. classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +175 -28
  26. classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +21 -14
  27. classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +9 -5
  28. classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +20 -1
  29. classiq/evaluators/qmod_node_evaluators/min_max_evaluation.py +97 -0
  30. classiq/evaluators/qmod_node_evaluators/name_evaluation.py +11 -26
  31. classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +56 -0
  32. classiq/evaluators/qmod_node_evaluators/piecewise_evaluation.py +40 -0
  33. classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +2 -3
  34. classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +48 -21
  35. classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +53 -9
  36. classiq/evaluators/qmod_node_evaluators/utils.py +27 -5
  37. classiq/evaluators/qmod_type_inference/classical_type_inference.py +188 -0
  38. classiq/evaluators/qmod_type_inference/quantum_type_inference.py +292 -0
  39. classiq/evaluators/quantum_type_utils.py +0 -131
  40. classiq/execution/execution_session.py +1 -1
  41. classiq/execution/qnn.py +4 -1
  42. classiq/execution/user_budgets.py +1 -1
  43. classiq/interface/_version.py +1 -1
  44. classiq/interface/backend/backend_preferences.py +10 -30
  45. classiq/interface/backend/quantum_backend_providers.py +63 -52
  46. classiq/interface/generator/arith/binary_ops.py +107 -115
  47. classiq/interface/generator/arith/extremum_operations.py +33 -45
  48. classiq/interface/generator/arith/number_utils.py +4 -1
  49. classiq/interface/generator/circuit_code/types_and_constants.py +0 -9
  50. classiq/interface/generator/compiler_keywords.py +2 -0
  51. classiq/interface/generator/function_param_list.py +133 -5
  52. classiq/interface/generator/functions/classical_type.py +59 -2
  53. classiq/interface/generator/functions/qmod_python_interface.py +15 -0
  54. classiq/interface/generator/functions/type_name.py +6 -0
  55. classiq/interface/generator/model/preferences/preferences.py +1 -17
  56. classiq/interface/generator/quantum_program.py +1 -13
  57. classiq/interface/helpers/model_normalizer.py +2 -2
  58. classiq/interface/helpers/text_utils.py +7 -2
  59. classiq/interface/interface_version.py +1 -1
  60. classiq/interface/model/classical_if.py +40 -0
  61. classiq/interface/model/handle_binding.py +28 -16
  62. classiq/interface/model/quantum_type.py +61 -2
  63. classiq/interface/pretty_print/expression_to_qmod.py +24 -11
  64. classiq/interface/pyomo_extension/__init__.py +0 -4
  65. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +2 -2
  66. classiq/model_expansions/arithmetic.py +43 -1
  67. classiq/model_expansions/arithmetic_compute_result_attrs.py +255 -0
  68. classiq/model_expansions/capturing/captured_vars.py +2 -5
  69. classiq/model_expansions/quantum_operations/allocate.py +22 -15
  70. classiq/model_expansions/quantum_operations/arithmetic/explicit_boolean_expressions.py +1 -3
  71. classiq/model_expansions/quantum_operations/assignment_result_processor.py +52 -71
  72. classiq/model_expansions/quantum_operations/bind.py +15 -7
  73. classiq/model_expansions/quantum_operations/call_emitter.py +2 -10
  74. classiq/model_expansions/quantum_operations/classical_var_emitter.py +6 -0
  75. classiq/open_library/functions/__init__.py +3 -0
  76. classiq/open_library/functions/lcu.py +117 -0
  77. classiq/qmod/builtins/enums.py +2 -2
  78. classiq/qmod/builtins/structs.py +33 -18
  79. classiq/qmod/pretty_print/expression_to_python.py +7 -9
  80. {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/METADATA +3 -3
  81. {classiq-0.86.0.dist-info → classiq-0.87.0.dist-info}/RECORD +83 -89
  82. classiq/interface/generator/amplitude_estimation.py +0 -34
  83. classiq/interface/generator/function_param_list_without_self_reference.py +0 -160
  84. classiq/interface/generator/grover_diffuser.py +0 -93
  85. classiq/interface/generator/grover_operator.py +0 -106
  86. classiq/interface/generator/oracles/__init__.py +0 -3
  87. classiq/interface/generator/oracles/arithmetic_oracle.py +0 -82
  88. classiq/interface/generator/oracles/custom_oracle.py +0 -65
  89. classiq/interface/generator/oracles/oracle_abc.py +0 -76
  90. classiq/interface/generator/oracles/oracle_function_param_list.py +0 -6
  91. classiq/interface/generator/piecewise_linear_amplitude_loading.py +0 -165
  92. classiq/interface/generator/qpe.py +0 -169
  93. classiq/interface/grover/grover_modelling_params.py +0 -13
  94. classiq/model_expansions/transformers/var_splitter.py +0 -224
  95. /classiq/{interface/grover → evaluators/qmod_type_inference}/__init__.py +0 -0
  96. {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"] * cast(int, hamiltonian.num_qubits)
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(observable.pauli_list)
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: "IBMQ",
11
+ ProviderVendor.IBM_QUANTUM: "IBM_CLOUD",
12
12
  ProviderVendor.AZURE_QUANTUM: "AZURE",
13
13
  ProviderVendor.AMAZON_BRAKET: "AMAZON",
14
14
  ProviderVendor.GOOGLE: "GOOGLE",
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.86.0'
6
+ SEMVER_VERSION = '0.87.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))