classiq 0.51.0__py3-none-any.whl → 0.52.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/_internals/api_wrapper.py +41 -15
- classiq/_internals/authentication/auth0.py +20 -4
- classiq/_internals/authentication/password_manager.py +16 -4
- classiq/_internals/client.py +2 -2
- classiq/_internals/host_checker.py +5 -3
- classiq/_internals/jobs.py +3 -3
- classiq/analyzer/analyzer_utilities.py +1 -1
- classiq/applications/chemistry/ground_state_problem.py +1 -1
- classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +2 -2
- classiq/execution/__init__.py +3 -0
- classiq/execution/execution_session.py +2 -2
- classiq/execution/iqcc.py +63 -0
- classiq/execution/jobs.py +2 -2
- classiq/executor.py +2 -2
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +19 -9
- classiq/interface/analyzer/cytoscape_graph.py +10 -3
- classiq/interface/analyzer/result.py +6 -5
- classiq/interface/applications/qsvm.py +13 -12
- classiq/interface/backend/backend_preferences.py +78 -105
- classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
- classiq/interface/backend/pydantic_backend.py +24 -12
- classiq/interface/backend/quantum_backend_providers.py +2 -0
- classiq/interface/chemistry/fermionic_operator.py +7 -7
- classiq/interface/chemistry/ground_state_problem.py +23 -18
- classiq/interface/chemistry/molecule.py +10 -5
- classiq/interface/chemistry/operator.py +71 -44
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
- classiq/interface/debug_info/debug_info.py +3 -4
- classiq/interface/execution/iqcc.py +21 -0
- classiq/interface/execution/jobs.py +10 -10
- classiq/interface/executor/aws_execution_cost.py +37 -20
- classiq/interface/executor/execution_preferences.py +1 -2
- classiq/interface/executor/execution_request.py +2 -2
- classiq/interface/executor/execution_result.py +4 -2
- classiq/interface/executor/iqae_result.py +1 -1
- classiq/interface/executor/optimizer_preferences.py +14 -10
- classiq/interface/executor/quantum_code.py +21 -16
- classiq/interface/executor/register_initialization.py +10 -10
- classiq/interface/executor/result.py +19 -16
- classiq/interface/executor/vqe_result.py +1 -1
- classiq/interface/finance/function_input.py +27 -18
- classiq/interface/finance/log_normal_model_input.py +2 -2
- classiq/interface/finance/model_input.py +3 -2
- classiq/interface/generator/amplitude_loading.py +8 -6
- classiq/interface/generator/arith/argument_utils.py +24 -0
- classiq/interface/generator/arith/arithmetic.py +5 -3
- classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
- classiq/interface/generator/arith/arithmetic_operations.py +6 -3
- classiq/interface/generator/arith/binary_ops.py +88 -63
- classiq/interface/generator/arith/extremum_operations.py +22 -13
- classiq/interface/generator/arith/logical_ops.py +6 -4
- classiq/interface/generator/arith/number_utils.py +3 -3
- classiq/interface/generator/arith/register_user_input.py +32 -17
- classiq/interface/generator/arith/unary_ops.py +5 -4
- classiq/interface/generator/chemistry_function_params.py +2 -1
- classiq/interface/generator/circuit_code/circuit_code.py +2 -1
- classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
- classiq/interface/generator/complex_type.py +14 -18
- classiq/interface/generator/control_state.py +32 -26
- classiq/interface/generator/expressions/expression.py +6 -5
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +3 -3
- classiq/interface/generator/function_params.py +22 -39
- classiq/interface/generator/functions/classical_function_declaration.py +1 -1
- classiq/interface/generator/functions/classical_type.py +32 -23
- classiq/interface/generator/functions/concrete_types.py +8 -7
- classiq/interface/generator/functions/function_declaration.py +4 -5
- classiq/interface/generator/functions/type_name.py +5 -4
- classiq/interface/generator/generated_circuit_data.py +9 -6
- classiq/interface/generator/grover_diffuser.py +26 -18
- classiq/interface/generator/grover_operator.py +32 -22
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
- classiq/interface/generator/hardware/hardware_data.py +27 -26
- classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
- classiq/interface/generator/hartree_fock.py +2 -1
- classiq/interface/generator/identity.py +7 -2
- classiq/interface/generator/linear_pauli_rotations.py +27 -14
- classiq/interface/generator/mcu.py +15 -12
- classiq/interface/generator/mcx.py +18 -10
- classiq/interface/generator/model/constraints.py +4 -2
- classiq/interface/generator/model/model.py +2 -1
- classiq/interface/generator/model/preferences/preferences.py +30 -32
- classiq/interface/generator/oracles/custom_oracle.py +13 -10
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
- classiq/interface/generator/qpe.py +38 -26
- classiq/interface/generator/qsvm.py +4 -4
- classiq/interface/generator/quantum_function_call.py +57 -44
- classiq/interface/generator/quantum_program.py +8 -6
- classiq/interface/generator/range_types.py +10 -11
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
- classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
- classiq/interface/generator/standard_gates/u_gate.py +7 -10
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
- classiq/interface/generator/state_preparation/distributions.py +12 -12
- classiq/interface/generator/state_preparation/state_preparation.py +22 -16
- classiq/interface/generator/types/enum_declaration.py +2 -1
- classiq/interface/generator/ucc.py +2 -1
- classiq/interface/generator/unitary_gate.py +2 -1
- classiq/interface/generator/user_defined_function_params.py +3 -0
- classiq/interface/generator/visitor.py +1 -1
- classiq/interface/hardware.py +18 -3
- classiq/interface/helpers/custom_pydantic_types.py +38 -47
- classiq/interface/helpers/pydantic_model_helpers.py +3 -2
- classiq/interface/helpers/versioned_model.py +1 -4
- classiq/interface/ide/ide_data.py +5 -5
- classiq/interface/ide/visual_model.py +5 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/jobs.py +12 -22
- classiq/interface/model/bind_operation.py +2 -1
- classiq/interface/model/classical_parameter_declaration.py +10 -4
- classiq/interface/model/handle_binding.py +20 -24
- classiq/interface/model/inplace_binary_operation.py +16 -9
- classiq/interface/model/model.py +21 -11
- classiq/interface/model/port_declaration.py +10 -7
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
- classiq/interface/model/quantum_function_declaration.py +22 -11
- classiq/interface/model/quantum_statement.py +6 -7
- classiq/interface/model/quantum_type.py +22 -19
- classiq/interface/model/statement_block.py +9 -9
- classiq/interface/server/global_versions.py +4 -5
- classiq/interface/server/routes.py +8 -0
- classiq/model_expansions/evaluators/parameter_types.py +3 -3
- classiq/model_expansions/expression_renamer.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +11 -12
- classiq/model_expansions/quantum_operations/emitter.py +22 -0
- classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +65 -14
- classiq/model_expansions/quantum_operations/invert.py +1 -1
- classiq/model_expansions/quantum_operations/phase.py +4 -5
- classiq/model_expansions/quantum_operations/power.py +1 -1
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
- classiq/model_expansions/quantum_operations/within_apply.py +1 -1
- classiq/qmod/builtins/__init__.py +1 -3
- classiq/qmod/builtins/functions/__init__.py +4 -0
- classiq/qmod/builtins/functions/arithmetic.py +10 -0
- classiq/qmod/create_model_function.py +14 -8
- classiq/qmod/quantum_expandable.py +22 -9
- classiq/qmod/quantum_function.py +1 -1
- classiq/qmod/semantics/static_semantics_visitor.py +3 -1
- classiq/qmod/type_attribute_remover.py +1 -1
- classiq/qmod/write_qmod.py +2 -4
- classiq/synthesis.py +11 -13
- {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
- {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/RECORD +150 -148
- {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -2,6 +2,9 @@ ANALYZER_PREFIX = "/analyzer"
|
|
2
2
|
CHEMISTRY_PREFIX = "/chemistry"
|
3
3
|
EXECUTION_PREFIX = "/execution"
|
4
4
|
CONVERSION_PREFIX = "/conversion"
|
5
|
+
PROVIDERS_PREFIX = "/providers"
|
6
|
+
|
7
|
+
IQCC_PREFIX = PROVIDERS_PREFIX + "/iqcc"
|
5
8
|
|
6
9
|
EXECUTION_NON_VERSIONED_PREFIX = "/execution/v1"
|
7
10
|
SYNTHESIS_NON_VERSIONED_PREFIX = "/synthesis/v1"
|
@@ -71,3 +74,8 @@ CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_FULL = (
|
|
71
74
|
)
|
72
75
|
|
73
76
|
STATIC_SEMANTICS_VALIDATION_PATH = "/validate_static_semantics"
|
77
|
+
|
78
|
+
IQCC_INIT_AUTH_SUFFIX = "/init_auth"
|
79
|
+
IQCC_INIT_AUTH_FULL_PATH = IQCC_PREFIX + IQCC_INIT_AUTH_SUFFIX
|
80
|
+
IQCC_PROBE_AUTH_SUFFIX = "/probe_auth"
|
81
|
+
IQCC_PROBE_AUTH_FULL_PATH = IQCC_PREFIX + IQCC_PROBE_AUTH_SUFFIX
|
@@ -118,7 +118,7 @@ def _update_operand_signature_environment(
|
|
118
118
|
def _cast(
|
119
119
|
quantum_type: QuantumType, quantum_symbol: QuantumSymbol, param_name: str
|
120
120
|
) -> QuantumSymbol:
|
121
|
-
updated_quantum_type = quantum_type.
|
121
|
+
updated_quantum_type = quantum_type.model_copy()
|
122
122
|
_inject_quantum_arg_info_to_type(updated_quantum_type, quantum_symbol, param_name)
|
123
123
|
return QuantumSymbol(
|
124
124
|
handle=quantum_symbol.handle, quantum_type=updated_quantum_type
|
@@ -132,13 +132,13 @@ def _evaluate_type_from_arg(
|
|
132
132
|
return parameter
|
133
133
|
|
134
134
|
updated_quantum_type: QuantumType = evaluate_type_in_quantum_symbol(
|
135
|
-
parameter.quantum_type.
|
135
|
+
parameter.quantum_type.model_copy(), inner_scope, parameter.name
|
136
136
|
)
|
137
137
|
if parameter.direction != PortDeclarationDirection.Output:
|
138
138
|
updated_quantum_type = _inject_quantum_arg_info_to_type(
|
139
139
|
updated_quantum_type, argument.as_type(QuantumSymbol), parameter.name
|
140
140
|
)
|
141
|
-
return parameter.
|
141
|
+
return parameter.model_copy(update={"quantum_type": updated_quantum_type})
|
142
142
|
|
143
143
|
|
144
144
|
def evaluate_type_in_quantum_symbol(
|
@@ -30,7 +30,7 @@ class ExpressionRenamer(Transformer):
|
|
30
30
|
update_dict = dict(
|
31
31
|
positional_args=[self.visit(arg) for arg in node.positional_args],
|
32
32
|
)
|
33
|
-
return node.
|
33
|
+
return node.model_copy(update=update_dict)
|
34
34
|
|
35
35
|
def visit_Expression(self, expression: Expression) -> Expression:
|
36
36
|
parsed_expr = ast.parse(expression.expr)
|
@@ -23,7 +23,6 @@ from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
23
23
|
ArithmeticOperation,
|
24
24
|
ArithmeticOperationKind,
|
25
25
|
)
|
26
|
-
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
27
26
|
from classiq.interface.model.quantum_type import QuantumBit, QuantumBitvector
|
28
27
|
from classiq.interface.model.statement_block import ConcreteQuantumStatement
|
29
28
|
from classiq.interface.model.variable_declaration_statement import (
|
@@ -43,7 +42,6 @@ from classiq.model_expansions.quantum_operations.expression_operation import (
|
|
43
42
|
ExpressionOperationEmitter,
|
44
43
|
)
|
45
44
|
from classiq.model_expansions.scope import Scope
|
46
|
-
from classiq.qmod.builtins.functions import inplace_prepare_int
|
47
45
|
|
48
46
|
ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
|
49
47
|
|
@@ -51,7 +49,7 @@ ARRAY_CAST_SUFFIX = HANDLE_ID_SEPARATOR + "array_cast"
|
|
51
49
|
class ControlEmitter(ExpressionOperationEmitter[Control]):
|
52
50
|
def emit(self, control: Control, /) -> None:
|
53
51
|
condition = self._evaluate_op_expression(control)
|
54
|
-
control = control.
|
52
|
+
control = control.model_copy(update=dict(expression=condition))
|
55
53
|
|
56
54
|
arrays_with_subscript = self._get_symbols_to_split(condition)
|
57
55
|
if len(arrays_with_subscript) > 0:
|
@@ -76,7 +74,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
76
74
|
def _emit_propagated(self, control: Control) -> None:
|
77
75
|
if control.is_generative():
|
78
76
|
context = self._register_generative_context(control, CONTROL_OPERATOR_NAME)
|
79
|
-
control = control.
|
77
|
+
control = control.model_copy(update={"body": context.statements("body")})
|
80
78
|
|
81
79
|
if self._should_wrap_control(control):
|
82
80
|
self._emit_wrapped(control)
|
@@ -106,7 +104,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
106
104
|
)
|
107
105
|
self._update_control_state(control)
|
108
106
|
self._builder.emit_statement(
|
109
|
-
control.
|
107
|
+
control.model_copy(update=dict(body=context.statements("body")))
|
110
108
|
)
|
111
109
|
|
112
110
|
def _emit_wrapped(self, control: Control) -> None:
|
@@ -119,7 +117,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
119
117
|
)
|
120
118
|
self._update_control_state(control)
|
121
119
|
self._builder.emit_statement(
|
122
|
-
control.
|
120
|
+
control.model_copy(update=dict(body=[wrapping_function]))
|
123
121
|
)
|
124
122
|
|
125
123
|
@staticmethod
|
@@ -157,7 +155,7 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
157
155
|
self, control: Control, handle_name: str
|
158
156
|
) -> Control:
|
159
157
|
handle_expr = self._interpreter.evaluate(Expression(expr=handle_name)).emit()
|
160
|
-
return control.
|
158
|
+
return control.model_copy(update=dict(expression=handle_expr))
|
161
159
|
|
162
160
|
def _emit_with_x_gates(
|
163
161
|
self, control: Control, ctrl: QmodSizedProxy, ctrl_state: str
|
@@ -166,12 +164,13 @@ class ControlEmitter(ExpressionOperationEmitter[Control]):
|
|
166
164
|
|
167
165
|
x_gate_value = self._get_x_gate_value(ctrl_state)
|
168
166
|
if x_gate_value != 0:
|
169
|
-
|
170
|
-
|
171
|
-
|
167
|
+
compute_op.append(
|
168
|
+
ArithmeticOperation(
|
169
|
+
result_var=ctrl.handle,
|
170
|
+
expression=Expression(expr=str(x_gate_value)),
|
171
|
+
operation_kind=ArithmeticOperationKind.InplaceXor,
|
172
|
+
)
|
172
173
|
)
|
173
|
-
prepare_int_call.set_func_decl(inplace_prepare_int.func_decl)
|
174
|
-
compute_op.append(prepare_int_call)
|
175
174
|
|
176
175
|
if isinstance(ctrl, QmodQNumProxy):
|
177
176
|
# Canonical control does not accept QNum, so we have to cast it
|
@@ -11,7 +11,13 @@ from typing import (
|
|
11
11
|
cast,
|
12
12
|
)
|
13
13
|
|
14
|
+
import sympy
|
15
|
+
|
14
16
|
from classiq.interface.debug_info.debug_info import FunctionDebugInfo
|
17
|
+
from classiq.interface.generator.expressions.evaluated_expression import (
|
18
|
+
EvaluatedExpression,
|
19
|
+
)
|
20
|
+
from classiq.interface.generator.expressions.expression import Expression
|
15
21
|
from classiq.interface.ide.visual_model import OperationLevel
|
16
22
|
from classiq.interface.model.classical_parameter_declaration import (
|
17
23
|
ClassicalParameterDeclaration,
|
@@ -47,6 +53,9 @@ from classiq.model_expansions.function_builder import (
|
|
47
53
|
)
|
48
54
|
from classiq.model_expansions.generative_functions import emit_operands_as_declarative
|
49
55
|
from classiq.model_expansions.scope import Evaluated, QuantumSymbol, Scope
|
56
|
+
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
57
|
+
translate_sympy_quantum_expression,
|
58
|
+
)
|
50
59
|
from classiq.model_expansions.utils.counted_name_allocator import CountedNameAllocator
|
51
60
|
from classiq.qmod.builtins.functions import allocate, free
|
52
61
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
@@ -274,3 +283,16 @@ class Emitter(Generic[QuantumStatementT]):
|
|
274
283
|
context = self._interpreter._expand_operation(gen_closure)
|
275
284
|
self._generative_contexts[context_name] = context
|
276
285
|
return context
|
286
|
+
|
287
|
+
def _evaluate_expression(self, expression: Expression) -> Expression:
|
288
|
+
evaluated_expression = self._interpreter.evaluate(expression)
|
289
|
+
if isinstance(evaluated_expression.value, sympy.Basic):
|
290
|
+
new_expression = Expression(
|
291
|
+
expr=translate_sympy_quantum_expression(evaluated_expression.value)
|
292
|
+
)
|
293
|
+
else:
|
294
|
+
new_expression = Expression(expr=str(evaluated_expression.value))
|
295
|
+
new_expression._evaluated_expr = EvaluatedExpression(
|
296
|
+
value=evaluated_expression.value
|
297
|
+
)
|
298
|
+
return new_expression
|
@@ -3,8 +3,6 @@ from abc import abstractmethod
|
|
3
3
|
from itertools import chain
|
4
4
|
from typing import TYPE_CHECKING, Dict, List, Tuple, TypeVar
|
5
5
|
|
6
|
-
import sympy
|
7
|
-
|
8
6
|
from classiq.interface.exceptions import (
|
9
7
|
ClassiqExpansionError,
|
10
8
|
ClassiqInternalExpansionError,
|
@@ -36,9 +34,6 @@ from classiq.interface.model.within_apply_operation import WithinApply
|
|
36
34
|
|
37
35
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
38
36
|
from classiq.model_expansions.scope import QuantumSymbol
|
39
|
-
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
40
|
-
translate_sympy_quantum_expression,
|
41
|
-
)
|
42
37
|
from classiq.model_expansions.visitors.variable_references import VarRefCollector
|
43
38
|
|
44
39
|
ExpressionOperationT = TypeVar("ExpressionOperationT", bound=QuantumExpressionOperation)
|
@@ -74,7 +69,7 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
74
69
|
},
|
75
70
|
expression,
|
76
71
|
)
|
77
|
-
new_op = op.
|
72
|
+
new_op = op.model_copy(update=dict(expression=new_expression))
|
78
73
|
|
79
74
|
self._interpreter.emit_statement(
|
80
75
|
WithinApply(
|
@@ -194,23 +189,10 @@ class ExpressionOperationEmitter(Emitter[ExpressionOperationT]):
|
|
194
189
|
def _evaluate_op_expression(self, op: ExpressionOperationT) -> Expression:
|
195
190
|
return self._evaluate_expression(op.expression)
|
196
191
|
|
197
|
-
def _evaluate_expression(self, expression: Expression) -> Expression:
|
198
|
-
evaluated_expression = self._interpreter.evaluate(expression)
|
199
|
-
if isinstance(evaluated_expression.value, sympy.Basic):
|
200
|
-
new_expression = Expression(
|
201
|
-
expr=translate_sympy_quantum_expression(evaluated_expression.value)
|
202
|
-
)
|
203
|
-
else:
|
204
|
-
new_expression = Expression(expr=str(evaluated_expression.value))
|
205
|
-
new_expression._evaluated_expr = EvaluatedExpression(
|
206
|
-
value=evaluated_expression.value
|
207
|
-
)
|
208
|
-
return new_expression
|
209
|
-
|
210
192
|
def _evaluate_types_in_expression(
|
211
193
|
self, op: ExpressionOperationT, expression: Expression
|
212
194
|
) -> ExpressionOperationT:
|
213
|
-
op_with_evaluated_types = op.
|
195
|
+
op_with_evaluated_types = op.model_copy(update={"expression": expression})
|
214
196
|
vrc = VarRefCollector()
|
215
197
|
vrc.visit(ast.parse(op_with_evaluated_types.expression.expr))
|
216
198
|
handles = vrc.var_handles
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import TYPE_CHECKING, List, Tuple
|
1
|
+
from typing import TYPE_CHECKING, List, Tuple, Union
|
2
2
|
|
3
3
|
from classiq.interface.generator.expressions.expression import Expression
|
4
4
|
from classiq.interface.generator.functions.port_declaration import (
|
@@ -35,20 +35,37 @@ from classiq.model_expansions.evaluators.quantum_type_utils import (
|
|
35
35
|
)
|
36
36
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
37
37
|
from classiq.model_expansions.scope import QuantumSymbol, Scope
|
38
|
-
from classiq.qmod.builtins.functions import
|
38
|
+
from classiq.qmod.builtins.functions import (
|
39
|
+
CX,
|
40
|
+
allocate,
|
41
|
+
integer_xor,
|
42
|
+
modular_add,
|
43
|
+
modular_add_constant,
|
44
|
+
real_xor_constant,
|
45
|
+
)
|
39
46
|
|
40
47
|
|
41
48
|
def _binary_function_declaration(
|
42
|
-
op: BinaryOperation,
|
49
|
+
op: BinaryOperation, constant: bool
|
43
50
|
) -> NamedParamsQuantumFunctionDeclaration:
|
44
51
|
return {
|
45
|
-
|
46
|
-
|
47
|
-
|
52
|
+
False: {
|
53
|
+
BinaryOperation.Addition: modular_add.func_decl,
|
54
|
+
BinaryOperation.Xor: integer_xor.func_decl,
|
55
|
+
},
|
56
|
+
True: {
|
57
|
+
BinaryOperation.Addition: modular_add_constant.func_decl,
|
58
|
+
BinaryOperation.Xor: real_xor_constant.func_decl,
|
59
|
+
},
|
60
|
+
}[constant][op]
|
48
61
|
|
49
62
|
|
50
63
|
class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
51
64
|
def emit(self, op: InplaceBinaryOperation, /) -> None:
|
65
|
+
if isinstance(op.value, Expression):
|
66
|
+
self._emit_constant_operation(op)
|
67
|
+
return
|
68
|
+
|
52
69
|
value_var = self._interpreter.evaluate(op.value).as_type(QuantumSymbol)
|
53
70
|
target_var = self._interpreter.evaluate(op.target).as_type(QuantumSymbol)
|
54
71
|
value_var, target_var = evaluate_types_in_quantum_symbols(
|
@@ -95,7 +112,7 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
|
95
112
|
value_var=value_var,
|
96
113
|
target_var=target_var,
|
97
114
|
internal_function_declaration=_binary_function_declaration(
|
98
|
-
op.operation
|
115
|
+
op.operation, constant=False
|
99
116
|
),
|
100
117
|
),
|
101
118
|
scope=Scope(parent=self._current_scope),
|
@@ -105,6 +122,18 @@ class InplaceBinaryOperationEmitter(Emitter[InplaceBinaryOperation]):
|
|
105
122
|
inplace_binary_op_function, [op.value, op.target]
|
106
123
|
)
|
107
124
|
|
125
|
+
def _emit_constant_operation(self, op: InplaceBinaryOperation) -> None:
|
126
|
+
if TYPE_CHECKING:
|
127
|
+
assert isinstance(op.value, Expression)
|
128
|
+
value = self._evaluate_expression(op.value)
|
129
|
+
self._interpreter.emit(
|
130
|
+
_internal_inplace_binary_operation_function_call(
|
131
|
+
_binary_function_declaration(op.operation, constant=True),
|
132
|
+
value,
|
133
|
+
op.target,
|
134
|
+
)
|
135
|
+
)
|
136
|
+
|
108
137
|
|
109
138
|
def _build_inplace_binary_operation(
|
110
139
|
value_var: QuantumSymbol,
|
@@ -164,12 +193,12 @@ def _build_inplace_binary_operation(
|
|
164
193
|
|
165
194
|
def _internal_inplace_binary_operation_function_call(
|
166
195
|
internal_function_declaration: NamedParamsQuantumFunctionDeclaration,
|
167
|
-
|
196
|
+
value: Union[HandleBinding, Expression],
|
168
197
|
target_var: HandleBinding,
|
169
198
|
) -> QuantumFunctionCall:
|
170
199
|
internal_function_call = QuantumFunctionCall(
|
171
200
|
function=internal_function_declaration.name,
|
172
|
-
positional_args=[
|
201
|
+
positional_args=[value, target_var],
|
173
202
|
)
|
174
203
|
internal_function_call.set_func_decl(internal_function_declaration)
|
175
204
|
return internal_function_call
|
@@ -230,10 +259,7 @@ def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
|
|
230
259
|
if not quantum_type.sign_value or size_diff >= 0:
|
231
260
|
return var, [], [], [], []
|
232
261
|
|
233
|
-
significand_var, sign_var, sign_split_bind = _split_sign(kind, var)
|
234
262
|
padding_var, padding_allocation = _allocate_padding(kind, size_diff)
|
235
|
-
padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
|
236
|
-
|
237
263
|
padded_var = QuantumSymbol(
|
238
264
|
handle=HandleBinding(name=f"padded_{kind}"),
|
239
265
|
quantum_type=QuantumNumeric(
|
@@ -242,17 +268,42 @@ def _pad_with_sign_bit(kind: str, var: QuantumSymbol, size_diff: int) -> Tuple[
|
|
242
268
|
fraction_digits=Expression(expr="0"),
|
243
269
|
),
|
244
270
|
)
|
271
|
+
var_decls = [
|
272
|
+
VariableDeclarationStatement(
|
273
|
+
name=var.handle.name,
|
274
|
+
quantum_type=var.quantum_type,
|
275
|
+
)
|
276
|
+
for var in (padding_var, padded_var)
|
277
|
+
]
|
278
|
+
|
279
|
+
if quantum_type.size_in_bits == 1: # qnum<1, SIGNED, ?>
|
280
|
+
padding_init_ops = _init_padding(var, padding_var, size_diff)
|
281
|
+
padding_rebind = BindOperation(
|
282
|
+
in_handles=[var.handle, padding_var.handle],
|
283
|
+
out_handles=[padded_var.handle],
|
284
|
+
)
|
285
|
+
return (
|
286
|
+
padded_var,
|
287
|
+
var_decls,
|
288
|
+
[padding_allocation],
|
289
|
+
padding_init_ops,
|
290
|
+
[padding_rebind],
|
291
|
+
)
|
292
|
+
|
293
|
+
significand_var, sign_var, sign_split_bind = _split_sign(kind, var)
|
294
|
+
padding_init_ops = _init_padding(sign_var, padding_var, size_diff)
|
295
|
+
|
245
296
|
padding_rebind = BindOperation(
|
246
297
|
in_handles=[significand_var.handle, sign_var.handle, padding_var.handle],
|
247
298
|
out_handles=[padded_var.handle],
|
248
299
|
)
|
249
300
|
|
250
|
-
var_decls
|
301
|
+
var_decls += [
|
251
302
|
VariableDeclarationStatement(
|
252
303
|
name=var.handle.name,
|
253
304
|
quantum_type=var.quantum_type,
|
254
305
|
)
|
255
|
-
for var in (significand_var, sign_var
|
306
|
+
for var in (significand_var, sign_var)
|
256
307
|
]
|
257
308
|
|
258
309
|
return (
|
@@ -16,7 +16,7 @@ class InvertEmitter(Emitter[Invert]):
|
|
16
16
|
def _emit_propagated(self, invert: Invert, /) -> None:
|
17
17
|
if invert.is_generative():
|
18
18
|
context = self._register_generative_context(invert, INVERT_OPERATOR_NAME)
|
19
|
-
invert = invert.
|
19
|
+
invert = invert.model_copy(update={"body": context.statements("body")})
|
20
20
|
|
21
21
|
if self._should_wrap(invert.body):
|
22
22
|
self._emit_wrapped(invert)
|
@@ -35,19 +35,18 @@ from classiq.qmod.semantics.error_manager import ErrorManager
|
|
35
35
|
class PhaseEmitter(ExpressionOperationEmitter[PhaseOperation]):
|
36
36
|
def _negate_expression(self, expression: Expression, /) -> Expression:
|
37
37
|
return self._evaluate_expression(
|
38
|
-
|
39
|
-
expression.copy(update=dict(expr=f"-({expression.expr})"))
|
38
|
+
expression.model_copy(update=dict(expr=f"-({expression.expr})"))
|
40
39
|
)
|
41
40
|
|
42
41
|
def emit(self, phase_op: PhaseOperation, /) -> None:
|
43
42
|
phase_expression = self._evaluate_op_expression(phase_op)
|
44
|
-
phase_op = phase_op.
|
43
|
+
phase_op = phase_op.model_copy(update=dict(expression=phase_expression))
|
45
44
|
arrays_with_subscript = self._get_symbols_to_split(phase_op.expression)
|
46
45
|
if len(arrays_with_subscript) > 0:
|
47
46
|
self._emit_with_split(phase_op, phase_op.expression, arrays_with_subscript)
|
48
47
|
return
|
49
|
-
|
50
|
-
phase_op = phase_op.
|
48
|
+
|
49
|
+
phase_op = phase_op.model_copy(
|
51
50
|
update=dict(expression=self._negate_expression(phase_op.expression))
|
52
51
|
)
|
53
52
|
phase_op = self._evaluate_types_in_expression(phase_op, phase_op.expression)
|
@@ -27,7 +27,7 @@ class PowerEmitter(Emitter[Power]):
|
|
27
27
|
def _emit_propagated(self, power: Power) -> None:
|
28
28
|
if power.is_generative():
|
29
29
|
context = self._register_generative_context(power, POWER_OPERATOR_NAME)
|
30
|
-
power = power.
|
30
|
+
power = power.model_copy(update={"body": context.statements("body")})
|
31
31
|
|
32
32
|
self._power = power
|
33
33
|
self._power_value = self._get_power_value()
|
@@ -1,7 +1,11 @@
|
|
1
1
|
import ast
|
2
|
+
import re
|
2
3
|
from typing import Tuple
|
3
4
|
|
4
|
-
from classiq.interface.exceptions import
|
5
|
+
from classiq.interface.exceptions import (
|
6
|
+
ClassiqExpansionError,
|
7
|
+
ClassiqInternalExpansionError,
|
8
|
+
)
|
5
9
|
from classiq.interface.generator.compiler_keywords import INPLACE_ARITH_AUX_VAR_PREFIX
|
6
10
|
from classiq.interface.generator.expressions.expression import Expression
|
7
11
|
from classiq.interface.model.handle_binding import HandleBinding
|
@@ -38,13 +42,22 @@ from classiq.qmod import builtins
|
|
38
42
|
from classiq.qmod.builtins.functions import X, allocate
|
39
43
|
|
40
44
|
|
41
|
-
def
|
45
|
+
def _is_constant(expr: str) -> bool:
|
42
46
|
try:
|
43
|
-
|
47
|
+
float(expr)
|
48
|
+
return True
|
44
49
|
except ValueError:
|
45
50
|
return False
|
46
51
|
|
47
52
|
|
53
|
+
def _is_zero(expr: str) -> bool:
|
54
|
+
return _is_constant(expr) and float(expr) == 0
|
55
|
+
|
56
|
+
|
57
|
+
def _is_variable(expr: str) -> bool:
|
58
|
+
return re.fullmatch("[a-zA-Z_][a-zA-Z0-9_]*", expr) is not None
|
59
|
+
|
60
|
+
|
48
61
|
class QuantumAssignmentOperationEmitter(
|
49
62
|
ExpressionOperationEmitter[QuantumAssignmentOperation]
|
50
63
|
):
|
@@ -86,6 +99,7 @@ class QuantumAssignmentOperationEmitter(
|
|
86
99
|
or op.result_type.size_in_bits > 1
|
87
100
|
or not _is_res_boolean(op)
|
88
101
|
or target.quantum_type.size_in_bits > 1
|
102
|
+
or _is_constant(expression.expr)
|
89
103
|
):
|
90
104
|
_validate_naive_inplace_handles(op)
|
91
105
|
self._build_naive_inplace(op, expression)
|
@@ -131,7 +145,7 @@ class QuantumAssignmentOperationEmitter(
|
|
131
145
|
expr=ast.unparse(optimizer.visit(ast.parse(expression.expr)))
|
132
146
|
)
|
133
147
|
optimized_expression = self._evaluate_expression(optimized_expression)
|
134
|
-
optimized_op = op.
|
148
|
+
optimized_op = op.model_copy(update=dict(expression=optimized_expression))
|
135
149
|
return optimized_op, optimized_expression, optimizer.is_convertible
|
136
150
|
|
137
151
|
def _adapt_boolean_inplace(
|
@@ -141,12 +155,43 @@ class QuantumAssignmentOperationEmitter(
|
|
141
155
|
adapted_expression = self._evaluate_expression(
|
142
156
|
Expression(expr=ast.unparse(adapter.visit(ast.parse(expression.expr))))
|
143
157
|
)
|
144
|
-
adapted_op = op.
|
158
|
+
adapted_op = op.model_copy(update=dict(expression=adapted_expression))
|
145
159
|
return adapted_op, adapted_expression, adapter.to_invert
|
146
160
|
|
147
161
|
def _build_naive_inplace(
|
148
162
|
self, qe: ArithmeticOperation, new_expression: Expression
|
149
163
|
) -> None:
|
164
|
+
if qe.operation_kind == ArithmeticOperationKind.InplaceXor:
|
165
|
+
op = BinaryOperation.Xor
|
166
|
+
elif qe.operation_kind == ArithmeticOperationKind.InplaceAdd:
|
167
|
+
op = BinaryOperation.Addition
|
168
|
+
else:
|
169
|
+
raise ClassiqInternalExpansionError(
|
170
|
+
f"Unrecognized operation kind {qe.operation_kind!r}"
|
171
|
+
)
|
172
|
+
|
173
|
+
if _is_constant(new_expression.expr):
|
174
|
+
self._interpreter.emit_statement(
|
175
|
+
InplaceBinaryOperation(
|
176
|
+
operation=op,
|
177
|
+
target=qe.result_var,
|
178
|
+
value=new_expression,
|
179
|
+
)
|
180
|
+
)
|
181
|
+
return
|
182
|
+
|
183
|
+
if _is_variable(new_expression.expr):
|
184
|
+
value_var = self._interpreter.evaluate(new_expression.expr).value
|
185
|
+
if isinstance(value_var, QuantumSymbol):
|
186
|
+
self._interpreter.emit_statement(
|
187
|
+
InplaceBinaryOperation(
|
188
|
+
operation=op,
|
189
|
+
target=qe.result_var,
|
190
|
+
value=value_var.handle,
|
191
|
+
)
|
192
|
+
)
|
193
|
+
return
|
194
|
+
|
150
195
|
aux_var = self._counted_name_allocator.allocate(INPLACE_ARITH_AUX_VAR_PREFIX)
|
151
196
|
self._interpreter.emit_statement(
|
152
197
|
VariableDeclarationStatement(name=aux_var, quantum_type=QuantumNumeric())
|
@@ -156,10 +201,6 @@ class QuantumAssignmentOperationEmitter(
|
|
156
201
|
expression=new_expression,
|
157
202
|
operation_kind=ArithmeticOperationKind.Assignment,
|
158
203
|
)
|
159
|
-
if qe.operation_kind == ArithmeticOperationKind.InplaceXor:
|
160
|
-
op = BinaryOperation.Xor
|
161
|
-
else:
|
162
|
-
op = BinaryOperation.Addition
|
163
204
|
inplace_store = InplaceBinaryOperation(
|
164
205
|
operation=op,
|
165
206
|
target=qe.result_var,
|
@@ -12,8 +12,8 @@ from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
|
12
12
|
|
13
13
|
class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
|
14
14
|
def emit(self, variable_declaration: VariableDeclarationStatement, /) -> None:
|
15
|
-
var_decl = variable_declaration.
|
16
|
-
var_decl.quantum_type = variable_declaration.quantum_type.
|
15
|
+
var_decl = variable_declaration.model_copy()
|
16
|
+
var_decl.quantum_type = variable_declaration.quantum_type.model_copy()
|
17
17
|
self._current_scope[variable_declaration.name] = Evaluated(
|
18
18
|
value=QuantumSymbol(
|
19
19
|
handle=HandleBinding(name=var_decl.name),
|
@@ -19,7 +19,7 @@ class WithinApplyEmitter(Emitter[WithinApply]):
|
|
19
19
|
within_apply_context = self._register_generative_context(
|
20
20
|
within_apply, WITHIN_APPLY_NAME, ["within", "apply"]
|
21
21
|
)
|
22
|
-
within_apply = within_apply.
|
22
|
+
within_apply = within_apply.model_copy(
|
23
23
|
update={
|
24
24
|
"compute": within_apply_context.statements("within"),
|
25
25
|
"action": within_apply_context.statements("apply"),
|
@@ -17,9 +17,7 @@ from .operations import __all__ as _builtin_operations
|
|
17
17
|
from .structs import * # noqa: F403
|
18
18
|
from .structs import __all__ as _builtin_structs
|
19
19
|
|
20
|
-
FinanceFunctionInput.
|
21
|
-
FinanceFunctionType=FinanceFunctionType # noqa: F405
|
22
|
-
)
|
20
|
+
FinanceFunctionInput.model_rebuild()
|
23
21
|
BUILTIN_CONSTANTS = [
|
24
22
|
constant._get_constant_node()
|
25
23
|
for constant in [
|
@@ -69,6 +69,8 @@ CORE_LIB_DECLS = [
|
|
69
69
|
add,
|
70
70
|
modular_add,
|
71
71
|
integer_xor,
|
72
|
+
modular_add_constant,
|
73
|
+
real_xor_constant,
|
72
74
|
U,
|
73
75
|
CCX,
|
74
76
|
allocate,
|
@@ -192,6 +194,8 @@ __all__ = [
|
|
192
194
|
"add",
|
193
195
|
"modular_add",
|
194
196
|
"integer_xor",
|
197
|
+
"modular_add_constant",
|
198
|
+
"real_xor_constant",
|
195
199
|
"U",
|
196
200
|
"CCX",
|
197
201
|
"allocate",
|
@@ -43,11 +43,21 @@ def modular_add(left: QArray[QBit], right: QArray[QBit]) -> None:
|
|
43
43
|
pass
|
44
44
|
|
45
45
|
|
46
|
+
@qfunc(external=True)
|
47
|
+
def modular_add_constant(left: CReal, right: QNum) -> None:
|
48
|
+
pass
|
49
|
+
|
50
|
+
|
46
51
|
@qfunc(external=True)
|
47
52
|
def integer_xor(left: QArray[QBit], right: QArray[QBit]) -> None:
|
48
53
|
pass
|
49
54
|
|
50
55
|
|
56
|
+
@qfunc(external=True)
|
57
|
+
def real_xor_constant(left: CReal, right: QNum) -> None:
|
58
|
+
pass
|
59
|
+
|
60
|
+
|
51
61
|
@qfunc(external=True)
|
52
62
|
def modular_increment(a: CInt, x: QNum) -> None:
|
53
63
|
"""
|
@@ -106,7 +106,7 @@ def _expand_generative_model(
|
|
106
106
|
preferences,
|
107
107
|
classical_execution_function,
|
108
108
|
)
|
109
|
-
generative_functions = _get_generative_functions(gen_main)
|
109
|
+
generative_functions = _get_generative_functions(gen_main, preferences)
|
110
110
|
model.functions = generative_functions
|
111
111
|
model.types = list(QMODULE.type_decls.values())
|
112
112
|
model.enums = list(QMODULE.enum_decls.values())
|
@@ -114,20 +114,25 @@ def _expand_generative_model(
|
|
114
114
|
return model
|
115
115
|
|
116
116
|
|
117
|
-
def _get_generative_functions(
|
117
|
+
def _get_generative_functions(
|
118
|
+
gen_main: QFunc, preferences: Optional[Preferences]
|
119
|
+
) -> List[NativeFunctionDefinition]:
|
118
120
|
# The Interpreter accepts a model and a list of generative functions.
|
119
121
|
# Since the main function is generative, it can only be expanded using the
|
120
122
|
# Interpreter.
|
121
123
|
# To solve this deadlock, we create a wrapper model
|
122
124
|
# `qfunc main(...) { _gen_main(...); }` and rename `main` to `_gen_main` before
|
123
125
|
# passing them to the Interpreter.
|
124
|
-
gen_model = _get_wrapper_main(gen_main)
|
126
|
+
gen_model = _get_wrapper_main(gen_main, preferences)
|
125
127
|
gen_functions = _get_all_model_functions_as_generative_functions()
|
126
128
|
functions_dict = _interpret_generative_model(gen_model, gen_functions)
|
127
129
|
return list(functions_dict.values())
|
128
130
|
|
129
131
|
|
130
|
-
def _get_wrapper_main(gen_main: QFunc) -> Model:
|
132
|
+
def _get_wrapper_main(gen_main: QFunc, preferences: Optional[Preferences]) -> Model:
|
133
|
+
extra_args = {}
|
134
|
+
if preferences is not None:
|
135
|
+
extra_args["preferences"] = preferences
|
131
136
|
return Model(
|
132
137
|
functions=[
|
133
138
|
NativeFunctionDefinition(
|
@@ -145,6 +150,7 @@ def _get_wrapper_main(gen_main: QFunc) -> Model:
|
|
145
150
|
],
|
146
151
|
),
|
147
152
|
],
|
153
|
+
**extra_args,
|
148
154
|
)
|
149
155
|
|
150
156
|
|
@@ -159,7 +165,7 @@ def _get_all_model_functions_as_generative_functions() -> List[GenerativeQFunc]:
|
|
159
165
|
if gen_func.func_decl.name != MAIN_FUNCTION_NAME
|
160
166
|
else GenerativeQFunc(
|
161
167
|
gen_func._py_callable,
|
162
|
-
gen_func.func_decl.
|
168
|
+
gen_func.func_decl.model_copy(update={"name": GEN_MAIN_NAME}),
|
163
169
|
)
|
164
170
|
)
|
165
171
|
for gen_func in gen_functions
|
@@ -182,9 +188,9 @@ def _interpret_generative_model(
|
|
182
188
|
expanded_gen_main_name = cast(
|
183
189
|
QuantumFunctionCall, functions_dict[MAIN_FUNCTION_NAME].body[0]
|
184
190
|
).func_name
|
185
|
-
functions_dict[MAIN_FUNCTION_NAME] = functions_dict[
|
186
|
-
|
187
|
-
)
|
191
|
+
functions_dict[MAIN_FUNCTION_NAME] = functions_dict[
|
192
|
+
expanded_gen_main_name
|
193
|
+
].model_copy(update={"name": MAIN_FUNCTION_NAME})
|
188
194
|
functions_dict.pop(expanded_gen_main_name)
|
189
195
|
|
190
196
|
return functions_dict
|