classiq 0.93.0__py3-none-any.whl → 0.99.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/__init__.py +11 -19
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +7 -7
- classiq/_analyzer_extras/interactive_hardware.py +19 -12
- classiq/_internals/api_wrapper.py +31 -142
- classiq/_internals/async_utils.py +4 -7
- classiq/_internals/authentication/auth0.py +41 -15
- classiq/_internals/authentication/authorization_code.py +9 -0
- classiq/_internals/authentication/authorization_flow.py +41 -0
- classiq/_internals/authentication/device.py +33 -52
- classiq/_internals/authentication/hybrid_flow.py +19 -0
- classiq/_internals/authentication/password_manager.py +13 -13
- classiq/_internals/authentication/token_manager.py +9 -9
- classiq/_internals/client.py +17 -44
- classiq/_internals/config.py +19 -5
- classiq/_internals/help.py +1 -2
- classiq/_internals/host_checker.py +3 -3
- classiq/_internals/jobs.py +14 -14
- classiq/_internals/type_validation.py +3 -3
- classiq/analyzer/analyzer.py +18 -18
- classiq/analyzer/rb.py +17 -8
- classiq/analyzer/show_interactive_hack.py +1 -1
- classiq/applications/__init__.py +2 -2
- classiq/applications/chemistry/__init__.py +0 -30
- classiq/applications/chemistry/op_utils.py +4 -4
- classiq/applications/chemistry/problems.py +3 -3
- classiq/applications/chemistry/ucc.py +1 -2
- classiq/applications/chemistry/z2_symmetries.py +4 -4
- classiq/applications/combinatorial_helpers/allowed_constraints.py +1 -3
- classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +2 -1
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +2 -2
- classiq/applications/combinatorial_helpers/encoding_mapping.py +2 -3
- classiq/applications/combinatorial_helpers/encoding_utils.py +2 -2
- classiq/applications/combinatorial_helpers/optimization_model.py +3 -4
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +2 -2
- classiq/applications/combinatorial_helpers/pyomo_utils.py +8 -8
- classiq/applications/combinatorial_helpers/sympy_utils.py +1 -3
- classiq/applications/combinatorial_helpers/transformations/encoding.py +3 -3
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +1 -2
- classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -3
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +4 -6
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +15 -10
- classiq/applications/hamiltonian/pauli_decomposition.py +6 -4
- classiq/applications/iqae/iqae.py +14 -11
- classiq/applications/qnn/datasets/dataset_base_classes.py +6 -6
- classiq/applications/qnn/datasets/dataset_parity.py +6 -6
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +1 -1
- classiq/applications/qnn/qlayer.py +9 -8
- classiq/applications/qnn/torch_utils.py +5 -6
- classiq/applications/qnn/types.py +2 -1
- classiq/applications/qsp/__init__.py +20 -2
- classiq/applications/qsp/qsp.py +238 -10
- classiq/applications/qsvm/qsvm_data_generation.py +1 -2
- classiq/evaluators/classical_expression.py +0 -4
- classiq/evaluators/parameter_types.py +10 -8
- classiq/evaluators/qmod_annotated_expression.py +31 -26
- classiq/evaluators/qmod_expression_visitors/qmod_expression_evaluator.py +14 -14
- classiq/evaluators/qmod_expression_visitors/qmod_expression_simplifier.py +2 -1
- classiq/evaluators/qmod_expression_visitors/sympy_wrappers.py +8 -8
- classiq/evaluators/qmod_node_evaluators/binary_op_evaluation.py +4 -4
- classiq/evaluators/qmod_node_evaluators/classical_function_evaluation.py +14 -4
- classiq/evaluators/qmod_node_evaluators/list_evaluation.py +2 -2
- classiq/evaluators/qmod_node_evaluators/numeric_attrs_utils.py +3 -3
- classiq/evaluators/qmod_node_evaluators/subscript_evaluation.py +9 -9
- classiq/evaluators/qmod_node_evaluators/utils.py +6 -6
- classiq/evaluators/qmod_type_inference/classical_type_inference.py +9 -10
- classiq/evaluators/qmod_type_inference/quantum_type_inference.py +5 -5
- classiq/execution/__init__.py +0 -3
- classiq/execution/execution_session.py +28 -21
- classiq/execution/jobs.py +26 -26
- classiq/execution/qnn.py +1 -2
- classiq/execution/user_budgets.py +71 -37
- classiq/executor.py +1 -3
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +4 -4
- classiq/interface/analyzer/cytoscape_graph.py +3 -3
- classiq/interface/analyzer/result.py +4 -4
- classiq/interface/ast_node.py +3 -3
- classiq/interface/backend/backend_preferences.py +26 -50
- classiq/interface/backend/ionq/ionq_quantum_program.py +5 -5
- classiq/interface/backend/provider_config/__init__.py +0 -0
- classiq/interface/backend/provider_config/provider_config.py +8 -0
- classiq/interface/backend/provider_config/providers/__init__.py +0 -0
- classiq/interface/backend/provider_config/providers/alice_bob.py +47 -0
- classiq/interface/backend/provider_config/providers/aqt.py +16 -0
- classiq/interface/backend/provider_config/providers/azure.py +37 -0
- classiq/interface/backend/provider_config/providers/braket.py +39 -0
- classiq/interface/backend/provider_config/providers/ibm.py +26 -0
- classiq/interface/backend/provider_config/providers/ionq.py +22 -0
- classiq/interface/backend/quantum_backend_providers.py +20 -2
- classiq/interface/chemistry/ansatz_library.py +3 -5
- classiq/interface/chemistry/operator.py +3 -3
- classiq/interface/combinatorial_optimization/examples/knapsack.py +2 -4
- classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +1 -2
- classiq/interface/compression_utils.py +2 -3
- classiq/interface/debug_info/debug_info.py +8 -7
- classiq/interface/exceptions.py +6 -7
- classiq/interface/execution/primitives.py +6 -6
- classiq/interface/executor/estimate_cost.py +1 -1
- classiq/interface/executor/execution_preferences.py +3 -5
- classiq/interface/executor/execution_request.py +10 -10
- classiq/interface/executor/execution_result.py +1 -2
- classiq/interface/executor/quantum_code.py +8 -8
- classiq/interface/executor/result.py +28 -18
- classiq/interface/executor/user_budget.py +25 -17
- classiq/interface/executor/vqe_result.py +5 -6
- classiq/interface/generator/ansatz_library.py +6 -8
- classiq/interface/generator/application_apis/__init__.py +0 -3
- classiq/interface/generator/arith/arithmetic.py +2 -2
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +2 -3
- classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -5
- classiq/interface/generator/arith/arithmetic_expression_parser.py +11 -4
- classiq/interface/generator/arith/arithmetic_expression_validator.py +12 -15
- classiq/interface/generator/arith/arithmetic_operations.py +4 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +70 -107
- classiq/interface/generator/arith/arithmetic_result_builder.py +4 -4
- classiq/interface/generator/arith/ast_node_rewrite.py +8 -4
- classiq/interface/generator/arith/binary_ops.py +15 -40
- classiq/interface/generator/arith/logical_ops.py +2 -3
- classiq/interface/generator/arith/number_utils.py +2 -2
- classiq/interface/generator/arith/register_user_input.py +3 -3
- classiq/interface/generator/arith/unary_ops.py +2 -2
- classiq/interface/generator/circuit_code/circuit_code.py +8 -10
- classiq/interface/generator/circuit_code/types_and_constants.py +1 -1
- classiq/interface/generator/complex_type.py +2 -2
- classiq/interface/generator/copy.py +1 -3
- classiq/interface/generator/expressions/atomic_expression_functions.py +0 -5
- classiq/interface/generator/expressions/evaluated_expression.py +2 -3
- classiq/interface/generator/expressions/expression.py +2 -2
- classiq/interface/generator/expressions/proxies/classical/classical_array_proxy.py +4 -7
- classiq/interface/generator/function_param_list.py +0 -40
- classiq/interface/generator/function_params.py +5 -6
- classiq/interface/generator/functions/classical_function_declaration.py +2 -2
- classiq/interface/generator/functions/classical_type.py +3 -3
- classiq/interface/generator/functions/type_modifier.py +0 -15
- classiq/interface/generator/functions/type_name.py +2 -2
- classiq/interface/generator/generated_circuit_data.py +14 -18
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +2 -4
- classiq/interface/generator/hardware/hardware_data.py +8 -8
- classiq/interface/generator/hardware_efficient_ansatz.py +9 -9
- classiq/interface/generator/mcu.py +3 -3
- classiq/interface/generator/mcx.py +3 -3
- classiq/interface/generator/model/constraints.py +34 -5
- classiq/interface/generator/model/preferences/preferences.py +15 -21
- classiq/interface/generator/model/quantum_register.py +7 -10
- classiq/interface/generator/noise_properties.py +3 -7
- classiq/interface/generator/parameters.py +1 -1
- classiq/interface/generator/partitioned_register.py +1 -2
- classiq/interface/generator/preferences/qasm_to_qmod_params.py +11 -0
- classiq/interface/generator/quantum_function_call.py +9 -12
- classiq/interface/generator/quantum_program.py +10 -23
- classiq/interface/generator/range_types.py +3 -3
- classiq/interface/generator/slice_parsing_utils.py +4 -5
- classiq/interface/generator/standard_gates/standard_gates.py +2 -4
- classiq/interface/generator/synthesis_execution_parameter.py +1 -3
- classiq/interface/generator/synthesis_metadata/synthesis_duration.py +9 -0
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +2 -3
- classiq/interface/generator/transpiler_basis_gates.py +12 -4
- classiq/interface/generator/types/builtin_enum_declarations.py +0 -145
- classiq/interface/generator/types/compilation_metadata.py +12 -1
- classiq/interface/generator/types/enum_declaration.py +2 -1
- classiq/interface/generator/validations/flow_graph.py +3 -3
- classiq/interface/generator/visitor.py +10 -12
- classiq/interface/hardware.py +2 -3
- classiq/interface/helpers/classproperty.py +2 -2
- classiq/interface/helpers/custom_encoders.py +2 -1
- classiq/interface/helpers/custom_pydantic_types.py +1 -1
- classiq/interface/helpers/text_utils.py +1 -4
- classiq/interface/ide/visual_model.py +6 -5
- classiq/interface/interface_version.py +1 -1
- classiq/interface/jobs.py +3 -3
- classiq/interface/model/allocate.py +4 -4
- classiq/interface/model/block.py +6 -2
- classiq/interface/model/bounds.py +3 -3
- classiq/interface/model/classical_if.py +4 -0
- classiq/interface/model/control.py +8 -1
- classiq/interface/model/inplace_binary_operation.py +2 -2
- classiq/interface/model/invert.py +4 -0
- classiq/interface/model/model.py +4 -4
- classiq/interface/model/model_visitor.py +40 -1
- classiq/interface/model/parameter.py +1 -3
- classiq/interface/model/port_declaration.py +1 -1
- classiq/interface/model/power.py +4 -0
- classiq/interface/model/quantum_expressions/quantum_expression.py +1 -2
- classiq/interface/model/quantum_function_call.py +3 -6
- classiq/interface/model/quantum_function_declaration.py +1 -0
- classiq/interface/model/quantum_lambda_function.py +4 -4
- classiq/interface/model/quantum_statement.py +11 -4
- classiq/interface/model/quantum_type.py +14 -14
- classiq/interface/model/repeat.py +4 -0
- classiq/interface/model/skip_control.py +4 -0
- classiq/interface/model/validation_handle.py +2 -3
- classiq/interface/model/variable_declaration_statement.py +2 -2
- classiq/interface/model/within_apply_operation.py +4 -0
- classiq/interface/pretty_print/expression_to_qmod.py +3 -4
- classiq/interface/server/routes.py +0 -16
- classiq/interface/source_reference.py +3 -4
- classiq/model_expansions/arithmetic.py +11 -7
- classiq/model_expansions/arithmetic_compute_result_attrs.py +30 -27
- classiq/model_expansions/capturing/captured_vars.py +3 -3
- classiq/model_expansions/capturing/mangling_utils.py +1 -2
- classiq/model_expansions/closure.py +12 -11
- classiq/model_expansions/function_builder.py +14 -6
- classiq/model_expansions/generative_functions.py +7 -12
- classiq/model_expansions/interpreters/base_interpreter.py +3 -7
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +2 -1
- classiq/model_expansions/interpreters/generative_interpreter.py +5 -3
- classiq/model_expansions/quantum_operations/allocate.py +4 -4
- classiq/model_expansions/quantum_operations/assignment_result_processor.py +2 -4
- classiq/model_expansions/quantum_operations/call_emitter.py +31 -37
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +2 -2
- classiq/model_expansions/quantum_operations/emitter.py +3 -5
- classiq/model_expansions/quantum_operations/expression_evaluator.py +3 -3
- classiq/model_expansions/quantum_operations/skip_control_verifier.py +1 -2
- classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
- classiq/model_expansions/scope.py +7 -7
- classiq/model_expansions/scope_initialization.py +4 -0
- classiq/model_expansions/visitors/symbolic_param_inference.py +6 -6
- classiq/model_expansions/visitors/uncomputation_signature_inference.py +328 -0
- classiq/model_expansions/visitors/variable_references.py +15 -14
- classiq/open_library/functions/__init__.py +28 -11
- classiq/open_library/functions/amplitude_loading.py +81 -0
- classiq/open_library/functions/discrete_sine_cosine_transform.py +5 -5
- classiq/open_library/functions/grover.py +8 -10
- classiq/open_library/functions/lcu.py +47 -18
- classiq/open_library/functions/modular_exponentiation.py +93 -8
- classiq/open_library/functions/qsvt.py +66 -79
- classiq/open_library/functions/qsvt_temp.py +536 -0
- classiq/open_library/functions/state_preparation.py +130 -27
- classiq/qmod/__init__.py +6 -4
- classiq/qmod/builtins/classical_execution_primitives.py +4 -23
- classiq/qmod/builtins/classical_functions.py +1 -42
- classiq/qmod/builtins/enums.py +15 -153
- classiq/qmod/builtins/functions/__init__.py +9 -18
- classiq/qmod/builtins/functions/allocation.py +25 -4
- classiq/qmod/builtins/functions/arithmetic.py +22 -27
- classiq/qmod/builtins/functions/exponentiation.py +51 -2
- classiq/qmod/builtins/functions/mcx_func.py +7 -0
- classiq/qmod/builtins/functions/standard_gates.py +46 -27
- classiq/qmod/builtins/operations.py +165 -79
- classiq/qmod/builtins/structs.py +24 -91
- classiq/qmod/cfunc.py +3 -2
- classiq/qmod/classical_function.py +2 -1
- classiq/qmod/cparam.py +2 -8
- classiq/qmod/create_model_function.py +7 -7
- classiq/qmod/declaration_inferrer.py +33 -30
- classiq/qmod/expression_query.py +7 -4
- classiq/qmod/model_state_container.py +2 -2
- classiq/qmod/native/pretty_printer.py +25 -14
- classiq/qmod/pretty_print/expression_to_python.py +5 -3
- classiq/qmod/pretty_print/pretty_printer.py +39 -17
- classiq/qmod/python_classical_type.py +40 -13
- classiq/qmod/qfunc.py +124 -19
- classiq/qmod/qmod_constant.py +2 -2
- classiq/qmod/qmod_parameter.py +5 -2
- classiq/qmod/qmod_variable.py +47 -46
- classiq/qmod/quantum_callable.py +18 -13
- classiq/qmod/quantum_expandable.py +31 -26
- classiq/qmod/quantum_function.py +84 -36
- classiq/qmod/semantics/annotation/call_annotation.py +5 -5
- classiq/qmod/semantics/error_manager.py +12 -14
- classiq/qmod/semantics/lambdas.py +1 -2
- classiq/qmod/semantics/validation/types_validation.py +1 -2
- classiq/qmod/symbolic.py +2 -4
- classiq/qmod/utilities.py +13 -20
- classiq/qmod/write_qmod.py +3 -4
- classiq/quantum_program.py +1 -3
- classiq/synthesis.py +11 -7
- {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/METADATA +2 -3
- {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/RECORD +271 -299
- {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/WHEEL +1 -1
- classiq/applications/chemistry/ansatz_parameters.py +0 -29
- classiq/applications/chemistry/chemistry_execution_parameters.py +0 -16
- classiq/applications/chemistry/chemistry_model_constructor.py +0 -532
- classiq/applications/chemistry/ground_state_problem.py +0 -42
- classiq/applications/qsvm/__init__.py +0 -8
- classiq/applications/qsvm/qsvm.py +0 -11
- classiq/evaluators/qmod_expression_visitors/qmod_expression_bwc.py +0 -129
- classiq/execution/iqcc.py +0 -128
- classiq/interface/applications/qsvm.py +0 -117
- classiq/interface/chemistry/elements.py +0 -120
- classiq/interface/chemistry/fermionic_operator.py +0 -208
- classiq/interface/chemistry/ground_state_problem.py +0 -132
- classiq/interface/chemistry/ground_state_result.py +0 -8
- classiq/interface/chemistry/molecule.py +0 -71
- classiq/interface/execution/iqcc.py +0 -44
- classiq/interface/generator/application_apis/chemistry_declarations.py +0 -69
- classiq/interface/generator/application_apis/entangler_declarations.py +0 -29
- classiq/interface/generator/application_apis/qsvm_declarations.py +0 -6
- classiq/interface/generator/chemistry_function_params.py +0 -50
- classiq/interface/generator/entangler_params.py +0 -72
- classiq/interface/generator/entanglers.py +0 -14
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +0 -27
- classiq/interface/generator/hartree_fock.py +0 -26
- classiq/interface/generator/hva.py +0 -22
- classiq/interface/generator/linear_pauli_rotations.py +0 -92
- classiq/interface/generator/qft.py +0 -37
- classiq/interface/generator/qsvm.py +0 -96
- classiq/interface/generator/state_preparation/__init__.py +0 -14
- classiq/interface/generator/state_preparation/bell_state_preparation.py +0 -27
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +0 -28
- classiq/interface/generator/state_preparation/distributions.py +0 -53
- classiq/interface/generator/state_preparation/exponential_state_preparation.py +0 -14
- classiq/interface/generator/state_preparation/ghz_state_preparation.py +0 -14
- classiq/interface/generator/state_preparation/metrics.py +0 -41
- classiq/interface/generator/state_preparation/state_preparation.py +0 -113
- classiq/interface/generator/state_preparation/state_preparation_abc.py +0 -24
- classiq/interface/generator/state_preparation/uniform_distibution_state_preparation.py +0 -13
- classiq/interface/generator/state_preparation/w_state_preparation.py +0 -13
- classiq/interface/generator/ucc.py +0 -74
- classiq/interface/helpers/backward_compatibility.py +0 -9
- classiq/model_expansions/transformers/type_modifier_inference.py +0 -392
- classiq/open_library/functions/lookup_table.py +0 -58
- classiq/qmod/builtins/functions/chemistry.py +0 -123
- classiq/qmod/builtins/functions/qsvm.py +0 -24
- {classiq-0.93.0.dist-info → classiq-0.99.0.dist-info}/licenses/LICENSE.txt +0 -0
classiq/applications/qsp/qsp.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import builtins
|
|
2
2
|
import importlib.util
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from functools import wraps
|
|
4
|
-
from typing import Callable, Optional
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
-
from matplotlib import pyplot as plt
|
|
8
7
|
from numpy.polynomial import Chebyshev, Polynomial
|
|
9
8
|
from numpy.polynomial.chebyshev import cheb2poly, poly2cheb
|
|
10
9
|
|
|
@@ -51,7 +50,7 @@ def qsvt_phases(
|
|
|
51
50
|
) -> np.ndarray:
|
|
52
51
|
r"""
|
|
53
52
|
Get QSVT phases that will generate the given Chebyshev polynomial.
|
|
54
|
-
The phases are ready to be used in `qsvt` and `qsvt_lcu` functions in the classiq library. The
|
|
53
|
+
The phases are ready to be used in `qsvt` and `qsvt_lcu` functions in the classiq library. The convention
|
|
55
54
|
is the reflection signal operator, and the measurement basis is the hadamard basis (see https://arxiv.org/abs/2105.02859
|
|
56
55
|
APPENDIX A.).
|
|
57
56
|
The current implementation is using the pyqsp package, based on techniques in https://arxiv.org/abs/2003.02831.
|
|
@@ -119,13 +118,15 @@ def qsvt_phases(
|
|
|
119
118
|
|
|
120
119
|
def _plot_qsp_approx(
|
|
121
120
|
poly_cheb: np.ndarray,
|
|
122
|
-
f_target: Callable[[
|
|
121
|
+
f_target: Callable[[float], complex],
|
|
123
122
|
interval: tuple[float, float] = (-1, 1),
|
|
124
123
|
) -> None:
|
|
124
|
+
from matplotlib import pyplot as plt
|
|
125
|
+
|
|
125
126
|
grid_full = np.linspace(-1, 1, 3000)
|
|
126
127
|
grid_interval = np.linspace(interval[0], interval[1], 3000)
|
|
127
128
|
|
|
128
|
-
y_target = f_target(grid_interval)
|
|
129
|
+
y_target = np.vectorize(f_target, otypes=[float])(grid_interval)
|
|
129
130
|
y_approx = np.polynomial.Chebyshev(poly_cheb)(grid_full)
|
|
130
131
|
|
|
131
132
|
# Plot
|
|
@@ -152,12 +153,12 @@ def _plot_qsp_approx(
|
|
|
152
153
|
|
|
153
154
|
|
|
154
155
|
def qsp_approximate(
|
|
155
|
-
f_target: Callable[[
|
|
156
|
+
f_target: Callable[[float], complex],
|
|
156
157
|
degree: int,
|
|
157
|
-
parity:
|
|
158
|
+
parity: int | None = None,
|
|
158
159
|
interval: tuple[float, float] = (-1, 1),
|
|
159
160
|
bound: float = 0.99,
|
|
160
|
-
num_grid_points:
|
|
161
|
+
num_grid_points: int | None = None,
|
|
161
162
|
plot: bool = False,
|
|
162
163
|
) -> tuple[np.ndarray, float]:
|
|
163
164
|
"""
|
|
@@ -192,7 +193,8 @@ def qsp_approximate(
|
|
|
192
193
|
# Select grid points for the objective in [w_min, w_max]
|
|
193
194
|
xj_obj = xj_full[(xj_full >= interval[0]) & (xj_full <= interval[1])]
|
|
194
195
|
|
|
195
|
-
yj_obj = f_target(xj_obj)
|
|
196
|
+
yj_obj = np.vectorize(f_target, otypes=[float])(xj_obj)
|
|
197
|
+
|
|
196
198
|
# heuristic verification
|
|
197
199
|
bound = min(1, bound)
|
|
198
200
|
assert (
|
|
@@ -313,7 +315,7 @@ def gqsp_phases(
|
|
|
313
315
|
- Laurent polynomials are supported by degree shifting. If
|
|
314
316
|
P(z) = sum_{k=m}^n c_k * z^k with m < 0, the phases correspond to the
|
|
315
317
|
degree-shifted polynomial z^{-m} * P(z) (so the minimal degree is zero).
|
|
316
|
-
- The phase finiding works in the monomial basis. If
|
|
318
|
+
- The phase finiding works in the monomial basis. If a Chebyshev basis polynomial is provided,
|
|
317
319
|
it will be converted to the monomial basis (and introduce an additional overhead).
|
|
318
320
|
|
|
319
321
|
Args:
|
|
@@ -364,3 +366,229 @@ def gqsp_phases(
|
|
|
364
366
|
s = np.array([s[0][1 : i + 1], s[1][:i]])
|
|
365
367
|
|
|
366
368
|
return thetas, phis, lambdas
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def poly_jacobi_anger_cos(degree: int, t: float) -> np.ndarray:
|
|
372
|
+
r"""
|
|
373
|
+
Gets the Chebyshev polynomial coefficients approximating cos(t*x) using the Jacobi-Anger expansion.
|
|
374
|
+
$$\cos(xt) = J_0(t) + 2\sum_{k=1}^{d/2} (-1)^k J_{2k}(t)\, T_{2k}(x) $$
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
degree: the degree of the approximating polynomial.
|
|
378
|
+
t: the parameter in cos(t*x). Can be negative.
|
|
379
|
+
Returns:
|
|
380
|
+
coeffs: The Chebyshev approximating coefficients.
|
|
381
|
+
"""
|
|
382
|
+
from scipy.special import jv
|
|
383
|
+
|
|
384
|
+
coeffs = np.zeros(degree + 1 if degree % 2 == 0 else degree)
|
|
385
|
+
for k in range(degree // 2 + 1):
|
|
386
|
+
coeffs[2 * k] = (2 if k > 0 else 1) * (-1) ** k * jv(2 * k, t)
|
|
387
|
+
|
|
388
|
+
return coeffs
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def poly_jacobi_anger_sin(degree: int, t: float) -> np.ndarray:
|
|
392
|
+
r"""
|
|
393
|
+
Gets the Chebyshev polynomial coefficients approximating sin(t*x) using the Jacobi-Anger expansion.
|
|
394
|
+
$$\sin(xt) = 2\sum_{k=0}^{d/2} (-1)^k J_{2k+1}(t)\, T_{2k+1}(x)$$
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
degree: the degree of the approximating polynomial.
|
|
398
|
+
t: the parameter in sin(t*x).
|
|
399
|
+
Returns:
|
|
400
|
+
coeffs: The Chebyshev approximating coefficients.
|
|
401
|
+
"""
|
|
402
|
+
from scipy.special import jv
|
|
403
|
+
|
|
404
|
+
coeffs = np.zeros(degree + 1 if degree % 2 == 1 else degree)
|
|
405
|
+
for k in range(len(coeffs) // 2):
|
|
406
|
+
idx = 2 * k + 1
|
|
407
|
+
coeffs[idx] = 2 * (-1) ** k * jv(idx, t)
|
|
408
|
+
return coeffs
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def poly_jacobi_anger_exp_sin(degree: int, t: float) -> np.ndarray:
|
|
412
|
+
r"""
|
|
413
|
+
Gets the Chebyshev polynomial coefficients approximating exp(i*t*sin(x)) using the Jacobi-Anger expansion:
|
|
414
|
+
$$e^{it\sin(x)} = \sum_{k=-d}^{d} J_{k}(t) e^{ikx}$$
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
degree: the maximum degree of the approximating polynomial (negative and positive).
|
|
418
|
+
t: the parameter in exp(i*t*sin(x)).
|
|
419
|
+
Returns:
|
|
420
|
+
coeffs: The approximating coefficients in monomial basis, starting from the negative ones to the positive ones (length is 2*degree+1).
|
|
421
|
+
"""
|
|
422
|
+
from scipy.special import jv
|
|
423
|
+
|
|
424
|
+
coeffs = [jv(k, t) for k in range(-degree, degree + 1)]
|
|
425
|
+
return np.array(coeffs)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def poly_jacobi_anger_exp_cos(degree: int, t: float) -> np.ndarray:
|
|
429
|
+
r"""
|
|
430
|
+
Gets the Chebyshev polynomial coefficients approximating exp(i*t*cos(x)) using the Jacobi-Anger expansion:
|
|
431
|
+
$$e^{it\cos(x)} = \sum_{k=-d}^{d} i^k J_{k}(t) e^{ikx}$$
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
degree: the maximum degree of the approximating polynomial (negative and positive).
|
|
435
|
+
t: the parameter in exp(i*t*cos(x)).
|
|
436
|
+
Returns:
|
|
437
|
+
coeffs: The approximating coefficients in monomial basis, starting from the negative ones to the positive ones (length is 2*degree+1).
|
|
438
|
+
"""
|
|
439
|
+
from scipy.special import jv
|
|
440
|
+
|
|
441
|
+
coeffs = [jv(k, t) * (1j**k) for k in range(-degree, degree + 1)]
|
|
442
|
+
return np.array(coeffs)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def poly_jacobi_anger_degree(eps: float, t: float) -> int:
|
|
446
|
+
r"""
|
|
447
|
+
Get needed degree based on the maximum allowed uniform error on the interval [-1, 1]
|
|
448
|
+
for the Jacobi-Anger approximation. relevant for all poly_*_jacobi_anger functions.
|
|
449
|
+
Args:
|
|
450
|
+
eps: maximum allowed uniform error
|
|
451
|
+
t: the parameter in exp(i*t*cos(x))\exp(i*t*sin(x))\cos(t*x)\sin(t*x)
|
|
452
|
+
Returns:
|
|
453
|
+
degree: the minimal degree such that the polynomial approximation
|
|
454
|
+
using Jacobi-Anger expansion is within eps uniform error. relevant
|
|
455
|
+
"""
|
|
456
|
+
# based on the approximation in https://arxiv.org/pdf/1806.01838 eq. (56)
|
|
457
|
+
from scipy.optimize import fsolve
|
|
458
|
+
|
|
459
|
+
deg = np.ceil(
|
|
460
|
+
fsolve(lambda r: (np.e * np.abs(t) / (2 * r)) ** r - 4 / 5 * eps, t)[0]
|
|
461
|
+
)
|
|
462
|
+
return int(max(deg, 1) + 1)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def poly_jacobi_anger_error(degree: int, t: float) -> float:
|
|
466
|
+
r"""
|
|
467
|
+
Get the uniform error on the interval [-1, 1] for the Jacobi-Anger approximation,
|
|
468
|
+
based on the truncation degree. Relevant for all poly_*_jacobi_anger functions.
|
|
469
|
+
Args:
|
|
470
|
+
degree: truncation maximal degree
|
|
471
|
+
t: the parameter in exp(i*t*cos(x))\exp(i*t*sin(x))\cos(t*x)\sin(t*x)
|
|
472
|
+
Returns:
|
|
473
|
+
eps: a bound on the approximation uniform error
|
|
474
|
+
"""
|
|
475
|
+
# based on the approximation in https://arxiv.org/pdf/1806.01838 eq. (56)
|
|
476
|
+
eps = 5 / 4 * (np.e * np.abs(t) / (2 * degree)) ** degree
|
|
477
|
+
return eps
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def poly_inversion(degree: int, kappa: float) -> tuple[np.ndarray, float]:
|
|
481
|
+
"""
|
|
482
|
+
Gets the Chebyshev odd polynomial coefficients approximating 1/x on [1/kappa, 1] and bounded by 1 in magnitude on [-1, 1].
|
|
483
|
+
Based on the paper https://arxiv.org/pdf/2507.15537.
|
|
484
|
+
|
|
485
|
+
Note: To be used within the QSVT framework, the polynomial should be scaled to be bounded by 1 on [-1, 1].
|
|
486
|
+
The maximum absolute value of the returned polynomial on [-1, 1] can be larger than kappa, so the user
|
|
487
|
+
should use the returned max_value to scale down the polynomial accordingly.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
degree: The degree of the approximating polynomial.
|
|
491
|
+
kappa: The number defining the interval [1/kappa, 1], usually represents the condition number in the setting of matrix inversion.
|
|
492
|
+
|
|
493
|
+
Returns:
|
|
494
|
+
coeffs: The Chebyshev polynomial coefficients approximating 1/x on [1/kappa, 1]
|
|
495
|
+
using the optimal polynomial of given degree.
|
|
496
|
+
max_value: An upper bound on the maximum absolute value of the polynomial on [-1, 1]. The value
|
|
497
|
+
can be used to scale down the polynomial for the usage within QSVT.
|
|
498
|
+
"""
|
|
499
|
+
|
|
500
|
+
def _evaluate_l_n(x: np.ndarray, n: int, a: float) -> np.ndarray:
|
|
501
|
+
"""
|
|
502
|
+
L_n(x; a) = 2^{-(n-1)} [ T_n(x) + ((1-a)/(1+a)) T_{n-1}(x)]. (eq. 6)
|
|
503
|
+
"""
|
|
504
|
+
x = np.asarray(x, dtype=float)
|
|
505
|
+
assert n >= 1, "n must be >= 1"
|
|
506
|
+
assert 0.0 < a < 1.0, "1/kappa must be in (0, 1)"
|
|
507
|
+
|
|
508
|
+
alpha = (1 + a) / (2 * (1 - a))
|
|
509
|
+
l1 = (x + (1 - a) / (1 + a)) / alpha
|
|
510
|
+
l2 = (x**2 + (1 - a) / (1 + a) * x / 2 - 1 / 2) / alpha**2
|
|
511
|
+
if n == 1:
|
|
512
|
+
return l1
|
|
513
|
+
for _ in range(3, n + 1):
|
|
514
|
+
l1, l2 = l2, x * l2 / alpha - l1 / (4 * alpha**2)
|
|
515
|
+
return l2
|
|
516
|
+
|
|
517
|
+
def _substitute_x(x: np.ndarray, a: float) -> np.ndarray:
|
|
518
|
+
"""
|
|
519
|
+
helper function for the variable substitution in eq. (5).
|
|
520
|
+
"""
|
|
521
|
+
return (2.0 * x * x - (1.0 + a * a)) / (1.0 - a * a)
|
|
522
|
+
|
|
523
|
+
def _evaluate_p(x: np.ndarray, d: int, a: float) -> np.ndarray:
|
|
524
|
+
"""
|
|
525
|
+
Evaluate P_{2n-1}(x; a) with d odd, n=(d+1)//2.
|
|
526
|
+
Uses Eq. (5) with L_n from Eq. (6).
|
|
527
|
+
"""
|
|
528
|
+
n = (d + 1) // 2
|
|
529
|
+
x = np.asarray(x, dtype=float)
|
|
530
|
+
|
|
531
|
+
# main branch
|
|
532
|
+
l_n = _evaluate_l_n(_substitute_x(x, a), n, a)
|
|
533
|
+
l_0 = _evaluate_l_n(_substitute_x(0.0, a), n, a) # type: ignore[arg-type]
|
|
534
|
+
return (1.0 - (l_n / l_0)) / x
|
|
535
|
+
|
|
536
|
+
a = 1 / kappa
|
|
537
|
+
assert degree % 2 == 1, "degree must be odd"
|
|
538
|
+
|
|
539
|
+
coeffs = np.polynomial.chebyshev.chebinterpolate(
|
|
540
|
+
_evaluate_p, degree, args=(degree, a)
|
|
541
|
+
)
|
|
542
|
+
# enforce odd parity numerically:
|
|
543
|
+
coeffs[0::2] = 0.0
|
|
544
|
+
|
|
545
|
+
# calculate maximum value on [-1, 1]:
|
|
546
|
+
sampling_ratio = 25
|
|
547
|
+
grid = np.linspace(0, 1, degree * 25)
|
|
548
|
+
max_sampled = np.max(np.abs(np.polynomial.chebyshev.Chebyshev(coeffs)(grid)))
|
|
549
|
+
max_value = (
|
|
550
|
+
max_sampled * 1 / (np.cos(np.pi / (4 * sampling_ratio)))
|
|
551
|
+
) # according to (25) in the paper
|
|
552
|
+
|
|
553
|
+
return coeffs, max_value
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def poly_inversion_degree(eps: float, kappa: float) -> int:
|
|
557
|
+
"""
|
|
558
|
+
Get the needed degree based on the target uniform error on the interval [1/kappa, 1],
|
|
559
|
+
for the polynomial approximation of 1/x using the function poly_inversion.
|
|
560
|
+
Based on the paper https://arxiv.org/pdf/2507.15537.
|
|
561
|
+
|
|
562
|
+
Args:
|
|
563
|
+
eps: The target uniform approximation error.
|
|
564
|
+
kappa: The number defining the interval [1/kappa, 1], usually represents the condition number in the setting of matrix inversion.
|
|
565
|
+
Returns:
|
|
566
|
+
degree: The minimal degree such that the polynomial approximation of 1/x on [1/kappa, 1]
|
|
567
|
+
is within eps uniform error.
|
|
568
|
+
"""
|
|
569
|
+
a = 1 / kappa
|
|
570
|
+
n = int(
|
|
571
|
+
np.ceil(
|
|
572
|
+
(np.log(1 / eps) + np.log(1 / a) + np.log(1 + a))
|
|
573
|
+
/ np.log((1 + a) / (1 - a))
|
|
574
|
+
)
|
|
575
|
+
)
|
|
576
|
+
return 2 * n - 1
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def poly_inversion_error(degree: int, kappa: float) -> float:
|
|
580
|
+
"""
|
|
581
|
+
Calculates uniform error on the interval [1/kappa, 1] for the polynomial
|
|
582
|
+
approximation of 1/x given by poly_inversion.
|
|
583
|
+
Based on the paper https://arxiv.org/pdf/2507.15537
|
|
584
|
+
|
|
585
|
+
Args:
|
|
586
|
+
degree: Inversion polynomial degree.
|
|
587
|
+
kappa: The number defining the interval [1/kappa, 1], usually represents the condition number in the setting of matrix inversion.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
eps: Uniform approximation error on [1/kappa, 1].
|
|
591
|
+
"""
|
|
592
|
+
a = 1 / kappa
|
|
593
|
+
n = (degree + 1) // 2
|
|
594
|
+
return (1 - a) ** n / (a * (1 + a) ** (n - 1))
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
|
|
@@ -14,7 +13,7 @@ def generate_data(
|
|
|
14
13
|
range_min: float = 0,
|
|
15
14
|
range_max: float = 2 * np.pi,
|
|
16
15
|
std: float = 0.5,
|
|
17
|
-
sources:
|
|
16
|
+
sources: np.ndarray | None = None,
|
|
18
17
|
) -> dict[int, np.ndarray]:
|
|
19
18
|
if sources is None:
|
|
20
19
|
sources = np.random.uniform(
|
|
@@ -17,9 +17,6 @@ from classiq.interface.generator.expressions.proxies.classical.utils import (
|
|
|
17
17
|
from classiq.interface.generator.functions.classical_type import ClassicalArray, Integer
|
|
18
18
|
|
|
19
19
|
from classiq.evaluators.qmod_annotated_expression import QmodAnnotatedExpression
|
|
20
|
-
from classiq.evaluators.qmod_expression_visitors.qmod_expression_bwc import (
|
|
21
|
-
QmodExpressionBwc,
|
|
22
|
-
)
|
|
23
20
|
from classiq.evaluators.qmod_expression_visitors.qmod_expression_evaluator import (
|
|
24
21
|
evaluate_qmod_expression,
|
|
25
22
|
)
|
|
@@ -59,7 +56,6 @@ def evaluate_classical_expression(expr: Expression, scope: Scope) -> Evaluated:
|
|
|
59
56
|
if expr.is_evaluated():
|
|
60
57
|
return Evaluated(value=expr.value.value)
|
|
61
58
|
expr_ast = ast.parse(expr.expr)
|
|
62
|
-
expr_ast = QmodExpressionBwc().visit(expr_ast)
|
|
63
59
|
expr_val = evaluate_qmod_expression(
|
|
64
60
|
ast.unparse(expr_ast),
|
|
65
61
|
classical_struct_declarations=list(QMODULE.type_decls.values()),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Any, NoReturn,
|
|
1
|
+
from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, Union
|
|
2
2
|
|
|
3
3
|
import sympy
|
|
4
4
|
|
|
@@ -25,7 +25,6 @@ from classiq.interface.generator.functions.port_declaration import (
|
|
|
25
25
|
from classiq.interface.generator.functions.type_name import (
|
|
26
26
|
TypeName,
|
|
27
27
|
)
|
|
28
|
-
from classiq.interface.helpers.backward_compatibility import zip_strict
|
|
29
28
|
from classiq.interface.model.classical_parameter_declaration import (
|
|
30
29
|
ClassicalParameterDeclaration,
|
|
31
30
|
)
|
|
@@ -80,7 +79,7 @@ def evaluate_parameter_types_from_args(
|
|
|
80
79
|
f"{len(arguments)} were given"
|
|
81
80
|
)
|
|
82
81
|
|
|
83
|
-
for parameter, argument in
|
|
82
|
+
for parameter, argument in zip(parameters, arguments, strict=True):
|
|
84
83
|
if isinstance(parameter, ClassicalParameterDeclaration):
|
|
85
84
|
arg_val = argument.value
|
|
86
85
|
if not isinstance(arg_val, QmodAnnotatedExpression):
|
|
@@ -88,11 +87,11 @@ def evaluate_parameter_types_from_args(
|
|
|
88
87
|
|
|
89
88
|
evaluated_params = [
|
|
90
89
|
_evaluate_type_from_arg(parameter, argument, closure)
|
|
91
|
-
for parameter, argument in
|
|
90
|
+
for parameter, argument in zip(parameters, arguments, strict=True)
|
|
92
91
|
]
|
|
93
92
|
|
|
94
93
|
parameter_names = {parameter.name for parameter in parameters}
|
|
95
|
-
for parameter, argument in
|
|
94
|
+
for parameter, argument in zip(parameters, arguments, strict=True):
|
|
96
95
|
if isinstance(parameter, QuantumOperandDeclaration):
|
|
97
96
|
_update_operand_signature_environment(
|
|
98
97
|
argument.value, parameter_names, closure
|
|
@@ -134,6 +133,9 @@ def _evaluate_type_from_arg(
|
|
|
134
133
|
# FIXME: Remove suzuki_trotter overloading (CLS-2912)
|
|
135
134
|
if closure.name == "suzuki_trotter" and parameter.name == "pauli_operator":
|
|
136
135
|
return parameter
|
|
136
|
+
# FIXME: Remove qdrift overloading (CLS-4347)
|
|
137
|
+
if closure.name == "qdrift" and parameter.name == "pauli_operator":
|
|
138
|
+
return parameter
|
|
137
139
|
if isinstance(parameter, ClassicalParameterDeclaration):
|
|
138
140
|
return _evaluate_classical_type_from_arg(parameter, argument, closure)
|
|
139
141
|
if isinstance(parameter, PortDeclaration):
|
|
@@ -271,9 +273,9 @@ def _evaluate_op_type_from_arg(
|
|
|
271
273
|
|
|
272
274
|
def _raise_argument_type_error(
|
|
273
275
|
arg_val: Any,
|
|
274
|
-
arg_type:
|
|
276
|
+
arg_type: QmodType | AnonQuantumOperandDeclaration,
|
|
275
277
|
param_name: str,
|
|
276
|
-
param_type:
|
|
278
|
+
param_type: QmodType | AnonQuantumOperandDeclaration,
|
|
277
279
|
) -> NoReturn:
|
|
278
280
|
raise ClassiqExpansionError(
|
|
279
281
|
f"Argument {str(arg_val)!r} of type "
|
|
@@ -378,7 +380,7 @@ def _eval_expr(
|
|
|
378
380
|
if expected_type is int and isinstance(val, float) and int(val) == val:
|
|
379
381
|
val = int(val)
|
|
380
382
|
|
|
381
|
-
failing_type:
|
|
383
|
+
failing_type: str | None = None
|
|
382
384
|
if isinstance(val, QmodAnnotatedExpression):
|
|
383
385
|
val_type = val.get_type(val.root)
|
|
384
386
|
if not isinstance(val_type, expected_qmod_type):
|
|
@@ -2,7 +2,7 @@ import ast
|
|
|
2
2
|
from collections.abc import Mapping, Sequence
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
import sympy
|
|
8
8
|
|
|
@@ -98,26 +98,24 @@ class QmodAnnotatedExpression:
|
|
|
98
98
|
def get_node(self, node_id: QmodExprNodeId) -> ast.AST:
|
|
99
99
|
return self._node_mapping[node_id]
|
|
100
100
|
|
|
101
|
-
def set_value(self, node:
|
|
101
|
+
def set_value(self, node: ast.AST | QmodExprNodeId, value: Any) -> None:
|
|
102
102
|
if self._locked:
|
|
103
103
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
104
104
|
if isinstance(node, ast.AST):
|
|
105
105
|
node = id(node)
|
|
106
106
|
self._values[node] = value
|
|
107
107
|
|
|
108
|
-
def get_value(self, node:
|
|
108
|
+
def get_value(self, node: ast.AST | QmodExprNodeId) -> Any:
|
|
109
109
|
if isinstance(node, ast.AST):
|
|
110
110
|
node = id(node)
|
|
111
111
|
return self._values[node]
|
|
112
112
|
|
|
113
|
-
def has_value(self, node:
|
|
113
|
+
def has_value(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
114
114
|
if isinstance(node, ast.AST):
|
|
115
115
|
node = id(node)
|
|
116
116
|
return node in self._values
|
|
117
117
|
|
|
118
|
-
def set_type(
|
|
119
|
-
self, node: Union[ast.AST, QmodExprNodeId], qmod_type: QmodType
|
|
120
|
-
) -> None:
|
|
118
|
+
def set_type(self, node: ast.AST | QmodExprNodeId, qmod_type: QmodType) -> None:
|
|
121
119
|
if self._locked:
|
|
122
120
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
123
121
|
if isinstance(node, ast.AST):
|
|
@@ -126,12 +124,12 @@ class QmodAnnotatedExpression:
|
|
|
126
124
|
node = id(node)
|
|
127
125
|
self._types[node] = qmod_type
|
|
128
126
|
|
|
129
|
-
def get_type(self, node:
|
|
127
|
+
def get_type(self, node: ast.AST | QmodExprNodeId) -> QmodType:
|
|
130
128
|
if isinstance(node, ast.AST):
|
|
131
129
|
node = id(node)
|
|
132
130
|
return self._types[node]
|
|
133
131
|
|
|
134
|
-
def get_quantum_type(self, node:
|
|
132
|
+
def get_quantum_type(self, node: ast.AST | QmodExprNodeId) -> QuantumType:
|
|
135
133
|
if isinstance(node, ast.AST):
|
|
136
134
|
node = id(node)
|
|
137
135
|
qmod_type = self._types[node]
|
|
@@ -139,7 +137,7 @@ class QmodAnnotatedExpression:
|
|
|
139
137
|
raise ClassiqInternalExpansionError
|
|
140
138
|
return cast(QuantumType, qmod_type)
|
|
141
139
|
|
|
142
|
-
def get_classical_type(self, node:
|
|
140
|
+
def get_classical_type(self, node: ast.AST | QmodExprNodeId) -> ClassicalType:
|
|
143
141
|
if isinstance(node, ast.AST):
|
|
144
142
|
node = id(node)
|
|
145
143
|
qmod_type = self._types[node]
|
|
@@ -147,7 +145,7 @@ class QmodAnnotatedExpression:
|
|
|
147
145
|
raise ClassiqInternalExpansionError
|
|
148
146
|
return cast(ClassicalType, qmod_type)
|
|
149
147
|
|
|
150
|
-
def set_var(self, node:
|
|
148
|
+
def set_var(self, node: ast.AST | QmodExprNodeId, var: HandleBinding) -> None:
|
|
151
149
|
if self._locked:
|
|
152
150
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
153
151
|
var = var.collapse()
|
|
@@ -158,25 +156,25 @@ class QmodAnnotatedExpression:
|
|
|
158
156
|
else:
|
|
159
157
|
self._quantum_vars[node] = var
|
|
160
158
|
|
|
161
|
-
def get_var(self, node:
|
|
159
|
+
def get_var(self, node: ast.AST | QmodExprNodeId) -> HandleBinding:
|
|
162
160
|
if isinstance(node, ast.AST):
|
|
163
161
|
node = id(node)
|
|
164
162
|
return (self._classical_vars | self._quantum_vars)[node]
|
|
165
163
|
|
|
166
|
-
def has_var(self, node:
|
|
164
|
+
def has_var(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
167
165
|
return self.has_classical_var(node) or self.has_quantum_var(node)
|
|
168
166
|
|
|
169
|
-
def has_classical_var(self, node:
|
|
167
|
+
def has_classical_var(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
170
168
|
if isinstance(node, ast.AST):
|
|
171
169
|
node = id(node)
|
|
172
170
|
return node in self._classical_vars
|
|
173
171
|
|
|
174
|
-
def has_quantum_var(self, node:
|
|
172
|
+
def has_quantum_var(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
175
173
|
if isinstance(node, ast.AST):
|
|
176
174
|
node = id(node)
|
|
177
175
|
return node in self._quantum_vars
|
|
178
176
|
|
|
179
|
-
def remove_var(self, node:
|
|
177
|
+
def remove_var(self, node: ast.AST | QmodExprNodeId) -> None:
|
|
180
178
|
if self._locked:
|
|
181
179
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
182
180
|
if isinstance(node, ast.AST):
|
|
@@ -188,9 +186,9 @@ class QmodAnnotatedExpression:
|
|
|
188
186
|
|
|
189
187
|
def set_quantum_subscript(
|
|
190
188
|
self,
|
|
191
|
-
node:
|
|
192
|
-
value:
|
|
193
|
-
index:
|
|
189
|
+
node: ast.AST | QmodExprNodeId,
|
|
190
|
+
value: ast.AST | QmodExprNodeId,
|
|
191
|
+
index: ast.AST | QmodExprNodeId,
|
|
194
192
|
) -> None:
|
|
195
193
|
if self._locked:
|
|
196
194
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
@@ -204,11 +202,18 @@ class QmodAnnotatedExpression:
|
|
|
204
202
|
value=value, index=index
|
|
205
203
|
)
|
|
206
204
|
|
|
207
|
-
def has_quantum_subscript(self, node:
|
|
205
|
+
def has_quantum_subscript(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
208
206
|
if isinstance(node, ast.AST):
|
|
209
207
|
node = id(node)
|
|
210
208
|
return node in self._quantum_subscripts
|
|
211
209
|
|
|
210
|
+
def get_quantum_subcript(
|
|
211
|
+
self, node: ast.AST | QmodExprNodeId
|
|
212
|
+
) -> QuantumSubscriptAnnotation:
|
|
213
|
+
if isinstance(node, ast.AST):
|
|
214
|
+
node = id(node)
|
|
215
|
+
return self._quantum_subscripts[node]
|
|
216
|
+
|
|
212
217
|
def get_quantum_subscripts(
|
|
213
218
|
self,
|
|
214
219
|
) -> Mapping[QmodExprNodeId, QuantumSubscriptAnnotation]:
|
|
@@ -216,7 +221,7 @@ class QmodAnnotatedExpression:
|
|
|
216
221
|
|
|
217
222
|
def set_quantum_type_attr(
|
|
218
223
|
self,
|
|
219
|
-
node:
|
|
224
|
+
node: ast.AST | QmodExprNodeId,
|
|
220
225
|
value: HandleBinding,
|
|
221
226
|
attr: str,
|
|
222
227
|
) -> None:
|
|
@@ -228,7 +233,7 @@ class QmodAnnotatedExpression:
|
|
|
228
233
|
value=value, attr=attr
|
|
229
234
|
)
|
|
230
235
|
|
|
231
|
-
def has_quantum_type_attribute(self, node:
|
|
236
|
+
def has_quantum_type_attribute(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
232
237
|
if isinstance(node, ast.AST):
|
|
233
238
|
node = id(node)
|
|
234
239
|
return node in self._quantum_type_attrs
|
|
@@ -240,8 +245,8 @@ class QmodAnnotatedExpression:
|
|
|
240
245
|
|
|
241
246
|
def set_concatenation(
|
|
242
247
|
self,
|
|
243
|
-
node:
|
|
244
|
-
elements: Sequence[
|
|
248
|
+
node: ast.AST | QmodExprNodeId,
|
|
249
|
+
elements: Sequence[ast.AST | QmodExprNodeId],
|
|
245
250
|
) -> None:
|
|
246
251
|
if self._locked:
|
|
247
252
|
raise ClassiqInternalExpansionError("QAE is locked")
|
|
@@ -257,7 +262,7 @@ class QmodAnnotatedExpression:
|
|
|
257
262
|
inlined_elements.extend(self._concatenations.pop(element).elements)
|
|
258
263
|
self._concatenations[node] = ConcatenationAnnotation(elements=inlined_elements)
|
|
259
264
|
|
|
260
|
-
def has_concatenation(self, node:
|
|
265
|
+
def has_concatenation(self, node: ast.AST | QmodExprNodeId) -> bool:
|
|
261
266
|
if isinstance(node, ast.AST):
|
|
262
267
|
node = id(node)
|
|
263
268
|
return node in self._concatenations
|
|
@@ -271,7 +276,7 @@ class QmodAnnotatedExpression:
|
|
|
271
276
|
def get_quantum_vars(self) -> Mapping[QmodExprNodeId, HandleBinding]:
|
|
272
277
|
return self._quantum_vars
|
|
273
278
|
|
|
274
|
-
def clear_node_data(self, node:
|
|
279
|
+
def clear_node_data(self, node: ast.AST | QmodExprNodeId) -> None:
|
|
275
280
|
if isinstance(node, ast.AST):
|
|
276
281
|
node = id(node)
|
|
277
282
|
self._node_mapping.pop(node, None)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
from collections.abc import Mapping, Sequence
|
|
2
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
3
3
|
from enum import IntEnum
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, cast
|
|
5
5
|
|
|
6
6
|
from classiq.interface.exceptions import (
|
|
7
7
|
ClassiqExpansionError,
|
|
@@ -79,13 +79,13 @@ class QmodExpressionEvaluator(ast.NodeVisitor):
|
|
|
79
79
|
*,
|
|
80
80
|
treat_qnum_as_float: bool = False,
|
|
81
81
|
machine_precision: int = DEFAULT_MACHINE_PRECISION,
|
|
82
|
-
classical_struct_declarations:
|
|
83
|
-
enum_declarations:
|
|
84
|
-
classical_function_declarations:
|
|
82
|
+
classical_struct_declarations: Sequence[StructDeclaration] | None = None,
|
|
83
|
+
enum_declarations: Sequence[EnumDeclaration] | None = None,
|
|
84
|
+
classical_function_declarations: None | (
|
|
85
85
|
Sequence[ClassicalFunctionDeclaration]
|
|
86
|
-
|
|
87
|
-
classical_function_callables:
|
|
88
|
-
scope:
|
|
86
|
+
) = None,
|
|
87
|
+
classical_function_callables: Mapping[str, Callable] | None = None,
|
|
88
|
+
scope: Mapping[str, Any] | None = None,
|
|
89
89
|
) -> None:
|
|
90
90
|
self._expr_val = expr_val
|
|
91
91
|
self._treat_qnum_as_float = treat_qnum_as_float
|
|
@@ -258,13 +258,13 @@ def evaluate_qmod_expression(
|
|
|
258
258
|
*,
|
|
259
259
|
treat_qnum_as_float: bool = False,
|
|
260
260
|
machine_precision: int = DEFAULT_MACHINE_PRECISION,
|
|
261
|
-
classical_struct_declarations:
|
|
262
|
-
enum_declarations:
|
|
263
|
-
classical_function_declarations:
|
|
261
|
+
classical_struct_declarations: Sequence[StructDeclaration] | None = None,
|
|
262
|
+
enum_declarations: Sequence[EnumDeclaration] | None = None,
|
|
263
|
+
classical_function_declarations: None | (
|
|
264
264
|
Sequence[ClassicalFunctionDeclaration]
|
|
265
|
-
|
|
266
|
-
classical_function_callables:
|
|
267
|
-
scope:
|
|
265
|
+
) = None,
|
|
266
|
+
classical_function_callables: Mapping[str, Callable] | None = None,
|
|
267
|
+
scope: Mapping[str, Any] | None = None,
|
|
268
268
|
) -> QmodAnnotatedExpression:
|
|
269
269
|
expr_ast = ast.parse(expr, mode="eval").body
|
|
270
270
|
expr_value = QmodAnnotatedExpression(expr_ast)
|