classiq 0.51.1__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/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 +38 -9
- 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 +4 -4
- 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.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
- {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
- {classiq-0.51.1.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
|
@@ -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
|
"""
|
@@ -165,7 +165,7 @@ def _get_all_model_functions_as_generative_functions() -> List[GenerativeQFunc]:
|
|
165
165
|
if gen_func.func_decl.name != MAIN_FUNCTION_NAME
|
166
166
|
else GenerativeQFunc(
|
167
167
|
gen_func._py_callable,
|
168
|
-
gen_func.func_decl.
|
168
|
+
gen_func.func_decl.model_copy(update={"name": GEN_MAIN_NAME}),
|
169
169
|
)
|
170
170
|
)
|
171
171
|
for gen_func in gen_functions
|
@@ -188,9 +188,9 @@ def _interpret_generative_model(
|
|
188
188
|
expanded_gen_main_name = cast(
|
189
189
|
QuantumFunctionCall, functions_dict[MAIN_FUNCTION_NAME].body[0]
|
190
190
|
).func_name
|
191
|
-
functions_dict[MAIN_FUNCTION_NAME] = functions_dict[
|
192
|
-
|
193
|
-
)
|
191
|
+
functions_dict[MAIN_FUNCTION_NAME] = functions_dict[
|
192
|
+
expanded_gen_main_name
|
193
|
+
].model_copy(update={"name": MAIN_FUNCTION_NAME})
|
194
194
|
functions_dict.pop(expanded_gen_main_name)
|
195
195
|
|
196
196
|
return functions_dict
|
@@ -17,12 +17,16 @@ from typing import (
|
|
17
17
|
overload,
|
18
18
|
)
|
19
19
|
|
20
|
+
import pydantic
|
20
21
|
from sympy import Basic
|
21
22
|
from typing_extensions import Self
|
22
23
|
|
23
24
|
from classiq.interface.exceptions import ClassiqValueError
|
24
25
|
from classiq.interface.generator.expressions.expression import Expression
|
25
|
-
from classiq.interface.generator.functions.concrete_types import
|
26
|
+
from classiq.interface.generator.functions.concrete_types import (
|
27
|
+
NativePythonClassicalTypes,
|
28
|
+
PythonClassicalPydanticTypes,
|
29
|
+
)
|
26
30
|
from classiq.interface.model.classical_parameter_declaration import (
|
27
31
|
AnonClassicalParameterDeclaration,
|
28
32
|
)
|
@@ -334,15 +338,24 @@ def prepare_arg(
|
|
334
338
|
def _validate_classical_arg(
|
335
339
|
arg: Any, arg_decl: AnonClassicalParameterDeclaration, func_name: Optional[str]
|
336
340
|
) -> None:
|
341
|
+
is_native_or_compatible_type = not isinstance(
|
342
|
+
arg, (*NativePythonClassicalTypes, CParam, SymbolicExpr, Basic, PythonEnum)
|
343
|
+
) and not is_dataclass(
|
344
|
+
arg
|
345
|
+
) # type: ignore[unreachable]
|
346
|
+
try:
|
347
|
+
is_pydantic_classical_type = isinstance(
|
348
|
+
arg, pydantic.BaseModel
|
349
|
+
) and not isinstance(arg, PythonClassicalPydanticTypes)
|
350
|
+
except ClassiqValueError:
|
351
|
+
is_pydantic_classical_type = False
|
352
|
+
|
353
|
+
is_incompatible_symbolic_expr = isinstance(arg, SymbolicExpr) and arg.is_quantum
|
354
|
+
|
337
355
|
if (
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
and not is_dataclass(arg) # type:ignore[unreachable]
|
342
|
-
or isinstance(arg, SymbolicExpr)
|
343
|
-
and arg.is_quantum
|
344
|
-
):
|
345
|
-
func_name_message = "" if func_name is None else f" of function {func_name!r}"
|
356
|
+
is_native_or_compatible_type or is_pydantic_classical_type
|
357
|
+
) or is_incompatible_symbolic_expr:
|
358
|
+
func_name_message = f" of function {func_name!r}" if func_name else ""
|
346
359
|
raise ClassiqValueError(
|
347
360
|
f"Argument {str(arg)!r} to parameter {arg_decl.name!r}{func_name_message} "
|
348
361
|
f"has incompatible type; expected "
|
classiq/qmod/quantum_function.py
CHANGED
@@ -82,7 +82,7 @@ class QFunc(QExpandable):
|
|
82
82
|
return
|
83
83
|
super().expand()
|
84
84
|
self._qmodule.native_defs[self.func_decl.name] = NativeFunctionDefinition(
|
85
|
-
**{**self.func_decl.
|
85
|
+
**{**self.func_decl.model_dump(), **{"body": self.body}}
|
86
86
|
)
|
87
87
|
|
88
88
|
def _add_constants_from_classical_code(
|
@@ -209,7 +209,9 @@ class StaticSemanticsVisitor(Visitor):
|
|
209
209
|
**self.current_scope.operands,
|
210
210
|
},
|
211
211
|
)
|
212
|
-
elif isinstance(op, InplaceBinaryOperation)
|
212
|
+
elif isinstance(op, InplaceBinaryOperation) and isinstance(
|
213
|
+
op.value, HandleBinding
|
214
|
+
):
|
213
215
|
check_no_overlapping_quantum_args(
|
214
216
|
[op.target, op.value], op.operation.value
|
215
217
|
)
|
@@ -10,7 +10,7 @@ def decl_without_type_attributes(
|
|
10
10
|
operand_declaration: AnonQuantumOperandDeclaration,
|
11
11
|
) -> AnonQuantumOperandDeclaration:
|
12
12
|
remover = AttributeRemover()
|
13
|
-
return operand_declaration.
|
13
|
+
return operand_declaration.model_copy(
|
14
14
|
update=dict(
|
15
15
|
positional_arg_declarations=[
|
16
16
|
remover.visit(arg) if isinstance(arg, PortDeclaration) else arg
|