Skip to content

qoolqit.embedding.algorithms.interaction_embedding

[docs] module qoolqit.embedding.algorithms.interaction_embedding

from __future__ import annotations

from dataclasses import dataclass

import numpy as np
from scipy.optimize import minimize
from scipy.spatial.distance import pdist, squareform

from qoolqit.graphs import DataGraph

from ..base_embedder import EmbeddingConfig


@dataclass
class InteractionEmbeddingConfig(EmbeddingConfig):
    """Configuration parameters for the interaction embedding."""

    method: str = "Nelder-Mead"
    maxiter: int = 200000
    tol: float = 1e-8


def interaction_embedding(matrix: np.ndarray, method: str, maxiter: int, tol: float) -> np.ndarray:
    """Matrix embedding into the interaction term of the Rydberg Analog Model.

    Uses scipy.minimize to find the optimal set of node coordinates such that the
    matrix of values 1/(r_ij)^6 approximate the off-diagonal terms of the input matrix.

    Check scipy.minimize documentation for more information on each parameter.

    Arguments:
        matrix: the matrix to embed.
        method: the method used by scipy.minimize.
        maxiter: maximum number of iterations.
        tol: tolerance for termination.
    """

    def cost_function(new_coords: np.ndarray, matrix: np.ndarray) -> np.float:
        """Cost function."""
        new_coords = np.reshape(new_coords, (len(matrix), 2))
        # Cost based on minimizing the distance between the matrix and the interaction 1/r^6
        new_matrix = squareform(1.0 / (pdist(new_coords) ** 6))
        return np.linalg.norm(new_matrix - matrix)

    np.random.seed(0)

    # Initial guess for the coordinates
    x0 = np.random.random(len(matrix) * 2)

    res = minimize(
        cost_function,
        x0,
        args=(matrix,),
        method=method,
        tol=tol,
        options={"maxiter": maxiter, "maxfev": None},
    )

    coords = np.reshape(res.x, (len(matrix), 2))

    centered_coords = coords - np.mean(coords, axis=0)

    graph = DataGraph.from_coordinates(centered_coords.tolist())

    return graph