Qubo embedding
import torch
from qubosolver.config import EmbeddingConfig, SolverConfigfrom qubosolver.solver import QUBOInstance, QuboSolverfrom qoolqit import AnalogDevice, DigitalAnalogDeviceimport matplotlib.pyplot as pltplt.rcParams["animation.html"] = "jshtml"import warningswarnings.filterwarnings("ignore", module="matplotlib")
%matplotlib inlineEmbeddings
Section titled “Embeddings”When using quantum approaches, we have to define a map from the instance variables to atoms on a quantum device. We call this step an embedding. This tutorial aims to show small code snippet on how to use the different embedding methods (blade, custom, greedy) as well as how to parametrize the algorithms through the SolverConfig according to a given QUBO matrix.
# import QUBO matrix manuallycoefficients = torch.load("qubo_size_15.pt", weights_only=True)instance = QUBOInstance(coefficients)- Define a
SolverConfigto be passed to any solver
config = SolverConfig(use_quantum=True)For now, the SolverConfig contains parameters according to all available procedures (pre-post processing, embedding, ...). It has a default behavior that is compliant to the minimum requirements to run the workflow, as long as the given QUBO matrix fits with these default paremeters.
If one want to access to the default attributes, it is easily readable through the following:
config.print_specs()config_name: ''
use_quantum: True
embedding: {'embedding_method': <EmbedderType.GREEDY: 'greedy'>, 'draw_steps': False, 'animation_save_path': None, 'greedy_layout': <LayoutType.TRIANGULAR: <class 'pulser.register.special_layouts.TriangularLatticeLayout'>>, 'greedy_traps': 1, 'greedy_spacing': 4.0, 'greedy_density': None}
drive_shaping: {'drive_shaping_method': <DriveType.ADIABATIC: 'adiabatic'>, 'dmm': True}
classical: {'classical_solver_type': 'cplex', 'cplex_maxtime': 600.0, 'cplex_log_path': 'solver.log'}
backend: <qoolqit.execution.backends.LocalEmulator object at 0x12727b190>
device: DigitalAnalogDevice
do_postprocessing: False
do_preprocessing: False
activate_trivial_solutions: True
- Define a
QuboSolver, by passing the instance and the defined configuration
solver = QuboSolver(instance, config)- Call the embedding method according to the provided set of parameters defined by the
SolverConfig.
register = solver.embedding()From the chosen embedding method, we get a set of two-dimensional coordinates that should be embeddable on the register:
register.draw()BLaDE parametrization
Section titled “BLaDE parametrization”Following previous workflow, we can reiterate using a more fined parametrization of the SolverConfig for the blade embedding method.
Here is a code snippet of an arbitrary parametrization of BLaDE using multiple layers of -dimension and a number of steps per round (i.e. number of iteration per layer):
blade_settings = EmbeddingConfig(embedding_method="blade", blade_dimensions=[5 ,4, 3, 2], blade_steps_per_round=300)blade_config = SolverConfig.from_kwargs( use_quantum=True, device=AnalogDevice(), embedding=blade_settings,)
solver = QuboSolver(instance, blade_config)register = solver.embedding()register.draw()Greedy embedder parametrization
Section titled “Greedy embedder parametrization”We do the same using the greedy embedding method, using a triangular lattice layout on a DigitalAnalogDevice with a number of greedy_traps at least equal to the number of variables in the QUBO:
greedy_settings = EmbeddingConfig(embedding_method="greedy", greedy_layout="triangular", greedy_traps=instance.size)
greedy_config = SolverConfig.from_kwargs( use_quantum=True, device=AnalogDevice(), embedding=greedy_settings,)
solver = QuboSolver(instance, greedy_config)register = solver.embedding()register.draw()Custom embedder
Section titled “Custom embedder”If one desires to develop his own embedding method, a subclass of qubosolver.pipeline.embedder.BaseEmbedder should be implemented with a mandatory embed method.
The embed method def embed(self) -> qoolqit.Register specify how the problem is mapped into a register of qubits when running using a quantum device. Let us show a simple example where each variable is mapped into a qubit lying on a horizontal line (with coordinates , normalized by the device specs).
import typingfrom qubosolver.pipeline.embedder import BaseEmbedderfrom qoolqit import Registerfrom qubosolver.config import SolverConfig
class FixedEmbedder(BaseEmbedder):
@typing.no_type_check def embed(self) -> Register: # note `self._distance_conversion` is used to normalize coordinates to fit a device qubits = {f"q{i}": (i / self._distance_conversion ,0) for i in range(self.instance.coefficients.shape[0])} register = Register(qubits) return register
custom_config = SolverConfig.from_kwargs( use_quantum=True, embedding_method=FixedEmbedder,)solver = QuboSolver(instance, custom_config)register = solver.embedding()register.draw()Greedy algorithm - Vizualisation
Section titled “Greedy algorithm - Vizualisation”from qubosolver.solver import QUBOInstance, QuboSolverfrom qubosolver.config import SolverConfig, EmbeddingConfigimport torch
Q = torch.tensor([ [-4.0, 1.0, 2.0, 1.5, 2.3, 0.9, 1.8, 2.7, 1.2], [ 1.0,-3.2, 1.7, 2.1, 0.8, 1.9, 2.2, 1.1, 1.6], [ 2.0, 1.7,-5.1, 0.7, 2.5, 1.3, 2.6, 1.4, 2.0], [ 1.5, 2.1, 0.7,-2.7, 1.2, 2.4, 0.6, 1.8, 2.1], [ 2.3, 0.8, 2.5, 1.2,-6.3, 1.0, 1.7, 2.8, 1.5], [ 0.9, 1.9, 1.3, 2.4, 1.0,-4.5, 2.3, 1.6, 0.9], [ 1.8, 2.2, 2.6, 0.6, 1.7, 2.3,-3.8, 1.2, 2.2], [ 2.7, 1.1, 1.4, 1.8, 2.8, 1.6, 1.2,-5.9, 1.4], [ 1.2, 1.6, 2.0, 2.1, 1.5, 0.9, 2.2, 1.4,-2.4],], dtype=torch.float32)
instance = QUBOInstance(Q)
greedy_settings = EmbeddingConfig( embedding_method="greedy", greedy_layout="triangular", # or "square" greedy_traps=instance.size + 6, greedy_spacing=5.0, draw_steps=True, # ← single toggle animation_save_path="greedy_demo.gif", # ← optional file export)
cfg = SolverConfig.from_kwargs( use_quantum=True, embedding=greedy_settings, device=AnalogDevice(),)
solver = QuboSolver(instance, cfg)geometry = solver.embedding() # → inline animation + optional mp4Animation.save using <class 'matplotlib.animation.PillowWriter'> [anim] GIF saved to: greedy_demo.gif Animation.save using <class 'matplotlib.animation.HTMLWriter'>
The above should display an animation inline:
