classiq 0.54.0__py3-none-any.whl → 0.56.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/interface/_version.py +1 -1
- classiq/interface/debug_info/debug_info.py +11 -0
- classiq/interface/executor/result.py +0 -3
- classiq/interface/generator/functions/builtins/internal_operators.py +9 -1
- classiq/interface/generator/generated_circuit_data.py +0 -1
- classiq/interface/generator/model/preferences/preferences.py +4 -0
- classiq/interface/generator/types/compilation_metadata.py +5 -0
- classiq/interface/generator/visitor.py +13 -1
- classiq/interface/ide/visual_model.py +5 -1
- classiq/interface/interface_version.py +1 -1
- classiq/interface/model/control.py +22 -1
- classiq/interface/model/handle_binding.py +28 -0
- classiq/interface/model/model.py +4 -0
- classiq/interface/model/native_function_definition.py +1 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +2 -26
- classiq/interface/model/quantum_statement.py +6 -0
- classiq/model_expansions/capturing/mangling_utils.py +22 -0
- classiq/model_expansions/capturing/propagated_var_stack.py +36 -25
- classiq/model_expansions/closure.py +77 -12
- classiq/model_expansions/function_builder.py +9 -10
- classiq/model_expansions/generative_functions.py +2 -2
- classiq/model_expansions/interpreter.py +29 -26
- classiq/model_expansions/quantum_operations/control.py +114 -29
- classiq/model_expansions/quantum_operations/emitter.py +37 -11
- classiq/model_expansions/quantum_operations/expression_operation.py +80 -18
- classiq/model_expansions/quantum_operations/power.py +5 -0
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +7 -37
- classiq/model_expansions/quantum_operations/quantum_function_call.py +2 -32
- classiq/model_expansions/quantum_operations/repeat.py +5 -0
- classiq/model_expansions/quantum_operations/within_apply.py +0 -16
- classiq/model_expansions/scope_initialization.py +2 -3
- classiq/qmod/builtins/functions/arithmetic.py +0 -2
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +0 -12
- classiq/qmod/builtins/functions/exponentiation.py +0 -6
- classiq/qmod/builtins/functions/grover.py +0 -17
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +0 -5
- classiq/qmod/builtins/functions/modular_exponentiation.py +0 -3
- classiq/qmod/builtins/functions/qaoa_penalty.py +0 -8
- classiq/qmod/builtins/functions/qft_functions.py +0 -3
- classiq/qmod/builtins/functions/qpe.py +0 -6
- classiq/qmod/builtins/functions/qsvt.py +0 -12
- classiq/qmod/builtins/functions/standard_gates.py +0 -88
- classiq/qmod/builtins/functions/state_preparation.py +7 -15
- classiq/qmod/builtins/functions/swap_test.py +0 -3
- classiq/qmod/builtins/operations.py +152 -17
- classiq/qmod/create_model_function.py +10 -12
- classiq/qmod/model_state_container.py +5 -1
- classiq/qmod/native/pretty_printer.py +6 -1
- classiq/qmod/pretty_print/pretty_printer.py +25 -11
- classiq/qmod/qmod_constant.py +31 -3
- classiq/qmod/quantum_function.py +25 -19
- classiq/qmod/synthesize_separately.py +1 -2
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/METADATA +2 -3
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/RECORD +55 -55
- classiq/model_expansions/call_to_model_converter.py +0 -190
- {classiq-0.54.0.dist-info → classiq-0.56.0.dist-info}/WHEEL +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
import ast
|
2
2
|
from abc import abstractmethod
|
3
3
|
from itertools import chain
|
4
|
-
from typing import TYPE_CHECKING, TypeVar
|
4
|
+
from typing import TYPE_CHECKING, TypeVar, Union
|
5
5
|
|
6
6
|
from classiq.interface.exceptions import (
|
7
7
|
ClassiqExpansionError,
|
@@ -12,7 +12,9 @@ from classiq.interface.generator.expressions.evaluated_expression import (
|
|
12
12
|
)
|
13
13
|
from classiq.interface.generator.expressions.expression import Expression
|
14
14
|
from classiq.interface.generator.functions.type_name import TypeName
|
15
|
+
from classiq.interface.generator.visitor import NodeType, Transformer
|
15
16
|
from classiq.interface.model.bind_operation import BindOperation
|
17
|
+
from classiq.interface.model.control import Control
|
16
18
|
from classiq.interface.model.handle_binding import (
|
17
19
|
FieldHandleBinding,
|
18
20
|
HandleBinding,
|
@@ -20,6 +22,7 @@ from classiq.interface.model.handle_binding import (
|
|
20
22
|
SubscriptHandleBinding,
|
21
23
|
)
|
22
24
|
from classiq.interface.model.quantum_expressions.quantum_expression import (
|
25
|
+
QuantumAssignmentOperation,
|
23
26
|
QuantumExpressionOperation,
|
24
27
|
)
|
25
28
|
from classiq.interface.model.quantum_type import (
|
@@ -38,6 +41,7 @@ from classiq.model_expansions.scope import QuantumSymbol
|
|
38
41
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
39
42
|
|
40
43
|
ExpressionOperationT = TypeVar("ExpressionOperationT", bound=QuantumExpressionOperation)
|
44
|
+
AST_NODE = TypeVar("AST_NODE", bound=NodeType)
|
41
45
|
|
42
46
|
|
43
47
|
class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
@@ -49,7 +53,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
49
53
|
self,
|
50
54
|
op: ExpressionOperationT,
|
51
55
|
expression: Expression,
|
52
|
-
symbols_to_split:
|
56
|
+
symbols_to_split: dict[QuantumSymbol, set[HandleBinding]],
|
53
57
|
) -> None:
|
54
58
|
symbols_parts, bind_ops = self._get_bind_ops(symbols_to_split)
|
55
59
|
|
@@ -79,8 +83,8 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
79
83
|
)
|
80
84
|
)
|
81
85
|
|
82
|
-
@staticmethod
|
83
86
|
def _get_updated_op_split_symbols(
|
87
|
+
self,
|
84
88
|
op: ExpressionOperationT,
|
85
89
|
symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
|
86
90
|
) -> ExpressionOperationT:
|
@@ -109,11 +113,10 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
109
113
|
)
|
110
114
|
return new_expr
|
111
115
|
|
112
|
-
|
113
|
-
def _check_all_handles_were_replaced(new_expr_str: str) -> None:
|
116
|
+
def _check_all_handles_were_replaced(self, new_expr_str: str) -> None:
|
114
117
|
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
115
118
|
vrc.visit(ast.parse(new_expr_str))
|
116
|
-
for handle in vrc
|
119
|
+
for handle in self._get_handles(vrc):
|
117
120
|
if isinstance(
|
118
121
|
handle,
|
119
122
|
(SubscriptHandleBinding, SlicedHandleBinding, FieldHandleBinding),
|
@@ -122,12 +125,12 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
122
125
|
|
123
126
|
def _get_bind_ops(
|
124
127
|
self,
|
125
|
-
symbols_to_split:
|
128
|
+
symbols_to_split: dict[QuantumSymbol, set[HandleBinding]],
|
126
129
|
) -> tuple[list[list[tuple[QuantumSymbol, str]]], list[BindOperation]]:
|
127
130
|
bind_ops = []
|
128
131
|
symbols_parts = []
|
129
|
-
for symbol in symbols_to_split:
|
130
|
-
symbol_parts = self._get_symbol_parts(symbol)
|
132
|
+
for symbol, target_parts in symbols_to_split.items():
|
133
|
+
symbol_parts = self._get_symbol_parts(symbol, target_parts)
|
131
134
|
symbols_parts.append(symbol_parts)
|
132
135
|
bind_ops.append(
|
133
136
|
BindOperation(
|
@@ -141,11 +144,14 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
141
144
|
return symbols_parts, bind_ops
|
142
145
|
|
143
146
|
def _get_symbol_parts(
|
144
|
-
self, symbol: QuantumSymbol
|
147
|
+
self, symbol: QuantumSymbol, target_parts: set[HandleBinding]
|
145
148
|
) -> list[tuple[QuantumSymbol, str]]:
|
146
149
|
quantum_type = symbol.quantum_type
|
147
150
|
|
148
|
-
if
|
151
|
+
if all(
|
152
|
+
symbol.handle == target_part or symbol.handle not in target_part.prefixes()
|
153
|
+
for target_part in target_parts
|
154
|
+
) or isinstance(quantum_type, (QuantumBit, QuantumNumeric)):
|
149
155
|
return [
|
150
156
|
(
|
151
157
|
symbol,
|
@@ -161,7 +167,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
161
167
|
)
|
162
168
|
return list(
|
163
169
|
chain.from_iterable(
|
164
|
-
self._get_symbol_parts(symbol[idx])
|
170
|
+
self._get_symbol_parts(symbol[idx], target_parts)
|
165
171
|
for idx in range(quantum_type.length_value)
|
166
172
|
)
|
167
173
|
)
|
@@ -171,27 +177,33 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
171
177
|
|
172
178
|
return list(
|
173
179
|
chain.from_iterable(
|
174
|
-
self._get_symbol_parts(field_symbol)
|
180
|
+
self._get_symbol_parts(field_symbol, target_parts)
|
175
181
|
for field_symbol in symbol.fields.values()
|
176
182
|
)
|
177
183
|
)
|
178
184
|
|
179
|
-
def _get_symbols_to_split(
|
185
|
+
def _get_symbols_to_split(
|
186
|
+
self, expression: Expression
|
187
|
+
) -> dict[QuantumSymbol, set[HandleBinding]]:
|
180
188
|
vrc = VarRefCollector(ignore_duplicated_handles=True)
|
181
189
|
vrc.visit(ast.parse(expression.expr))
|
182
190
|
symbol_names_to_split = dict.fromkeys(
|
183
191
|
handle.name
|
184
|
-
for handle in vrc
|
192
|
+
for handle in self._get_handles(vrc)
|
185
193
|
if isinstance(handle, (SubscriptHandleBinding, FieldHandleBinding))
|
186
194
|
)
|
187
|
-
return
|
188
|
-
symbol
|
195
|
+
return {
|
196
|
+
symbol: {
|
197
|
+
handle.collapse()
|
198
|
+
for handle in vrc.var_handles
|
199
|
+
if handle.name == symbol.handle.name
|
200
|
+
}
|
189
201
|
for symbol_name in symbol_names_to_split
|
190
202
|
if isinstance(
|
191
203
|
symbol := self._current_scope[symbol_name].value,
|
192
204
|
QuantumSymbol,
|
193
205
|
)
|
194
|
-
|
206
|
+
}
|
195
207
|
|
196
208
|
def _evaluate_op_expression(self, op: ExpressionOperationT) -> Expression:
|
197
209
|
return self._evaluate_expression(op.expression)
|
@@ -214,3 +226,53 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
214
226
|
self._machine_precision,
|
215
227
|
)
|
216
228
|
return op_with_evaluated_types
|
229
|
+
|
230
|
+
@staticmethod
|
231
|
+
def _all_vars_boolean(op: QuantumExpressionOperation) -> bool:
|
232
|
+
if not all(
|
233
|
+
var_type.has_size_in_bits and var_type.size_in_bits == 1
|
234
|
+
for var_type in op.var_types.values()
|
235
|
+
):
|
236
|
+
return False
|
237
|
+
return not any(
|
238
|
+
isinstance(var_type, QuantumNumeric)
|
239
|
+
and (var_type.sign_value or var_type.fraction_digits_value > 0)
|
240
|
+
for var_type in op.var_types.values()
|
241
|
+
)
|
242
|
+
|
243
|
+
@staticmethod
|
244
|
+
def _is_res_boolean(op: Union[QuantumAssignmentOperation, Control]) -> bool:
|
245
|
+
if not (op.result_type.has_size_in_bits and op.result_type.size_in_bits == 1):
|
246
|
+
return False
|
247
|
+
return not (
|
248
|
+
isinstance(op.result_type, QuantumNumeric)
|
249
|
+
and (op.result_type.sign_value or op.result_type.fraction_digits_value > 0)
|
250
|
+
)
|
251
|
+
|
252
|
+
def _get_handles(self, collector: VarRefCollector) -> list[HandleBinding]:
|
253
|
+
return [
|
254
|
+
handle
|
255
|
+
for handle in collector.var_handles
|
256
|
+
if isinstance(self._interpreter.evaluate(handle.name).value, QuantumSymbol)
|
257
|
+
]
|
258
|
+
|
259
|
+
def _rewrite(
|
260
|
+
self,
|
261
|
+
subject: AST_NODE,
|
262
|
+
symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
|
263
|
+
) -> AST_NODE:
|
264
|
+
class ReplaceSplitVars(Transformer):
|
265
|
+
@staticmethod
|
266
|
+
def visit_HandleBinding(handle: HandleBinding) -> HandleBinding:
|
267
|
+
handle = handle.collapse()
|
268
|
+
for handle_to_replace, replacement in symbol_mapping.items():
|
269
|
+
handle = handle.replace_prefix(
|
270
|
+
handle_to_replace, HandleBinding(name=replacement[0])
|
271
|
+
)
|
272
|
+
return handle
|
273
|
+
|
274
|
+
@staticmethod
|
275
|
+
def visit_Expression(expr: Expression) -> Expression:
|
276
|
+
return self._update_op_expression(symbol_mapping, expr)
|
277
|
+
|
278
|
+
return ReplaceSplitVars().visit(subject)
|
@@ -2,6 +2,7 @@ from typing import Union
|
|
2
2
|
|
3
3
|
import sympy
|
4
4
|
|
5
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
5
6
|
from classiq.interface.generator.expressions.evaluated_expression import (
|
6
7
|
EvaluatedExpression,
|
7
8
|
)
|
@@ -72,4 +73,8 @@ class PowerEmitter(Emitter[Power]):
|
|
72
73
|
|
73
74
|
def _get_power_value(self) -> Union[int, sympy.Basic]:
|
74
75
|
power_value = self._interpreter.evaluate(self._power.power).value
|
76
|
+
if isinstance(power_value, int) and power_value < 0:
|
77
|
+
raise ClassiqExpansionError(
|
78
|
+
f"power exponent must be non-negative, got {power_value}"
|
79
|
+
)
|
75
80
|
return power_value
|
@@ -29,6 +29,7 @@ from classiq.interface.model.variable_declaration_statement import (
|
|
29
29
|
)
|
30
30
|
from classiq.interface.model.within_apply_operation import WithinApply
|
31
31
|
|
32
|
+
from classiq.model_expansions.capturing.mangling_utils import demangle_handle
|
32
33
|
from classiq.model_expansions.evaluators.quantum_type_utils import copy_type_information
|
33
34
|
from classiq.model_expansions.quantum_operations.expression_operation import (
|
34
35
|
ExpressionOperationEmitter,
|
@@ -101,7 +102,7 @@ class QuantumAssignmentOperationEmitter(
|
|
101
102
|
if (
|
102
103
|
op.operation_kind != ArithmeticOperationKind.InplaceXor
|
103
104
|
or op.result_type.size_in_bits > 1
|
104
|
-
or not _is_res_boolean(op)
|
105
|
+
or not self._is_res_boolean(op)
|
105
106
|
or target.quantum_type.size_in_bits > 1
|
106
107
|
or _is_constant(expression.expr)
|
107
108
|
):
|
@@ -141,7 +142,8 @@ class QuantumAssignmentOperationEmitter(
|
|
141
142
|
ArithmeticOperationKind.Assignment,
|
142
143
|
ArithmeticOperationKind.InplaceXor,
|
143
144
|
)
|
144
|
-
or not _all_vars_boolean(op)
|
145
|
+
or not self._all_vars_boolean(op)
|
146
|
+
or not self._is_res_boolean(op)
|
145
147
|
):
|
146
148
|
return op, expression, False
|
147
149
|
optimizer = BooleanExpressionOptimizer()
|
@@ -227,50 +229,18 @@ class QuantumAssignmentOperationEmitter(
|
|
227
229
|
self._interpreter.emit_statement(allocate_call)
|
228
230
|
return True
|
229
231
|
|
230
|
-
@staticmethod
|
231
232
|
def _get_updated_op_split_symbols(
|
233
|
+
self,
|
232
234
|
op: QuantumAssignmentOperation,
|
233
235
|
symbol_mapping: dict[HandleBinding, tuple[str, QuantumType]],
|
234
236
|
) -> QuantumAssignmentOperation:
|
235
|
-
if op.result_var not in symbol_mapping:
|
236
|
-
return op
|
237
|
-
handle_str, quantum_type = symbol_mapping[op.result_var]
|
238
|
-
if handle_str in op.expression.expr:
|
239
|
-
raise ClassiqExpansionError(
|
240
|
-
HANDLE_ERROR_MESSAGE.format(handle_str=str(op.result_var))
|
241
|
-
)
|
242
|
-
new_result_handle = HandleBinding(name=handle_str)
|
243
237
|
return op.model_copy(
|
244
|
-
update=dict(result_var=
|
238
|
+
update=dict(result_var=self._rewrite(op.result_var, symbol_mapping))
|
245
239
|
)
|
246
240
|
|
247
241
|
|
248
242
|
def _validate_naive_inplace_handles(qe: ArithmeticOperation) -> None:
|
249
243
|
if qe.result_var in qe.var_handles:
|
250
244
|
raise ClassiqExpansionError(
|
251
|
-
HANDLE_ERROR_MESSAGE.format(handle_str=str(qe.result_var))
|
245
|
+
HANDLE_ERROR_MESSAGE.format(handle_str=str(demangle_handle(qe.result_var)))
|
252
246
|
)
|
253
|
-
|
254
|
-
|
255
|
-
def _all_vars_boolean(op: ArithmeticOperation) -> bool:
|
256
|
-
if not all(
|
257
|
-
var_type.has_size_in_bits and var_type.size_in_bits == 1
|
258
|
-
for var_type in op.var_types.values()
|
259
|
-
):
|
260
|
-
return False
|
261
|
-
if any(
|
262
|
-
isinstance(var_type, QuantumNumeric)
|
263
|
-
and (var_type.sign_value or var_type.fraction_digits_value > 0)
|
264
|
-
for var_type in op.var_types.values()
|
265
|
-
):
|
266
|
-
return False
|
267
|
-
return _is_res_boolean(op)
|
268
|
-
|
269
|
-
|
270
|
-
def _is_res_boolean(op: ArithmeticOperation) -> bool:
|
271
|
-
if not (op.result_type.has_size_in_bits and op.result_type.size_in_bits == 1):
|
272
|
-
return False
|
273
|
-
return not (
|
274
|
-
isinstance(op.result_type, QuantumNumeric)
|
275
|
-
and (op.result_type.sign_value or op.result_type.fraction_digits_value > 0)
|
276
|
-
)
|
@@ -2,10 +2,6 @@ from typing import TYPE_CHECKING
|
|
2
2
|
|
3
3
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
4
4
|
|
5
|
-
from classiq.model_expansions.call_to_model_converter import (
|
6
|
-
BlockFunctionInfo,
|
7
|
-
CallToModelConverter,
|
8
|
-
)
|
9
5
|
from classiq.model_expansions.closure import FunctionClosure
|
10
6
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
11
7
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
@@ -18,37 +14,11 @@ class QuantumFunctionCallEmitter(Emitter[QuantumFunctionCall]):
|
|
18
14
|
def __init__(self, interpreter: "Interpreter") -> None:
|
19
15
|
super().__init__(interpreter)
|
20
16
|
self._model = self._interpreter._model
|
21
|
-
self._synthesized_separately_blocks = (
|
22
|
-
self._interpreter._synthesized_separately_blocks
|
23
|
-
)
|
24
17
|
|
25
18
|
def emit(self, call: QuantumFunctionCall, /) -> None:
|
26
|
-
function
|
27
|
-
FunctionClosure
|
28
|
-
)
|
19
|
+
function = self._interpreter.evaluate(call.function).as_type(FunctionClosure)
|
29
20
|
args = call.positional_args
|
30
21
|
with ErrorManager().call(
|
31
22
|
function.name
|
32
23
|
), function.scope.freeze(), self._propagated_var_stack.capture_variables(call):
|
33
|
-
|
34
|
-
if function.synthesis_data.should_synthesize_separately:
|
35
|
-
interpreted_call_converter = CallToModelConverter(
|
36
|
-
call,
|
37
|
-
function.positional_arg_declarations,
|
38
|
-
function.scope.data,
|
39
|
-
self._model,
|
40
|
-
)
|
41
|
-
self._update_synthesized_separately_models(
|
42
|
-
interpreted_call_converter, new_call.func_name
|
43
|
-
)
|
44
|
-
|
45
|
-
def _update_synthesized_separately_models(
|
46
|
-
self, call_converter: CallToModelConverter, call_name: str
|
47
|
-
) -> None:
|
48
|
-
synthesized_separately_blocks = self._synthesized_separately_blocks
|
49
|
-
block_id = call_converter.block_id
|
50
|
-
block_function = synthesized_separately_blocks.get(block_id)
|
51
|
-
if block_function is None:
|
52
|
-
block_function = BlockFunctionInfo.from_call_converter(call_converter)
|
53
|
-
synthesized_separately_blocks[block_id] = block_function
|
54
|
-
block_function.calls.add(call_name)
|
24
|
+
self._emit_quantum_function_call(function, args)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from classiq.interface.exceptions import ClassiqExpansionError
|
1
2
|
from classiq.interface.generator.expressions.expression import Expression
|
2
3
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
3
4
|
REPEAT_OPERATOR_NAME,
|
@@ -17,6 +18,10 @@ from classiq.qmod.quantum_function import GenerativeQFunc
|
|
17
18
|
class RepeatEmitter(Emitter[Repeat]):
|
18
19
|
def emit(self, repeat: Repeat, /) -> None:
|
19
20
|
count = self._interpreter.evaluate(repeat.count).as_type(int)
|
21
|
+
if count < 0:
|
22
|
+
raise ClassiqExpansionError(
|
23
|
+
f"repeat count must be non-negative, got {count}"
|
24
|
+
)
|
20
25
|
for i in range(count):
|
21
26
|
with self._propagated_var_stack.capture_variables(repeat):
|
22
27
|
self._emit_propagated(repeat, i)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
2
|
-
COMPUTE_OPERATOR_NAME,
|
3
2
|
WITHIN_APPLY_NAME,
|
4
3
|
)
|
5
4
|
from classiq.interface.model.within_apply_operation import WithinApply
|
@@ -26,10 +25,6 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
26
25
|
}
|
27
26
|
)
|
28
27
|
|
29
|
-
if self._should_wrap(within_apply.compute):
|
30
|
-
self._emit_wrapped(within_apply)
|
31
|
-
return
|
32
|
-
|
33
28
|
self._emit_as_operation(within_apply)
|
34
29
|
|
35
30
|
def _emit_as_operation(self, within_apply: WithinApply) -> None:
|
@@ -46,14 +41,3 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
46
41
|
source_ref=within_apply.source_ref,
|
47
42
|
)
|
48
43
|
)
|
49
|
-
|
50
|
-
def _emit_wrapped(self, within_apply: WithinApply) -> None:
|
51
|
-
wrapped_compute = self._create_expanded_wrapping_function(
|
52
|
-
COMPUTE_OPERATOR_NAME, within_apply.compute
|
53
|
-
)
|
54
|
-
wrapped_within_apply = WithinApply(
|
55
|
-
compute=[wrapped_compute],
|
56
|
-
action=within_apply.action,
|
57
|
-
source_ref=within_apply.source_ref,
|
58
|
-
)
|
59
|
-
self._builder.emit_statement(wrapped_within_apply)
|
@@ -43,7 +43,7 @@ def get_main_renamer(
|
|
43
43
|
return ExpressionRenamer(var_mapping={})
|
44
44
|
|
45
45
|
|
46
|
-
def
|
46
|
+
def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
47
47
|
for constant in constants:
|
48
48
|
scope[constant.name] = Evaluated(
|
49
49
|
value=evaluate_classical_expression(constant.value, scope).value
|
@@ -60,7 +60,6 @@ def _add_functions_to_scope(
|
|
60
60
|
positional_arg_declarations=function.positional_arg_declarations,
|
61
61
|
body=function.body,
|
62
62
|
scope=Scope(parent=scope),
|
63
|
-
synthesis_data=function.synthesis_data,
|
64
63
|
)
|
65
64
|
)
|
66
65
|
|
@@ -143,5 +142,5 @@ def init_top_level_scope(
|
|
143
142
|
) -> None:
|
144
143
|
_add_functions_to_scope(model.functions, scope)
|
145
144
|
_add_generative_functions_to_scope(generative_functions, scope)
|
146
|
-
|
145
|
+
add_constants_to_scope(model.constants, scope)
|
147
146
|
_init_builtins_scope(scope)
|
@@ -23,8 +23,6 @@ def unitary(
|
|
23
23
|
Args:
|
24
24
|
elements: A 2d array of complex numbers representing the unitary matrix. This matrix must be unitary.
|
25
25
|
target: The quantum state to apply the unitary on. Should be of corresponding size.
|
26
|
-
|
27
|
-
Links: [Reference Manual](https://docs.classiq.io/qmod/builtins/functions/standard_gates/unitary)
|
28
26
|
"""
|
29
27
|
pass
|
30
28
|
|
@@ -105,9 +105,6 @@ def qct_qst_type1(x: QArray[QBit]) -> None:
|
|
105
105
|
|
106
106
|
Args:
|
107
107
|
x: The qubit array to apply the transform to.
|
108
|
-
|
109
|
-
Links:
|
110
|
-
- [Quantum Sine and Cosine Transforms](https://docs.classiq.io/latest/reference-manual/qmod/library-reference/open-library-functions/qct_qst/qct_qst/)
|
111
108
|
"""
|
112
109
|
within_apply(lambda: _t_operator(x), lambda: qft(x))
|
113
110
|
|
@@ -134,9 +131,6 @@ def qct_qst_type2(x: QArray[QBit], q: QBit) -> None:
|
|
134
131
|
Args:
|
135
132
|
x: The LSB part of the qubit array to apply the transform to.
|
136
133
|
q: The MSB of the qubit array to apply the transform to.
|
137
|
-
|
138
|
-
Links:
|
139
|
-
- [Quantum Sine and Cosine Transforms](https://docs.classiq.io/latest/reference-manual/qmod/library-reference/open-library-functions/qct_qst/qct_qst/)
|
140
134
|
"""
|
141
135
|
extended_state: QArray = QArray("extended_state")
|
142
136
|
_vn_operator(x, q)
|
@@ -156,9 +150,6 @@ def qct_type2(x: QArray[QBit]) -> None:
|
|
156
150
|
|
157
151
|
Args:
|
158
152
|
x: The qubit array to apply the transform to.
|
159
|
-
|
160
|
-
Links:
|
161
|
-
- [Quantum Sine and Cosine Transforms](https://docs.classiq.io/latest/reference-manual/qmod/library-reference/open-library-functions/qct_qst/qct_qst/)
|
162
153
|
"""
|
163
154
|
q = QBit("q")
|
164
155
|
within_apply(lambda: allocate(1, q), lambda: qct_qst_type2(x, q))
|
@@ -174,9 +165,6 @@ def qst_type2(x: QArray[QBit]) -> None:
|
|
174
165
|
|
175
166
|
Args:
|
176
167
|
x: The qubit array to apply the transform to.
|
177
|
-
|
178
|
-
Links:
|
179
|
-
- [Quantum Sine and Cosine Transforms](https://docs.classiq.io/latest/reference-manual/qmod/library-reference/open-library-functions/qct_qst/qct_qst/)
|
180
168
|
"""
|
181
169
|
q = QBit("q")
|
182
170
|
within_apply(
|
@@ -45,8 +45,6 @@ def suzuki_trotter(
|
|
45
45
|
The Suzuki-Trotter decomposition of a given order nullifies the error of the Taylor series expansion of the product of exponentials up to that order.
|
46
46
|
The error of a Suzuki-Trotter decomposition decreases as the order and number of repetitions increase.
|
47
47
|
|
48
|
-
See [N. Hatano and M. Suzuki, Finding Exponential Product Formulas of Higher Orders (2005)](https://arxiv.org/abs/math-ph/0506007).
|
49
|
-
|
50
48
|
Args:
|
51
49
|
pauli_operator: The Pauli operator to be exponentiated.
|
52
50
|
evolution_coefficient: A global evolution coefficient multiplying the Pauli operator.
|
@@ -73,8 +71,6 @@ def qdrift(
|
|
73
71
|
The QDrift method randomizes the order of the operators in the product of exponentials to stochastically reduce the error of the approximation.
|
74
72
|
The error of the QDrift method decreases as the number of QDrift steps increases.
|
75
73
|
|
76
|
-
See [E. Campbell, Random Compiler for Fast Hamiltonian Simulation (2019)](https://arxiv.org/abs/1811.08017).
|
77
|
-
|
78
74
|
Args:
|
79
75
|
pauli_operator: The Pauli operator to be exponentiated.
|
80
76
|
evolution_coefficient: A global evolution coefficient multiplying the Pauli operator.
|
@@ -100,8 +96,6 @@ def exponentiation_with_depth_constraint(
|
|
100
96
|
The Suzuki-Trotter decomposition is a method for approximating the exponential of a sum of operators by a product of exponentials of each operator.
|
101
97
|
This function automatically determines the order and number of repetitions of the Suzuki-Trotter decomposition to minimize the error given a depth constraint.
|
102
98
|
|
103
|
-
See [A. M. Childs et al., Toward the first quantum simulation with quantum speedup (2017)](https://arxiv.org/abs/1711.10980).
|
104
|
-
|
105
99
|
Args:
|
106
100
|
pauli_operator: The Pauli operator to be exponentiated.
|
107
101
|
evolution_coefficient: A global coefficient multiplying the Pauli operator.
|
@@ -39,11 +39,6 @@ def phase_oracle(
|
|
39
39
|
Args:
|
40
40
|
predicate: A predicate function that takes a QArray of QBits and sets a single QBit |1> if the predicate is true, and |0> otherwise.
|
41
41
|
target: The target QArray of QBits to apply the phase oracle to.
|
42
|
-
|
43
|
-
Usage Examples:
|
44
|
-
[Grover Algorithm](https://docs.classiq.io/latest/explore/functions/qmod_library_reference/classiq_open_library/grover_operator/grover_operator/)
|
45
|
-
|
46
|
-
[Hidden shift](https://docs.classiq.io/latest/explore/algorithms/algebraic/hidden_shift/hidden_shift/)
|
47
42
|
"""
|
48
43
|
aux = QBit("aux")
|
49
44
|
within_apply(
|
@@ -125,18 +120,10 @@ def grover_operator(
|
|
125
120
|
where $S_{\\psi_1}$ is a reflection about marked states, and $S_{\\psi_0}$ is a reflection
|
126
121
|
about a given state defined by $|\\psi_0\rangle = A|0\rangle$.
|
127
122
|
|
128
|
-
|
129
123
|
Args:
|
130
124
|
oracle: A unitary operator which adds a phase of (-1) to marked states.
|
131
125
|
space_transform: The operator which creates $|\\psi_0\rangle$, the initial state, used by the diffuser to reflect about it.
|
132
126
|
packed_vars: The state to which to apply the grover operator.
|
133
|
-
|
134
|
-
|
135
|
-
For further reading, see:
|
136
|
-
|
137
|
-
- [The Grover Operator notebook](../explore/functions/qmod_library_reference/classiq_open_library/grover_operator/grover_operator/)
|
138
|
-
- [Wikipedia page](https://en.wikipedia.org/wiki/Grover%27s_algorithm).
|
139
|
-
|
140
127
|
"""
|
141
128
|
oracle(packed_vars)
|
142
129
|
grover_diffuser(lambda qba: space_transform(qba), packed_vars)
|
@@ -158,10 +145,6 @@ def grover_search(
|
|
158
145
|
packed_vars: Packed form of the variable to apply the grover operator on.
|
159
146
|
|
160
147
|
Returns: None
|
161
|
-
|
162
|
-
Links:
|
163
|
-
[Grover Algorithm](https://docs.classiq.io/latest/explore/functions/qmod_library_reference/classiq_open_library/grover_operator/grover_operator/)
|
164
|
-
|
165
148
|
"""
|
166
149
|
hadamard_transform(packed_vars)
|
167
150
|
power(
|
@@ -61,11 +61,6 @@ def linear_pauli_rotations(
|
|
61
61
|
q: List of indicator qubits for each of the given Pauli bases.
|
62
62
|
|
63
63
|
Notice that bases, slopes, offset and q should be of the same size.
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
Links:
|
68
|
-
[linear_pauli_rotations](https://docs.classiq.io/latest/explore/functions/qmod_library_reference/classiq_open_library/linear_pauli_rotations/linear_pauli_rotations)
|
69
64
|
"""
|
70
65
|
repeat(
|
71
66
|
q.len,
|
@@ -186,9 +186,6 @@ def modular_exp(n: CInt, a: CInt, x: QArray[QBit], power: QArray[QBit]) -> None:
|
|
186
186
|
a: The base of the exponentiation. Should be non-negative.
|
187
187
|
x: A quantum number that multiplies the modular exponentiation and holds the output. It should be at least the size of $\\lceil \\log(n) \rceil$.
|
188
188
|
power: The power of the exponentiation.
|
189
|
-
|
190
|
-
Usage Example:
|
191
|
-
[Modular Exponentiation](https://docs.classiq.io/latest/explore/functions/function_usage_examples/arithmetic/modular_exp/modular_exp_example)
|
192
189
|
"""
|
193
190
|
repeat(
|
194
191
|
count=power.len,
|
@@ -17,9 +17,6 @@ def qaoa_mixer_layer(b: CReal, target: QArray[QBit]) -> None:
|
|
17
17
|
The mixer layer is a sequence of `X` gates applied to each qubit in the target quantum
|
18
18
|
array variable.
|
19
19
|
|
20
|
-
Please refer to the [QAOA mixer tutorial](https://docs.classiq.io/latest/reference-manual/built-in-algorithms/combinatorial-optimization/problem-solving/) for an example
|
21
|
-
|
22
|
-
|
23
20
|
Args:
|
24
21
|
b: The rotation parameter for the mixer layer.
|
25
22
|
target: The target quantum array.
|
@@ -40,7 +37,6 @@ def qaoa_cost_layer(
|
|
40
37
|
The cost layer represents the primary objective that the QAOA algorithm seeks to optimize, such as
|
41
38
|
minimizing energy or maximizing profit, depending on the application.
|
42
39
|
|
43
|
-
For more details on defining cost functions in QAOA models using Pyomo, see: [Problem Formulation](https://docs.classiq.io/latest/reference-manual/built-in-algorithms/combinatorial-optimization/)
|
44
40
|
Args:
|
45
41
|
g: The rotation parameter for the cost layer (prefactor).
|
46
42
|
hamiltonian: The Hamiltonian terms for the QAOA model.
|
@@ -62,7 +58,6 @@ def qaoa_layer(
|
|
62
58
|
Quantum Approximate Optimization Algorithm (QAOA). The cost layer encodes the problem's objective,
|
63
59
|
while the mixer layer introduces quantum superposition and drives the search across the solution space.
|
64
60
|
|
65
|
-
For more details mon the QAOA problem formulation, please see the following [tutorial](https://docs.classiq.io/latest/reference-manual/built-in-algorithms/combinatorial-optimization/)
|
66
61
|
Args:
|
67
62
|
g: The rotation parameter for the cost layer.
|
68
63
|
b: The rotation parameter for the mixer layer.
|
@@ -107,9 +102,6 @@ def qaoa_penalty(
|
|
107
102
|
enforce certain constraints (e.g., binary or integer variables) during the
|
108
103
|
optimization process.
|
109
104
|
|
110
|
-
Please refer to the [Optimization Problem tutorial](https://docs.classiq.io/latest/reference-manual/built-in-algorithms/combinatorial-optimization/problem-formulation/) for details.
|
111
|
-
|
112
|
-
|
113
105
|
Args:
|
114
106
|
num_qubits: The number of qubits in the quantum circuit.
|
115
107
|
params_list The list of QAOA parameters.
|
@@ -46,9 +46,6 @@ def qft(target: QArray[QBit]) -> None:
|
|
46
46
|
|
47
47
|
Args:
|
48
48
|
target: The quantum object to be transformed
|
49
|
-
|
50
|
-
Further reading in Classiq Library:
|
51
|
-
Link: [qft library reference](https://github.com/Classiq/classiq-library/blob/main/functions/qmod_library_reference/classiq_open_library/qft/qft.ipynb)
|
52
49
|
"""
|
53
50
|
repeat(
|
54
51
|
target.len / 2, # type:ignore[arg-type]
|
@@ -19,9 +19,6 @@ def qpe_flexible(unitary_with_power: QCallable[CInt], phase: QNum) -> None:
|
|
19
19
|
Args:
|
20
20
|
unitary_with_power: A callable that returns the unitary operator $U^k$ given an integer $k$. This callable is used to control the application of powers of the unitary operator.
|
21
21
|
phase: The quantum variable that represents the estimated phase (eigenvalue), assuming initialized to zero.
|
22
|
-
|
23
|
-
Further reading in Classiq Library:
|
24
|
-
Link: [qpe library reference](https://github.com/Classiq/classiq-library/blob/main/functions/qmod_library_reference/classiq_open_library/qpe/qpe.ipynb)
|
25
22
|
"""
|
26
23
|
phase_array: QArray = QArray("phase_array")
|
27
24
|
bind(phase, phase_array)
|
@@ -48,8 +45,5 @@ def qpe(unitary: QCallable, phase: QNum) -> None:
|
|
48
45
|
Args:
|
49
46
|
unitary: A callable representing the unitary operator $U$, whose eigenvalue is to be estimated.
|
50
47
|
phase: The quantum variable that represents the estimated phase (eigenvalue), assuming initialized to zero.
|
51
|
-
|
52
|
-
Further reading in Classiq Library:
|
53
|
-
Link: [qpe library reference](https://github.com/Classiq/classiq-library/blob/main/functions/qmod_library_reference/classiq_open_library/qpe/qpe.ipynb)
|
54
48
|
"""
|
55
49
|
qpe_flexible(unitary_with_power=lambda k: power(k, unitary), phase=phase)
|