Skip to content

Results are limited to the current section : Qoolqit

Embedding

In this section, you will learn how to:

  • understand how problem graphs are mapped into the analog Rydberg model through embedding,
  • use QoolQit embedders to embed graphs, i.e. assigning coordinates to nodes,
  • test whether an embedding satisfies hardware constraints (e.g. unit-disk condition),
  • convert embedded graphs into qubit registers.

Embedding data and problems into the Rydberg analog model is an active area of research. An embedding is typically defined as a structure-preserving mapping fembedding:XYf_\text{embedding}: X \rightarrow Y that transforms an object XX into an object YY. In our context, we seek to develop effective embedding functions that map problem-specific data and structures into representations compatible with the Rydberg analog model.

Currently, QoolQit focuses on register embedders - algorithms that assign coordinates to graph nodes, enabling the creation of qubit registers from abstract graph structures.

In QoolQit, all embedders follow a basic interface. For example, the InteractionEmbedder (discussed in detail later) interface provides the following methods:

from qoolqit import InteractionEmbedder, InteractionEmbedderConfig
# Initialize the embedder
config = InteractionEmbedderConfig()
embedder = InteractionEmbedder(config=config)
# Access information about the embedding algorithm
embedder.info
# Access the configuration of the embedding algorithm
embedder.config
# Embed the data with the embedder
embedded_data = embedder.embed(data)

All the available embedders are listed in following section. For more details on defining custom embedders, the reader can refer to Custom embedders.

Below, we will exemplify how to use some of the pre-defined concrete embedders directly available in QoolQit, and then show some considerations when defining custom embedders.

Interaction embedding means to encode a matrix in the interaction term of the Rydberg analog model. For a matrix UU, the goal is to find the set of coordinates that minimize

min{(x,y)} ijUij1rij6, \min_{\{(x,\, y)\}}~\sum_{ij}\left\|U_{ij}-\frac{1}{r^6_{ij}}\right\|,

where rij=(xixj)2+(yiyj)2r_{ij} = \sqrt{(x_i-x_j)^2 + (y_i-y_j)^2} is the distance between qubits ii and jj. This requires the matrix UU to be positive and symmetric, and only the off-diagonal terms are embedded.

In QoolQit, the InteractionEmbedder performs this minimization using scipy.minimize, and it maps a np.ndarray to a DataGraph with coordinates.

from qoolqit.embedding import InteractionEmbedder
embedder = InteractionEmbedder()
print(embedder)
print(embedder.info)
import numpy as np
A = np.random.rand(6, 6)
A += A.T
print(A)
import matplotlib.pyplot as plt
from qoolqit import Register
embedded_graph = embedder.embed(A)
register = Register.from_graph(embedded_graph)
embedded_graph.draw()
register.draw()
interactions = list(register.interactions().values())
triang_upper = np.triu(A, k = 1)
off_diagonal = triang_upper[triang_upper != 0].tolist()
print([f"{f:.4f}" for f in sorted(interactions)])
print([f"{f:.4f}" for f in sorted(off_diagonal)])

The spring-layout embedding utilizes the Fruchterman-Reingold force-directed algorithm. It assigns spring-like forces to the edges that keep nodes closer, while treating nodes themselves as repelling objects. The system is then simulated until the nodes find an equilibrium position, which represent the final coordinates assigned to the nodes.

In QoolQit, the SpringLayoutEmbedder directly wraps the nx.spring_layout function, and it maps a DataGraph without coordinates to another DataGraph with coordinates.

from qoolqit.embedding import SpringLayoutEmbedder
embedder = SpringLayoutEmbedder()
print(embedder)
print(embedder.info)
embedder.config.iterations = 100
embedder.config.seed = 1
print(embedder)
from qoolqit import DataGraph
graph_1 = DataGraph.random_er(n = 7, p = 0.3, seed = 3)
embedded_graph_1 = embedder.embed(graph_1)
fig, axs = plt.subplots(1, 2)
graph_1.draw(ax=axs[0])
embedded_graph_1.draw(ax=axs[1])
embedded_graph_1.is_ud_graph()
graph_2 = DataGraph.random_er(n = 7, p = 0.8, seed = 3)
embedded_graph_2 = embedder.embed(graph_2)
fig, axs = plt.subplots(1, 2)
graph_2.draw(ax=axs[0])
embedded_graph_2.draw(ax=axs[1])
embedded_graph_2.is_ud_graph()
from qoolqit import Register
register_1 = Register.from_graph(embedded_graph_1)
register_2 = Register.from_graph(embedded_graph_2)
register_1.draw()
register_2.draw()

Coming soon...