Source code for seemps.register.qubo

from __future__ import annotations
import numpy as np
from typing import Union, Optional
from ..typing import Vector, Operator
from ..mpo import MPOList, MPO


[docs] def qubo_mpo( J: Optional[Operator] = None, h: Optional[Vector] = None, **kwdargs ) -> MPO: """Return the MPO associated to a QUBO operator. The operator is defined according to the mathematical notation :math:`\\sum_i J_{ij} s_i s_j + \\sum_i h_i s_i`, with the matrix of interactions 'J' and the vector of local fields 'h'. At least one of these must be provided. Parameters ---------- J : Optional[Operator] Matrix of Ising coupling between qubits (Default value = None) h : Optional[Vector] : Vector of local magnetic fields (Default value = None) **kwdargs : Other arguments accepted by :class:`MPO` Returns ------- MPO Matrix-product operator implementing this Hamiltonian """ if J is None: # # Just magnetic field. A much simpler operator if h is None: raise Exception("In QUBO_MPO, must provide either J or h") # data = [] id2 = np.eye(2) for i, hi in enumerate(h): A = np.zeros((2, 2, 2, 2), dtype=hi.dtype) A[0, 1, 1, 1] = hi A[1, :, :, 1] = id2 A[0, :, :, 0] = id2 data.append(A) A = A[:, :, :, [1]] data[-1] = A data[0] = data[0][[0], :, :, :] else: if h is not None: J = J + np.diag(h) L = len(J) id2 = np.eye(2) data = [] for i in range(L): A = np.zeros((i + 2, 2, 2, i + 3)) A[0, 1, 1, 1] = J[i, i] A[1, :, :, 1] = np.eye(2) A[0, :, :, 0] = np.eye(2) A[0, 1, 1, i + 2] = 1.0 for j in range(i): A[j + 2, 1, 1, 1] = J[i, j] + J[j, i] A[j + 2, :, :, j + 2] = np.eye(2) data.append(A) data[-1] = data[-1][:, :, :, [1]] data[0] = data[0][[0], :, :, :] return MPO(data, **kwdargs)
[docs] def qubo_exponential_mpo( J: Optional[Operator] = None, h: Optional[Vector] = None, beta: float = -1.0, **kwdargs, ) -> Union[MPO, MPOList]: """Return the MPO associated to the exponential $\\exp(\\beta H)$ of a QUBO operator. The QUBO operator is defined as a sum of longitudinal couplings and magnetic fields :math:`H = \\sum_i J_{ij} s_i s_j + \\sum_i h_i s_i` described by the interaction matrix `J` and the vector field `h`. At least one of these must be provided. Parameters ---------- J : Optional[Operator] Matrix of Ising coupling between qubits (Default value = None) h : Optional[Vector] : Vector of local magnetic fields (Default value = None) beta : float : Exponential prefactor (Default value = -1.0) **kwdargs : Other arguments accepted by :class:`MPO` Returns ------- MPOList | MPO MPO or set of them to implement the exponential of an Ising interaction. """ if J is None: # # Just magnetic field. A much simpler operator if h is None: raise Exception("In QUBO_MPO, must provide either J or h") # data = [] for i, hi in enumerate(h): A = np.zeros((1, 2, 2, 1)) A[0, 1, 1, 1] = np.exp(beta * hi) A[0, 0, 0, 0] = 1.0 data.append(A) return MPO(data, **kwdargs) else: if h is not None: J = J + np.diag(h) J = (J + J.T) / 2 L = len(J) noop = np.eye(2).reshape(1, 2, 2, 1) out = [] for i in range(L): data = [noop] * i A = np.zeros((1, 2, 2, 2)) A[0, 1, 1, 1] = np.exp(beta * J[i, i]) A[0, 0, 0, 0] = 1.0 for j in range(i + 1, L): A = np.zeros((2, 2, 2, 2)) A[1, 1, 1, 1] = np.exp(beta * J[i, j]) A[1, 0, 0, 1] = 1.0 A[0, 0, 0, 0] = 1.0 A[0, 1, 1, 0] = 1.0 data.append(A) data[-1] = A[:, :, :, [0]] + A[:, :, :, [1]] out.append(MPO(data, **kwdargs)) return MPOList(out)