classiq 0.84.0__py3-none-any.whl → 0.86.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/applications/combinatorial_optimization/combinatorial_problem.py +24 -45
- classiq/evaluators/classical_expression.py +32 -15
- classiq/evaluators/qmod_annotated_expression.py +207 -0
- classiq/evaluators/qmod_expression_visitors/__init__.py +0 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +134 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +232 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_renamer.py +44 -0
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +308 -0
- classiq/evaluators/qmod_node_evaluators/__init__.py +0 -0
- classiq/evaluators/qmod_node_evaluators/attribute_evaluation.py +112 -0
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +132 -0
- classiq/evaluators/qmod_node_evaluators/bool_op_evaluation.py +70 -0
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +311 -0
- classiq/evaluators/qmod_node_evaluators/compare_evaluation.py +107 -0
- classiq/evaluators/qmod_node_evaluators/constant_evaluation.py +67 -0
- classiq/evaluators/qmod_node_evaluators/list_evaluation.py +107 -0
- classiq/evaluators/qmod_node_evaluators/measurement_evaluation.py +25 -0
- classiq/evaluators/qmod_node_evaluators/name_evaluation.py +50 -0
- classiq/evaluators/qmod_node_evaluators/struct_instantiation_evaluation.py +66 -0
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +225 -0
- classiq/evaluators/qmod_node_evaluators/unary_op_evaluation.py +58 -0
- classiq/evaluators/qmod_node_evaluators/utils.py +80 -0
- classiq/execution/execution_session.py +53 -6
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +1 -1
- classiq/interface/analyzer/result.py +1 -1
- classiq/interface/debug_info/debug_info.py +0 -4
- classiq/interface/executor/quantum_code.py +2 -2
- classiq/interface/generator/arith/arithmetic_expression_validator.py +5 -1
- classiq/interface/generator/arith/binary_ops.py +43 -51
- classiq/interface/generator/arith/number_utils.py +3 -2
- classiq/interface/generator/arith/register_user_input.py +15 -0
- classiq/interface/generator/arith/unary_ops.py +32 -28
- classiq/interface/generator/expressions/atomic_expression_functions.py +5 -0
- classiq/interface/generator/expressions/expression_types.py +2 -2
- classiq/interface/generator/expressions/proxies/classical/qmod_struct_instance.py +7 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +2 -0
- classiq/interface/generator/functions/classical_function_declaration.py +0 -4
- classiq/interface/generator/functions/classical_type.py +0 -32
- classiq/interface/generator/functions/concrete_types.py +20 -0
- classiq/interface/generator/generated_circuit_data.py +7 -10
- classiq/interface/generator/quantum_program.py +6 -1
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +29 -0
- classiq/interface/ide/operation_registry.py +45 -0
- classiq/interface/ide/visual_model.py +84 -2
- classiq/interface/model/bounds.py +12 -2
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +7 -4
- classiq/interface/model/quantum_type.py +67 -33
- classiq/interface/model/variable_declaration_statement.py +33 -6
- classiq/model_expansions/arithmetic.py +115 -0
- classiq/model_expansions/arithmetic_compute_result_attrs.py +71 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +10 -6
- classiq/model_expansions/function_builder.py +4 -1
- classiq/model_expansions/generative_functions.py +15 -2
- classiq/model_expansions/interpreters/base_interpreter.py +7 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +18 -1
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +63 -21
- classiq/model_expansions/quantum_operations/bounds.py +7 -1
- classiq/model_expansions/quantum_operations/call_emitter.py +5 -2
- classiq/model_expansions/quantum_operations/classical_var_emitter.py +16 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +30 -10
- classiq/model_expansions/scope.py +7 -0
- classiq/model_expansions/scope_initialization.py +2 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +1 -1
- classiq/model_expansions/transformers/type_modifier_inference.py +5 -0
- classiq/model_expansions/transformers/var_splitter.py +1 -1
- classiq/model_expansions/visitors/boolean_expression_transformers.py +1 -1
- classiq/open_library/functions/__init__.py +0 -2
- classiq/open_library/functions/qaoa_penalty.py +8 -1
- classiq/open_library/functions/state_preparation.py +1 -32
- classiq/qmod/__init__.py +2 -0
- classiq/qmod/builtins/operations.py +66 -2
- classiq/qmod/classical_variable.py +74 -0
- classiq/qmod/declaration_inferrer.py +5 -3
- classiq/qmod/native/pretty_printer.py +18 -14
- classiq/qmod/pretty_print/pretty_printer.py +34 -15
- classiq/qmod/qfunc.py +2 -19
- classiq/qmod/qmod_variable.py +5 -8
- classiq/qmod/quantum_expandable.py +1 -1
- classiq/qmod/quantum_function.py +42 -2
- classiq/qmod/symbolic_type.py +2 -1
- classiq/qmod/write_qmod.py +3 -1
- {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/METADATA +1 -1
- {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/RECORD +86 -62
- classiq/interface/model/quantum_variable_declaration.py +0 -7
- /classiq/{model_expansions/sympy_conversion/arithmetics.py → evaluators/qmod_expression_visitors/sympy_wrappers.py} +0 -0
- {classiq-0.84.0.dist-info → classiq-0.86.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
from classiq.model_expansions.arithmetic import NumericAttributes
|
2
|
+
|
3
|
+
|
4
|
+
def compute_result_attrs_assign(
|
5
|
+
source: NumericAttributes,
|
6
|
+
machine_precision: int,
|
7
|
+
) -> NumericAttributes:
|
8
|
+
if machine_precision >= source.fraction_digits:
|
9
|
+
return source
|
10
|
+
|
11
|
+
trimmed_digits = source.fraction_digits - machine_precision
|
12
|
+
return NumericAttributes(
|
13
|
+
size=source.size - trimmed_digits,
|
14
|
+
is_signed=source.is_signed,
|
15
|
+
fraction_digits=machine_precision,
|
16
|
+
bounds=source.bounds,
|
17
|
+
trim_bounds=True,
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
def compute_result_attrs_bitwise_invert(
|
22
|
+
arg: NumericAttributes,
|
23
|
+
machine_precision: int,
|
24
|
+
) -> NumericAttributes:
|
25
|
+
fraction_digits = min(arg.fraction_digits, machine_precision)
|
26
|
+
trimmed_bits = arg.fraction_digits - fraction_digits
|
27
|
+
return NumericAttributes(
|
28
|
+
size=arg.size - trimmed_bits,
|
29
|
+
is_signed=arg.is_signed,
|
30
|
+
fraction_digits=fraction_digits,
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
def compute_result_attrs_negate(
|
35
|
+
arg: NumericAttributes,
|
36
|
+
machine_precision: int,
|
37
|
+
) -> NumericAttributes:
|
38
|
+
lb = -arg.ub
|
39
|
+
ub = -arg.lb
|
40
|
+
|
41
|
+
if arg.size == 1:
|
42
|
+
return NumericAttributes(
|
43
|
+
size=1,
|
44
|
+
is_signed=lb < 0,
|
45
|
+
fraction_digits=arg.fraction_digits,
|
46
|
+
bounds=(lb, ub),
|
47
|
+
)
|
48
|
+
else:
|
49
|
+
return NumericAttributes.from_bounds(
|
50
|
+
lb, ub, arg.fraction_digits, machine_precision
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
def compute_result_attrs_add(
|
55
|
+
left: NumericAttributes,
|
56
|
+
right: NumericAttributes,
|
57
|
+
machine_precision: int,
|
58
|
+
) -> NumericAttributes:
|
59
|
+
lb = left.lb + right.lb
|
60
|
+
ub = left.ub + right.ub
|
61
|
+
fraction_places = max(left.fraction_digits, right.fraction_digits)
|
62
|
+
return NumericAttributes.from_bounds(lb, ub, fraction_places, machine_precision)
|
63
|
+
|
64
|
+
|
65
|
+
def compute_result_attrs_subtract(
|
66
|
+
left: NumericAttributes,
|
67
|
+
right: NumericAttributes,
|
68
|
+
machine_precision: int,
|
69
|
+
) -> NumericAttributes:
|
70
|
+
tmp = compute_result_attrs_negate(right, machine_precision)
|
71
|
+
return compute_result_attrs_add(left, tmp, machine_precision)
|
@@ -9,6 +9,9 @@ from classiq.interface.exceptions import (
|
|
9
9
|
ClassiqExpansionError,
|
10
10
|
ClassiqInternalExpansionError,
|
11
11
|
)
|
12
|
+
from classiq.interface.generator.expressions.atomic_expression_functions import (
|
13
|
+
MEASUREMENT_FUNCTIONS,
|
14
|
+
)
|
12
15
|
from classiq.interface.generator.expressions.expression_types import (
|
13
16
|
ExpressionValue,
|
14
17
|
QmodStructInstance,
|
@@ -49,11 +52,7 @@ from classiq.interface.generator.functions.classical_type import (
|
|
49
52
|
from classiq.interface.generator.functions.type_name import TypeName
|
50
53
|
from classiq.interface.helpers.backward_compatibility import zip_strict
|
51
54
|
|
52
|
-
from classiq.
|
53
|
-
HandleIdentifier,
|
54
|
-
HandleTable,
|
55
|
-
)
|
56
|
-
from classiq.model_expansions.sympy_conversion.arithmetics import (
|
55
|
+
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import (
|
57
56
|
BitwiseAnd,
|
58
57
|
BitwiseNot,
|
59
58
|
BitwiseOr,
|
@@ -62,6 +61,10 @@ from classiq.model_expansions.sympy_conversion.arithmetics import (
|
|
62
61
|
LShift,
|
63
62
|
RShift,
|
64
63
|
)
|
64
|
+
from classiq.model_expansions.model_tables import (
|
65
|
+
HandleIdentifier,
|
66
|
+
HandleTable,
|
67
|
+
)
|
65
68
|
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
66
69
|
MISSING_SLICE_VALUE_PLACEHOLDER,
|
67
70
|
)
|
@@ -398,7 +401,8 @@ def _symbolic_function(func: str) -> Callable:
|
|
398
401
|
|
399
402
|
|
400
403
|
QMOD_CLASSICAL_FUNCTIONS = [
|
401
|
-
_symbolic_function(func)
|
404
|
+
_symbolic_function(func)
|
405
|
+
for func in qmod_classical_functions + list(MEASUREMENT_FUNCTIONS)
|
402
406
|
]
|
403
407
|
|
404
408
|
ATOMIC_EXPRESSION_FUNCTIONS = {
|
@@ -9,6 +9,7 @@ from classiq.interface.generator.compiler_keywords import (
|
|
9
9
|
LAMBDA_KEYWORD,
|
10
10
|
)
|
11
11
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
12
|
+
BLOCK_OPERATOR_NAME,
|
12
13
|
WITHIN_APPLY_NAME,
|
13
14
|
)
|
14
15
|
from classiq.interface.model.model import MAIN_FUNCTION_NAME
|
@@ -35,6 +36,8 @@ from classiq.model_expansions.utils.counted_name_allocator import CountedNameAll
|
|
35
36
|
|
36
37
|
ClosureType = TypeVar("ClosureType", bound=Closure)
|
37
38
|
|
39
|
+
BLOCKS_ALLOWED_CAPTURING = (WITHIN_APPLY_NAME, BLOCK_OPERATOR_NAME)
|
40
|
+
|
38
41
|
|
39
42
|
@dataclass
|
40
43
|
class Block:
|
@@ -142,7 +145,7 @@ class OperationBuilder:
|
|
142
145
|
captured_vars = self.current_block.captured_vars
|
143
146
|
if (
|
144
147
|
not isinstance(self.current_operation, FunctionClosure)
|
145
|
-
and self.current_operation.name
|
148
|
+
and self.current_operation.name not in BLOCKS_ALLOWED_CAPTURING
|
146
149
|
):
|
147
150
|
validate_captured_directions(
|
148
151
|
captured_vars.filter_var_decls(
|
@@ -20,6 +20,7 @@ from classiq.interface.helpers.datastructures import LenList
|
|
20
20
|
from classiq.interface.helpers.pydantic_model_helpers import nameables_to_dict
|
21
21
|
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
22
22
|
from classiq.interface.model.port_declaration import PortDeclaration
|
23
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
23
24
|
from classiq.interface.model.quantum_function_declaration import (
|
24
25
|
PositionalArg,
|
25
26
|
QuantumFunctionDeclaration,
|
@@ -32,6 +33,7 @@ from classiq.model_expansions.closure import (
|
|
32
33
|
GenerativeClosure,
|
33
34
|
)
|
34
35
|
from classiq.model_expansions.scope import Evaluated
|
36
|
+
from classiq.qmod.builtins.functions import __all__ as all_builtin_func_names
|
35
37
|
from classiq.qmod.generative import generative_mode_context, set_frontend_interpreter
|
36
38
|
from classiq.qmod.model_state_container import QMODULE
|
37
39
|
from classiq.qmod.qmod_parameter import CParamStruct, create_param
|
@@ -50,6 +52,9 @@ if TYPE_CHECKING:
|
|
50
52
|
)
|
51
53
|
|
52
54
|
|
55
|
+
ALL_STANDARD_GATES = {func for func in all_builtin_func_names if func.isupper()}
|
56
|
+
|
57
|
+
|
53
58
|
def _unwrap_traceback_frame(e: Exception) -> Exception:
|
54
59
|
fallback_error = ClassiqExpansionError(str(e))
|
55
60
|
traceback = exc_info()[2]
|
@@ -130,6 +135,15 @@ class _InterpreterExpandable(QFunc):
|
|
130
135
|
self._interpreter = interpreter
|
131
136
|
|
132
137
|
def append_statement_to_body(self, stmt: QuantumStatement) -> None:
|
138
|
+
if (
|
139
|
+
not isinstance(stmt, QuantumFunctionCall)
|
140
|
+
or stmt.func_name not in ALL_STANDARD_GATES
|
141
|
+
):
|
142
|
+
stmt = self._annotate_statement(stmt)
|
143
|
+
with generative_mode_context(False):
|
144
|
+
self._interpreter.emit_statement(stmt)
|
145
|
+
|
146
|
+
def _annotate_statement(self, stmt: QuantumStatement) -> QuantumStatement:
|
133
147
|
current_operation = self._interpreter._builder._operations[-1]
|
134
148
|
dummy_function = NativeFunctionDefinition(
|
135
149
|
name=current_operation.name,
|
@@ -155,8 +169,7 @@ class _InterpreterExpandable(QFunc):
|
|
155
169
|
)
|
156
170
|
resolve_function_calls(dummy_function, func_decls)
|
157
171
|
stmt = dummy_function.body[-1]
|
158
|
-
|
159
|
-
self._interpreter.emit_statement(stmt)
|
172
|
+
return stmt
|
160
173
|
|
161
174
|
def _get_function_declarations(self) -> Mapping[str, QuantumFunctionDeclaration]:
|
162
175
|
scope_func_decls: dict[str, QuantumFunctionDeclaration] = {}
|
@@ -20,6 +20,9 @@ from classiq.interface.generator.expressions.atomic_expression_functions import
|
|
20
20
|
CLASSICAL_ATTRIBUTES,
|
21
21
|
)
|
22
22
|
from classiq.interface.generator.expressions.expression import Expression
|
23
|
+
from classiq.interface.generator.functions.classical_function_declaration import (
|
24
|
+
ClassicalFunctionDeclaration,
|
25
|
+
)
|
23
26
|
from classiq.interface.generator.types.compilation_metadata import CompilationMetadata
|
24
27
|
from classiq.interface.model.handle_binding import (
|
25
28
|
FieldHandleBinding,
|
@@ -69,6 +72,7 @@ from classiq.qmod.builtins.constants import __all__ as builtin_constants
|
|
69
72
|
from classiq.qmod.builtins.enums import BUILTIN_ENUM_DECLARATIONS
|
70
73
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
71
74
|
from classiq.qmod.model_state_container import QMODULE
|
75
|
+
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
72
76
|
from classiq.qmod.semantics.error_manager import ErrorManager
|
73
77
|
from classiq.qmod.semantics.validation.model_validation import validate_model
|
74
78
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
@@ -89,6 +93,9 @@ class BaseInterpreter:
|
|
89
93
|
|
90
94
|
init_builtin_types()
|
91
95
|
init_top_level_scope(model, self._top_level_scope)
|
96
|
+
QStructAnnotator().visit(
|
97
|
+
ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS
|
98
|
+
)
|
92
99
|
self._functions_compilation_metadata: dict[str, CompilationMetadata] = dict(
|
93
100
|
self._model.functions_compilation_metadata
|
94
101
|
)
|
@@ -7,6 +7,7 @@ from numpy.random import permutation
|
|
7
7
|
from classiq.interface.generator.constant import Constant
|
8
8
|
from classiq.interface.generator.expressions.expression import Expression
|
9
9
|
from classiq.interface.generator.functions.builtins.internal_operators import (
|
10
|
+
BLOCK_OPERATOR_NAME,
|
10
11
|
CLASSICAL_IF_OPERATOR_NAME,
|
11
12
|
CONTROL_OPERATOR_NAME,
|
12
13
|
INVERT_OPERATOR_NAME,
|
@@ -15,6 +16,7 @@ from classiq.interface.generator.functions.builtins.internal_operators import (
|
|
15
16
|
)
|
16
17
|
from classiq.interface.model.allocate import Allocate
|
17
18
|
from classiq.interface.model.bind_operation import BindOperation
|
19
|
+
from classiq.interface.model.block import Block
|
18
20
|
from classiq.interface.model.bounds import SetBoundsStatement
|
19
21
|
from classiq.interface.model.classical_if import ClassicalIf
|
20
22
|
from classiq.interface.model.control import Control
|
@@ -68,6 +70,9 @@ from classiq.model_expansions.quantum_operations.block_evaluator import (
|
|
68
70
|
RepeatElimination,
|
69
71
|
)
|
70
72
|
from classiq.model_expansions.quantum_operations.bounds import SetBoundsEmitter
|
73
|
+
from classiq.model_expansions.quantum_operations.classical_var_emitter import (
|
74
|
+
ClassicalVarEmitter,
|
75
|
+
)
|
71
76
|
from classiq.model_expansions.quantum_operations.composite_emitter import (
|
72
77
|
CompositeEmitter,
|
73
78
|
)
|
@@ -87,6 +92,7 @@ from classiq.model_expansions.scope_initialization import (
|
|
87
92
|
from classiq.qmod.builtins.functions import permute
|
88
93
|
from classiq.qmod.model_state_container import ModelStateContainer
|
89
94
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
95
|
+
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
90
96
|
|
91
97
|
|
92
98
|
class GenerativeInterpreter(BaseInterpreter):
|
@@ -192,6 +198,7 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
192
198
|
[
|
193
199
|
HandleEvaluator(self, "result_var"),
|
194
200
|
ExpressionEvaluator(self, "expression"),
|
201
|
+
ClassicalVarEmitter(self),
|
195
202
|
AssignmentResultProcessor(self),
|
196
203
|
],
|
197
204
|
).emit(op)
|
@@ -303,9 +310,18 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
303
310
|
def emit_set_bounds(self, op: SetBoundsStatement) -> None:
|
304
311
|
CompositeEmitter[SetBoundsStatement](
|
305
312
|
self,
|
306
|
-
[
|
313
|
+
[
|
314
|
+
ExpressionEvaluator(self, "lower_bound"),
|
315
|
+
ExpressionEvaluator(self, "upper_bound"),
|
316
|
+
HandleEvaluator(self, "target"),
|
317
|
+
SetBoundsEmitter(self),
|
318
|
+
],
|
307
319
|
).emit(op)
|
308
320
|
|
321
|
+
@emit.register
|
322
|
+
def emit_block(self, block: Block) -> None:
|
323
|
+
BlockEvaluator(self, BLOCK_OPERATOR_NAME, "statements").emit(block)
|
324
|
+
|
309
325
|
def _expand_body(self, operation: Closure) -> None:
|
310
326
|
if isinstance(operation, FunctionClosure) and operation.name == "permute":
|
311
327
|
# special expansion since permute is generative
|
@@ -358,4 +374,5 @@ class GenerativeInterpreter(BaseInterpreter):
|
|
358
374
|
)
|
359
375
|
|
360
376
|
def add_constant(self, constant: Constant) -> None:
|
377
|
+
QStructAnnotator().visit(constant.const_type)
|
361
378
|
add_constants_to_scope([constant], self._top_level_scope)
|
@@ -1,10 +1,12 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
2
2
|
|
3
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
4
4
|
from classiq.interface.generator.arith.arithmetic import compute_arithmetic_result_type
|
5
5
|
from classiq.interface.generator.expressions.expression import Expression
|
6
6
|
from classiq.interface.model.allocate import Allocate
|
7
7
|
from classiq.interface.model.bind_operation import BindOperation
|
8
|
+
from classiq.interface.model.block import Block
|
9
|
+
from classiq.interface.model.bounds import SetBoundsStatement
|
8
10
|
from classiq.interface.model.handle_binding import (
|
9
11
|
ConcreteHandleBinding,
|
10
12
|
HandleBinding,
|
@@ -19,6 +21,7 @@ from classiq.interface.model.quantum_expressions.quantum_expression import (
|
|
19
21
|
)
|
20
22
|
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
21
23
|
from classiq.interface.model.quantum_type import QuantumBitvector, QuantumNumeric
|
24
|
+
from classiq.interface.model.statement_block import StatementBlock
|
22
25
|
from classiq.interface.model.variable_declaration_statement import (
|
23
26
|
VariableDeclarationStatement,
|
24
27
|
)
|
@@ -30,14 +33,25 @@ from classiq.model_expansions.quantum_operations.arithmetic.explicit_boolean_exp
|
|
30
33
|
validate_assignment_bool_expression,
|
31
34
|
)
|
32
35
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
33
|
-
from classiq.model_expansions.scope import
|
36
|
+
from classiq.model_expansions.scope import ClassicalSymbol
|
34
37
|
from classiq.model_expansions.transformers.ast_renamer import rename_variables
|
35
38
|
from classiq.qmod.builtins.functions.standard_gates import CX
|
36
39
|
|
40
|
+
if TYPE_CHECKING:
|
41
|
+
from classiq.model_expansions.interpreters.base_interpreter import BaseInterpreter
|
42
|
+
|
37
43
|
|
38
44
|
class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
45
|
+
def __init__(
|
46
|
+
self, interpreter: "BaseInterpreter", replace_assignment_if_needed: bool = False
|
47
|
+
) -> None:
|
48
|
+
super().__init__(interpreter)
|
49
|
+
self._replace_assignment_if_needed = replace_assignment_if_needed
|
50
|
+
|
39
51
|
def emit(self, op: QuantumAssignmentOperation, /) -> bool:
|
40
|
-
result_symbol = self._interpreter.evaluate(op.result_var).
|
52
|
+
result_symbol = self._interpreter.evaluate(op.result_var).value
|
53
|
+
if isinstance(result_symbol, ClassicalSymbol):
|
54
|
+
return False
|
41
55
|
result_type = result_symbol.quantum_type
|
42
56
|
|
43
57
|
if not (
|
@@ -70,9 +84,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
70
84
|
self._validate_declared_attributes(
|
71
85
|
result_type, inferred_result_type, str(op.result_var)
|
72
86
|
)
|
73
|
-
self.
|
74
|
-
|
75
|
-
|
87
|
+
if self._replace_assignment_if_needed:
|
88
|
+
self._assign_to_inferred_var_and_bind(op, result_type, inferred_result_type)
|
89
|
+
return True
|
90
|
+
else:
|
91
|
+
return False
|
76
92
|
|
77
93
|
def _infer_result_type(self, op: ArithmeticOperation) -> Optional[QuantumNumeric]:
|
78
94
|
expr = self._evaluate_expression(op.expression)
|
@@ -182,6 +198,7 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
182
198
|
result_type: QuantumNumeric,
|
183
199
|
inferred_result_type: QuantumNumeric,
|
184
200
|
) -> None:
|
201
|
+
stmts: StatementBlock = []
|
185
202
|
handles: list[HandleBinding] = []
|
186
203
|
|
187
204
|
extra_fraction_digits = (
|
@@ -190,20 +207,22 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
190
207
|
)
|
191
208
|
if extra_fraction_digits > 0:
|
192
209
|
handles.append(
|
193
|
-
self._declare_qarray(
|
210
|
+
self._declare_qarray(
|
211
|
+
"extra_fraction_digits", extra_fraction_digits, stmts
|
212
|
+
)
|
194
213
|
)
|
195
214
|
|
196
215
|
inferred_result_name = self._counted_name_allocator.allocate("inferred_result")
|
197
216
|
inferred_result_handle = HandleBinding(name=inferred_result_name)
|
198
|
-
|
217
|
+
stmts.append(
|
199
218
|
VariableDeclarationStatement(
|
200
|
-
name=inferred_result_name,
|
219
|
+
name=inferred_result_name, qmod_type=inferred_result_type
|
201
220
|
)
|
202
221
|
)
|
203
222
|
handles.append(inferred_result_handle)
|
204
223
|
modified_op = op.model_copy(update={"result_var": inferred_result_handle})
|
205
224
|
self._interpreter.add_to_debug_info(modified_op)
|
206
|
-
|
225
|
+
stmts.append(modified_op)
|
207
226
|
|
208
227
|
result_integer_size = (
|
209
228
|
result_type.size_in_bits - result_type.fraction_digits_value
|
@@ -214,11 +233,11 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
214
233
|
)
|
215
234
|
extra_integers = result_integer_size - inferred_result_integer_size
|
216
235
|
if extra_integers > 0:
|
217
|
-
handles.append(
|
236
|
+
handles.append(
|
237
|
+
self._declare_qarray("extra_integers", extra_integers, stmts)
|
238
|
+
)
|
218
239
|
|
219
|
-
|
220
|
-
BindOperation(in_handles=handles, out_handles=[op.result_var])
|
221
|
-
)
|
240
|
+
stmts.append(BindOperation(in_handles=handles, out_handles=[op.result_var]))
|
222
241
|
|
223
242
|
if (
|
224
243
|
result_type.sign_value
|
@@ -226,22 +245,44 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
226
245
|
and extra_integers > 0
|
227
246
|
):
|
228
247
|
sign_idx = result_type.size_in_bits - extra_integers - 1
|
229
|
-
self._sign_extension(
|
248
|
+
self._sign_extension(
|
249
|
+
op.result_var, sign_idx, result_type.size_in_bits, stmts
|
250
|
+
)
|
251
|
+
|
252
|
+
if (inferred_bounds := inferred_result_type.get_bounds()) is not None:
|
253
|
+
lower_bound = Expression(expr=str(inferred_bounds[0]))
|
254
|
+
upper_bound = Expression(expr=str(inferred_bounds[1]))
|
255
|
+
else:
|
256
|
+
lower_bound, upper_bound = None, None
|
257
|
+
stmts.append(
|
258
|
+
SetBoundsStatement(
|
259
|
+
target=op.result_var,
|
260
|
+
lower_bound=lower_bound,
|
261
|
+
upper_bound=upper_bound,
|
262
|
+
)
|
263
|
+
)
|
264
|
+
|
265
|
+
self._interpreter.emit(
|
266
|
+
Block(
|
267
|
+
statements=stmts,
|
268
|
+
uuid=op.uuid,
|
269
|
+
back_ref=op.back_ref,
|
270
|
+
)
|
271
|
+
)
|
230
272
|
|
231
273
|
def _declare_qarray(
|
232
274
|
self,
|
233
275
|
prefix: str,
|
234
276
|
size: int,
|
277
|
+
stmts: StatementBlock,
|
235
278
|
allocate: bool = True,
|
236
279
|
) -> HandleBinding:
|
237
280
|
name = self._counted_name_allocator.allocate(prefix)
|
238
281
|
handle = HandleBinding(name=name)
|
239
282
|
quantum_type = QuantumBitvector(length=Expression(expr=str(size)))
|
240
|
-
|
241
|
-
VariableDeclarationStatement(name=name, quantum_type=quantum_type)
|
242
|
-
)
|
283
|
+
stmts.append(VariableDeclarationStatement(name=name, qmod_type=quantum_type))
|
243
284
|
if allocate:
|
244
|
-
|
285
|
+
stmts.append(Allocate(target=handle))
|
245
286
|
return handle
|
246
287
|
|
247
288
|
def _sign_extension(
|
@@ -249,9 +290,10 @@ class AssignmentResultProcessor(Emitter[QuantumAssignmentOperation]):
|
|
249
290
|
result_var: ConcreteHandleBinding,
|
250
291
|
sign_idx: int,
|
251
292
|
size: int,
|
293
|
+
stmts: StatementBlock,
|
252
294
|
) -> None:
|
253
|
-
aux = self._declare_qarray("inferred_result_aux", size, allocate=False)
|
254
|
-
|
295
|
+
aux = self._declare_qarray("inferred_result_aux", size, stmts, allocate=False)
|
296
|
+
stmts.append(
|
255
297
|
WithinApply(
|
256
298
|
compute=[BindOperation(in_handles=[result_var], out_handles=[aux])],
|
257
299
|
action=[
|
@@ -24,7 +24,13 @@ class SetBoundsEmitter(Emitter[SetBoundsStatement]):
|
|
24
24
|
raise ClassiqExpansionError(
|
25
25
|
f"Cannot set bounds of a non-numeric variable {op.target.qmod_expr!r}"
|
26
26
|
)
|
27
|
-
|
27
|
+
|
28
|
+
if op.lower_bound is not None and op.upper_bound is not None:
|
29
|
+
target.quantum_type.set_bounds(
|
30
|
+
(op.lower_bound.to_float_value(), op.upper_bound.to_float_value())
|
31
|
+
)
|
32
|
+
else:
|
33
|
+
target.quantum_type.reset_bounds()
|
28
34
|
if self._keep_statement:
|
29
35
|
self.emit_statement(op)
|
30
36
|
return True
|
@@ -157,7 +157,10 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
157
157
|
return any(isinstance(stmt, VariableDeclarationStatement) for stmt in body)
|
158
158
|
|
159
159
|
def _create_expanded_wrapping_function(
|
160
|
-
self,
|
160
|
+
self,
|
161
|
+
name: str,
|
162
|
+
body: Sequence[QuantumStatement],
|
163
|
+
debug_info: Optional[FunctionDebugInfo] = None,
|
161
164
|
) -> QuantumFunctionCall:
|
162
165
|
wrapping_function = FunctionClosure.create(
|
163
166
|
name=self._counted_name_allocator.allocate(name),
|
@@ -165,7 +168,7 @@ class CallEmitter(Generic[QuantumStatementT], Emitter[QuantumStatementT], VarSpl
|
|
165
168
|
scope=Scope(parent=self._current_scope),
|
166
169
|
lambda_external_vars=self._builder.current_block.captured_vars,
|
167
170
|
)
|
168
|
-
return self._create_quantum_function_call(wrapping_function, list(),
|
171
|
+
return self._create_quantum_function_call(wrapping_function, list(), debug_info)
|
169
172
|
|
170
173
|
def _emit_quantum_function_call(
|
171
174
|
self,
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
2
|
+
ArithmeticOperation,
|
3
|
+
)
|
4
|
+
|
5
|
+
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
6
|
+
from classiq.model_expansions.scope import ClassicalSymbol
|
7
|
+
|
8
|
+
|
9
|
+
class ClassicalVarEmitter(Emitter[ArithmeticOperation]):
|
10
|
+
def emit(self, op: ArithmeticOperation, /) -> bool:
|
11
|
+
result_symbol = self._interpreter.evaluate(op.result_var).value
|
12
|
+
if not isinstance(result_symbol, ClassicalSymbol):
|
13
|
+
return False
|
14
|
+
op._classical_assignment = True
|
15
|
+
self.emit_statement(op)
|
16
|
+
return True
|
@@ -1,14 +1,19 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Union
|
2
|
+
|
1
3
|
from classiq.interface.exceptions import ClassiqExpansionError
|
4
|
+
from classiq.interface.generator.functions.classical_type import ClassicalType
|
2
5
|
from classiq.interface.model.handle_binding import HandleBinding
|
6
|
+
from classiq.interface.model.quantum_type import QuantumType
|
3
7
|
from classiq.interface.model.variable_declaration_statement import (
|
4
8
|
VariableDeclarationStatement,
|
5
9
|
)
|
6
10
|
|
7
11
|
from classiq.evaluators.parameter_types import (
|
12
|
+
evaluate_type_in_classical_symbol,
|
8
13
|
evaluate_type_in_quantum_symbol,
|
9
14
|
)
|
10
15
|
from classiq.model_expansions.quantum_operations.emitter import Emitter
|
11
|
-
from classiq.model_expansions.scope import Evaluated, QuantumSymbol
|
16
|
+
from classiq.model_expansions.scope import ClassicalSymbol, Evaluated, QuantumSymbol
|
12
17
|
|
13
18
|
|
14
19
|
class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement]):
|
@@ -16,24 +21,39 @@ class VariableDeclarationStatementEmitter(Emitter[VariableDeclarationStatement])
|
|
16
21
|
var_decl = variable_declaration.model_copy(
|
17
22
|
update=dict(back_ref=variable_declaration.uuid)
|
18
23
|
)
|
19
|
-
var_decl.
|
24
|
+
var_decl.qmod_type = variable_declaration.qmod_type.model_copy()
|
20
25
|
if variable_declaration.name in self._current_scope:
|
21
26
|
raise ClassiqExpansionError(
|
22
27
|
f"Variable {variable_declaration.name!r} is already defined"
|
23
28
|
)
|
24
|
-
|
25
|
-
|
29
|
+
var_value: Union[QuantumSymbol, ClassicalSymbol]
|
30
|
+
if variable_declaration.is_quantum:
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
assert isinstance(var_decl.qmod_type, QuantumType)
|
33
|
+
var_value = QuantumSymbol(
|
26
34
|
handle=HandleBinding(name=var_decl.name),
|
27
35
|
quantum_type=evaluate_type_in_quantum_symbol(
|
28
|
-
var_decl.
|
36
|
+
var_decl.qmod_type,
|
29
37
|
self._current_scope,
|
30
38
|
var_decl.name,
|
31
39
|
),
|
32
|
-
)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
)
|
41
|
+
self._builder.current_block.captured_vars.init_var(
|
42
|
+
var_decl.name, self._builder.current_function
|
43
|
+
)
|
44
|
+
else:
|
45
|
+
if TYPE_CHECKING:
|
46
|
+
assert isinstance(var_decl.qmod_type, ClassicalType)
|
47
|
+
var_value = ClassicalSymbol(
|
48
|
+
handle=HandleBinding(name=var_decl.name),
|
49
|
+
classical_type=evaluate_type_in_classical_symbol(
|
50
|
+
var_decl.qmod_type,
|
51
|
+
self._current_scope,
|
52
|
+
var_decl.name,
|
53
|
+
),
|
54
|
+
)
|
55
|
+
self._current_scope[variable_declaration.name] = Evaluated(
|
56
|
+
value=var_value, defining_function=self._builder.current_function
|
37
57
|
)
|
38
58
|
self.emit_statement(var_decl)
|
39
59
|
return True
|
@@ -21,6 +21,7 @@ from classiq.interface.generator.expressions.proxies.classical.classical_scalar_
|
|
21
21
|
from classiq.interface.generator.expressions.proxies.classical.qmod_struct_instance import (
|
22
22
|
QmodStructInstance,
|
23
23
|
)
|
24
|
+
from classiq.interface.generator.functions.classical_type import ClassicalType
|
24
25
|
from classiq.interface.generator.functions.type_name import TypeName
|
25
26
|
from classiq.interface.helpers.text_utils import readable_list, s
|
26
27
|
from classiq.interface.model.handle_binding import (
|
@@ -202,6 +203,12 @@ class QuantumSymbolList(QuantumVariable):
|
|
202
203
|
return str(self.handles)
|
203
204
|
|
204
205
|
|
206
|
+
@dataclass(frozen=True)
|
207
|
+
class ClassicalSymbol:
|
208
|
+
handle: HandleBinding
|
209
|
+
classical_type: ClassicalType
|
210
|
+
|
211
|
+
|
205
212
|
@singledispatch
|
206
213
|
def evaluated_to_str(value: Any) -> str:
|
207
214
|
return str(value)
|
@@ -28,6 +28,7 @@ from classiq.qmod.builtins.functions import (
|
|
28
28
|
from classiq.qmod.builtins.structs import BUILTIN_STRUCT_DECLARATIONS
|
29
29
|
from classiq.qmod.model_state_container import QMODULE
|
30
30
|
from classiq.qmod.quantum_function import GenerativeQFunc
|
31
|
+
from classiq.qmod.semantics.annotation.qstruct_annotator import QStructAnnotator
|
31
32
|
|
32
33
|
|
33
34
|
def add_constants_to_scope(constants: list[Constant], scope: Scope) -> None:
|
@@ -133,3 +134,4 @@ def init_top_level_scope(model: Model, scope: Scope) -> None:
|
|
133
134
|
def init_builtin_types() -> None:
|
134
135
|
QMODULE.enum_decls |= BUILTIN_ENUM_DECLARATIONS
|
135
136
|
QMODULE.type_decls |= BUILTIN_STRUCT_DECLARATIONS
|
137
|
+
QStructAnnotator().visit(BUILTIN_STRUCT_DECLARATIONS)
|
@@ -21,7 +21,7 @@ from classiq.interface.generator.expressions.proxies.classical.any_classical_val
|
|
21
21
|
AnyClassicalValue,
|
22
22
|
)
|
23
23
|
|
24
|
-
from classiq.
|
24
|
+
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import LogicalXor
|
25
25
|
|
26
26
|
|
27
27
|
def sympy_to_python(
|
@@ -16,6 +16,7 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
16
16
|
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
17
17
|
from classiq.interface.model.allocate import Allocate
|
18
18
|
from classiq.interface.model.bind_operation import BindOperation
|
19
|
+
from classiq.interface.model.block import Block
|
19
20
|
from classiq.interface.model.control import Control
|
20
21
|
from classiq.interface.model.invert import Invert
|
21
22
|
from classiq.interface.model.model_visitor import ModelVisitor
|
@@ -352,6 +353,10 @@ class TypeModifierValidation(ModelVisitor):
|
|
352
353
|
self.visit(within_apply.compute)
|
353
354
|
self.visit(within_apply.action)
|
354
355
|
|
356
|
+
def visit_Block(self, block: Block) -> None:
|
357
|
+
with self.source_reference_context(block.source_ref):
|
358
|
+
self.visit(block.statements)
|
359
|
+
|
355
360
|
|
356
361
|
def _merge_overlapping(bound_vars: Sequence[Collection[str]]) -> list[set[str]]:
|
357
362
|
"""
|
@@ -218,7 +218,7 @@ class VarSplitter(ModelRenamer):
|
|
218
218
|
return [
|
219
219
|
VariableDeclarationStatement(
|
220
220
|
name=part.target_var_name,
|
221
|
-
|
221
|
+
qmod_type=part.target_var_type,
|
222
222
|
)
|
223
223
|
for part in chain.from_iterable(symbol_parts.values())
|
224
224
|
]
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Union
|
|
4
4
|
|
5
5
|
from classiq.interface.exceptions import ClassiqInternalExpansionError
|
6
6
|
|
7
|
-
from classiq.
|
7
|
+
from classiq.evaluators.qmod_expression_visitors.sympy_wrappers import LogicalXor
|
8
8
|
|
9
9
|
|
10
10
|
class BooleanExpressionOptimizer(ast.NodeTransformer):
|