Solver Class

It interface the problems with the quantum solvers.

Supported solvers

The framework currently supports the following solvers:ù

  • D-Wave quantum annealer

  • D-Wave simulated annealer

  • qiskit Quantum Approximate Optimization Algorithm (QAOA)

  • qiskit Variational Quantum Eigensolver (VQE)

  • qiskit Grover Adaptive Search (GAS)

Solver Selection and Configuration

The class provides for exploiting the solver:

  • solve_simulated_annealing(

    problem: Problem, auto_setting: bool = False, beta_range: list[float] | None = None, num_reads: int = 100, annealing_time: int = 100, num_sweeps_per_beta: int = 1, beta_schedule_type: str = “geometric”, seed: int | None = None, initial_states: SampleSet | None = None, initial_states_generator: str = “random”, max_lambda_update: int = 5, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False,

    )Solve the problem using the simulated annealer. The parameters are:
    • problem: the problem to solve

    • auto_setting: if True, the parameters are automatically set

    • beta_range: the range of beta values to use

    • num_reads: the number of reads

    • annealing_time: the annealing time

    • num_sweeps_per_beta: the number of sweeps per beta

    • beta_schedule_type: the beta schedule type

    • seed: the seed

    • initial_states: the initial states

    • initial_states_generator: the initial states generator

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

  • solve_dwave_quantum_annealer(

    problem: Problem, token: str, auto_setting: bool = False, failover: bool = True, config_file: str | None = None, endpoint: str | None = None, solver: dict[str, str] | str = “Advantage_system4.1”, annealing_time_scheduling: float | list[list[float]] = 20.0, num_reads: int = 100, auto_scale: bool = True, flux_drift_compensation: bool = True, initial_state: dict[str, int] | None = None, programming_thermalization: float = 1000.0, readout_thermalization: float = 0.0, reduce_intersample_correlation: bool = True, max_lambda_update: int = 5, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False, save_compilation_time: bool = False,

    )Solve the problem using the D-Wave quantum annealer. The parameters are:
    • problem: the problem to solve

    • token: the token to access the D-Wave API

    • auto_setting: if True, the parameters are automatically set

    • failover: if True, the failover is enabled

    • config_file: the configuration file

    • endpoint: the endpoint

    • solver: the solver to use

    • annealing_time_scheduling: the annealing time scheduling

    • num_reads: the number of reads

    • auto_scale: if True, the problem is automatically scaled

    • flux_drift_compensation: if True, the flux drift compensation is enabled

    • initial_state: the initial state

    • programming_thermalization: the programming thermalization

    • readout_thermalization: the readout thermalization

    • reduce_intersample_correlation: if True, the intersample correlation is reduced

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

  • solve_grover_adaptive_search_qubo(

    problem: Problem, auto_setting: bool = False, qubit_values: int = 0, coeff_precision: float = 1.0, threshold: int = 10, num_runs: int = 10, max_lambda_update: int = 5, boundaries_estimation_method: str = “”, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False, save_compilation_time: bool = False,

    )Solve the problem using the Grover Adaptive Search. The parameters are:
    • problem: the problem to solve

    • auto_setting: if True, the parameters are automatically set

    • qubit_values: the number of qubit values, if the user want to specify it manually

    • coeff_precision: the coefficient precision

    • threshold: the threshold

    • num_runs: the number of runs

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • boundaries_estimation_method: the boundaries estimation method for estimating the necessary number of qubit value

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

  • solve_qaoa_qubo(

    problem: Problem, auto_setting: bool = False, num_runs: int = 10, optimizer: Optimizer | None = None, reps: int = 1, initial_state: QuantumCircuit | None = None, mixer: QuantumCircuit = None, initial_point: np.ndarray[Any, Any] | None = None, aggregation: float | Callable[[list[float]], float] | None = None, callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, max_lambda_update: int = 5, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False, save_compilation_time: bool = False,

    )Solve the problem using the Quantum Approximate Optimization Algorithm. The parameters are:
    • problem: the problem to solve

    • auto_setting: if True, the parameters are automatically set

    • num_runs: the number of runs

    • optimizer: the optimizer

    • reps: the number of repetitions

    • initial_state: the initial state

    • mixer: the mixer

    • initial_point: the initial point

    • aggregation: the aggregation function

    • callback: the callback function

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

  • solve_vqe_qubo(

    self, problem: Problem, auto_setting: bool = False, num_runs: int = 10, optimizer: Optimizer | None = None, ansatz: QuantumCircuit | None = None, initial_point: np.ndarray[Any, Any] | None = None, aggregation: float | Callable[[list[float]], float] | None = None, callback: Callable[[int, np.ndarray[Any, Any], float, float], None] | None = None, max_lambda_update: int = 5, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False, save_compilation_time: bool = False,

    )Solve the problem using the Variational Quantum Eigensolver. The parameters are:
    • problem: the problem to solve

    • auto_setting: if True, the parameters are automatically set

    • num_runs: the number of runs

    • optimizer: the optimizer

    • ansatz: the ansatz

    • initial_point: the initial point

    • aggregation: the aggregation function

    • callback: the callback function

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

For each of them, the outcome is a Solution object.

Best Solver Prediction:

  • solve(

    self, problem: Problem, num_runs: int = 10, coeff_precision: float = 1.0, token: str = “”, max_lambda_update: int = 5, lambda_update_mechanism: str = “sequential penalty increase”, lambda_strategy: str = “upper lower bound posiform and negaform method”, lambda_value: float = 1.0, save_time: bool = False, save_compilation_time: bool = False,

    ) -> Solution | bool | None: Solve the problem using the best solver. The parameters are:
    • problem: the problem to solve

    • num_runs: the number of trial

    • coeff_precision: the wanted precision for coefficients (in case of Grover Adaptive Search)

    • token: the token to access the D-Wave API

    • max_lambda_update: the maximum lambda update if the constraints are not satisfied

    • lambda_update_mechanism: the lambda update mechanism among:
      • sequential penalty increase

      • scaled sequential penalty increase

      • binary search penalty algorithm

    • lambda_strategy: for selecting the lambda generation mechanisms

    • save_time: if save the time required for solver execution

    • save_compilation_time: if save the time required for compilation

Examples:

Simulated Annealing

from mqt.qao.constraints import Constraints
from mqt.qao.variables import Variables
from mqt.qao.objectivefunction import ObjectiveFunction
from mqt.qao.problem import Problem
from mqt.qao.solver import Solver

variables = Variables()
m1 = variables.add_continuous_variables_array(
    "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2"
)
m2 = variables.add_continuous_variables_array(
    "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2"
)
objective_function = ObjectiveFunction()
objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0))
constraint = Constraints()
constraint.add_constraint(constraint_expr, variable_precision=True)
problem = Problem()
problem.create_problem(variables, constraint, objective_function)
solver = Solver()
solution = solver.solve_simulated_annealing(
    problem,
    max_lambda_update=max_lambda_update,
    lambda_update_mechanism=lambda_update,
    lambda_strategy=lambda_strategy,
)

Quantum Annealing

from mqt.qao.constraints import Constraints
from mqt.qao.variables import Variables
from mqt.qao.objectivefunction import ObjectiveFunction
from mqt.qao.problem import Problem
from mqt.qao.solver import Solver

variables = Variables()
m1 = variables.add_continuous_variables_array(
    "M1", [1, 2], -1, 2, -1, "uniform", "logarithmic 2"
)
m2 = variables.add_continuous_variables_array(
    "M2", [2, 1], -1, 2, -1, "uniform", "logarithmic 2"
)
objective_function = ObjectiveFunction()
objective_function.add_objective_function(np.matmul(m1, m2).item(0, 0))
constraint = Constraints()
constraint.add_constraint(constraint_expr, variable_precision=True)
problem = Problem()
problem.create_problem(variables, constraint, objective_function)
solver = Solver()
solution = solver.solve_dwave_quantum_annealer(
    token,
    problem,
    max_lambda_update=max_lambda_update,
    lambda_update_mechanism=lambda_update,
    lambda_strategy=lambda_strategy,
)

Quantum Approximate Optimization Algorithm

from mqt.qao.constraints import Constraints
from mqt.qao.variables import Variables
from mqt.qao.objectivefunction import ObjectiveFunction
from mqt.qao.problem import Problem
from mqt.qao.solver import Solver

variables = Variables()
constraint = Constraints()
a0 = variables.add_binary_variable("a")
b0 = variables.add_binary_variable("b")
c0 = variables.add_binary_variable("c")
cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0)
objective_function = ObjectiveFunction()
objective_function.add_objective_function(cost_function)
problem = Problem()
problem.create_problem(variables, constraint, objective_function)
solver = Solver()
solution = solver.solve_qaoa_qubo(
    problem,
    num_runs=10,
)

Variational Quantum Eigensolver

from mqt.qao.constraints import Constraints
from mqt.qao.variables import Variables
from mqt.qao.objectivefunction import ObjectiveFunction
from mqt.qao.problem import Problem
from mqt.qao.solver import Solver

variables = Variables()
constraint = Constraints()
a0 = variables.add_binary_variable("a")
b0 = variables.add_binary_variable("b")
c0 = variables.add_binary_variable("c")
cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0)
objective_function = ObjectiveFunction()
objective_function.add_objective_function(cost_function)
problem = Problem()
problem.create_problem(variables, constraint, objective_function)
solver = Solver()
solution = solver.solve_vqe_qubo(
    problem,
    num_runs=10,
)

Predicted Best Solver

from mqt.qao.constraints import Constraints
from mqt.qao.variables import Variables
from mqt.qao.objectivefunction import ObjectiveFunction
from mqt.qao.problem import Problem
from mqt.qao.solver import Solver

variables = Variables()
constraint = Constraints()
a0 = variables.add_binary_variable("a")
b0 = variables.add_binary_variable("b")
c0 = variables.add_binary_variable("c")
cost_function = cast(Expr, -a0 + 2 * b0 - 3 * c0 - 2 * a0 * c0 - 1 * b0 * c0)
objective_function = ObjectiveFunction()
objective_function.add_objective_function(cost_function)
problem = Problem()
problem.create_problem(variables, constraint, objective_function)
solver = Solver()
solution = solver.solve(
    problem,
    num_runs=10,
)