classiq 0.38.0__py3-none-any.whl → 0.65.4__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 +47 -32
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +2 -1
- classiq/_internals/api_wrapper.py +235 -97
- classiq/_internals/async_utils.py +1 -3
- classiq/_internals/authentication/auth0.py +26 -10
- classiq/_internals/authentication/authentication.py +11 -0
- classiq/_internals/authentication/device.py +10 -5
- classiq/_internals/authentication/password_manager.py +18 -6
- classiq/_internals/authentication/token_manager.py +10 -5
- classiq/_internals/client.py +94 -33
- classiq/_internals/config.py +3 -4
- classiq/_internals/host_checker.py +38 -15
- classiq/_internals/jobs.py +60 -57
- classiq/_internals/type_validation.py +9 -9
- classiq/analyzer/__init__.py +1 -3
- classiq/analyzer/analyzer.py +24 -19
- classiq/analyzer/analyzer_utilities.py +10 -10
- classiq/analyzer/rb.py +15 -15
- classiq/analyzer/show_interactive_hack.py +27 -4
- classiq/analyzer/url_utils.py +2 -3
- classiq/applications/__init__.py +3 -12
- classiq/applications/chemistry/__init__.py +14 -10
- classiq/applications/chemistry/ansatz_parameters.py +4 -4
- classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +165 -158
- classiq/applications/chemistry/ground_state_problem.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/allowed_constraints.py +4 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/arithmetic_expression.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/isolation.py +1 -1
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/combinatorial_problem_utils.py +51 -15
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_mapping.py +12 -12
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/encoding_utils.py +8 -6
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/memory.py +7 -11
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/optimization_model.py +67 -40
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +46 -0
- classiq/applications/combinatorial_helpers/pyomo_utils.py +447 -0
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/encoding.py +15 -20
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/fixed_variables.py +14 -15
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/ising_converter.py +11 -15
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty.py +1 -2
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/penalty_support.py +3 -7
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/sign_seperation.py +2 -3
- classiq/{applications_model_constructors → applications}/combinatorial_helpers/transformations/slack_variables.py +5 -8
- classiq/applications/combinatorial_optimization/__init__.py +20 -6
- classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
- classiq/{applications_model_constructors → applications/combinatorial_optimization}/combinatorial_optimization_model_constructor.py +35 -33
- classiq/applications/combinatorial_optimization/combinatorial_problem.py +229 -0
- classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
- classiq/applications/finance/__init__.py +4 -5
- classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +48 -42
- classiq/applications/grover/__init__.py +9 -0
- classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +52 -51
- classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
- classiq/applications/libraries/qmci_library.py +22 -0
- classiq/applications/qnn/__init__.py +2 -4
- classiq/applications/qnn/circuit_utils.py +6 -6
- classiq/applications/qnn/datasets/__init__.py +9 -11
- classiq/applications/qnn/datasets/dataset_base_classes.py +7 -5
- classiq/applications/qnn/datasets/dataset_not.py +2 -1
- classiq/applications/qnn/datasets/dataset_parity.py +2 -2
- classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
- classiq/applications/qnn/qlayer.py +30 -10
- classiq/applications/qnn/torch_utils.py +4 -3
- classiq/applications/qnn/types.py +5 -5
- classiq/applications/qsvm/__init__.py +6 -4
- classiq/applications/qsvm/qsvm.py +3 -6
- classiq/applications/qsvm/qsvm_data_generation.py +3 -3
- classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +30 -28
- classiq/execution/__init__.py +8 -3
- classiq/execution/all_hardware_devices.py +11 -0
- classiq/execution/execution_session.py +400 -0
- classiq/execution/iqcc.py +63 -0
- classiq/execution/jobs.py +197 -25
- classiq/execution/qnn.py +79 -0
- classiq/executor.py +20 -115
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +43 -13
- classiq/interface/analyzer/cytoscape_graph.py +15 -9
- classiq/interface/analyzer/result.py +28 -32
- classiq/interface/applications/qsvm.py +20 -29
- classiq/interface/ast_node.py +16 -0
- classiq/interface/backend/backend_preferences.py +390 -121
- classiq/interface/backend/ionq/ionq_quantum_program.py +15 -23
- classiq/interface/backend/pydantic_backend.py +25 -22
- classiq/interface/backend/quantum_backend_providers.py +69 -16
- classiq/interface/chemistry/fermionic_operator.py +30 -21
- classiq/interface/chemistry/ground_state_problem.py +28 -25
- classiq/interface/chemistry/molecule.py +14 -10
- classiq/interface/chemistry/operator.py +64 -231
- classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
- classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -3
- classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -4
- classiq/interface/combinatorial_optimization/examples/knapsack.py +3 -3
- classiq/interface/combinatorial_optimization/examples/mht.py +10 -6
- classiq/interface/combinatorial_optimization/examples/portfolio_variations.py +2 -2
- classiq/interface/combinatorial_optimization/examples/set_cover.py +1 -2
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +8 -9
- classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
- classiq/interface/combinatorial_optimization/result.py +1 -3
- classiq/interface/combinatorial_optimization/solver_types.py +1 -1
- classiq/interface/debug_info/debug_info.py +86 -0
- classiq/{exceptions.py → interface/exceptions.py} +37 -9
- classiq/interface/execution/iqcc.py +19 -0
- classiq/interface/execution/jobs.py +15 -12
- classiq/interface/execution/primitives.py +18 -0
- classiq/interface/executor/constants.py +1 -0
- classiq/interface/executor/execution_preferences.py +26 -114
- classiq/interface/executor/execution_request.py +24 -46
- classiq/interface/executor/execution_result.py +30 -8
- classiq/interface/executor/iqae_result.py +4 -6
- classiq/interface/executor/optimizer_preferences.py +17 -14
- classiq/interface/executor/quantum_code.py +28 -24
- classiq/interface/executor/quantum_instruction_set.py +2 -2
- classiq/interface/executor/register_initialization.py +11 -14
- classiq/interface/executor/result.py +83 -56
- classiq/interface/executor/vqe_result.py +10 -10
- classiq/interface/finance/function_input.py +35 -25
- classiq/interface/finance/gaussian_model_input.py +5 -5
- classiq/interface/finance/log_normal_model_input.py +4 -4
- classiq/interface/finance/model_input.py +4 -4
- classiq/interface/generator/adjacency.py +1 -3
- classiq/interface/generator/amplitude_loading.py +22 -12
- classiq/interface/generator/ansatz_library.py +5 -5
- classiq/interface/generator/application_apis/arithmetic_declarations.py +8 -5
- classiq/interface/generator/application_apis/chemistry_declarations.py +27 -187
- classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +18 -21
- classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
- classiq/interface/generator/application_apis/finance_declarations.py +48 -69
- classiq/interface/generator/application_apis/qsvm_declarations.py +0 -70
- classiq/interface/generator/arith/argument_utils.py +46 -5
- classiq/interface/generator/arith/arithmetic.py +35 -16
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +6 -7
- classiq/interface/generator/arith/arithmetic_expression_abc.py +66 -25
- classiq/interface/generator/arith/arithmetic_expression_parser.py +11 -11
- classiq/interface/generator/arith/arithmetic_expression_validator.py +47 -43
- classiq/interface/generator/arith/arithmetic_operations.py +14 -6
- classiq/interface/generator/arith/arithmetic_param_getters.py +7 -8
- classiq/interface/generator/arith/arithmetic_result_builder.py +21 -17
- classiq/interface/generator/arith/ast_node_rewrite.py +3 -2
- classiq/interface/generator/arith/binary_ops.py +218 -130
- classiq/interface/generator/arith/endianness.py +1 -1
- classiq/interface/generator/arith/extremum_operations.py +96 -25
- classiq/interface/generator/arith/logical_ops.py +14 -12
- classiq/interface/generator/arith/number_utils.py +12 -6
- classiq/interface/generator/arith/register_user_input.py +60 -37
- classiq/interface/generator/arith/unary_ops.py +49 -29
- classiq/interface/generator/arith/uncomputation_methods.py +1 -1
- classiq/interface/generator/builtin_api_builder.py +2 -9
- classiq/interface/generator/chemistry_function_params.py +3 -3
- classiq/interface/generator/circuit_code/circuit_code.py +7 -7
- classiq/interface/generator/circuit_code/types_and_constants.py +4 -7
- classiq/interface/generator/commuting_pauli_exponentiation.py +7 -7
- classiq/interface/generator/compiler_keywords.py +5 -1
- classiq/interface/generator/complex_type.py +13 -18
- classiq/interface/generator/constant.py +3 -4
- classiq/interface/generator/control_state.py +34 -29
- classiq/interface/generator/copy.py +47 -0
- classiq/interface/generator/custom_ansatz.py +2 -5
- classiq/interface/generator/distance.py +3 -5
- classiq/interface/generator/excitations.py +3 -2
- classiq/interface/generator/expressions/atomic_expression_functions.py +21 -5
- classiq/interface/generator/expressions/enums/__init__.py +0 -10
- classiq/interface/generator/expressions/enums/finance_functions.py +12 -22
- classiq/interface/generator/expressions/evaluated_expression.py +5 -5
- classiq/interface/generator/expressions/expression.py +26 -14
- classiq/interface/generator/expressions/expression_constants.py +9 -3
- classiq/interface/generator/expressions/non_symbolic_expr.py +119 -0
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +99 -0
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +34 -8
- classiq/interface/generator/expressions/qmod_qstruct_proxy.py +36 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +30 -2
- classiq/interface/generator/expressions/qmod_struct_instance.py +14 -2
- classiq/interface/generator/expressions/sympy_supported_expressions.py +19 -11
- classiq/interface/generator/finance.py +2 -2
- classiq/interface/generator/function_param_library.py +6 -6
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -10
- classiq/interface/generator/function_params.py +36 -64
- classiq/interface/generator/functions/__init__.py +0 -22
- classiq/interface/generator/functions/builtins/internal_operators.py +16 -0
- classiq/interface/generator/functions/classical_function_declaration.py +18 -9
- classiq/interface/generator/functions/classical_type.py +47 -166
- classiq/interface/generator/functions/concrete_types.py +55 -0
- classiq/interface/generator/functions/function_declaration.py +13 -14
- classiq/interface/generator/functions/port_declaration.py +1 -13
- classiq/interface/generator/functions/qmod_python_interface.py +2 -1
- classiq/interface/generator/functions/type_name.py +90 -0
- classiq/interface/generator/generated_circuit_data.py +153 -20
- classiq/interface/generator/grover_diffuser.py +32 -25
- classiq/interface/generator/grover_operator.py +34 -25
- classiq/interface/generator/hamiltonian_evolution/exponentiation.py +4 -6
- classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +9 -9
- classiq/interface/generator/hardware/hardware_data.py +72 -34
- classiq/interface/generator/hardware_efficient_ansatz.py +20 -16
- classiq/interface/generator/hartree_fock.py +13 -5
- classiq/interface/generator/identity.py +10 -6
- classiq/interface/generator/linear_pauli_rotations.py +32 -20
- classiq/interface/generator/mcmt_method.py +1 -1
- classiq/interface/generator/mcu.py +17 -15
- classiq/interface/generator/mcx.py +24 -17
- classiq/interface/generator/model/__init__.py +2 -5
- classiq/interface/generator/model/constraints.py +26 -8
- classiq/interface/generator/model/model.py +27 -190
- classiq/interface/generator/model/preferences/preferences.py +115 -41
- classiq/{quantum_register.py → interface/generator/model/quantum_register.py} +14 -17
- classiq/interface/generator/oracles/arithmetic_oracle.py +2 -4
- classiq/interface/generator/oracles/custom_oracle.py +15 -13
- classiq/interface/generator/oracles/oracle_abc.py +7 -7
- classiq/interface/generator/partitioned_register.py +7 -7
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +45 -29
- classiq/interface/generator/preferences/optimization.py +1 -2
- classiq/interface/generator/qpe.py +41 -30
- classiq/interface/generator/qsvm.py +9 -10
- classiq/interface/generator/quantum_function_call.py +88 -73
- classiq/interface/generator/quantum_program.py +41 -24
- classiq/interface/generator/range_types.py +11 -12
- classiq/interface/generator/register_role.py +18 -6
- classiq/interface/generator/slice_parsing_utils.py +5 -5
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +30 -39
- classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
- classiq/interface/generator/standard_gates/standard_gates.py +3 -3
- classiq/interface/generator/standard_gates/u_gate.py +7 -10
- classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
- classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
- classiq/interface/generator/state_preparation/distributions.py +16 -15
- classiq/interface/generator/state_preparation/metrics.py +4 -7
- classiq/interface/generator/state_preparation/state_preparation.py +25 -20
- classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +20 -6
- classiq/interface/generator/transpiler_basis_gates.py +7 -3
- classiq/interface/generator/types/builtin_enum_declarations.py +178 -0
- classiq/interface/generator/types/compilation_metadata.py +6 -0
- classiq/interface/generator/types/enum_declaration.py +54 -0
- classiq/interface/generator/types/qstruct_declaration.py +18 -0
- classiq/interface/generator/types/struct_declaration.py +7 -11
- classiq/interface/generator/ucc.py +5 -4
- classiq/interface/generator/unitary_gate.py +5 -5
- classiq/interface/generator/user_defined_function_params.py +4 -1
- classiq/interface/generator/validations/flow_graph.py +7 -7
- classiq/interface/generator/validations/validator_functions.py +4 -4
- classiq/interface/generator/visitor.py +23 -16
- classiq/interface/hardware.py +29 -8
- classiq/interface/helpers/classproperty.py +8 -0
- classiq/interface/helpers/custom_encoders.py +2 -2
- classiq/interface/helpers/custom_pydantic_types.py +40 -50
- classiq/interface/helpers/datastructures.py +26 -0
- classiq/interface/helpers/hashable_mixin.py +3 -2
- classiq/interface/helpers/hashable_pydantic_base_model.py +2 -1
- classiq/interface/helpers/pydantic_model_helpers.py +7 -5
- classiq/interface/helpers/validation_helpers.py +3 -20
- classiq/interface/helpers/versioned_model.py +1 -4
- classiq/interface/ide/ide_data.py +16 -20
- classiq/interface/ide/visual_model.py +130 -0
- classiq/interface/interface_version.py +1 -0
- classiq/interface/jobs.py +29 -69
- classiq/interface/model/allocate.py +16 -0
- classiq/interface/model/bind_operation.py +32 -9
- classiq/interface/model/classical_if.py +15 -0
- classiq/interface/model/classical_parameter_declaration.py +33 -3
- classiq/interface/model/control.py +45 -0
- classiq/interface/model/handle_binding.py +298 -20
- classiq/interface/model/inplace_binary_operation.py +29 -24
- classiq/interface/model/invert.py +12 -0
- classiq/interface/model/model.py +69 -61
- classiq/interface/model/native_function_definition.py +17 -20
- classiq/interface/model/parameter.py +13 -0
- classiq/interface/model/phase_operation.py +11 -0
- classiq/interface/model/port_declaration.py +27 -9
- classiq/interface/model/power.py +14 -0
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +30 -18
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +51 -14
- classiq/interface/model/quantum_expressions/quantum_expression.py +12 -35
- classiq/interface/model/quantum_function_call.py +141 -343
- classiq/interface/model/quantum_function_declaration.py +190 -157
- classiq/interface/model/quantum_lambda_function.py +33 -32
- classiq/interface/model/quantum_statement.py +71 -12
- classiq/interface/model/quantum_type.py +177 -40
- classiq/interface/model/quantum_variable_declaration.py +3 -25
- classiq/interface/model/repeat.py +15 -0
- classiq/interface/model/statement_block.py +40 -14
- classiq/interface/model/validation_handle.py +13 -6
- classiq/interface/model/variable_declaration_statement.py +3 -1
- classiq/interface/model/within_apply_operation.py +7 -5
- classiq/interface/server/global_versions.py +6 -7
- classiq/interface/server/routes.py +17 -21
- classiq/interface/source_reference.py +59 -0
- classiq/model_expansions/atomic_expression_functions_defs.py +253 -0
- classiq/model_expansions/capturing/__init__.py +0 -0
- classiq/model_expansions/capturing/captured_vars.py +435 -0
- classiq/model_expansions/capturing/mangling_utils.py +56 -0
- classiq/model_expansions/closure.py +171 -0
- classiq/model_expansions/debug_flag.py +3 -0
- classiq/model_expansions/evaluators/__init__.py +0 -0
- classiq/model_expansions/evaluators/arg_type_match.py +158 -0
- classiq/model_expansions/evaluators/argument_types.py +42 -0
- classiq/model_expansions/evaluators/classical_expression.py +36 -0
- classiq/model_expansions/evaluators/control.py +144 -0
- classiq/model_expansions/evaluators/parameter_types.py +226 -0
- classiq/model_expansions/evaluators/quantum_type_utils.py +239 -0
- classiq/model_expansions/evaluators/type_type_match.py +90 -0
- classiq/model_expansions/expression_evaluator.py +135 -0
- classiq/model_expansions/expression_renamer.py +76 -0
- classiq/model_expansions/function_builder.py +247 -0
- classiq/model_expansions/generative_functions.py +158 -0
- classiq/model_expansions/interpreters/__init__.py +0 -0
- classiq/model_expansions/interpreters/base_interpreter.py +263 -0
- classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
- classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
- classiq/model_expansions/model_tables.py +18 -0
- classiq/model_expansions/quantum_operations/__init__.py +9 -0
- classiq/model_expansions/quantum_operations/bind.py +60 -0
- classiq/model_expansions/quantum_operations/call_emitter.py +266 -0
- classiq/model_expansions/quantum_operations/classicalif.py +53 -0
- classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
- classiq/model_expansions/quantum_operations/emitter.py +181 -0
- classiq/model_expansions/quantum_operations/quantum_function_call.py +33 -0
- classiq/model_expansions/quantum_operations/repeat.py +56 -0
- classiq/model_expansions/quantum_operations/shallow_emitter.py +180 -0
- classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
- classiq/model_expansions/scope.py +240 -0
- classiq/model_expansions/scope_initialization.py +150 -0
- classiq/model_expansions/sympy_conversion/__init__.py +0 -0
- classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +179 -0
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +123 -0
- classiq/model_expansions/transformers/__init__.py +0 -0
- classiq/model_expansions/transformers/ast_renamer.py +26 -0
- classiq/model_expansions/transformers/var_splitter.py +299 -0
- classiq/model_expansions/utils/__init__.py +0 -0
- classiq/model_expansions/utils/counted_name_allocator.py +11 -0
- classiq/model_expansions/utils/handles_collector.py +33 -0
- classiq/model_expansions/visitors/__init__.py +0 -0
- classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
- classiq/model_expansions/visitors/variable_references.py +144 -0
- classiq/open_library/__init__.py +4 -0
- classiq/open_library/functions/__init__.py +130 -0
- classiq/open_library/functions/amplitude_estimation.py +30 -0
- classiq/open_library/functions/discrete_sine_cosine_transform.py +181 -0
- classiq/open_library/functions/grover.py +157 -0
- classiq/open_library/functions/hea.py +115 -0
- classiq/open_library/functions/linear_pauli_rotation.py +82 -0
- classiq/open_library/functions/modular_exponentiation.py +201 -0
- classiq/open_library/functions/qaoa_penalty.py +117 -0
- classiq/open_library/functions/qft_functions.py +54 -0
- classiq/open_library/functions/qpe.py +46 -0
- classiq/open_library/functions/qsvt.py +331 -0
- classiq/open_library/functions/state_preparation.py +301 -0
- classiq/open_library/functions/swap_test.py +27 -0
- classiq/open_library/functions/utility_functions.py +81 -0
- classiq/open_library/functions/variational.py +52 -0
- classiq/qmod/__init__.py +10 -10
- classiq/qmod/builtins/__init__.py +19 -2
- classiq/qmod/builtins/classical_execution_primitives.py +36 -14
- classiq/qmod/builtins/classical_functions.py +39 -43
- classiq/qmod/builtins/constants.py +10 -0
- classiq/qmod/builtins/enums.py +208 -0
- classiq/qmod/builtins/functions/__init__.py +137 -0
- classiq/qmod/builtins/functions/allocation.py +150 -0
- classiq/qmod/builtins/functions/arithmetic.py +55 -0
- classiq/qmod/builtins/functions/benchmarking.py +8 -0
- classiq/qmod/builtins/functions/chemistry.py +91 -0
- classiq/qmod/builtins/functions/exponentiation.py +105 -0
- classiq/qmod/builtins/functions/finance.py +34 -0
- classiq/qmod/builtins/functions/operators.py +16 -0
- classiq/qmod/builtins/functions/qsvm.py +24 -0
- classiq/qmod/builtins/functions/standard_gates.py +651 -0
- classiq/qmod/builtins/operations.py +373 -40
- classiq/qmod/builtins/structs.py +103 -80
- classiq/qmod/cfunc.py +2 -2
- classiq/qmod/classical_function.py +4 -8
- classiq/qmod/cparam.py +64 -0
- classiq/qmod/create_model_function.py +56 -0
- classiq/qmod/declaration_inferrer.py +143 -101
- classiq/qmod/expression_query.py +20 -4
- classiq/qmod/generative.py +42 -0
- classiq/qmod/model_state_container.py +18 -6
- classiq/qmod/native/__init__.py +7 -0
- classiq/qmod/native/expression_to_qmod.py +16 -11
- classiq/qmod/native/pretty_printer.py +187 -97
- classiq/qmod/pretty_print/__init__.py +7 -0
- classiq/qmod/pretty_print/expression_to_python.py +222 -0
- classiq/qmod/pretty_print/pretty_printer.py +572 -0
- classiq/qmod/python_classical_type.py +67 -0
- classiq/qmod/qfunc.py +60 -8
- classiq/qmod/qmod_constant.py +93 -26
- classiq/qmod/qmod_parameter.py +68 -59
- classiq/qmod/qmod_variable.py +468 -155
- classiq/qmod/quantum_callable.py +17 -7
- classiq/qmod/quantum_expandable.py +269 -96
- classiq/qmod/quantum_function.py +196 -41
- classiq/qmod/semantics/__init__.py +0 -0
- classiq/qmod/semantics/annotation/__init__.py +0 -0
- classiq/qmod/semantics/annotation/call_annotation.py +92 -0
- classiq/qmod/semantics/annotation/qstruct_annotator.py +23 -0
- classiq/qmod/semantics/error_manager.py +88 -0
- classiq/qmod/semantics/lambdas.py +25 -0
- classiq/qmod/semantics/static_semantics_visitor.py +384 -0
- classiq/qmod/semantics/validation/__init__.py +0 -0
- classiq/qmod/semantics/validation/constants_validation.py +16 -0
- classiq/qmod/semantics/validation/func_call_validation.py +99 -0
- classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
- classiq/qmod/semantics/validation/handle_validation.py +85 -0
- classiq/qmod/semantics/validation/main_validation.py +33 -0
- classiq/qmod/semantics/validation/types_validation.py +128 -0
- classiq/qmod/symbolic.py +147 -123
- classiq/qmod/symbolic_expr.py +27 -12
- classiq/qmod/symbolic_type.py +2 -5
- classiq/qmod/type_attribute_remover.py +32 -0
- classiq/qmod/utilities.py +98 -4
- classiq/qmod/write_qmod.py +17 -3
- classiq/synthesis.py +210 -22
- {classiq-0.38.0.dist-info → classiq-0.65.4.dist-info}/METADATA +16 -9
- classiq-0.65.4.dist-info/RECORD +521 -0
- classiq/_internals/_qfunc_ext.py +0 -6
- classiq/applications/benchmarking/__init__.py +0 -9
- classiq/applications/benchmarking/mirror_benchmarking.py +0 -70
- classiq/applications/numpy_utils.py +0 -37
- classiq/applications_model_constructors/__init__.py +0 -25
- classiq/applications_model_constructors/combinatorial_helpers/multiple_comp_basis_sp.py +0 -34
- classiq/applications_model_constructors/combinatorial_helpers/pauli_helpers/pauli_utils.py +0 -65
- classiq/applications_model_constructors/combinatorial_helpers/pyomo_utils.py +0 -243
- classiq/applications_model_constructors/libraries/ampltitude_estimation_library.py +0 -11
- classiq/applications_model_constructors/libraries/qmci_library.py +0 -107
- classiq/builtin_functions/__init__.py +0 -43
- classiq/builtin_functions/amplitude_loading.py +0 -3
- classiq/builtin_functions/binary_ops.py +0 -1
- classiq/builtin_functions/exponentiation.py +0 -5
- classiq/builtin_functions/qpe.py +0 -4
- classiq/builtin_functions/qsvm.py +0 -7
- classiq/builtin_functions/range_types.py +0 -5
- classiq/builtin_functions/standard_gates.py +0 -1
- classiq/builtin_functions/state_preparation.py +0 -6
- classiq/builtin_functions/suzuki_trotter.py +0 -3
- classiq/interface/executor/aws_execution_cost.py +0 -73
- classiq/interface/executor/error_mitigation.py +0 -6
- classiq/interface/generator/credit_risk_example/linear_gci.py +0 -122
- classiq/interface/generator/credit_risk_example/weighted_adder.py +0 -69
- classiq/interface/generator/expressions/enums/chemistry.py +0 -28
- classiq/interface/generator/expressions/enums/classical_enum.py +0 -5
- classiq/interface/generator/expressions/enums/ladder_operator.py +0 -16
- classiq/interface/generator/expressions/enums/optimizers.py +0 -9
- classiq/interface/generator/expressions/enums/pauli.py +0 -8
- classiq/interface/generator/expressions/enums/qsvm_feature_map_entanglement.py +0 -9
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +0 -641
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/exponentiation_functions.py +0 -89
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +0 -1229
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -95
- classiq/interface/generator/functions/foreign_function_definition.py +0 -114
- classiq/interface/generator/functions/function_implementation.py +0 -107
- classiq/interface/generator/functions/native_function_definition.py +0 -155
- classiq/interface/generator/functions/quantum_function_declaration.py +0 -69
- classiq/interface/generator/functions/register.py +0 -44
- classiq/interface/generator/functions/register_mapping_data.py +0 -106
- classiq/interface/generator/inequality_mixer.py +0 -51
- classiq/interface/generator/model/classical_main_validator.py +0 -106
- classiq/interface/generator/range_mixer.py +0 -56
- classiq/interface/generator/state_propagator.py +0 -74
- classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
- classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -22
- classiq/interface/ide/show.py +0 -34
- classiq/interface/model/call_synthesis_data.py +0 -68
- classiq/interface/model/common_model_types.py +0 -23
- classiq/interface/model/quantum_expressions/control_state.py +0 -38
- classiq/interface/model/quantum_if_operation.py +0 -94
- classiq/interface/model/resolvers/function_call_resolver.py +0 -43
- classiq/interface/model/validations/handle_validation_base.py +0 -55
- classiq/interface/model/validations/handles_validator.py +0 -156
- classiq/interface/model/validations/port_to_wire_name_generator.py +0 -12
- classiq/model/__init__.py +0 -14
- classiq/model/composite_function_generator.py +0 -33
- classiq/model/function_handler.py +0 -462
- classiq/model/logic_flow.py +0 -149
- classiq/model/logic_flow_change_handler.py +0 -71
- classiq/model/model.py +0 -229
- classiq/qmod/builtins/functions.py +0 -913
- classiq/qmod/qmod_struct.py +0 -37
- classiq/quantum_functions/__init__.py +0 -17
- classiq/quantum_functions/annotation_parser.py +0 -205
- classiq/quantum_functions/decorators.py +0 -22
- classiq/quantum_functions/function_library.py +0 -181
- classiq/quantum_functions/function_parser.py +0 -74
- classiq/quantum_functions/quantum_function.py +0 -236
- classiq-0.38.0.dist-info/RECORD +0 -454
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/arithmetic/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/__init__.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +0 -0
- /classiq/{applications_model_constructors → applications}/combinatorial_helpers/py.typed +0 -0
- /classiq/{applications_model_constructors/combinatorial_helpers/transformations → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
- /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
- /classiq/{interface/generator/credit_risk_example → applications/hamiltonian}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations → applications/libraries}/__init__.py +0 -0
- /classiq/interface/{model/resolvers → debug_info}/__init__.py +0 -0
- /classiq/{_internals → interface}/enum_utils.py +0 -0
- /classiq/interface/{model/validations → generator/functions/builtins}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → model_expansions/__init__.py} +0 -0
- {classiq-0.38.0.dist-info → classiq-0.65.4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,253 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
from enum import Enum
|
3
|
+
from typing import Any, Callable, Union
|
4
|
+
|
5
|
+
from sympy import Eq, Expr, Number, Piecewise, Symbol
|
6
|
+
|
7
|
+
from classiq.interface.exceptions import (
|
8
|
+
ClassiqExpansionError,
|
9
|
+
ClassiqInternalExpansionError,
|
10
|
+
)
|
11
|
+
from classiq.interface.generator.expressions.expression_types import (
|
12
|
+
ExpressionValue,
|
13
|
+
QmodStructInstance,
|
14
|
+
)
|
15
|
+
from classiq.interface.generator.expressions.qmod_qscalar_proxy import QmodQNumProxy
|
16
|
+
from classiq.interface.generator.expressions.qmod_qstruct_proxy import QmodQStructProxy
|
17
|
+
from classiq.interface.generator.expressions.qmod_sized_proxy import QmodSizedProxy
|
18
|
+
from classiq.interface.generator.expressions.type_proxy import TypeProxy
|
19
|
+
from classiq.interface.generator.functions.classical_function_declaration import (
|
20
|
+
ClassicalFunctionDeclaration,
|
21
|
+
)
|
22
|
+
from classiq.interface.generator.functions.classical_type import (
|
23
|
+
Bool,
|
24
|
+
ClassicalList,
|
25
|
+
ClassicalType,
|
26
|
+
OpaqueHandle,
|
27
|
+
QmodPyObject,
|
28
|
+
Real,
|
29
|
+
StructMetaType,
|
30
|
+
)
|
31
|
+
from classiq.interface.generator.functions.type_name import TypeName
|
32
|
+
|
33
|
+
from classiq.model_expansions.model_tables import (
|
34
|
+
HandleIdentifier,
|
35
|
+
HandleTable,
|
36
|
+
)
|
37
|
+
from classiq.model_expansions.sympy_conversion.arithmetics import (
|
38
|
+
BitwiseAnd,
|
39
|
+
BitwiseNot,
|
40
|
+
BitwiseOr,
|
41
|
+
BitwiseXor,
|
42
|
+
LogicalXor,
|
43
|
+
)
|
44
|
+
from classiq.model_expansions.sympy_conversion.expression_to_sympy import (
|
45
|
+
MISSING_SLICE_VALUE_PLACEHOLDER,
|
46
|
+
)
|
47
|
+
from classiq.model_expansions.sympy_conversion.sympy_to_python import (
|
48
|
+
sympy_to_python,
|
49
|
+
)
|
50
|
+
from classiq.qmod.model_state_container import QMODULE
|
51
|
+
|
52
|
+
|
53
|
+
def qmod_val_to_python(val: ExpressionValue, qmod_type: ClassicalType) -> Any:
|
54
|
+
if isinstance(qmod_type, TypeName):
|
55
|
+
if (
|
56
|
+
isinstance(val, QmodStructInstance)
|
57
|
+
and val.struct_declaration == QMODULE.type_decls[qmod_type.name]
|
58
|
+
):
|
59
|
+
return {
|
60
|
+
field_name: qmod_val_to_python(val.fields[field_name], field_type)
|
61
|
+
for field_name, field_type in val.struct_declaration.variables.items()
|
62
|
+
}
|
63
|
+
|
64
|
+
if isinstance(val, (Enum, int)):
|
65
|
+
return val
|
66
|
+
|
67
|
+
elif isinstance(qmod_type, ClassicalList):
|
68
|
+
if isinstance(val, list):
|
69
|
+
return [qmod_val_to_python(elem, qmod_type.element_type) for elem in val]
|
70
|
+
|
71
|
+
elif isinstance(qmod_type, OpaqueHandle):
|
72
|
+
if isinstance(val, HandleIdentifier):
|
73
|
+
return HandleTable.get_handle_object(val)
|
74
|
+
|
75
|
+
elif isinstance(val, Expr):
|
76
|
+
return sympy_to_python(val)
|
77
|
+
|
78
|
+
elif isinstance(qmod_type, Real):
|
79
|
+
if isinstance(val, (float, int)):
|
80
|
+
return val
|
81
|
+
|
82
|
+
elif isinstance(qmod_type, Bool):
|
83
|
+
if isinstance(val, bool):
|
84
|
+
return val
|
85
|
+
|
86
|
+
elif isinstance(qmod_type, StructMetaType):
|
87
|
+
if isinstance(val, TypeProxy):
|
88
|
+
return val.struct_declaration
|
89
|
+
|
90
|
+
elif isinstance(val, int): # other scalars are represented as int
|
91
|
+
return val
|
92
|
+
|
93
|
+
raise ClassiqInternalExpansionError(
|
94
|
+
f"Bad value {val!r} of type {type(val)!r} for {qmod_type!r}"
|
95
|
+
)
|
96
|
+
|
97
|
+
|
98
|
+
def python_val_to_qmod(val: Any, qmod_type: ClassicalType) -> ExpressionValue:
|
99
|
+
if isinstance(qmod_type, TypeName):
|
100
|
+
if qmod_type.name in QMODULE.enum_decls:
|
101
|
+
return val
|
102
|
+
|
103
|
+
struct_decl = QMODULE.type_decls[qmod_type.name]
|
104
|
+
if not isinstance(val, Mapping):
|
105
|
+
raise ClassiqInternalExpansionError(
|
106
|
+
f"Bad value for struct {struct_decl.name}"
|
107
|
+
)
|
108
|
+
qmod_dict = {
|
109
|
+
field_name: python_val_to_qmod(val[field_name], field_type)
|
110
|
+
for field_name, field_type in struct_decl.variables.items()
|
111
|
+
}
|
112
|
+
return QmodStructInstance(struct_decl, qmod_dict)
|
113
|
+
|
114
|
+
if isinstance(qmod_type, ClassicalList):
|
115
|
+
if not isinstance(val, list):
|
116
|
+
raise ClassiqInternalExpansionError("Bad value for list")
|
117
|
+
return [python_val_to_qmod(elem, qmod_type.element_type) for elem in val]
|
118
|
+
|
119
|
+
if isinstance(qmod_type, OpaqueHandle):
|
120
|
+
if not isinstance(val, QmodPyObject):
|
121
|
+
raise ClassiqInternalExpansionError("Bad value opaque handle")
|
122
|
+
return HandleTable.set_handle_object(val)
|
123
|
+
|
124
|
+
return val
|
125
|
+
|
126
|
+
|
127
|
+
def python_call_wrapper(func: Callable, *args: ExpressionValue) -> Any:
|
128
|
+
func_decl = ClassicalFunctionDeclaration.FOREIGN_FUNCTION_DECLARATIONS[
|
129
|
+
func.__name__
|
130
|
+
]
|
131
|
+
python_args = [
|
132
|
+
qmod_val_to_python(args[idx], param_type.classical_type)
|
133
|
+
for idx, param_type in enumerate(func_decl.param_decls)
|
134
|
+
]
|
135
|
+
assert func_decl.return_type is not None
|
136
|
+
return python_val_to_qmod(func(*python_args), func_decl.return_type)
|
137
|
+
|
138
|
+
|
139
|
+
def struct_literal(struct_type_symbol: Symbol, **kwargs: Any) -> QmodStructInstance:
|
140
|
+
return QmodStructInstance(
|
141
|
+
QMODULE.type_decls[struct_type_symbol.name],
|
142
|
+
{field: sympy_to_python(field_value) for field, field_value in kwargs.items()},
|
143
|
+
)
|
144
|
+
|
145
|
+
|
146
|
+
def get_field(
|
147
|
+
proxy: Union[QmodSizedProxy, QmodStructInstance, QmodQStructProxy, list],
|
148
|
+
field: str,
|
149
|
+
) -> ExpressionValue:
|
150
|
+
if isinstance(proxy, type) and issubclass(proxy, Enum):
|
151
|
+
return getattr(proxy, field)
|
152
|
+
if isinstance(proxy, Symbol) and not isinstance(proxy, QmodSizedProxy):
|
153
|
+
raise ClassiqExpansionError(
|
154
|
+
f"Cannot evaluate '{proxy}.{field}': Variable {str(proxy)!r} is not "
|
155
|
+
f"initialized"
|
156
|
+
)
|
157
|
+
if isinstance(proxy, list):
|
158
|
+
if field != "len":
|
159
|
+
raise ClassiqExpansionError(
|
160
|
+
f"List {str(proxy)!r} has no attribute {field!r}. "
|
161
|
+
f"Available attributes: len"
|
162
|
+
)
|
163
|
+
return len(proxy)
|
164
|
+
if field not in proxy.fields:
|
165
|
+
if isinstance(proxy, (QmodStructInstance, QmodQStructProxy)):
|
166
|
+
property_name = "field"
|
167
|
+
else:
|
168
|
+
property_name = "attribute"
|
169
|
+
suffix = (
|
170
|
+
f". Available {property_name}s: {', '.join(proxy.fields.keys())}"
|
171
|
+
if len(proxy.fields) > 0
|
172
|
+
else ""
|
173
|
+
)
|
174
|
+
proxy_str = proxy.__name__ if isinstance(proxy, type) else f"{str(proxy)!r}"
|
175
|
+
raise ClassiqExpansionError(
|
176
|
+
f"{proxy.type_name} {proxy_str} has no {property_name} {field!r}{suffix}"
|
177
|
+
)
|
178
|
+
return proxy.fields[field]
|
179
|
+
|
180
|
+
|
181
|
+
def get_type(struct_type: Symbol) -> TypeProxy:
|
182
|
+
return TypeProxy(QMODULE.type_decls[struct_type.name])
|
183
|
+
|
184
|
+
|
185
|
+
def _unwrap_sympy_numeric(n: Any) -> Any:
|
186
|
+
if not isinstance(n, Number) or not n.is_constant():
|
187
|
+
return n
|
188
|
+
if n.is_Integer:
|
189
|
+
return int(n)
|
190
|
+
return float(n)
|
191
|
+
|
192
|
+
|
193
|
+
def do_div(lhs: Any, rhs: Any) -> Any:
|
194
|
+
lhs = _unwrap_sympy_numeric(lhs)
|
195
|
+
rhs = _unwrap_sympy_numeric(rhs)
|
196
|
+
return lhs / rhs
|
197
|
+
|
198
|
+
|
199
|
+
def do_subscript(value: Any, index: Any) -> Any:
|
200
|
+
if not isinstance(value, list) or not isinstance(index, QmodQNumProxy):
|
201
|
+
if isinstance(index, (QmodSizedProxy, QmodStructInstance)):
|
202
|
+
raise ClassiqExpansionError(
|
203
|
+
f"Subscript {value}[{index}] is not supported. Supported subscripts "
|
204
|
+
f"include:\n"
|
205
|
+
f"\t1. `qbv[idx]`, where `qbv` is a quantum array and `idx` is a "
|
206
|
+
f"classical integer.\n"
|
207
|
+
f"\t2. `l[n]`, where `l` is a list of classical real numbers and `n` "
|
208
|
+
f"is a classical or quantum integer."
|
209
|
+
)
|
210
|
+
return value[index]
|
211
|
+
if index.is_signed or index.fraction_digits > 0:
|
212
|
+
raise ClassiqExpansionError(
|
213
|
+
"Quantum numeric subscript must be an unsigned integer (is_signed=False, "
|
214
|
+
"fraction_digits=0)"
|
215
|
+
)
|
216
|
+
if len(value) != 2**index.size:
|
217
|
+
raise ClassiqExpansionError(
|
218
|
+
f"Quantum numeric subscript size mismatch: The quantum numeric has "
|
219
|
+
f"{index.size} qubits but the list size is {len(value)} != 2**{index.size}"
|
220
|
+
)
|
221
|
+
return Piecewise(
|
222
|
+
*[(item, Eq(index, idx)) for idx, item in enumerate(value[:-1])],
|
223
|
+
(value[-1], True),
|
224
|
+
)
|
225
|
+
|
226
|
+
|
227
|
+
def do_slice(value: Any, lower: Any, upper: Any) -> Any:
|
228
|
+
if isinstance(lower, Symbol) and str(lower) == MISSING_SLICE_VALUE_PLACEHOLDER:
|
229
|
+
lower = None
|
230
|
+
if isinstance(upper, Symbol) and str(upper) == MISSING_SLICE_VALUE_PLACEHOLDER:
|
231
|
+
upper = None
|
232
|
+
return do_subscript(value, slice(lower, upper))
|
233
|
+
|
234
|
+
|
235
|
+
CORE_LIB_FUNCTIONS_LIST: list[Callable] = [
|
236
|
+
print,
|
237
|
+
sum,
|
238
|
+
struct_literal,
|
239
|
+
get_field,
|
240
|
+
get_type,
|
241
|
+
do_div,
|
242
|
+
do_slice,
|
243
|
+
do_subscript,
|
244
|
+
BitwiseAnd,
|
245
|
+
BitwiseXor,
|
246
|
+
BitwiseNot,
|
247
|
+
BitwiseOr,
|
248
|
+
LogicalXor,
|
249
|
+
]
|
250
|
+
|
251
|
+
ATOMIC_EXPRESSION_FUNCTIONS = {
|
252
|
+
**{core_func.__name__: core_func for core_func in CORE_LIB_FUNCTIONS_LIST},
|
253
|
+
}
|
File without changes
|
@@ -0,0 +1,435 @@
|
|
1
|
+
import dataclasses
|
2
|
+
from collections.abc import Sequence
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
5
|
+
|
6
|
+
from classiq.interface.enum_utils import StrEnum
|
7
|
+
from classiq.interface.exceptions import (
|
8
|
+
ClassiqExpansionError,
|
9
|
+
ClassiqInternalExpansionError,
|
10
|
+
)
|
11
|
+
from classiq.interface.generator.expressions.expression import Expression
|
12
|
+
from classiq.interface.generator.functions.port_declaration import (
|
13
|
+
PortDeclarationDirection,
|
14
|
+
)
|
15
|
+
from classiq.interface.model.handle_binding import (
|
16
|
+
HandleBinding,
|
17
|
+
NestedHandleBinding,
|
18
|
+
SlicedHandleBinding,
|
19
|
+
)
|
20
|
+
from classiq.interface.model.port_declaration import PortDeclaration
|
21
|
+
from classiq.interface.model.quantum_function_call import ArgValue
|
22
|
+
from classiq.interface.model.quantum_type import QuantumBitvector, QuantumType
|
23
|
+
from classiq.interface.model.variable_declaration_statement import (
|
24
|
+
VariableDeclarationStatement,
|
25
|
+
)
|
26
|
+
|
27
|
+
from classiq.model_expansions.capturing.mangling_utils import (
|
28
|
+
demangle_handle,
|
29
|
+
mangle_captured_var_name,
|
30
|
+
)
|
31
|
+
from classiq.model_expansions.transformers.var_splitter import SymbolPart, SymbolParts
|
32
|
+
|
33
|
+
if TYPE_CHECKING:
|
34
|
+
from classiq.model_expansions.closure import FunctionClosure
|
35
|
+
|
36
|
+
|
37
|
+
ALREADY_ALLOCATED_MESSAGE = "Cannot allocate variable '{}', it is already initialized"
|
38
|
+
ALREADY_FREED_MESSAGE = "Cannot free variable '{}', it is already uninitialized"
|
39
|
+
|
40
|
+
|
41
|
+
class PortDirection(StrEnum):
|
42
|
+
Input = "input"
|
43
|
+
Inout = "inout"
|
44
|
+
Output = "output"
|
45
|
+
Outin = "outin"
|
46
|
+
|
47
|
+
def negate(self) -> "PortDirection":
|
48
|
+
if self == PortDirection.Input:
|
49
|
+
return PortDirection.Output
|
50
|
+
if self == PortDirection.Output:
|
51
|
+
return PortDirection.Input
|
52
|
+
return self
|
53
|
+
|
54
|
+
@staticmethod
|
55
|
+
def load(direction: PortDeclarationDirection) -> "PortDirection":
|
56
|
+
if direction == PortDeclarationDirection.Input:
|
57
|
+
return PortDirection.Input
|
58
|
+
if direction == PortDeclarationDirection.Output:
|
59
|
+
return PortDirection.Output
|
60
|
+
if direction == PortDeclarationDirection.Inout:
|
61
|
+
return PortDirection.Inout
|
62
|
+
raise ClassiqInternalExpansionError
|
63
|
+
|
64
|
+
def dump(self) -> PortDeclarationDirection:
|
65
|
+
if self == PortDirection.Input:
|
66
|
+
return PortDeclarationDirection.Input
|
67
|
+
if self == PortDirection.Output:
|
68
|
+
return PortDeclarationDirection.Output
|
69
|
+
if self == PortDirection.Inout:
|
70
|
+
return PortDeclarationDirection.Inout
|
71
|
+
raise ClassiqInternalExpansionError
|
72
|
+
|
73
|
+
|
74
|
+
@dataclass(frozen=True)
|
75
|
+
class _CapturedHandle:
|
76
|
+
handle: HandleBinding
|
77
|
+
quantum_type: QuantumType
|
78
|
+
defining_function: "FunctionClosure"
|
79
|
+
direction: PortDirection
|
80
|
+
is_propagated: bool
|
81
|
+
|
82
|
+
@property
|
83
|
+
def mangled_name(self) -> str:
|
84
|
+
return mangle_captured_var_name(
|
85
|
+
self.handle.identifier,
|
86
|
+
self.defining_function.name,
|
87
|
+
self.defining_function.depth,
|
88
|
+
)
|
89
|
+
|
90
|
+
@property
|
91
|
+
def port(self) -> PortDeclaration:
|
92
|
+
return PortDeclaration(
|
93
|
+
name=self.mangled_name,
|
94
|
+
quantum_type=self.quantum_type,
|
95
|
+
direction=self.direction.dump(),
|
96
|
+
)
|
97
|
+
|
98
|
+
def is_same_var(self, other: "_CapturedHandle") -> bool:
|
99
|
+
return self.handle.name == other.handle.name and _same_closure(
|
100
|
+
self.defining_function, other.defining_function
|
101
|
+
)
|
102
|
+
|
103
|
+
def change_direction(self, new_direction: PortDirection) -> "_CapturedHandle":
|
104
|
+
return dataclasses.replace(self, direction=new_direction)
|
105
|
+
|
106
|
+
def set_propagated(self) -> "_CapturedHandle":
|
107
|
+
return dataclasses.replace(self, is_propagated=True)
|
108
|
+
|
109
|
+
def update_propagation(
|
110
|
+
self, other_captured_handle: "_CapturedHandle"
|
111
|
+
) -> "_CapturedHandle":
|
112
|
+
if self.is_propagated and not other_captured_handle.is_propagated:
|
113
|
+
return dataclasses.replace(self, is_propagated=False)
|
114
|
+
return self
|
115
|
+
|
116
|
+
def set_symbol(
|
117
|
+
self, handle: HandleBinding, quantum_type: QuantumType
|
118
|
+
) -> "_CapturedHandle":
|
119
|
+
return dataclasses.replace(self, handle=handle, quantum_type=quantum_type)
|
120
|
+
|
121
|
+
|
122
|
+
@dataclass
|
123
|
+
class CapturedVars:
|
124
|
+
_captured_handles: list[_CapturedHandle] = field(default_factory=list)
|
125
|
+
|
126
|
+
def capture_handle(
|
127
|
+
self,
|
128
|
+
handle: HandleBinding,
|
129
|
+
quantum_type: QuantumType,
|
130
|
+
defining_function: "FunctionClosure",
|
131
|
+
direction: PortDeclarationDirection,
|
132
|
+
) -> None:
|
133
|
+
self._capture_handle(
|
134
|
+
_CapturedHandle(
|
135
|
+
handle=handle,
|
136
|
+
quantum_type=quantum_type,
|
137
|
+
defining_function=defining_function,
|
138
|
+
direction=PortDirection.load(direction),
|
139
|
+
is_propagated=False,
|
140
|
+
)
|
141
|
+
)
|
142
|
+
|
143
|
+
def _capture_handle(self, captured_handle: _CapturedHandle) -> None:
|
144
|
+
if (
|
145
|
+
isinstance(captured_handle.handle, NestedHandleBinding)
|
146
|
+
and captured_handle.direction != PortDirection.Inout
|
147
|
+
):
|
148
|
+
verb = (
|
149
|
+
"free"
|
150
|
+
if captured_handle.direction == PortDirection.Input
|
151
|
+
else "allocate"
|
152
|
+
)
|
153
|
+
raise ClassiqExpansionError(
|
154
|
+
f"Cannot partially {verb} variable {captured_handle.handle.name}"
|
155
|
+
)
|
156
|
+
|
157
|
+
new_captured_handles = []
|
158
|
+
for existing_captured_handle in self._captured_handles:
|
159
|
+
if not existing_captured_handle.is_same_var(captured_handle):
|
160
|
+
new_captured_handles.append(existing_captured_handle)
|
161
|
+
continue
|
162
|
+
captured_handle = captured_handle.update_propagation(
|
163
|
+
existing_captured_handle
|
164
|
+
)
|
165
|
+
if existing_captured_handle.handle == captured_handle.handle:
|
166
|
+
captured_handle = self._conjugate_direction(
|
167
|
+
existing_captured_handle, captured_handle
|
168
|
+
)
|
169
|
+
elif captured_handle.handle.overlaps(existing_captured_handle.handle):
|
170
|
+
captured_handle = self._intersect_handles(
|
171
|
+
existing_captured_handle, captured_handle
|
172
|
+
)
|
173
|
+
else:
|
174
|
+
new_captured_handles.append(existing_captured_handle)
|
175
|
+
new_captured_handles.append(captured_handle)
|
176
|
+
self._captured_handles = new_captured_handles
|
177
|
+
|
178
|
+
def _conjugate_direction(
|
179
|
+
self,
|
180
|
+
existing_captured_handle: _CapturedHandle,
|
181
|
+
captured_handle: _CapturedHandle,
|
182
|
+
) -> _CapturedHandle:
|
183
|
+
if existing_captured_handle.direction == PortDirection.Input:
|
184
|
+
if captured_handle.direction == PortDirection.Output:
|
185
|
+
return captured_handle.change_direction(PortDirection.Inout)
|
186
|
+
if captured_handle.direction == PortDirection.Outin:
|
187
|
+
return captured_handle.change_direction(PortDirection.Input)
|
188
|
+
raise ClassiqExpansionError(
|
189
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
190
|
+
)
|
191
|
+
if existing_captured_handle.direction == PortDirection.Output:
|
192
|
+
if captured_handle.direction == PortDirection.Input:
|
193
|
+
return captured_handle.change_direction(PortDirection.Outin)
|
194
|
+
if captured_handle.direction in (
|
195
|
+
PortDirection.Output,
|
196
|
+
PortDirection.Outin,
|
197
|
+
):
|
198
|
+
raise ClassiqExpansionError(
|
199
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
200
|
+
)
|
201
|
+
return captured_handle.change_direction(PortDirection.Output)
|
202
|
+
if existing_captured_handle.direction == PortDirection.Inout:
|
203
|
+
if captured_handle.direction in (
|
204
|
+
PortDirection.Output,
|
205
|
+
PortDirection.Outin,
|
206
|
+
):
|
207
|
+
raise ClassiqExpansionError(
|
208
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
209
|
+
)
|
210
|
+
elif captured_handle.direction in (
|
211
|
+
PortDirection.Input,
|
212
|
+
PortDirection.Inout,
|
213
|
+
):
|
214
|
+
raise ClassiqExpansionError(
|
215
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
216
|
+
)
|
217
|
+
return captured_handle
|
218
|
+
|
219
|
+
def _intersect_handles(
|
220
|
+
self,
|
221
|
+
existing_captured_handle: _CapturedHandle,
|
222
|
+
captured_handle: _CapturedHandle,
|
223
|
+
) -> _CapturedHandle:
|
224
|
+
if captured_handle.handle in existing_captured_handle.handle:
|
225
|
+
if existing_captured_handle.direction in (
|
226
|
+
PortDirection.Input,
|
227
|
+
PortDirection.Outin,
|
228
|
+
):
|
229
|
+
raise ClassiqExpansionError(
|
230
|
+
ALREADY_FREED_MESSAGE.format(captured_handle.handle)
|
231
|
+
)
|
232
|
+
return existing_captured_handle
|
233
|
+
|
234
|
+
if existing_captured_handle.handle in captured_handle.handle:
|
235
|
+
if captured_handle.direction in (
|
236
|
+
PortDirection.Output,
|
237
|
+
PortDirection.Outin,
|
238
|
+
):
|
239
|
+
raise ClassiqExpansionError(
|
240
|
+
ALREADY_ALLOCATED_MESSAGE.format(captured_handle.handle)
|
241
|
+
)
|
242
|
+
return captured_handle
|
243
|
+
|
244
|
+
sliced_handle, quantum_type, other_handle = self._get_sliced_handle(
|
245
|
+
existing_captured_handle, captured_handle
|
246
|
+
)
|
247
|
+
if not isinstance(other_handle, SlicedHandleBinding):
|
248
|
+
return captured_handle.set_symbol(sliced_handle, quantum_type)
|
249
|
+
|
250
|
+
merged_handle, merged_quantum_type = self._merge_sliced_handles(
|
251
|
+
sliced_handle, other_handle, quantum_type
|
252
|
+
)
|
253
|
+
return captured_handle.set_symbol(merged_handle, merged_quantum_type)
|
254
|
+
|
255
|
+
@staticmethod
|
256
|
+
def _get_sliced_handle(
|
257
|
+
existing_captured_handle: _CapturedHandle,
|
258
|
+
captured_handle: _CapturedHandle,
|
259
|
+
) -> tuple[SlicedHandleBinding, QuantumBitvector, HandleBinding]:
|
260
|
+
handle_1 = existing_captured_handle.handle
|
261
|
+
quantum_type_1 = existing_captured_handle.quantum_type
|
262
|
+
handle_2 = captured_handle.handle
|
263
|
+
quantum_type_2 = captured_handle.quantum_type
|
264
|
+
if isinstance(handle_1, SlicedHandleBinding):
|
265
|
+
sliced_handle = handle_1
|
266
|
+
other_handle = handle_2
|
267
|
+
quantum_type = quantum_type_1
|
268
|
+
elif isinstance(handle_2, SlicedHandleBinding):
|
269
|
+
sliced_handle = handle_2
|
270
|
+
other_handle = handle_1
|
271
|
+
quantum_type = quantum_type_2
|
272
|
+
else:
|
273
|
+
raise ClassiqInternalExpansionError(
|
274
|
+
f"Unexpected overlapping handles {handle_1} and {handle_2}"
|
275
|
+
)
|
276
|
+
if not isinstance(quantum_type, QuantumBitvector):
|
277
|
+
raise ClassiqInternalExpansionError
|
278
|
+
return sliced_handle, quantum_type, other_handle
|
279
|
+
|
280
|
+
@staticmethod
|
281
|
+
def _merge_sliced_handles(
|
282
|
+
handle_1: SlicedHandleBinding,
|
283
|
+
handle_2: SlicedHandleBinding,
|
284
|
+
quantum_type: QuantumBitvector,
|
285
|
+
) -> tuple[HandleBinding, QuantumBitvector]:
|
286
|
+
if (
|
287
|
+
not handle_1.start.is_evaluated()
|
288
|
+
or not handle_1.end.is_evaluated()
|
289
|
+
or not handle_2.start.is_evaluated()
|
290
|
+
or not handle_2.end.is_evaluated()
|
291
|
+
):
|
292
|
+
raise ClassiqInternalExpansionError
|
293
|
+
|
294
|
+
new_start = min(handle_1.start.to_int_value(), handle_2.start.to_int_value())
|
295
|
+
new_end = max(handle_1.end.to_int_value(), handle_2.end.to_int_value())
|
296
|
+
merged_handle = SlicedHandleBinding(
|
297
|
+
base_handle=handle_1.base_handle,
|
298
|
+
start=Expression(expr=str(new_start)),
|
299
|
+
end=Expression(expr=str(new_end)),
|
300
|
+
)
|
301
|
+
merged_quantum_type = QuantumBitvector(
|
302
|
+
element_type=quantum_type.element_type,
|
303
|
+
length=Expression(expr=str(new_end - new_start)),
|
304
|
+
)
|
305
|
+
return merged_handle, merged_quantum_type
|
306
|
+
|
307
|
+
def update(self, other_captured_vars: "CapturedVars") -> None:
|
308
|
+
for captured_handle in other_captured_vars._captured_handles:
|
309
|
+
self._capture_handle(captured_handle)
|
310
|
+
|
311
|
+
def negate(self) -> "CapturedVars":
|
312
|
+
return CapturedVars(
|
313
|
+
_captured_handles=[
|
314
|
+
captured_handle.change_direction(captured_handle.direction.negate())
|
315
|
+
for captured_handle in self._captured_handles
|
316
|
+
]
|
317
|
+
)
|
318
|
+
|
319
|
+
def filter_vars(
|
320
|
+
self,
|
321
|
+
current_function: "FunctionClosure",
|
322
|
+
current_declarations: Optional[list[VariableDeclarationStatement]] = None,
|
323
|
+
) -> "CapturedVars":
|
324
|
+
current_declared_vars = (
|
325
|
+
None
|
326
|
+
if current_declarations is None
|
327
|
+
else {decl.name for decl in current_declarations}
|
328
|
+
)
|
329
|
+
return CapturedVars(
|
330
|
+
_captured_handles=[
|
331
|
+
captured_handle
|
332
|
+
for captured_handle in self._captured_handles
|
333
|
+
if not _same_closure(
|
334
|
+
captured_handle.defining_function, current_function
|
335
|
+
)
|
336
|
+
or (
|
337
|
+
current_declared_vars is not None
|
338
|
+
and captured_handle.handle.name not in current_declared_vars
|
339
|
+
)
|
340
|
+
]
|
341
|
+
)
|
342
|
+
|
343
|
+
def set_propagated(self) -> "CapturedVars":
|
344
|
+
return CapturedVars(
|
345
|
+
_captured_handles=[
|
346
|
+
captured_handle.set_propagated()
|
347
|
+
for captured_handle in self._captured_handles
|
348
|
+
]
|
349
|
+
)
|
350
|
+
|
351
|
+
def get_captured_ports(self) -> list[PortDeclaration]:
|
352
|
+
return [captured_handle.port for captured_handle in self._captured_handles]
|
353
|
+
|
354
|
+
def get_captured_args(
|
355
|
+
self, current_function: "FunctionClosure"
|
356
|
+
) -> list[HandleBinding]:
|
357
|
+
return [
|
358
|
+
(
|
359
|
+
captured_handle.handle
|
360
|
+
if _same_closure(current_function, captured_handle.defining_function)
|
361
|
+
else HandleBinding(name=captured_handle.mangled_name)
|
362
|
+
)
|
363
|
+
for captured_handle in self._captured_handles
|
364
|
+
]
|
365
|
+
|
366
|
+
def get_captured_mapping(self) -> SymbolParts:
|
367
|
+
return {
|
368
|
+
captured_handle.handle: [
|
369
|
+
SymbolPart(
|
370
|
+
source_handle=captured_handle.handle,
|
371
|
+
target_var_name=captured_handle.mangled_name,
|
372
|
+
target_var_type=captured_handle.quantum_type,
|
373
|
+
)
|
374
|
+
]
|
375
|
+
for captured_handle in self._captured_handles
|
376
|
+
if not captured_handle.is_propagated
|
377
|
+
}
|
378
|
+
|
379
|
+
def clone(self) -> "CapturedVars":
|
380
|
+
return CapturedVars(_captured_handles=list(self._captured_handles))
|
381
|
+
|
382
|
+
|
383
|
+
def _same_closure(closure_1: "FunctionClosure", closure_2: "FunctionClosure") -> bool:
|
384
|
+
return closure_1.depth == closure_2.depth
|
385
|
+
|
386
|
+
|
387
|
+
def validate_args_are_not_propagated(
|
388
|
+
args: Sequence[ArgValue], captured_vars: Sequence[HandleBinding]
|
389
|
+
) -> None:
|
390
|
+
if not captured_vars:
|
391
|
+
return
|
392
|
+
captured_handles = {demangle_handle(handle) for handle in captured_vars}
|
393
|
+
arg_handles = {
|
394
|
+
demangle_handle(arg) for arg in args if isinstance(arg, HandleBinding)
|
395
|
+
}
|
396
|
+
if any(
|
397
|
+
arg_handle.overlaps(captured_handle)
|
398
|
+
for arg_handle in arg_handles
|
399
|
+
for captured_handle in captured_handles
|
400
|
+
):
|
401
|
+
captured_handles_str = {str(handle) for handle in captured_handles}
|
402
|
+
arg_handles_str = {str(handle) for handle in arg_handles}
|
403
|
+
vars_msg = f"Explicitly passed variables: {arg_handles_str}, captured variables: {captured_handles_str}"
|
404
|
+
raise ClassiqExpansionError(
|
405
|
+
f"Cannot capture variables that are explicitly passed as arguments. "
|
406
|
+
f"{vars_msg}"
|
407
|
+
)
|
408
|
+
|
409
|
+
|
410
|
+
def validate_captured_directions(
|
411
|
+
captured_vars: CapturedVars, report_outin: bool = True
|
412
|
+
) -> None:
|
413
|
+
captured_inputs = [
|
414
|
+
captured_handle.handle.name
|
415
|
+
for captured_handle in captured_vars._captured_handles
|
416
|
+
if captured_handle.direction == PortDirection.Input
|
417
|
+
]
|
418
|
+
captured_outputs = [
|
419
|
+
captured_handle.handle.name
|
420
|
+
for captured_handle in captured_vars._captured_handles
|
421
|
+
if captured_handle.direction
|
422
|
+
in (
|
423
|
+
(PortDirection.Output, PortDirection.Outin)
|
424
|
+
if report_outin
|
425
|
+
else (PortDirection.Output,)
|
426
|
+
)
|
427
|
+
]
|
428
|
+
if len(captured_inputs) > 0:
|
429
|
+
raise ClassiqExpansionError(
|
430
|
+
f"Captured quantum variables {captured_inputs!r} cannot be used as inputs"
|
431
|
+
)
|
432
|
+
if len(captured_outputs) > 0:
|
433
|
+
raise ClassiqExpansionError(
|
434
|
+
f"Captured quantum variables {captured_outputs!r} cannot be used as outputs"
|
435
|
+
)
|