Source code for seemps.register.qubo

from __future__ import annotations
import numpy as np
from ..typing import Vector, Operator
from ..state import Strategy, DEFAULT_STRATEGY
from ..operators import MPOList, MPO


[docs] def qubo_mpo( J: Operator | None = None, h: Vector | None = None, strategy: Strategy = DEFAULT_STRATEGY, ) -> 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 : Operator | None Matrix of Ising coupling between qubits (Default value = None) h : Vector | None : Vector of local magnetic fields (Default value = None) strategy : Strategy, default = DEFAULT_STRATEGY 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("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) data[-1] = data[-1][:, :, :, [1]] data[0] = data[0][[0], :, :, :] else: Jmatrix = np.asarray(J) if h is not None: Jmatrix += np.diag(h) L = len(Jmatrix) id2 = np.eye(2) data = [] for i in range(L): A = np.zeros((i + 2, 2, 2, i + 3)) A[0, 1, 1, 1] = Jmatrix[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] = Jmatrix[i, j] + Jmatrix[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, strategy)
[docs] def qubo_exponential_mpo( J: Operator | None = None, h: Vector | None = None, beta: float = -1.0, strategy: Strategy = DEFAULT_STRATEGY, ) -> 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 : Operator | None Matrix of Ising coupling between qubits (Default value = None) h : Vector | None : 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("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, strategy) else: Jmatrix = np.asarray(J) if h is not None: Jmatrix += np.diag(h) Jmatrix = (Jmatrix + Jmatrix.T) / 2 L = len(Jmatrix) 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 * Jmatrix[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 * Jmatrix[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, strategy)) return MPOList(out)