Solving a Quadratic Unconstrained Binary Optimization instance¶
Solving a QUBO instance is straightforward with qubo-solver
. We can directly use the QuboSolver
class by providing a QUBOInstance
with a given SolverConfig
configuration.
SolverConfig
specifies whether to use a classical approach or a quantum one. Note that SolverConfig
comes with many options but the default ones can be used straightforwardly.
We have however more advanced tutorials on the quantum-related components to dive deeper into these advanced concepts.
Solving with a quantum approach¶
To use a quantum approach, several choices have to be made regarging the configuration, explained in more details in the SolverConfig
section of the documentation.
One main decision is about the backend, that is how we choose to perform quantum runs. We can decide to either perform our on emulators (locally, or remotely) or using a real quantum processing unit (QPU). Our QPU, based on the Rydberg Analog Model, is accessible remotely.
Available backend types and devices¶
The list of backend types available can be found via the BackendType
enumeration from Qooqit
, a Python package designed for algorithm development in the Rydberg Analog Model.
from qoolqit._solvers.types import BackendType
all_backends = BackendType.list()
print('Local Backends: ', list(filter(lambda b: 'remote' not in b, all_backends)))
print('Remote Backends: ', list(filter(lambda b: 'remote' in b, all_backends)))
Local Backends: ['qutip', 'emu_mps', 'emu_sv'] Remote Backends: ['remote_qpu', 'remote_emumps', 'remote_emutn', 'remote_emufree']
The backends can be divided into 3 main categories:
- Local emulators (Qutip, Emu_mps, Emu_sv, ...),
- Remote emulators), which can be accessed via
pasqal_cloud
, - A remote QPU, such as Fresnel.
For emulators, we use device specifications when performing quantum runs via DeviceType
:
from qoolqit._solvers.types import DeviceType
print([e.value for e in DeviceType])
[AnalogDevice, DigitalAnalogDevice]
Running locally with an emulator¶
We can perform quantum simulations locally via an emulator (here, we choose the BackendType.QUTIP
emulator).
import torch
from qubosolver import QUBOInstance
from qubosolver.config import SolverConfig
from qubosolver.solver import QuboSolver
from qoolqit._solvers.data import BackendConfig
from qoolqit._solvers.types import BackendType
# define QUBO
Q = torch.tensor([[1.0, 0.0], [0.0, 1.0]])
instance = QUBOInstance(coefficients=Q)
# Create a SolverConfig object to use a quantum backend
config = SolverConfig(use_quantum=True, backend_config = BackendConfig(backend=BackendType.QUTIP))
# Instantiate the quantum solver.
solver = QuboSolver(instance, config)
# Solve the QUBO problem.
solution = solver.solve()
Running with a remote connection¶
We can decide to perform our runs remotely via pasqal_cloud
.
To do so, we have to provide several information after setting up an account.
On a real QPU¶
The code above can be modified to solve the QUBO instance using our real QPU remotely as follows (run only with your pasqal_cloud
information):
# import torch
# from qubosolver import QUBOInstance
# from qubosolver.config import SolverConfig
# from qubosolver.solver import QuboSolver
# from qoolqit._solvers.data import BackendConfig
# from qoolqit._solvers.types import BackendType, DeviceType
# # define QUBO
# Q = torch.tensor([[1.0, 0.0], [0.0, 1.0]])
# instance = QUBOInstance(coefficients=Q)
# # define a remote backend
# backendconf = BackendConfig(backend=BackendType.REMOTE_QPU, username='#TO_PROVIDE', password='#TO_PROVIDE', project_id='#TO_PROVIDE')
# # Instantiate the quantum solver.
# solver = QuboSolver(instance, backend_config=backendconf)
# # Solve the QUBO problem.
# solution = solver.solve()
On a remote emulators¶
Emulators are also available remotely.
Note that the default device set for remote connections is our QPU, but for emulators, you can specify a DeviceType
as follows:
# import torch
# from qubosolver import QUBOInstance
# from qubosolver.config import SolverConfig
# from qubosolver.solver import QuboSolver
# from qoolqit._solvers.data import BackendConfig
# from qoolqit._solvers.types import BackendType, DeviceType
# # define QUBO
# Q = torch.tensor([[1.0, 0.0], [0.0, 1.0]])
# instance = QUBOInstance(coefficients=Q)
# # define a remote backend
# backendconf = BackendConfig(backend=BackendType.REMOTE_EMUFREE, device=DeviceType.DIGITAL_ANALOG_DEVICE, username='#TO_PROVIDE', password='#TO_PROVIDE', project_id='#TO_PROVIDE')
# # Instantiate the quantum solver.
# solver = QuboSolver(instance, backend_config=backendconf)
# # Solve the QUBO problem.
# solution = solver.solve()
Solving with a classical approach¶
We show below an example of solving a QUBO using CPLEX.
More information on classical approaches can be found in the Classical solvers
section of the Contents
documentation.
import torch
from qubosolver import QUBOInstance
from qubosolver.solver import QuboSolver
from qubosolver.config import ClassicalConfig, SolverConfig
from qubosolver.solver import QuboSolverClassical, QuboSolverQuantum
# define QUBO
Q = torch.tensor([[1.0, 0.0], [0.0, 1.0]])
instance = QUBOInstance(coefficients=Q)
# Create a SolverConfig object with classical solver options.
classical_config = ClassicalConfig(
classical_solver_type="cplex",
cplex_maxtime=10.0,
cplex_log_path="test_solver.log",
)
config = SolverConfig(use_quantum=False, classical=classical_config)
# Instantiate the classical solver via the pipeline's classical solver dispatcher.
classical_solver = QuboSolver(instance, config)
# Solve the QUBO problem.
solution = classical_solver.solve()