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
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import NamedTuple
|
|
6
|
+
|
|
7
|
+
from classiq.interface.ast_node import ASTNode
|
|
8
|
+
from classiq.interface.exceptions import (
|
|
9
|
+
ClassiqDeprecationWarning,
|
|
10
|
+
ClassiqInternalExpansionError,
|
|
11
|
+
)
|
|
12
|
+
from classiq.interface.generator.compiler_keywords import EXPANDED_KEYWORD
|
|
13
|
+
from classiq.interface.generator.functions.port_declaration import (
|
|
14
|
+
PortDeclarationDirection,
|
|
15
|
+
)
|
|
16
|
+
from classiq.interface.generator.functions.type_modifier import TypeModifier
|
|
17
|
+
from classiq.interface.generator.visitor import NodeType
|
|
18
|
+
from classiq.interface.model.allocate import Allocate
|
|
19
|
+
from classiq.interface.model.bind_operation import BindOperation
|
|
20
|
+
from classiq.interface.model.block import Block
|
|
21
|
+
from classiq.interface.model.classical_if import ClassicalIf
|
|
22
|
+
from classiq.interface.model.control import Control
|
|
23
|
+
from classiq.interface.model.invert import Invert
|
|
24
|
+
from classiq.interface.model.model_visitor import ModelStatementsVisitor
|
|
25
|
+
from classiq.interface.model.native_function_definition import NativeFunctionDefinition
|
|
26
|
+
from classiq.interface.model.power import Power
|
|
27
|
+
from classiq.interface.model.quantum_expressions.amplitude_loading_operation import (
|
|
28
|
+
AmplitudeLoadingOperation,
|
|
29
|
+
)
|
|
30
|
+
from classiq.interface.model.quantum_expressions.arithmetic_operation import (
|
|
31
|
+
ArithmeticOperation,
|
|
32
|
+
)
|
|
33
|
+
from classiq.interface.model.quantum_function_call import QuantumFunctionCall
|
|
34
|
+
from classiq.interface.model.skip_control import SkipControl
|
|
35
|
+
from classiq.interface.model.within_apply_operation import WithinApply
|
|
36
|
+
from classiq.interface.source_reference import SourceReference
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _BoundVars(NamedTuple):
|
|
40
|
+
in_identifiers: list[str]
|
|
41
|
+
out_identifiers: list[str]
|
|
42
|
+
source_ref: SourceReference | None
|
|
43
|
+
|
|
44
|
+
def reverse(self) -> "_BoundVars":
|
|
45
|
+
return _BoundVars(
|
|
46
|
+
in_identifiers=self.out_identifiers,
|
|
47
|
+
out_identifiers=self.in_identifiers,
|
|
48
|
+
source_ref=self.source_ref,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class UncomputationSignatureInference(ModelStatementsVisitor):
|
|
53
|
+
"""
|
|
54
|
+
Infers the uncomputation signature of a function (permutation/non-permutation for
|
|
55
|
+
the function, and const/non-const for each parameter).
|
|
56
|
+
|
|
57
|
+
A function is a permutation if and only if all its body operations are permutations
|
|
58
|
+
(note that amplitude loading operation is not a permutation).
|
|
59
|
+
|
|
60
|
+
A parameter is const if and only if it is used as a const argument in all the
|
|
61
|
+
body operations (including when binding it to a different variable). An exception
|
|
62
|
+
for this rule is that a const parameter can be used as a non-const argument to a
|
|
63
|
+
permutation function inside a `within` block.
|
|
64
|
+
|
|
65
|
+
This class assumes that dependent functions are already inferred, so it doesn't
|
|
66
|
+
recursively inferring function calls.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self) -> None:
|
|
70
|
+
self._is_permutation: bool = True
|
|
71
|
+
self._non_permutation_reasons: list[SourceReference | None] = []
|
|
72
|
+
self._non_const_with_reasons: dict[str, list[SourceReference | None]] = (
|
|
73
|
+
defaultdict(list)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
self._in_conjugation: bool = False
|
|
77
|
+
self._source_ref: SourceReference | None = None
|
|
78
|
+
|
|
79
|
+
# remember bound vars inside `within` to invert their effect after the `apply`
|
|
80
|
+
self._bound_vars_list: list[_BoundVars] = []
|
|
81
|
+
|
|
82
|
+
def run(self, func_def: NativeFunctionDefinition) -> None:
|
|
83
|
+
self._is_permutation = True
|
|
84
|
+
self._non_permutation_reasons.clear()
|
|
85
|
+
self._non_const_with_reasons.clear()
|
|
86
|
+
self.visit(func_def.body)
|
|
87
|
+
|
|
88
|
+
def is_permutation(self) -> bool:
|
|
89
|
+
return self._is_permutation
|
|
90
|
+
|
|
91
|
+
def non_permutation_reasons(self) -> list[SourceReference | None]:
|
|
92
|
+
if self._is_permutation:
|
|
93
|
+
raise ClassiqInternalExpansionError("Function is a permutation")
|
|
94
|
+
return self._non_permutation_reasons
|
|
95
|
+
|
|
96
|
+
def is_const(self, port: str) -> bool:
|
|
97
|
+
return port not in self._non_const_with_reasons
|
|
98
|
+
|
|
99
|
+
def non_const_reasons(self, port: str) -> list[SourceReference | None]:
|
|
100
|
+
if port not in self._non_const_with_reasons:
|
|
101
|
+
raise ClassiqInternalExpansionError("Parameter is constant")
|
|
102
|
+
return self._non_const_with_reasons[port]
|
|
103
|
+
|
|
104
|
+
def visit(self, node: NodeType) -> None:
|
|
105
|
+
if isinstance(node, ASTNode):
|
|
106
|
+
with self._source_reference_context(node.source_ref):
|
|
107
|
+
super().visit(node)
|
|
108
|
+
else:
|
|
109
|
+
super().visit(node)
|
|
110
|
+
|
|
111
|
+
def visit_QuantumFunctionCall(self, call: QuantumFunctionCall) -> None:
|
|
112
|
+
if not call.func_decl.permutation:
|
|
113
|
+
self._mark_as_non_permutation()
|
|
114
|
+
|
|
115
|
+
in_identifiers: list[str] = []
|
|
116
|
+
out_identifiers: list[str] = []
|
|
117
|
+
|
|
118
|
+
for handle, port in call.handles_with_params:
|
|
119
|
+
if port.type_modifier is not TypeModifier.Const:
|
|
120
|
+
self._mark_as_non_const(handle.name, call.func_decl.permutation)
|
|
121
|
+
|
|
122
|
+
if port.direction is PortDeclarationDirection.Input:
|
|
123
|
+
in_identifiers.append(handle.name)
|
|
124
|
+
elif port.direction is PortDeclarationDirection.Output:
|
|
125
|
+
out_identifiers.append(handle.name)
|
|
126
|
+
|
|
127
|
+
if in_identifiers or out_identifiers:
|
|
128
|
+
bound_vars = _BoundVars(in_identifiers, out_identifiers, call.source_ref)
|
|
129
|
+
self._mark_bind_outputs(bound_vars)
|
|
130
|
+
self._bound_vars_list.append(bound_vars)
|
|
131
|
+
|
|
132
|
+
def visit_Allocate(self, alloc: Allocate) -> None:
|
|
133
|
+
self._mark_as_non_const(alloc.target.name, True)
|
|
134
|
+
|
|
135
|
+
def visit_BindOperation(self, bind_op: BindOperation) -> None:
|
|
136
|
+
in_identifiers = [handle.name for handle in bind_op.in_handles]
|
|
137
|
+
out_identifiers = [handle.name for handle in bind_op.out_handles]
|
|
138
|
+
bound_vars = _BoundVars(in_identifiers, out_identifiers, bind_op.source_ref)
|
|
139
|
+
self._mark_bind_outputs(bound_vars)
|
|
140
|
+
self._bound_vars_list.append(bound_vars)
|
|
141
|
+
|
|
142
|
+
def visit_ArithmeticOperation(self, arith: ArithmeticOperation) -> None:
|
|
143
|
+
if arith.classical_assignment:
|
|
144
|
+
if arith.var_handles:
|
|
145
|
+
self._mark_as_non_permutation()
|
|
146
|
+
for handle in arith.var_handles:
|
|
147
|
+
self._mark_as_non_const(handle.name, False)
|
|
148
|
+
else:
|
|
149
|
+
self._mark_as_non_const(arith.result_var.name, True)
|
|
150
|
+
|
|
151
|
+
def visit_AmplitudeLoadingOperation(
|
|
152
|
+
self, amp_load: AmplitudeLoadingOperation
|
|
153
|
+
) -> None:
|
|
154
|
+
self._mark_as_non_permutation()
|
|
155
|
+
self._mark_as_non_const(amp_load.result_var.name, False)
|
|
156
|
+
|
|
157
|
+
def visit_Control(self, control: Control) -> None:
|
|
158
|
+
self.visit(control.body)
|
|
159
|
+
if control.else_block is not None:
|
|
160
|
+
self.visit(control.else_block)
|
|
161
|
+
|
|
162
|
+
def visit_Invert(self, invert: Invert) -> None:
|
|
163
|
+
self.visit(invert.body)
|
|
164
|
+
|
|
165
|
+
def visit_Power(self, power: Power) -> None:
|
|
166
|
+
self.visit(power.body)
|
|
167
|
+
|
|
168
|
+
def visit_WithinApply(self, within_apply: WithinApply) -> None:
|
|
169
|
+
with self._conjugation_context() as bound_vars_list:
|
|
170
|
+
self.visit(within_apply.compute)
|
|
171
|
+
self.visit(within_apply.action)
|
|
172
|
+
|
|
173
|
+
for bound_vars in reversed(bound_vars_list):
|
|
174
|
+
self._mark_bind_outputs(bound_vars.reverse())
|
|
175
|
+
|
|
176
|
+
def visit_Block(self, block: Block) -> None:
|
|
177
|
+
self.visit(block.statements)
|
|
178
|
+
|
|
179
|
+
def visit_SkipControl(self, block: SkipControl) -> None:
|
|
180
|
+
self.visit(block.body)
|
|
181
|
+
|
|
182
|
+
def visit_ClassicalIf(self, classical_if: ClassicalIf) -> None:
|
|
183
|
+
self.visit(classical_if.then)
|
|
184
|
+
self.visit(classical_if.else_)
|
|
185
|
+
|
|
186
|
+
def _mark_as_non_permutation(self) -> None:
|
|
187
|
+
self._is_permutation = False
|
|
188
|
+
self._non_permutation_reasons.append(self._source_ref)
|
|
189
|
+
|
|
190
|
+
def _mark_as_non_const(
|
|
191
|
+
self,
|
|
192
|
+
identifier: str,
|
|
193
|
+
permutation_op: bool,
|
|
194
|
+
source_ref: SourceReference | None = None,
|
|
195
|
+
) -> None:
|
|
196
|
+
if self._in_conjugation and permutation_op:
|
|
197
|
+
return
|
|
198
|
+
self._non_const_with_reasons[identifier].append(source_ref or self._source_ref)
|
|
199
|
+
|
|
200
|
+
def _mark_bind_outputs(self, bound_vars: _BoundVars) -> None:
|
|
201
|
+
if all(self.is_const(identifier) for identifier in bound_vars.in_identifiers):
|
|
202
|
+
return
|
|
203
|
+
for identifier in bound_vars.out_identifiers:
|
|
204
|
+
self._mark_as_non_const(identifier, False, bound_vars.source_ref)
|
|
205
|
+
|
|
206
|
+
@contextmanager
|
|
207
|
+
def _conjugation_context(self) -> Iterator[list[_BoundVars]]:
|
|
208
|
+
previous_bound_vars = self._bound_vars_list
|
|
209
|
+
previous_context = self._in_conjugation
|
|
210
|
+
self._bound_vars_list = []
|
|
211
|
+
self._in_conjugation = True
|
|
212
|
+
try:
|
|
213
|
+
yield self._bound_vars_list
|
|
214
|
+
finally:
|
|
215
|
+
self._in_conjugation = previous_context
|
|
216
|
+
self._bound_vars_list = previous_bound_vars
|
|
217
|
+
|
|
218
|
+
@contextmanager
|
|
219
|
+
def _source_reference_context(
|
|
220
|
+
self, source_ref: SourceReference | None
|
|
221
|
+
) -> Iterator[None]:
|
|
222
|
+
previous_source_ref = self._source_ref
|
|
223
|
+
self._source_ref = source_ref
|
|
224
|
+
try:
|
|
225
|
+
yield
|
|
226
|
+
finally:
|
|
227
|
+
self._source_ref = previous_source_ref
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def infer_and_validate_uncomputation_signature(
|
|
231
|
+
func_def: NativeFunctionDefinition,
|
|
232
|
+
disable_perm_check: bool = False,
|
|
233
|
+
disable_const_checks: list[str] | bool = False,
|
|
234
|
+
tighten_signature: bool = False,
|
|
235
|
+
) -> None:
|
|
236
|
+
"""
|
|
237
|
+
Runs the uncomputation signature inference in order to validate the function signature
|
|
238
|
+
and tighten it when requested (changing non-permutation to permutation and non-const
|
|
239
|
+
to const).
|
|
240
|
+
"""
|
|
241
|
+
for port in func_def.port_declarations:
|
|
242
|
+
if port.type_modifier is TypeModifier.Const and port.direction in (
|
|
243
|
+
PortDeclarationDirection.Input,
|
|
244
|
+
PortDeclarationDirection.Output,
|
|
245
|
+
):
|
|
246
|
+
warnings.warn(
|
|
247
|
+
_input_output_const(port.name, port.direction, func_def.name),
|
|
248
|
+
ClassiqDeprecationWarning,
|
|
249
|
+
stacklevel=1,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
if disable_perm_check and (disable_const_checks is True) and not tighten_signature:
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
visitor = UncomputationSignatureInference()
|
|
256
|
+
visitor.run(func_def)
|
|
257
|
+
|
|
258
|
+
if not disable_perm_check and func_def.permutation and not visitor.is_permutation():
|
|
259
|
+
for source_ref in visitor.non_permutation_reasons():
|
|
260
|
+
warnings.warn(
|
|
261
|
+
_non_permutation_usage(func_def.name, source_ref),
|
|
262
|
+
ClassiqDeprecationWarning,
|
|
263
|
+
stacklevel=1,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if tighten_signature and not func_def.permutation and visitor.is_permutation():
|
|
267
|
+
func_def.permutation = True
|
|
268
|
+
|
|
269
|
+
unchecked = (
|
|
270
|
+
set(disable_const_checks) if isinstance(disable_const_checks, list) else set()
|
|
271
|
+
)
|
|
272
|
+
for port in func_def.port_declarations:
|
|
273
|
+
if (
|
|
274
|
+
not ((disable_const_checks is True) or port.name in unchecked)
|
|
275
|
+
and port.type_modifier is TypeModifier.Const
|
|
276
|
+
and not visitor.is_const(port.name)
|
|
277
|
+
):
|
|
278
|
+
for source_ref in visitor.non_const_reasons(port.name):
|
|
279
|
+
warnings.warn(
|
|
280
|
+
_non_const_usage(port.name, source_ref),
|
|
281
|
+
ClassiqDeprecationWarning,
|
|
282
|
+
stacklevel=1,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
if (
|
|
286
|
+
tighten_signature
|
|
287
|
+
and port.type_modifier is not TypeModifier.Const
|
|
288
|
+
and visitor.is_const(port.name)
|
|
289
|
+
):
|
|
290
|
+
port.type_modifier = TypeModifier.Const
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _input_output_const(
|
|
294
|
+
port_name: str,
|
|
295
|
+
direction: PortDeclarationDirection,
|
|
296
|
+
function_name: str,
|
|
297
|
+
) -> str:
|
|
298
|
+
return (
|
|
299
|
+
f"{direction.capitalize()} parameters cannot be defined as constants"
|
|
300
|
+
f" (parameter {port_name!r} in function {function_name.split('_' + EXPANDED_KEYWORD)[0]!r}).\n"
|
|
301
|
+
"The deprecation warning will be elevated to an error starting 2025-12-03, at the earliest."
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _non_const_usage(
|
|
306
|
+
port_name: str,
|
|
307
|
+
source_ref: SourceReference | None = None,
|
|
308
|
+
) -> str:
|
|
309
|
+
source_ref_str = f"\n\tat {source_ref}" if source_ref else ""
|
|
310
|
+
return (
|
|
311
|
+
f"Non-constant usage of a constant parameter {port_name!r}.{source_ref_str}\n"
|
|
312
|
+
"Tip: if the commulative use of the parameter in the function is constant, "
|
|
313
|
+
"use the `disable_const_checks` flag to instruct the compiler to disregard individual operations.\n"
|
|
314
|
+
"The deprecation warning will be elevated to an error starting 2025-12-03, at the earliest."
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _non_permutation_usage(
|
|
319
|
+
function_name: str,
|
|
320
|
+
source_ref: SourceReference | None = None,
|
|
321
|
+
) -> str:
|
|
322
|
+
source_ref_str = f"\n\tat {source_ref}" if source_ref else ""
|
|
323
|
+
return (
|
|
324
|
+
f"Non-permutation operation used in a permutation function {function_name.split('_' + EXPANDED_KEYWORD)[0]!r}.{source_ref_str}\n"
|
|
325
|
+
"Tip: if the commulative effect of the function is a permutation, "
|
|
326
|
+
"use the `disable_perm_check` flag to instruct the compiler to disregard individual operations.\n"
|
|
327
|
+
"The deprecation warning will be elevated to an error starting 2025-12-03, at the earliest."
|
|
328
|
+
)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
from collections.abc import Iterator
|
|
3
3
|
from contextlib import contextmanager
|
|
4
|
-
from typing import Optional, Union
|
|
5
4
|
|
|
6
5
|
from classiq.interface.exceptions import (
|
|
7
6
|
ClassiqExpansionError,
|
|
@@ -46,13 +45,15 @@ class VarRefCollector(ast.NodeVisitor):
|
|
|
46
45
|
handle for handle, in_subscript in self._var_handles.items() if in_subscript
|
|
47
46
|
]
|
|
48
47
|
|
|
49
|
-
def visit(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
def visit(
|
|
49
|
+
self, node: ast.AST
|
|
50
|
+
) -> (
|
|
51
|
+
SubscriptHandleBinding
|
|
52
|
+
| SlicedHandleBinding
|
|
53
|
+
| FieldHandleBinding
|
|
54
|
+
| HandleBinding
|
|
55
|
+
| None
|
|
56
|
+
):
|
|
56
57
|
res = super().visit(node)
|
|
57
58
|
if not self._ignore_duplicated_handles and len(self._var_handles) != len(
|
|
58
59
|
{handle.name for handle in self._var_handles}
|
|
@@ -62,13 +63,13 @@ class VarRefCollector(ast.NodeVisitor):
|
|
|
62
63
|
)
|
|
63
64
|
return res
|
|
64
65
|
|
|
65
|
-
def visit_Subscript(self, node: ast.Subscript) ->
|
|
66
|
+
def visit_Subscript(self, node: ast.Subscript) -> HandleBinding | None:
|
|
66
67
|
return self._get_subscript_handle(node.value, node.slice)
|
|
67
68
|
|
|
68
|
-
def visit_Attribute(self, node: ast.Attribute) ->
|
|
69
|
+
def visit_Attribute(self, node: ast.Attribute) -> FieldHandleBinding | None:
|
|
69
70
|
return self._get_field_handle(node.value, node.attr)
|
|
70
71
|
|
|
71
|
-
def visit_Call(self, node: ast.Call) ->
|
|
72
|
+
def visit_Call(self, node: ast.Call) -> HandleBinding | None:
|
|
72
73
|
if not isinstance(node.func, ast.Name):
|
|
73
74
|
return self.generic_visit(node)
|
|
74
75
|
if node.func.id == "get_field":
|
|
@@ -89,7 +90,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
|
89
90
|
|
|
90
91
|
def _get_field_handle(
|
|
91
92
|
self, subject: ast.expr, field: str
|
|
92
|
-
) ->
|
|
93
|
+
) -> FieldHandleBinding | None:
|
|
93
94
|
with self.set_nested():
|
|
94
95
|
base_handle = self.visit(subject)
|
|
95
96
|
if base_handle is None:
|
|
@@ -104,7 +105,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
|
104
105
|
|
|
105
106
|
def _get_subscript_handle(
|
|
106
107
|
self, subject: ast.expr, subscript: ast.expr
|
|
107
|
-
) ->
|
|
108
|
+
) -> HandleBinding | None:
|
|
108
109
|
with self.set_in_subscript():
|
|
109
110
|
self.visit(subscript)
|
|
110
111
|
with self.set_nested():
|
|
@@ -138,7 +139,7 @@ class VarRefCollector(ast.NodeVisitor):
|
|
|
138
139
|
self._add_handle(handle)
|
|
139
140
|
return handle
|
|
140
141
|
|
|
141
|
-
def visit_Name(self, node: ast.Name) ->
|
|
142
|
+
def visit_Name(self, node: ast.Name) -> HandleBinding | None:
|
|
142
143
|
if not self._ignore_sympy_symbols and node.id in set(
|
|
143
144
|
SYMPY_SUPPORTED_EXPRESSIONS
|
|
144
145
|
) | set(DEFAULT_SUPPORTED_FUNC_NAMES):
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from classiq.qmod.quantum_function import BaseQFunc
|
|
2
|
+
|
|
1
3
|
from .amplitude_amplification import (
|
|
2
4
|
amplitude_amplification,
|
|
3
5
|
exact_amplitude_amplification,
|
|
4
6
|
)
|
|
5
7
|
from .amplitude_estimation import *
|
|
8
|
+
from .amplitude_loading import assign_amplitude_table
|
|
6
9
|
from .discrete_sine_cosine_transform import *
|
|
7
10
|
from .discrete_sine_cosine_transform import _qct_d_operator, _qct_pi_operator
|
|
8
11
|
from .grover import *
|
|
@@ -11,20 +14,20 @@ from .hea import *
|
|
|
11
14
|
from .lcu import *
|
|
12
15
|
from .linear_pauli_rotation import *
|
|
13
16
|
from .linear_pauli_rotation import _single_pauli
|
|
14
|
-
from .lookup_table import span_lookup_table
|
|
15
17
|
from .modular_exponentiation import *
|
|
16
18
|
from .modular_exponentiation import _check_msb
|
|
17
19
|
from .qaoa_penalty import *
|
|
18
20
|
from .qft_functions import *
|
|
19
21
|
from .qpe import *
|
|
20
|
-
from .qsvt import
|
|
22
|
+
from .qsvt import gqsp
|
|
23
|
+
from .qsvt_temp import * # change to .qsvt after deprecation
|
|
21
24
|
from .state_preparation import *
|
|
22
25
|
from .state_preparation import _prepare_uniform_trimmed_state_step
|
|
23
26
|
from .swap_test import *
|
|
24
27
|
from .utility_functions import *
|
|
25
28
|
from .variational import *
|
|
26
29
|
|
|
27
|
-
OPEN_LIBRARY_FUNCTIONS = [
|
|
30
|
+
OPEN_LIBRARY_FUNCTIONS: list[BaseQFunc] = [
|
|
28
31
|
qpe_flexible,
|
|
29
32
|
qpe,
|
|
30
33
|
_single_pauli,
|
|
@@ -46,13 +49,20 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
|
46
49
|
multiswap,
|
|
47
50
|
inplace_c_modular_multiply,
|
|
48
51
|
modular_exp,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
qsvt_step_old,
|
|
53
|
+
qsvt_step_new,
|
|
54
|
+
qsvt_old,
|
|
55
|
+
qsvt_new,
|
|
56
|
+
projector_controlled_double_phase_old,
|
|
57
|
+
projector_controlled_double_phase_new,
|
|
58
|
+
projector_controlled_phase_old,
|
|
59
|
+
projector_controlled_phase_new,
|
|
60
|
+
qsvt_inversion_old,
|
|
61
|
+
qsvt_inversion_new,
|
|
62
|
+
qsvt_lcu_old,
|
|
63
|
+
qsvt_lcu_new,
|
|
64
|
+
qsvt_lcu_step_old,
|
|
65
|
+
qsvt_lcu_step_new,
|
|
56
66
|
gqsp,
|
|
57
67
|
qaoa_mixer_layer,
|
|
58
68
|
qaoa_cost_layer,
|
|
@@ -82,6 +92,9 @@ OPEN_LIBRARY_FUNCTIONS = [
|
|
|
82
92
|
encode_in_angle,
|
|
83
93
|
encode_on_bloch,
|
|
84
94
|
_cond_phase_flip,
|
|
95
|
+
inplace_modular_multiply,
|
|
96
|
+
modular_multiply,
|
|
97
|
+
modular_add_qft_space,
|
|
85
98
|
]
|
|
86
99
|
|
|
87
100
|
__all__ = [
|
|
@@ -89,6 +102,7 @@ __all__ = [
|
|
|
89
102
|
"amplitude_amplification",
|
|
90
103
|
"amplitude_estimation",
|
|
91
104
|
"apply_to_all",
|
|
105
|
+
"assign_amplitude_table",
|
|
92
106
|
"c_modular_multiply",
|
|
93
107
|
"cc_modular_add",
|
|
94
108
|
"encode_in_angle",
|
|
@@ -101,14 +115,17 @@ __all__ = [
|
|
|
101
115
|
"grover_search",
|
|
102
116
|
"hadamard_transform",
|
|
103
117
|
"inplace_c_modular_multiply",
|
|
118
|
+
"inplace_modular_multiply",
|
|
104
119
|
"inplace_prepare_complex_amplitudes",
|
|
105
120
|
"inplace_prepare_int",
|
|
106
121
|
"inplace_prepare_sparse_amplitudes",
|
|
107
122
|
"lcu",
|
|
108
123
|
"lcu_pauli",
|
|
109
124
|
"linear_pauli_rotations",
|
|
125
|
+
"modular_add_qft_space",
|
|
110
126
|
"modular_exp",
|
|
111
127
|
"modular_increment",
|
|
128
|
+
"modular_multiply",
|
|
112
129
|
"multiswap",
|
|
113
130
|
"phase_oracle",
|
|
114
131
|
"prepare_basis_state",
|
|
@@ -120,6 +137,7 @@ __all__ = [
|
|
|
120
137
|
"prepare_ghz_state",
|
|
121
138
|
"prepare_int",
|
|
122
139
|
"prepare_linear_amplitudes",
|
|
140
|
+
"prepare_select",
|
|
123
141
|
"prepare_sparse_amplitudes",
|
|
124
142
|
"prepare_uniform_interval_state",
|
|
125
143
|
"prepare_uniform_trimmed_state",
|
|
@@ -145,7 +163,6 @@ __all__ = [
|
|
|
145
163
|
"qsvt_lcu_step",
|
|
146
164
|
"qsvt_step",
|
|
147
165
|
"reflect_about_zero",
|
|
148
|
-
"span_lookup_table",
|
|
149
166
|
"suzuki_trotter",
|
|
150
167
|
"swap_test",
|
|
151
168
|
"switch",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from typing import cast
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from sympy import fwht
|
|
5
|
+
|
|
6
|
+
from classiq.interface.exceptions import ClassiqValueError
|
|
7
|
+
|
|
8
|
+
from classiq.qmod.builtins.functions import CX, RY
|
|
9
|
+
from classiq.qmod.builtins.operations import skip_control
|
|
10
|
+
from classiq.qmod.qfunc import qfunc
|
|
11
|
+
from classiq.qmod.qmod_variable import Const, QArray, QBit
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_graycode(size: int, i: int) -> int:
|
|
15
|
+
if i == 2**size:
|
|
16
|
+
return _get_graycode(size, 0)
|
|
17
|
+
return i ^ (i >> 1)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _get_graycode_angles_wh(size: int, angles: list[float]) -> list[float]:
|
|
21
|
+
transformed_angles = fwht(np.array(angles) / 2**size)
|
|
22
|
+
return [transformed_angles[_get_graycode(size, j)] for j in range(2**size)]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _get_graycode_ctrls(size: int) -> list[int]:
|
|
26
|
+
return [
|
|
27
|
+
(_get_graycode(size, i) ^ _get_graycode(size, i + 1)).bit_length() - 1
|
|
28
|
+
for i in range(2**size)
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@qfunc
|
|
33
|
+
def assign_amplitude_table(
|
|
34
|
+
amplitudes: list[float], index: Const[QArray], indicator: QBit
|
|
35
|
+
) -> None:
|
|
36
|
+
"""
|
|
37
|
+
[Qmod Classiq-library function]
|
|
38
|
+
|
|
39
|
+
Load a specified list of real amplitudes into a quantum variable using an extra indicator qubit:
|
|
40
|
+
\\( |i\\rangle|0\\rangle \\rightarrow a(i)\\ |i\\rangle|1\\rangle + \\sqrt{1 - a(i)^2}\\ |i\\rangle|0\\rangle \\).
|
|
41
|
+
Here, \\(a(i)\\) is the i-th amplitude, determined by the QNum when the index is in state \\(i\\).
|
|
42
|
+
A list extracted from a given classical function \\(f(x)\\), with indexing according to a given QNum, can be obtained via the utility SDK function `lookup_table`.
|
|
43
|
+
This function expects the indicator qubit to be initialized to \\(|0\\rangle\\).
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
amplitudes: Real values for the amplitudes. Must be between -1 and 1
|
|
47
|
+
index: The quantum variable used for amplitude indexing
|
|
48
|
+
indicator: The quantum indicator qubit
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
```python
|
|
52
|
+
from classiq import *
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@qfunc
|
|
56
|
+
def main(x: Output[QNum[5, UNSIGNED, 5]], ind: Output[QBit]) -> None:
|
|
57
|
+
allocate(x)
|
|
58
|
+
hadamard_transform(x)
|
|
59
|
+
allocate(ind)
|
|
60
|
+
|
|
61
|
+
assign_amplitude_table(lookup_table(lambda x: x**2, x), x, ind)
|
|
62
|
+
```
|
|
63
|
+
"""
|
|
64
|
+
size = index.len
|
|
65
|
+
if len(amplitudes) != 2**size:
|
|
66
|
+
raise ClassiqValueError(
|
|
67
|
+
f"The number of amplitudes must be 2**index.size={2 ** size}, got "
|
|
68
|
+
f"{len(amplitudes)}"
|
|
69
|
+
)
|
|
70
|
+
if not all(-1 <= amp <= 1 for amp in amplitudes):
|
|
71
|
+
raise ClassiqValueError("All amplitudes must be between -1 and 1")
|
|
72
|
+
|
|
73
|
+
angles_to_load = cast(list[float], 2 * np.arcsin(amplitudes))
|
|
74
|
+
transformed_angles = _get_graycode_angles_wh(size, angles_to_load)
|
|
75
|
+
controllers = _get_graycode_ctrls(size)
|
|
76
|
+
|
|
77
|
+
for k in range(2**size):
|
|
78
|
+
RY(transformed_angles[k], indicator)
|
|
79
|
+
skip_control(
|
|
80
|
+
lambda k=k: CX(index[controllers[k]], indicator) # type:ignore[misc]
|
|
81
|
+
)
|
|
@@ -10,8 +10,8 @@ from classiq.qmod.builtins.operations import (
|
|
|
10
10
|
repeat,
|
|
11
11
|
within_apply,
|
|
12
12
|
)
|
|
13
|
-
from classiq.qmod.qfunc import qfunc
|
|
14
|
-
from classiq.qmod.qmod_variable import Const,
|
|
13
|
+
from classiq.qmod.qfunc import qfunc, qperm
|
|
14
|
+
from classiq.qmod.qmod_variable import Const, QArray, QBit, QNum
|
|
15
15
|
from classiq.qmod.symbolic import pi
|
|
16
16
|
from classiq.qmod.utilities import suppress_return_value
|
|
17
17
|
|
|
@@ -27,8 +27,8 @@ def _qct_d_operator(x: Const[QNum], q: QBit) -> None:
|
|
|
27
27
|
control(x == 0, lambda: invert(lambda: _b_operator(q)))
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
@
|
|
31
|
-
def _qct_pi_operator(x:
|
|
30
|
+
@qperm
|
|
31
|
+
def _qct_pi_operator(x: QNum, q: Const[QBit]) -> None:
|
|
32
32
|
control(
|
|
33
33
|
q == 1,
|
|
34
34
|
lambda: [
|
|
@@ -125,7 +125,7 @@ def qct_qst_type1(x: QArray[QBit]) -> None:
|
|
|
125
125
|
within_apply(lambda: _t_operator(x), lambda: qft(x))
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
@qfunc(
|
|
128
|
+
@qfunc(disable_const_checks=["q"])
|
|
129
129
|
def qct_qst_type2(x: QArray[QBit], q: Const[QBit]) -> None:
|
|
130
130
|
"""
|
|
131
131
|
[Qmod Classiq-library function]
|
|
@@ -8,23 +8,21 @@ from classiq.qmod.builtins.operations import (
|
|
|
8
8
|
power,
|
|
9
9
|
within_apply,
|
|
10
10
|
)
|
|
11
|
-
from classiq.qmod.qfunc import qfunc
|
|
11
|
+
from classiq.qmod.qfunc import qfunc, qperm
|
|
12
12
|
from classiq.qmod.qmod_parameter import CInt
|
|
13
|
-
from classiq.qmod.qmod_variable import Const,
|
|
14
|
-
from classiq.qmod.quantum_callable import QCallable
|
|
13
|
+
from classiq.qmod.qmod_variable import Const, QArray, QBit, QNum
|
|
14
|
+
from classiq.qmod.quantum_callable import QCallable, QPerm
|
|
15
15
|
from classiq.qmod.symbolic import pi
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
@
|
|
19
|
-
def _cond_phase_flip(
|
|
20
|
-
predicate: QCallable[Permutable[QBit]], target: Const[QBit]
|
|
21
|
-
) -> None:
|
|
18
|
+
@qperm(disable_perm_check=True, disable_const_checks=["target"])
|
|
19
|
+
def _cond_phase_flip(predicate: QPerm[QBit], target: Const[QBit]) -> None:
|
|
22
20
|
within_apply(lambda: H(target), lambda: predicate(target))
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
@
|
|
23
|
+
@qperm
|
|
26
24
|
def phase_oracle(
|
|
27
|
-
predicate:
|
|
25
|
+
predicate: QPerm[Const[QArray[QBit]], QBit],
|
|
28
26
|
target: Const[QArray[QBit]],
|
|
29
27
|
) -> None:
|
|
30
28
|
"""
|
|
@@ -55,7 +53,7 @@ def phase_oracle(
|
|
|
55
53
|
)
|
|
56
54
|
|
|
57
55
|
|
|
58
|
-
@
|
|
56
|
+
@qperm(disable_perm_check=True, disable_const_checks=["packed_vars"])
|
|
59
57
|
def reflect_about_zero(packed_vars: Const[QArray[QBit]]) -> None:
|
|
60
58
|
"""
|
|
61
59
|
[Qmod Classiq-library function]
|