classiq 0.53.0__py3-none-any.whl → 0.55.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 +1 -3
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +2 -1
- classiq/_internals/__init__.py +0 -20
- classiq/_internals/api_wrapper.py +8 -8
- classiq/_internals/async_utils.py +1 -3
- classiq/_internals/authentication/auth0.py +5 -5
- classiq/_internals/authentication/device.py +5 -4
- classiq/_internals/authentication/password_manager.py +3 -3
- classiq/_internals/authentication/token_manager.py +3 -2
- classiq/_internals/client.py +10 -12
- classiq/_internals/config.py +2 -2
- classiq/_internals/jobs.py +7 -6
- classiq/_internals/type_validation.py +9 -9
- classiq/analyzer/__init__.py +1 -3
- classiq/analyzer/analyzer.py +8 -7
- classiq/analyzer/analyzer_utilities.py +8 -8
- classiq/analyzer/rb.py +11 -11
- classiq/applications/__init__.py +1 -3
- classiq/applications/chemistry/__init__.py +1 -3
- classiq/applications/chemistry/ansatz_parameters.py +4 -4
- classiq/applications/chemistry/chemistry_model_constructor.py +10 -9
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +26 -9
- classiq/applications/combinatorial_helpers/encoding_mapping.py +10 -10
- classiq/applications/combinatorial_helpers/encoding_utils.py +4 -4
- classiq/applications/combinatorial_helpers/memory.py +5 -7
- classiq/applications/combinatorial_helpers/optimization_model.py +43 -24
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +4 -6
- classiq/applications/combinatorial_helpers/pyomo_utils.py +95 -24
- classiq/applications/combinatorial_helpers/sympy_utils.py +2 -2
- classiq/applications/combinatorial_helpers/transformations/encoding.py +8 -8
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +5 -5
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +7 -9
- classiq/applications/combinatorial_helpers/transformations/penalty.py +1 -2
- classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +1 -2
- classiq/applications/combinatorial_helpers/transformations/slack_variables.py +1 -2
- classiq/applications/combinatorial_optimization/__init__.py +1 -3
- classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
- classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
- classiq/applications/finance/__init__.py +1 -3
- classiq/applications/grover/__init__.py +1 -3
- classiq/applications/grover/grover_model_constructor.py +7 -9
- classiq/applications/hamiltonian/pauli_decomposition.py +6 -6
- classiq/applications/qnn/__init__.py +1 -3
- classiq/applications/qnn/circuit_utils.py +5 -5
- classiq/applications/qnn/datasets/__init__.py +1 -3
- classiq/applications/qnn/datasets/dataset_base_classes.py +5 -4
- classiq/applications/qnn/datasets/dataset_parity.py +2 -2
- classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
- classiq/applications/qnn/qlayer.py +3 -3
- classiq/applications/qnn/torch_utils.py +2 -2
- classiq/applications/qnn/types.py +5 -5
- classiq/applications/qsvm/qsvm.py +1 -3
- classiq/applications/qsvm/qsvm_data_generation.py +3 -3
- classiq/applications/qsvm/qsvm_model_constructor.py +5 -5
- classiq/execution/__init__.py +1 -3
- classiq/execution/all_hardware_devices.py +1 -3
- classiq/execution/execution_session.py +16 -16
- classiq/execution/jobs.py +4 -4
- classiq/execution/qaoa.py +3 -3
- classiq/execution/qnn.py +3 -3
- classiq/executor.py +3 -3
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +9 -10
- classiq/interface/analyzer/cytoscape_graph.py +5 -5
- classiq/interface/analyzer/result.py +17 -17
- classiq/interface/applications/qsvm.py +6 -10
- classiq/interface/backend/backend_preferences.py +4 -3
- classiq/interface/backend/ionq/ionq_quantum_program.py +4 -5
- classiq/interface/backend/pydantic_backend.py +1 -2
- classiq/interface/chemistry/fermionic_operator.py +5 -5
- classiq/interface/chemistry/ground_state_problem.py +7 -8
- classiq/interface/chemistry/molecule.py +4 -4
- classiq/interface/chemistry/operator.py +11 -13
- 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 +2 -3
- 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 +5 -7
- classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
- classiq/interface/combinatorial_optimization/result.py +1 -3
- classiq/interface/debug_info/debug_info.py +8 -7
- classiq/interface/exceptions.py +8 -6
- classiq/interface/execution/jobs.py +2 -2
- classiq/interface/execution/primitives.py +3 -3
- classiq/interface/executor/aws_execution_cost.py +4 -4
- classiq/interface/executor/execution_request.py +2 -3
- classiq/interface/executor/execution_result.py +3 -3
- classiq/interface/executor/iqae_result.py +3 -5
- classiq/interface/executor/optimizer_preferences.py +2 -2
- classiq/interface/executor/quantum_code.py +6 -6
- classiq/interface/executor/register_initialization.py +2 -4
- classiq/interface/executor/result.py +23 -27
- classiq/interface/executor/vqe_result.py +8 -8
- classiq/interface/finance/function_input.py +2 -2
- classiq/interface/finance/gaussian_model_input.py +5 -5
- classiq/interface/finance/log_normal_model_input.py +2 -2
- classiq/interface/finance/model_input.py +1 -2
- classiq/interface/generator/adjacency.py +1 -3
- classiq/interface/generator/ansatz_library.py +4 -4
- classiq/interface/generator/application_apis/finance_declarations.py +1 -1
- classiq/interface/generator/arith/argument_utils.py +3 -3
- classiq/interface/generator/arith/arithmetic.py +7 -7
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +5 -5
- classiq/interface/generator/arith/arithmetic_expression_abc.py +11 -11
- classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -7
- classiq/interface/generator/arith/arithmetic_expression_validator.py +8 -8
- classiq/interface/generator/arith/arithmetic_operations.py +4 -3
- classiq/interface/generator/arith/arithmetic_param_getters.py +6 -6
- classiq/interface/generator/arith/arithmetic_result_builder.py +9 -9
- classiq/interface/generator/arith/ast_node_rewrite.py +2 -1
- classiq/interface/generator/arith/binary_ops.py +10 -13
- classiq/interface/generator/arith/extremum_operations.py +3 -2
- classiq/interface/generator/arith/logical_ops.py +7 -6
- classiq/interface/generator/arith/number_utils.py +4 -4
- classiq/interface/generator/arith/register_user_input.py +4 -4
- classiq/interface/generator/arith/unary_ops.py +2 -1
- classiq/interface/generator/builtin_api_builder.py +2 -1
- classiq/interface/generator/circuit_code/circuit_code.py +4 -4
- classiq/interface/generator/circuit_code/types_and_constants.py +3 -5
- classiq/interface/generator/complex_type.py +1 -2
- classiq/interface/generator/control_state.py +2 -2
- classiq/interface/generator/custom_ansatz.py +1 -3
- classiq/interface/generator/distance.py +3 -5
- classiq/interface/generator/excitations.py +3 -2
- classiq/interface/generator/expressions/enums/finance_functions.py +1 -3
- classiq/interface/generator/expressions/evaluated_expression.py +4 -3
- classiq/interface/generator/expressions/expression.py +4 -5
- classiq/interface/generator/expressions/expression_constants.py +4 -4
- classiq/interface/generator/expressions/qmod_qarray_proxy.py +2 -1
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +2 -1
- classiq/interface/generator/expressions/qmod_qstruct_proxy.py +2 -1
- classiq/interface/generator/expressions/qmod_sized_proxy.py +2 -1
- classiq/interface/generator/expressions/qmod_struct_instance.py +2 -1
- classiq/interface/generator/expressions/sympy_supported_expressions.py +11 -13
- classiq/interface/generator/finance.py +2 -2
- classiq/interface/generator/function_param_library.py +6 -6
- classiq/interface/generator/function_params.py +13 -19
- classiq/interface/generator/functions/builtins/internal_operators.py +9 -1
- classiq/interface/generator/functions/classical_function_declaration.py +4 -3
- classiq/interface/generator/functions/classical_type.py +13 -13
- classiq/interface/generator/functions/concrete_types.py +1 -2
- classiq/interface/generator/functions/function_declaration.py +1 -1
- classiq/interface/generator/functions/qmod_python_interface.py +2 -1
- classiq/interface/generator/functions/type_name.py +3 -2
- classiq/interface/generator/generated_circuit_data.py +33 -22
- classiq/interface/generator/grover_diffuser.py +7 -7
- classiq/interface/generator/grover_operator.py +2 -2
- classiq/interface/generator/hardware/hardware_data.py +7 -6
- classiq/interface/generator/hardware_efficient_ansatz.py +8 -8
- classiq/interface/generator/identity.py +5 -6
- classiq/interface/generator/linear_pauli_rotations.py +6 -6
- classiq/interface/generator/mcu.py +2 -2
- classiq/interface/generator/mcx.py +6 -6
- classiq/interface/generator/model/__init__.py +1 -3
- classiq/interface/generator/model/constraints.py +2 -2
- classiq/interface/generator/model/model.py +5 -6
- classiq/interface/generator/model/preferences/preferences.py +11 -6
- classiq/interface/generator/model/quantum_register.py +6 -11
- classiq/interface/generator/oracles/arithmetic_oracle.py +1 -2
- classiq/interface/generator/oracles/custom_oracle.py +2 -2
- classiq/interface/generator/oracles/oracle_abc.py +6 -5
- classiq/interface/generator/partitioned_register.py +6 -5
- classiq/interface/generator/piecewise_linear_amplitude_loading.py +8 -7
- classiq/interface/generator/qpe.py +4 -4
- classiq/interface/generator/qsvm.py +3 -3
- classiq/interface/generator/quantum_function_call.py +24 -29
- classiq/interface/generator/quantum_program.py +9 -9
- classiq/interface/generator/register_role.py +2 -4
- classiq/interface/generator/slice_parsing_utils.py +4 -3
- classiq/interface/generator/standard_gates/standard_gates.py +3 -3
- classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
- classiq/interface/generator/state_preparation/distributions.py +6 -5
- classiq/interface/generator/state_preparation/metrics.py +2 -4
- classiq/interface/generator/state_preparation/state_preparation.py +4 -4
- classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +3 -3
- classiq/interface/generator/transpiler_basis_gates.py +2 -2
- classiq/interface/generator/types/compilation_metadata.py +5 -0
- classiq/interface/generator/types/enum_declaration.py +2 -3
- classiq/interface/generator/types/qstruct_declaration.py +2 -1
- classiq/interface/generator/types/struct_declaration.py +3 -2
- classiq/interface/generator/ucc.py +2 -1
- classiq/interface/generator/unitary_gate.py +2 -2
- classiq/interface/generator/user_defined_function_params.py +1 -1
- classiq/interface/generator/validations/flow_graph.py +6 -5
- classiq/interface/generator/validations/validator_functions.py +3 -2
- classiq/interface/generator/visitor.py +9 -14
- classiq/interface/hardware.py +5 -6
- classiq/interface/helpers/custom_encoders.py +2 -2
- classiq/interface/helpers/custom_pydantic_types.py +8 -9
- 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 +4 -3
- classiq/interface/helpers/validation_helpers.py +2 -2
- classiq/interface/ide/ide_data.py +11 -15
- classiq/interface/ide/visual_model.py +22 -22
- classiq/interface/jobs.py +2 -2
- classiq/interface/model/bind_operation.py +5 -4
- classiq/interface/model/classical_parameter_declaration.py +2 -2
- classiq/interface/model/control.py +22 -1
- classiq/interface/model/handle_binding.py +3 -2
- classiq/interface/model/inplace_binary_operation.py +2 -1
- classiq/interface/model/model.py +16 -11
- classiq/interface/model/native_function_definition.py +1 -1
- classiq/interface/model/port_declaration.py +2 -2
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +3 -2
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +4 -27
- classiq/interface/model/quantum_expressions/quantum_expression.py +8 -7
- classiq/interface/model/quantum_function_call.py +9 -14
- classiq/interface/model/quantum_function_declaration.py +10 -12
- classiq/interface/model/quantum_lambda_function.py +3 -16
- classiq/interface/model/quantum_statement.py +7 -3
- classiq/interface/model/quantum_type.py +5 -5
- classiq/interface/model/statement_block.py +2 -3
- classiq/interface/model/validation_handle.py +5 -4
- classiq/interface/server/global_versions.py +3 -3
- classiq/model_expansions/atomic_expression_functions_defs.py +3 -2
- classiq/model_expansions/capturing/captured_var_manager.py +4 -6
- classiq/model_expansions/capturing/propagated_var_stack.py +7 -7
- classiq/model_expansions/closure.py +83 -12
- classiq/model_expansions/evaluators/arg_type_match.py +3 -2
- classiq/model_expansions/evaluators/argument_types.py +3 -3
- classiq/model_expansions/evaluators/control.py +3 -3
- classiq/model_expansions/evaluators/parameter_types.py +7 -7
- classiq/model_expansions/evaluators/quantum_type_utils.py +2 -1
- classiq/model_expansions/evaluators/type_type_match.py +1 -1
- classiq/model_expansions/expression_evaluator.py +10 -9
- classiq/model_expansions/expression_renamer.py +6 -6
- classiq/model_expansions/function_builder.py +13 -12
- classiq/model_expansions/generative_functions.py +5 -4
- classiq/model_expansions/interpreter.py +20 -11
- classiq/model_expansions/model_tables.py +14 -14
- classiq/model_expansions/quantum_operations/bind.py +2 -4
- classiq/model_expansions/quantum_operations/classicalif.py +1 -1
- classiq/model_expansions/quantum_operations/control.py +81 -24
- classiq/model_expansions/quantum_operations/emitter.py +33 -20
- classiq/model_expansions/quantum_operations/expression_operation.py +47 -16
- classiq/model_expansions/quantum_operations/inplace_binary_operation.py +160 -35
- classiq/model_expansions/quantum_operations/phase.py +6 -6
- classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +28 -31
- classiq/model_expansions/quantum_operations/quantum_function_call.py +9 -0
- classiq/model_expansions/quantum_operations/repeat.py +1 -3
- classiq/model_expansions/quantum_operations/within_apply.py +0 -16
- classiq/model_expansions/scope.py +11 -10
- classiq/model_expansions/scope_initialization.py +5 -5
- classiq/model_expansions/sympy_conversion/expression_to_sympy.py +6 -6
- classiq/model_expansions/sympy_conversion/sympy_to_python.py +2 -2
- classiq/model_expansions/visitors/variable_references.py +5 -4
- classiq/qmod/builtins/classical_execution_primitives.py +9 -9
- classiq/qmod/builtins/functions/__init__.py +72 -55
- classiq/qmod/builtins/functions/amplitude_estimation.py +4 -1
- classiq/qmod/builtins/functions/arithmetic.py +14 -1
- classiq/qmod/builtins/functions/discrete_sine_cosine_transform.py +86 -6
- classiq/qmod/builtins/functions/grover.py +41 -45
- classiq/qmod/builtins/functions/hea.py +60 -4
- classiq/qmod/builtins/functions/linear_pauli_rotation.py +26 -4
- classiq/qmod/builtins/functions/modular_exponentiation.py +90 -29
- classiq/qmod/builtins/functions/operators.py +1 -1
- classiq/qmod/builtins/functions/qaoa_penalty.py +14 -5
- classiq/qmod/builtins/functions/qft_functions.py +57 -0
- classiq/qmod/builtins/functions/qpe.py +20 -4
- classiq/qmod/builtins/functions/qsvt.py +49 -4
- classiq/qmod/builtins/functions/standard_gates.py +4 -4
- classiq/qmod/builtins/functions/state_preparation.py +92 -10
- classiq/qmod/builtins/functions/swap_test.py +7 -1
- classiq/qmod/builtins/functions/utility_functions.py +43 -0
- classiq/qmod/builtins/functions/variational.py +18 -2
- classiq/qmod/builtins/operations.py +117 -22
- classiq/qmod/cfunc.py +2 -2
- classiq/qmod/classical_function.py +3 -7
- classiq/qmod/create_model_function.py +16 -17
- classiq/qmod/declaration_inferrer.py +7 -10
- classiq/qmod/expression_query.py +3 -3
- classiq/qmod/generative.py +2 -1
- classiq/qmod/model_state_container.py +10 -8
- classiq/qmod/native/__init__.py +1 -3
- classiq/qmod/native/expression_to_qmod.py +9 -8
- classiq/qmod/native/pretty_printer.py +12 -6
- classiq/qmod/pretty_print/__init__.py +1 -3
- classiq/qmod/pretty_print/expression_to_python.py +13 -12
- classiq/qmod/pretty_print/pretty_printer.py +38 -23
- classiq/qmod/python_classical_type.py +8 -4
- classiq/qmod/qfunc.py +4 -4
- classiq/qmod/qmod_variable.py +11 -10
- classiq/qmod/quantum_expandable.py +12 -15
- classiq/qmod/quantum_function.py +35 -22
- classiq/qmod/semantics/annotation.py +1 -1
- classiq/qmod/semantics/error_manager.py +8 -7
- classiq/qmod/semantics/static_semantics_visitor.py +19 -24
- classiq/qmod/semantics/validation/constants_validation.py +1 -1
- classiq/qmod/semantics/validation/func_call_validation.py +2 -2
- classiq/qmod/semantics/validation/main_validation.py +33 -0
- classiq/qmod/semantics/validation/types_validation.py +2 -1
- classiq/qmod/symbolic.py +5 -8
- classiq/qmod/symbolic_type.py +2 -2
- classiq/qmod/synthesize_separately.py +1 -2
- {classiq-0.53.0.dist-info → classiq-0.55.0.dist-info}/METADATA +1 -1
- {classiq-0.53.0.dist-info → classiq-0.55.0.dist-info}/RECORD +300 -297
- classiq/qmod/builtins/functions/qft.py +0 -23
- {classiq-0.53.0.dist-info → classiq-0.55.0.dist-info}/WHEEL +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
# flake8: noqa
|
2
2
|
|
3
|
-
from typing import
|
3
|
+
from typing import Optional
|
4
|
+
from collections.abc import Mapping
|
4
5
|
|
5
6
|
from classiq.interface.chemistry.fermionic_operator import (
|
6
7
|
FermionicOperator,
|
@@ -53,17 +54,17 @@ from classiq.applications.chemistry.chemistry_execution_parameters import (
|
|
53
54
|
from classiq.interface.exceptions import ClassiqError
|
54
55
|
from classiq.qmod.utilities import qmod_val_to_expr_str
|
55
56
|
|
56
|
-
_LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING:
|
57
|
+
_LADDER_OPERATOR_TYPE_INDICATOR_TO_QMOD_MAPPING: dict[str, str] = {
|
57
58
|
"+": "PLUS",
|
58
59
|
"-": "MINUS",
|
59
60
|
}
|
60
61
|
|
61
|
-
_CHEMISTRY_PROBLEM_PREFIX_MAPPING:
|
62
|
+
_CHEMISTRY_PROBLEM_PREFIX_MAPPING: dict[type[CHEMISTRY_PROBLEMS_TYPE], str] = {
|
62
63
|
MoleculeProblem: "molecule",
|
63
64
|
HamiltonianProblem: "fock_hamiltonian",
|
64
65
|
}
|
65
66
|
|
66
|
-
_ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING:
|
67
|
+
_ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING: dict[type[AnsatzParameters], str] = {
|
67
68
|
UCCParameters: "ucc",
|
68
69
|
HVAParameters: "hva",
|
69
70
|
}
|
@@ -71,7 +72,7 @@ _ANSATZ_PARAMETERS_FUNCTION_NAME_MAPPING: Dict[Type[AnsatzParameters], str] = {
|
|
71
72
|
_EXECUTION_RESULT = "vqe_result"
|
72
73
|
_MOLECULE_PROBLEM_RESULT = "molecule_result"
|
73
74
|
|
74
|
-
_HAE_GATE_MAPPING:
|
75
|
+
_HAE_GATE_MAPPING: dict[str, QuantumFunctionCall] = {
|
75
76
|
"h": QuantumFunctionCall(
|
76
77
|
function="H",
|
77
78
|
positional_args=[HandleBinding(name="q")],
|
@@ -191,7 +192,7 @@ _HAE_GATE_MAPPING: Dict[str, QuantumFunctionCall] = {
|
|
191
192
|
}
|
192
193
|
|
193
194
|
|
194
|
-
def _atoms_to_qmod_atoms(atoms:
|
195
|
+
def _atoms_to_qmod_atoms(atoms: list[Atom]) -> list[QmodChemistryAtom]:
|
195
196
|
return [
|
196
197
|
QmodChemistryAtom(
|
197
198
|
element=Element[atom.symbol], # type:ignore[arg-type]
|
@@ -285,7 +286,7 @@ def _get_chemistry_function(
|
|
285
286
|
chemistry_problem: CHEMISTRY_PROBLEMS_TYPE,
|
286
287
|
chemistry_function_name: str,
|
287
288
|
inouts: Mapping[IOName, HandleBinding],
|
288
|
-
ansatz_parameters_expressions: Optional[
|
289
|
+
ansatz_parameters_expressions: Optional[list[Expression]] = None,
|
289
290
|
) -> QuantumFunctionCall:
|
290
291
|
problem_prefix = _CHEMISTRY_PROBLEM_PREFIX_MAPPING[type(chemistry_problem)]
|
291
292
|
return QuantumFunctionCall(
|
@@ -400,7 +401,7 @@ def _get_execution_result_post_processing_statements(
|
|
400
401
|
raise ClassiqError(f"Invalid problem type: {problem}")
|
401
402
|
|
402
403
|
|
403
|
-
def _count_parametric_gates(gates:
|
404
|
+
def _count_parametric_gates(gates: list[str]) -> int:
|
404
405
|
return sum(_is_parametric_gate(_HAE_GATE_MAPPING[gate]) for gate in gates)
|
405
406
|
|
406
407
|
|
@@ -415,7 +416,7 @@ def _get_hea_port_size(hea_parameters: HEAParameters) -> int:
|
|
415
416
|
|
416
417
|
def _get_chemistry_quantum_main_params(
|
417
418
|
ansatz_parameters: AnsatzParameters,
|
418
|
-
) ->
|
419
|
+
) -> list[ClassicalParameterDeclaration]:
|
419
420
|
if not isinstance(ansatz_parameters, HEAParameters):
|
420
421
|
return []
|
421
422
|
return [
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import itertools
|
2
|
-
from
|
2
|
+
from functools import partial
|
3
|
+
from typing import Callable, Union
|
3
4
|
|
4
5
|
import numpy as np
|
5
6
|
import pyomo.environ as pyo
|
@@ -20,14 +21,17 @@ from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import
|
|
20
21
|
)
|
21
22
|
from classiq.applications.combinatorial_helpers.pyomo_utils import (
|
22
23
|
convert_pyomo_to_global_presentation,
|
24
|
+
evaluate_objective,
|
25
|
+
pyomo_to_qmod_qstruct,
|
23
26
|
)
|
24
27
|
from classiq.qmod.builtins.structs import PauliTerm
|
28
|
+
from classiq.qmod.qmod_variable import QStruct
|
25
29
|
|
26
30
|
|
27
31
|
def compute_qaoa_initial_point(
|
28
|
-
hamiltonian:
|
32
|
+
hamiltonian: list[PauliTerm],
|
29
33
|
repetitions: int,
|
30
|
-
) ->
|
34
|
+
) -> list[float]:
|
31
35
|
coeffs_ising = [pauli_term.coefficient for pauli_term in hamiltonian[1:]]
|
32
36
|
# the first coeff is the II...I term
|
33
37
|
coeffs_abs = np.abs(coeffs_ising) # type: ignore[arg-type]
|
@@ -42,26 +46,39 @@ def compute_qaoa_initial_point(
|
|
42
46
|
|
43
47
|
def pyo_model_to_hamiltonian(
|
44
48
|
pyo_model: pyo.ConcreteModel, penalty_energy: float
|
45
|
-
) ->
|
49
|
+
) -> list[PauliTerm]:
|
46
50
|
pauli_list = OptimizationModel(
|
47
51
|
pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
|
48
52
|
).ising.pauli_list
|
49
53
|
return pauli_operator_to_hamiltonian(pauli_list)
|
50
54
|
|
51
55
|
|
52
|
-
def
|
56
|
+
def pyo_model_to_qmod_problem(
|
57
|
+
pyo_model: pyo.ConcreteModel, penalty_energy: float
|
58
|
+
) -> tuple[type[QStruct], Callable]:
|
59
|
+
optimization_model = OptimizationModel(
|
60
|
+
pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
|
61
|
+
)
|
62
|
+
qmod_struct = pyomo_to_qmod_qstruct("QAOAVars", optimization_model.vars_not_encoded)
|
63
|
+
cost_func = partial(
|
64
|
+
evaluate_objective, *optimization_model.objective_not_encoded_sympy
|
65
|
+
)
|
66
|
+
return qmod_struct, cost_func
|
67
|
+
|
68
|
+
|
69
|
+
def _str_to_list_int(str_ints: str) -> list[int]:
|
53
70
|
return list(map(int, list(str_ints)))
|
54
71
|
|
55
72
|
|
56
73
|
def _decode_vector_str(
|
57
74
|
optimization_model: OptimizationModel, vector_str: str
|
58
|
-
) ->
|
75
|
+
) -> list[int]:
|
59
76
|
return optimization_model.decode(
|
60
77
|
_str_to_list_int(vector_str[::-1])
|
61
78
|
) # reverse qubit order
|
62
79
|
|
63
80
|
|
64
|
-
def _evaluate_operator(operator: SparsePauliOp, state: Union[
|
81
|
+
def _evaluate_operator(operator: SparsePauliOp, state: Union[list[int], str]) -> float:
|
65
82
|
if isinstance(state, list):
|
66
83
|
state = "".join([str(x) for x in state])
|
67
84
|
|
@@ -104,7 +121,7 @@ def _eigenstate_to_solution(
|
|
104
121
|
def _get_combi_solution_histogram(
|
105
122
|
optimization_model: OptimizationModel,
|
106
123
|
vqe_result: VQESolverResult,
|
107
|
-
) ->
|
124
|
+
) -> list[QmodPyStruct]:
|
108
125
|
if vqe_result.reduced_probabilities is None:
|
109
126
|
raise ValueError(
|
110
127
|
"reduced_probabilities is optional only for backwards compatibility, but it should always be present here"
|
@@ -121,7 +138,7 @@ def get_optimization_solution_from_pyo(
|
|
121
138
|
pyo_model: pyo.ConcreteModel,
|
122
139
|
vqe_result: VQESolverResult,
|
123
140
|
penalty_energy: float,
|
124
|
-
) ->
|
141
|
+
) -> list[QmodPyStruct]:
|
125
142
|
converted_pyo_model = convert_pyomo_to_global_presentation(pyo_model)
|
126
143
|
optimization_model = OptimizationModel(
|
127
144
|
converted_pyo_model, penalty_energy=penalty_energy, qsolver=QSolver.QAOAPenalty
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import itertools
|
2
2
|
from dataclasses import dataclass, field
|
3
|
-
from typing import
|
3
|
+
from typing import Optional, Union
|
4
4
|
|
5
5
|
import pyomo.environ as pyo
|
6
6
|
from pyomo.core.base import _GeneralVarData
|
@@ -16,20 +16,20 @@ from classiq.applications.combinatorial_helpers import pyomo_utils
|
|
16
16
|
class VarExpressionMapping:
|
17
17
|
var: _GeneralVarData
|
18
18
|
expr: pyo.Expression
|
19
|
-
encodings_vars:
|
19
|
+
encodings_vars: list[_GeneralVarData] = field(default_factory=list)
|
20
20
|
|
21
21
|
|
22
22
|
class EncodingMapping:
|
23
23
|
def __init__(self, encoding_type: EncodingType) -> None:
|
24
|
-
self._data:
|
24
|
+
self._data: list[VarExpressionMapping] = []
|
25
25
|
self.encoding_type = encoding_type
|
26
26
|
|
27
27
|
@property
|
28
|
-
def original_vars(self) ->
|
28
|
+
def original_vars(self) -> list[_GeneralVarData]:
|
29
29
|
return [pair.var for pair in self._data]
|
30
30
|
|
31
31
|
@property
|
32
|
-
def encodings_vars(self) ->
|
32
|
+
def encodings_vars(self) -> list[_GeneralVarData]:
|
33
33
|
return list(
|
34
34
|
itertools.chain.from_iterable(
|
35
35
|
var_mapping.encodings_vars for var_mapping in self._data
|
@@ -37,7 +37,7 @@ class EncodingMapping:
|
|
37
37
|
)
|
38
38
|
|
39
39
|
@property
|
40
|
-
def substitution_dict(self) ->
|
40
|
+
def substitution_dict(self) -> dict[int, pyo.Expression]:
|
41
41
|
return {id(mapping.var): mapping.expr for mapping in self._data}
|
42
42
|
|
43
43
|
def __len__(self) -> int:
|
@@ -47,7 +47,7 @@ class EncodingMapping:
|
|
47
47
|
self,
|
48
48
|
original_var: _GeneralVarData,
|
49
49
|
encoding_expr: pyo.Expression,
|
50
|
-
encodings_vars: Union[
|
50
|
+
encodings_vars: Union[list[_GeneralVarData], None] = None,
|
51
51
|
) -> None:
|
52
52
|
if encodings_vars is None:
|
53
53
|
encodings_vars = list(identify_variables(encoding_expr))
|
@@ -59,7 +59,7 @@ class EncodingMapping:
|
|
59
59
|
)
|
60
60
|
)
|
61
61
|
|
62
|
-
def _check_unique_encoding_vars(self, variables:
|
62
|
+
def _check_unique_encoding_vars(self, variables: list[_GeneralVarData]) -> None:
|
63
63
|
assert all(
|
64
64
|
not pyomo_utils.contains(var, self.encodings_vars) for var in variables
|
65
65
|
)
|
@@ -72,7 +72,7 @@ class EncodingMapping:
|
|
72
72
|
return var_expr_mapping
|
73
73
|
raise ClassiqCombOptError("No variable expression mapping found.")
|
74
74
|
|
75
|
-
def get_encoding_vars(self, original_var: _GeneralVarData) ->
|
75
|
+
def get_encoding_vars(self, original_var: _GeneralVarData) -> list[_GeneralVarData]:
|
76
76
|
return self.get_var_expr_mapping(original_var).encodings_vars
|
77
77
|
|
78
78
|
def get_original_var(
|
@@ -83,7 +83,7 @@ class EncodingMapping:
|
|
83
83
|
return original_var
|
84
84
|
return None
|
85
85
|
|
86
|
-
def decode(self, solution:
|
86
|
+
def decode(self, solution: list[int]) -> list[int]:
|
87
87
|
idx = 0
|
88
88
|
decoded_solution = []
|
89
89
|
for var_mapping in self._data:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import math
|
2
2
|
from itertools import filterfalse
|
3
|
-
from typing import Any,
|
3
|
+
from typing import Any, Union, cast
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
import pyomo.environ as pyo
|
@@ -70,7 +70,7 @@ def recursively_remove_monomial_expr(obj: Any) -> None:
|
|
70
70
|
|
71
71
|
|
72
72
|
def encode_expr(
|
73
|
-
expr: pyo.Expression, substitution_dict:
|
73
|
+
expr: pyo.Expression, substitution_dict: dict[int, pyo.Expression]
|
74
74
|
) -> pyo.Expression:
|
75
75
|
encoded_expr = clone_expression(expr=expr, substitute=substitution_dict)
|
76
76
|
recursively_remove_monomial_expr(encoded_expr)
|
@@ -78,7 +78,7 @@ def encode_expr(
|
|
78
78
|
|
79
79
|
|
80
80
|
def encode_constraints(
|
81
|
-
model: pyo.ConcreteModel, substitution_dict:
|
81
|
+
model: pyo.ConcreteModel, substitution_dict: dict[int, pyo.Expression]
|
82
82
|
) -> None:
|
83
83
|
all_constraints = pyomo_utils.extract(model, _GeneralConstraintData)
|
84
84
|
constraints = filterfalse(is_obj_encoded, all_constraints)
|
@@ -107,7 +107,7 @@ def deal_with_trivial_boolean_constraint(
|
|
107
107
|
|
108
108
|
|
109
109
|
def encode_objective(
|
110
|
-
model: pyo.ConcreteModel, substitution_dict:
|
110
|
+
model: pyo.ConcreteModel, substitution_dict: dict[int, pyo.Expression]
|
111
111
|
) -> None:
|
112
112
|
objective = next(model.component_objects(pyo.Objective))
|
113
113
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from typing import Dict, List, Tuple
|
4
|
-
|
5
3
|
from pyomo.core.base import _GeneralVarData
|
6
4
|
|
7
5
|
from classiq.interface.generator.function_params import IOName
|
@@ -21,13 +19,13 @@ class InternalQuantumReg:
|
|
21
19
|
class MemoryMapping:
|
22
20
|
def __init__(
|
23
21
|
self,
|
24
|
-
variables:
|
22
|
+
variables: list[_GeneralVarData],
|
25
23
|
vars_encoding_mapping: EncodingMapping | None = None,
|
26
24
|
) -> None:
|
27
|
-
self.substitution_dict:
|
28
|
-
self.qubit_allocation:
|
25
|
+
self.substitution_dict: dict[int, InternalQuantumReg] = dict()
|
26
|
+
self.qubit_allocation: dict[IOName, tuple[int, int]] = dict()
|
29
27
|
self.vars_encoding_mapping: EncodingMapping | None = vars_encoding_mapping
|
30
|
-
self.vars:
|
28
|
+
self.vars: list[_GeneralVarData] = variables
|
31
29
|
self._allocate_memory()
|
32
30
|
|
33
31
|
def __len__(self) -> int:
|
@@ -55,7 +53,7 @@ class MemoryMapping:
|
|
55
53
|
)
|
56
54
|
|
57
55
|
@property
|
58
|
-
def qregs(self) ->
|
56
|
+
def qregs(self) -> list[InternalQuantumReg]:
|
59
57
|
return list(self.substitution_dict.values())
|
60
58
|
|
61
59
|
@property
|
@@ -1,11 +1,13 @@
|
|
1
1
|
import copy
|
2
|
+
from functools import cached_property
|
2
3
|
from itertools import filterfalse
|
3
|
-
from typing import
|
4
|
+
from typing import Optional, Union
|
4
5
|
|
5
6
|
import pyomo.environ as pyo
|
6
7
|
from pyomo.core import ConcreteModel
|
7
8
|
from pyomo.core.base import _GeneralVarData
|
8
9
|
from pyomo.core.base.constraint import _GeneralConstraintData
|
10
|
+
from pyomo.core.expr.sympy_tools import sympyify_expression
|
9
11
|
from pyomo.environ import Expression
|
10
12
|
|
11
13
|
from classiq.interface.chemistry.operator import PauliOperator
|
@@ -21,6 +23,7 @@ from classiq.applications.combinatorial_helpers import (
|
|
21
23
|
)
|
22
24
|
from classiq.applications.combinatorial_helpers.encoding_mapping import EncodingMapping
|
23
25
|
from classiq.applications.combinatorial_helpers.memory import InternalQuantumReg
|
26
|
+
from classiq.applications.combinatorial_helpers.pyomo_utils import get_field_name
|
24
27
|
from classiq.applications.combinatorial_helpers.transformations import (
|
25
28
|
encoding,
|
26
29
|
ising_converter,
|
@@ -72,23 +75,27 @@ class OptimizationModel:
|
|
72
75
|
)
|
73
76
|
|
74
77
|
self.is_maximization = sense.is_maximization(model_copy)
|
75
|
-
self.objective = next(self._model.component_objects(pyo.Objective))
|
76
|
-
|
77
78
|
self.penalty_energy = penalty_energy
|
78
|
-
self._add_penalty_term()
|
79
79
|
|
80
|
-
self.
|
80
|
+
self.objective = next(self._model.component_objects(pyo.Objective))
|
81
|
+
if self.qsolver == QSolver.QAOAPenalty:
|
82
|
+
self.objective.expr += self._get_penalty_term(self.constraints)
|
83
|
+
if self.is_encoded:
|
84
|
+
self.objective.expr = self._model_encoder.encode_expr(
|
85
|
+
self.objective.expr
|
86
|
+
)
|
87
|
+
self._initialize_objective_not_encoded(model_copy)
|
81
88
|
|
82
89
|
@property
|
83
|
-
def vars(self) ->
|
90
|
+
def vars(self) -> list[_GeneralVarData]:
|
84
91
|
return pyomo_utils.extract(self._model, _GeneralVarData)
|
85
92
|
|
86
93
|
@property
|
87
|
-
def vars_not_encoded(self) ->
|
94
|
+
def vars_not_encoded(self) -> list[_GeneralVarData]:
|
88
95
|
return list(filterfalse(encoding_utils.is_obj_encoded, self.vars))
|
89
96
|
|
90
97
|
@property
|
91
|
-
def _ising_vars(self) ->
|
98
|
+
def _ising_vars(self) -> list[_GeneralVarData]:
|
92
99
|
if self.is_encoded:
|
93
100
|
return [
|
94
101
|
var
|
@@ -100,12 +107,12 @@ class OptimizationModel:
|
|
100
107
|
return self.vars
|
101
108
|
|
102
109
|
@property
|
103
|
-
def constraints(self) ->
|
110
|
+
def constraints(self) -> list[_GeneralConstraintData]:
|
104
111
|
all_constraints = pyomo_utils.extract(self._model, _GeneralConstraintData)
|
105
112
|
return list(filterfalse(encoding_utils.is_obj_encoded, all_constraints))
|
106
113
|
|
107
114
|
@property
|
108
|
-
def qregs(self) ->
|
115
|
+
def qregs(self) -> list[InternalQuantumReg]:
|
109
116
|
return self.memory_mapping.qregs
|
110
117
|
|
111
118
|
@property
|
@@ -116,19 +123,14 @@ class OptimizationModel:
|
|
116
123
|
def sign(self) -> int:
|
117
124
|
return -1 if self.is_maximization else 1
|
118
125
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
normalized_penalty_term = penalty.get_penalty_expression(self.constraints)
|
125
|
-
penalty_term = self.penalty_energy * normalized_penalty_term * self.sign
|
126
|
-
|
127
|
-
if self.is_encoded:
|
128
|
-
penalty_term = self._model_encoder.encode_expr(penalty_term)
|
129
|
-
return penalty_term
|
126
|
+
def _get_penalty_term(
|
127
|
+
self, constraints: list[_GeneralConstraintData]
|
128
|
+
) -> Union[int, Expression]:
|
129
|
+
normalized_penalty_term = penalty.get_penalty_expression(constraints)
|
130
|
+
return self.penalty_energy * normalized_penalty_term * self.sign
|
130
131
|
|
131
|
-
|
132
|
+
@cached_property
|
133
|
+
def ising(self) -> PauliOperator:
|
132
134
|
return (
|
133
135
|
ising_converter.convert_pyomo_to_hamiltonian(
|
134
136
|
self.objective.expr, self._ising_vars, self.qregs
|
@@ -136,11 +138,11 @@ class OptimizationModel:
|
|
136
138
|
* self.sign
|
137
139
|
)
|
138
140
|
|
139
|
-
def _remove_slack_variables_from_solution(self, solution:
|
141
|
+
def _remove_slack_variables_from_solution(self, solution: list[int]) -> list[int]:
|
140
142
|
variables = pyomo_utils.extract(self._model_original, pyo.Var)
|
141
143
|
return solution[: len(variables)]
|
142
144
|
|
143
|
-
def decode(self, solution:
|
145
|
+
def decode(self, solution: list[int]) -> list[int]:
|
144
146
|
if self.is_encoded:
|
145
147
|
solution = self._vars_encoding_mapping.decode(solution)
|
146
148
|
|
@@ -161,3 +163,20 @@ class OptimizationModel:
|
|
161
163
|
self._model
|
162
164
|
):
|
163
165
|
return slack_variables.slack_vars_convert(self._model)
|
166
|
+
|
167
|
+
def _initialize_objective_not_encoded(self, model_copy: pyo.ConcreteModel) -> None:
|
168
|
+
objective_not_encoded = next(model_copy.component_objects(pyo.Objective))
|
169
|
+
objective_map, objective_expr = sympyify_expression(objective_not_encoded)
|
170
|
+
objective_expr *= self.sign
|
171
|
+
if self.qsolver == QSolver.QAOAPenalty:
|
172
|
+
penalty = self._get_penalty_term(self.constraints)
|
173
|
+
penalty_map, penalty_expr = sympyify_expression(penalty)
|
174
|
+
objective_expr += penalty_expr * self.sign
|
175
|
+
objective_map.sympy2pyomo |= penalty_map.sympy2pyomo
|
176
|
+
for key, value in penalty_map.pyomo2sympy.items():
|
177
|
+
objective_map.pyomo2sympy[key] = value
|
178
|
+
sympy_mapping = {
|
179
|
+
sympy_var: get_field_name(pyomo_var)
|
180
|
+
for pyomo_var, sympy_var in objective_map.pyomo2sympy.items()
|
181
|
+
}
|
182
|
+
self.objective_not_encoded_sympy = sympy_mapping, objective_expr
|
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import List
|
2
|
-
|
3
1
|
from classiq.interface.exceptions import ClassiqNonNumericCoefficientInPauliError
|
4
2
|
from classiq.interface.generator.functions.qmod_python_interface import QmodPyStruct
|
5
3
|
from classiq.interface.helpers.custom_pydantic_types import PydanticPauliList
|
@@ -8,8 +6,8 @@ from classiq.qmod.builtins.enums import Pauli
|
|
8
6
|
from classiq.qmod.builtins.structs import PauliTerm
|
9
7
|
|
10
8
|
|
11
|
-
def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) ->
|
12
|
-
pauli_terms:
|
9
|
+
def pauli_operator_to_hamiltonian(pauli_list: PydanticPauliList) -> list[PauliTerm]:
|
10
|
+
pauli_terms: list[PauliTerm] = []
|
13
11
|
for pauli_term in pauli_list:
|
14
12
|
if not isinstance(pauli_term[1], complex) or pauli_term[1].imag != 0:
|
15
13
|
raise ClassiqNonNumericCoefficientInPauliError(
|
@@ -33,7 +31,7 @@ def pauli_enum_to_str(pauli: Pauli) -> str:
|
|
33
31
|
}[pauli]
|
34
32
|
|
35
33
|
|
36
|
-
def _pauli_terms_to_qmod(hamiltonian:
|
34
|
+
def _pauli_terms_to_qmod(hamiltonian: list[PauliTerm]) -> str:
|
37
35
|
qmod_strings = []
|
38
36
|
for term in hamiltonian:
|
39
37
|
pauli_str = ", ".join([pauli_enum_to_str(p) for p in term.pauli]) # type: ignore[attr-defined]
|
@@ -44,5 +42,5 @@ def _pauli_terms_to_qmod(hamiltonian: List[PauliTerm]) -> str:
|
|
44
42
|
return ", ".join(qmod_strings)
|
45
43
|
|
46
44
|
|
47
|
-
def _pauli_dict_to_pauli_terms(hamiltonian:
|
45
|
+
def _pauli_dict_to_pauli_terms(hamiltonian: list[QmodPyStruct]) -> list[PauliTerm]:
|
48
46
|
return [PauliTerm(**struct) for struct in hamiltonian]
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import
|
1
|
+
import math
|
2
|
+
import re
|
2
3
|
from enum import Enum
|
3
|
-
from typing import Any,
|
4
|
+
from typing import Any, Optional, TypeVar, Union
|
4
5
|
|
5
6
|
import pydantic
|
6
7
|
import pyomo.core.expr.numeric_expr as pyo_expr
|
@@ -20,9 +21,21 @@ from pyomo.core.expr.sympy_tools import (
|
|
20
21
|
|
21
22
|
from classiq.interface.exceptions import ClassiqValueError
|
22
23
|
from classiq.interface.generator.expressions.expression import Expression
|
24
|
+
from classiq.interface.generator.functions.classical_type import Integer
|
23
25
|
from classiq.interface.generator.types.struct_declaration import StructDeclaration
|
24
26
|
|
25
|
-
|
27
|
+
from classiq.qmod.qmod_variable import QBit, QNum, QStruct, QVar
|
28
|
+
from classiq.qmod.symbolic_expr import SymbolicExpr
|
29
|
+
|
30
|
+
ListVars = list[_GeneralVarData]
|
31
|
+
SUPPORTED_TYPES = [
|
32
|
+
pyo.Binary,
|
33
|
+
pyo.Integers,
|
34
|
+
pyo.NegativeIntegers,
|
35
|
+
pyo.NonNegativeIntegers,
|
36
|
+
pyo.NonPositiveIntegers,
|
37
|
+
pyo.PositiveIntegers,
|
38
|
+
]
|
26
39
|
|
27
40
|
|
28
41
|
class ObjectiveType(Enum):
|
@@ -33,7 +46,7 @@ class ObjectiveType(Enum):
|
|
33
46
|
class CombinatorialOptimizationStructDeclaration(StructDeclaration):
|
34
47
|
variable_lower_bound: int = pydantic.Field(default=0)
|
35
48
|
variable_upper_bound: int = pydantic.Field(default=1)
|
36
|
-
constraints:
|
49
|
+
constraints: list[Expression] = pydantic.Field(
|
37
50
|
default_factory=list, description="List of constraint expressions"
|
38
51
|
)
|
39
52
|
objective_type: ObjectiveType = pydantic.Field(
|
@@ -72,7 +85,7 @@ def index(var_data: _GeneralVarData, vars_data: ListVars) -> int:
|
|
72
85
|
T = TypeVar("T")
|
73
86
|
|
74
87
|
|
75
|
-
def extract(model: ConcreteModel, type_:
|
88
|
+
def extract(model: ConcreteModel, type_: type[T]) -> list[T]:
|
76
89
|
if type_ == _GeneralVarData:
|
77
90
|
type_ = Var
|
78
91
|
|
@@ -104,7 +117,7 @@ def delete_component(model: ConcreteModel, component: ComponentData) -> None:
|
|
104
117
|
model.del_component(parent_component)
|
105
118
|
|
106
119
|
|
107
|
-
def _delete_element_by_value(dict_:
|
120
|
+
def _delete_element_by_value(dict_: dict, value: Any) -> None:
|
108
121
|
iter_dict = {**dict_}
|
109
122
|
for k, v in iter_dict.items():
|
110
123
|
if v is value and k in dict_:
|
@@ -121,7 +134,7 @@ def get_name(component: Union[IndexedComponent, ComponentData]) -> str:
|
|
121
134
|
class FixedSympy2PyomoVisitor(Sympy2PyomoVisitor):
|
122
135
|
def beforeChild( # noqa: N802
|
123
136
|
self, node: Optional[sympy.Expr], child: sympy.Expr, child_idx: Optional[int]
|
124
|
-
) ->
|
137
|
+
) -> tuple[bool, Union[int, float, None]]:
|
125
138
|
if not child._args:
|
126
139
|
item = self.object_map.getPyomoSymbol(child, None)
|
127
140
|
if item is None:
|
@@ -142,10 +155,7 @@ def sympy2pyomo_expression(
|
|
142
155
|
def convert_pyomo_to_global_presentation(
|
143
156
|
pyo_model: pyo.ConcreteModel,
|
144
157
|
) -> pyo.ConcreteModel:
|
145
|
-
|
146
|
-
problem_struct = CombinatorialOptimizationStructDeclaration.model_validate_json(
|
147
|
-
pyo_model_str
|
148
|
-
)
|
158
|
+
problem_struct = pyomo2qmod("nativePyoModel", pyo_model)
|
149
159
|
|
150
160
|
pyomo_model = pyo.ConcreteModel()
|
151
161
|
|
@@ -190,10 +200,12 @@ def convert_pyomo_to_global_presentation(
|
|
190
200
|
return pyomo_model
|
191
201
|
|
192
202
|
|
193
|
-
def pyomo2qmod(
|
203
|
+
def pyomo2qmod(
|
204
|
+
struct_name: str, pyo_model: ConcreteModel
|
205
|
+
) -> CombinatorialOptimizationStructDeclaration:
|
194
206
|
symbols_map = PyomoSympyBimap()
|
195
207
|
|
196
|
-
variables:
|
208
|
+
variables: list[sympy.Symbol] = []
|
197
209
|
|
198
210
|
bounds_set = False
|
199
211
|
lower_bound = None
|
@@ -218,7 +230,7 @@ def pyomo2qmod(struct_name: str, pyo_model: ConcreteModel) -> str:
|
|
218
230
|
upper_bound = var_dict[key].ub
|
219
231
|
bounds_set = True
|
220
232
|
|
221
|
-
constraint_exprs:
|
233
|
+
constraint_exprs: list[sympy.Expr] = []
|
222
234
|
|
223
235
|
constraint_exprs.extend(
|
224
236
|
Pyomo2SympyVisitor(symbols_map).walk_expression(constraint_dict[key].expr)
|
@@ -232,15 +244,74 @@ def pyomo2qmod(struct_name: str, pyo_model: ConcreteModel) -> str:
|
|
232
244
|
pyo_objective
|
233
245
|
)
|
234
246
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
247
|
+
return CombinatorialOptimizationStructDeclaration(
|
248
|
+
name=struct_name,
|
249
|
+
variables={str(variable): Integer() for variable in variables},
|
250
|
+
variable_lower_bound=lower_bound,
|
251
|
+
variable_upper_bound=upper_bound,
|
252
|
+
constraints=[
|
253
|
+
Expression(expr=str(constraint_expr))
|
254
|
+
for constraint_expr in constraint_exprs
|
242
255
|
],
|
243
|
-
|
244
|
-
|
256
|
+
objective_type=objective_type_str,
|
257
|
+
objective_function=Expression(expr=str(objective_expr)),
|
258
|
+
)
|
259
|
+
|
260
|
+
|
261
|
+
def pyomo_to_qmod_qstruct(
|
262
|
+
struct_name: str, vars: list[_GeneralVarData]
|
263
|
+
) -> type[QStruct]:
|
264
|
+
qmod_struct = type(struct_name, (QStruct,), {})
|
265
|
+
var_names = {get_field_name(var): var for var in vars}
|
266
|
+
qmod_struct.__annotations__ = {
|
267
|
+
var_name: _get_qmod_field_type(var_name, var_data)
|
268
|
+
for var_name, var_data in var_names.items()
|
245
269
|
}
|
246
|
-
return
|
270
|
+
return qmod_struct
|
271
|
+
|
272
|
+
|
273
|
+
def _get_qmod_field_type(var_name: str, var_data: _GeneralVarData) -> type[QVar]:
|
274
|
+
if var_data.domain not in SUPPORTED_TYPES:
|
275
|
+
raise ClassiqValueError(
|
276
|
+
f"Type {str(var_data.domain)!r} of variable {var_name!r} is not supported"
|
277
|
+
)
|
278
|
+
|
279
|
+
if var_data.domain == pyo.Binary:
|
280
|
+
return QBit
|
281
|
+
|
282
|
+
bounds = var_data.bounds
|
283
|
+
if bounds is None:
|
284
|
+
raise ClassiqValueError(f"Variable {var_name!r} has no bounds")
|
285
|
+
lb, ub = bounds
|
286
|
+
if not isinstance(lb, int) or not isinstance(ub, int):
|
287
|
+
raise ClassiqValueError(
|
288
|
+
f"Non-integer bounds for variable {var_name!r} are not supported"
|
289
|
+
)
|
290
|
+
if lb > 0:
|
291
|
+
ub -= lb
|
292
|
+
qnum: Any = QNum # mypy shenanigans
|
293
|
+
return qnum[math.ceil(math.log2(ub - lb)), False, 0]
|
294
|
+
|
295
|
+
|
296
|
+
def evaluate_objective(
|
297
|
+
var_mapping: dict, sympy_expr: sympy.Expr, struct_obj: Any
|
298
|
+
) -> Any:
|
299
|
+
sympy_assignment = {
|
300
|
+
sympy_var: getattr(struct_obj, field_name)
|
301
|
+
for sympy_var, field_name in var_mapping.items()
|
302
|
+
}
|
303
|
+
|
304
|
+
# classical objective evaluation
|
305
|
+
if not isinstance(struct_obj, QStruct):
|
306
|
+
return float(sympy_expr.evalf(subs=sympy_assignment))
|
307
|
+
|
308
|
+
# quantum objective evaluation
|
309
|
+
expr_str = str(sympy_expr).replace("'", "")
|
310
|
+
for var_name, var_value in sympy_assignment.items():
|
311
|
+
var_name = str(var_name).replace("'", "")
|
312
|
+
expr_str = re.sub(rf"\b{var_name}\b", str(var_value), expr_str)
|
313
|
+
return SymbolicExpr(expr=expr_str, is_quantum=True)
|
314
|
+
|
315
|
+
|
316
|
+
def get_field_name(var: _GeneralVarData) -> str:
|
317
|
+
return var.local_name.replace("[", "_").replace("]", "")
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Optional
|
2
2
|
|
3
3
|
import pyomo.core as pyo
|
4
4
|
from pyomo.core.base import _GeneralVarData
|
@@ -6,7 +6,7 @@ from pyomo.core.expr.sympy_tools import Pyomo2SympyVisitor, PyomoSympyBimap
|
|
6
6
|
from sympy import Expr
|
7
7
|
|
8
8
|
|
9
|
-
def sympyify_vars(variables:
|
9
|
+
def sympyify_vars(variables: list[_GeneralVarData]) -> PyomoSympyBimap:
|
10
10
|
symbols_map = PyomoSympyBimap()
|
11
11
|
for var in variables:
|
12
12
|
Pyomo2SympyVisitor(symbols_map).walk_expression(var)
|