Skip to content

QUBOInstance

QUBOInstance(coefficients=None, device='cpu', dtype=torch.float32)

Represents a single instance of a Quadratic Unconstrained Binary Optimization (QUBO) problem.

ATTRIBUTE DESCRIPTION
coefficients

Tensor of shape (size, size), representing the QUBO coefficients.

TYPE: Tensor

device

Device where tensors are allocated (e.g., "cpu" or "cuda").

TYPE: str

dtype

Data type of the tensors (e.g., torch.float32).

TYPE: dtype

solution

Solution to the QUBO problem, if available.

TYPE: QUBOSolution | None

density

Fraction of non-zero entries in the coefficient matrix.

TYPE: float | None

density_type

Classification of the density (e.g., sparse, dense).

TYPE: DensityType | None

Initializes a QUBOInstance.

PARAMETER DESCRIPTION
coefficients

Coefficients of the QUBO problem. Can be a dictionary, array-like object, or None.

TYPE: dict | ArrayLike | None DEFAULT: None

device

Device where tensors are allocated (default: "cpu").

TYPE: str DEFAULT: 'cpu'

dtype

Data type of the tensors (default: torch.float32).

TYPE: dtype DEFAULT: float32

Source code in qubosolver/qubo_instance.py
def __init__(
    self,
    coefficients: dict | ArrayLike | None = None,
    device: str = "cpu",
    dtype: torch.dtype = torch.float32,
):
    """
    Initializes a QUBOInstance.

    Args:
        coefficients (dict | ArrayLike | None):
            Coefficients of the QUBO problem. Can be a dictionary, array-like object, or None.
        device (str):
            Device where tensors are allocated (default: "cpu").
        dtype (torch.dtype):
            Data type of the tensors (default: torch.float32).
    """
    self._coefficients: torch.Tensor = torch.zeros([0, 0], dtype=dtype, device=device)
    self.solution: QUBOSolution | None = None
    self.density: float | None = None
    self.density_type: DensityType | None = None

    if coefficients is None:
        self.coefficients = self._coefficients
    else:
        self.coefficients = coefficients

coefficients property writable

Getter for the QUBO coefficient matrix.

RETURNS DESCRIPTION
Tensor

torch.Tensor: Tensor of shape (size, size) representing the QUBO coefficients.

device property

Get the device on which the coefficient tensor is stored.

RETURNS DESCRIPTION
device

torch.device: The device (e.g., device("cpu") or device("cuda:0")).

dtype property

Get the data type of the coefficient tensor.

RETURNS DESCRIPTION
dtype

torch.dtype: The dtype (e.g., torch.float32).

normalized_coefficients property

Return the coefficient matrix normalised by the maximum off-diagonal value.

All coefficients are divided by _max_off_diag so that the largest off-diagonal entry becomes 1.0. Useful for embedding algorithms that require unit-scaled interactions.

RETURNS DESCRIPTION
Tensor

torch.Tensor: Normalised coefficient matrix of shape (size, size).

size property

Get the size of the QUBO matrix (number of variables).

RETURNS DESCRIPTION
int

Size of the QUBO matrix.

TYPE: int

__repr__()

Returns a string representation of the QUBOInstance.

RETURNS DESCRIPTION
str

A dictionary-like string summarizing the instance.

TYPE: str

Source code in qubosolver/qubo_instance.py
def __repr__(self) -> str:
    """
    Returns a string representation of the QUBOInstance.

    Returns:
        str: A dictionary-like string summarizing the instance.
    """
    return repr(
        f"QUBOInstance of size = {self.size},"
        f"density = {round(self.density, 2) if self.density else None},"
    )

evaluate_solution(solution)

Evaluates a solution for the QUBO problem.

PARAMETER DESCRIPTION
solution

Solution vector to evaluate.

TYPE: list | tuple | ArrayLike

RETURNS DESCRIPTION
float

The cost of the given solution.

TYPE: float

RAISES DESCRIPTION
ValueError

If the solution size does not match the QUBO size.

Source code in qubosolver/qubo_instance.py
def evaluate_solution(self, solution: list | tuple | ArrayLike) -> float:
    """
    Evaluates a solution for the QUBO problem.

    Args:
        solution (list | tuple | ArrayLike):
            Solution vector to evaluate.

    Returns:
        float:
            The cost of the given solution.

    Raises:
        ValueError: If the solution size does not match the QUBO size.
    """
    solution_tensor = convert_to_tensor(solution, device=self.device, dtype=self.dtype)  # type: ignore[arg-type]
    if solution_tensor.size(0) != self.size:
        raise ValueError("Solution size does not match the QUBO problem size.")
    cost = torch.matmul(
        solution_tensor, torch.matmul(self._coefficients, solution_tensor)
    ).item()
    solution = solution_tensor
    return float(cost)

load(file_like) staticmethod

Deserialises a QUBOInstance from a binary file-like object.

Reconstructs the instance from a file previously created with QUBOInstance.save.

PARAMETER DESCRIPTION
file_like

A file-like object opened in binary read mode containing the serialised QUBOInstance data.

TYPE: FileLike[bytes]

RETURNS DESCRIPTION
QUBOInstance

A new QUBOInstance reconstructed from the file.

TYPE: QUBOInstance

Example

with open("instance.bin", "rb") as f: ... instance = QUBOInstance.load(f)

Source code in qubosolver/qubo_instance.py
@staticmethod
def load(file_like: io_utils.FileLike[bytes]) -> QUBOInstance:
    """
    Deserialises a QUBOInstance from a binary file-like object.

    Reconstructs the instance from a file previously created with
    `QUBOInstance.save`.

    Args:
        file_like (io_utils.FileLike[bytes]): A file-like object opened in
            binary read mode containing the serialised QUBOInstance data.

    Returns:
        QUBOInstance: A new QUBOInstance reconstructed from the file.

    Example:
        >>> with open("instance.bin", "rb") as f:
        ...     instance = QUBOInstance.load(f)
    """
    with io_utils.open(file_like, "rb") as f:
        # torch.load might consume too much of the src buffer.
        # Use a dedicated limited buffer.
        buffer = io.BytesIO(io_utils.load_sized_buffer(f))
        Q = torch.load(buffer, weights_only=True)

    return QUBOInstance(Q)

save(file_like, instance) staticmethod

Serialises a QUBOInstance to a binary file-like object.

Uses torch.save internally to persist the coefficient tensor.

PARAMETER DESCRIPTION
file_like

A file-like object opened in binary write mode (e.g., an open file or a BytesIO buffer).

TYPE: FileLike[bytes]

instance

The QUBOInstance to serialise.

TYPE: QUBOInstance

RETURNS DESCRIPTION
None

None

Example

with open("instance.bin", "wb") as f: ... QUBOInstance.save(f, my_instance)

Source code in qubosolver/qubo_instance.py
@staticmethod
def save(file_like: io_utils.FileLike[bytes], instance: QUBOInstance) -> None:
    """
    Serialises a QUBOInstance to a binary file-like object.

    Uses `torch.save` internally to persist the coefficient tensor.

    Args:
        file_like (io_utils.FileLike[bytes]): A file-like object opened in
            binary write mode (e.g., an open file or a BytesIO buffer).
        instance (QUBOInstance): The QUBOInstance to serialise.

    Returns:
        None

    Example:
        >>> with open("instance.bin", "wb") as f:
        ...     QUBOInstance.save(f, my_instance)
    """
    with io_utils.open(file_like, "wb") as f:
        buffer = io.BytesIO()
        torch.save(instance.coefficients, buffer)
        io_utils.save_sized_buffer(f, buffer.getbuffer())

set_coefficients(new_coefficients=None)

Updates the coefficients of the QUBO problem.

PARAMETER DESCRIPTION
new_coefficients

Dictionary of new coefficients to set. Keys are (row, column) tuples.

TYPE: dict[tuple[int, int], float] | None DEFAULT: None

Source code in qubosolver/qubo_instance.py
def set_coefficients(
    self, new_coefficients: dict[tuple[int, int], float] | None = None
) -> None:
    """
    Updates the coefficients of the QUBO problem.

    Args:
        new_coefficients (dict[tuple[int, int], float] | None):
            Dictionary of new coefficients to set. Keys are (row, column) tuples.
    """
    if not new_coefficients:
        return

    max_index = max(max(i, j) for i, j in new_coefficients.keys())
    if max_index >= self.size:
        self._expand_size(max_index + 1)

    indices = torch.tensor(list(new_coefficients.keys()), dtype=torch.long, device=self.device)
    values = torch.tensor(list(new_coefficients.values()), dtype=self.dtype, device=self.device)
    self._coefficients[indices[:, 0], indices[:, 1]] = values
    off_diagonal_mask = indices[:, 0] != indices[:, 1]
    symmetric_indices = indices[off_diagonal_mask]
    self._coefficients[symmetric_indices[:, 1], symmetric_indices[:, 0]] = values[
        off_diagonal_mask
    ]

    self.update_metrics()

update_metrics()

Updates the density metrics of the QUBO problem.

Source code in qubosolver/qubo_instance.py
def update_metrics(self) -> None:
    """
    Updates the density metrics of the QUBO problem.
    """
    if self.size > 0:
        self.density = calculate_density(self._coefficients, self.size)
        self.density_type = classify_density(self.density)
    else:
        self.density = self.density_type = None