def multi_particle(H: sparse.coo_matrix) -> pyquil.paulis.PauliSum: """ Creates a Qubit-operator from a (sparse) matrix. This function uses (almost) all states and, thus, requires (approximately) log(N) qubits for an N-dimensional Hilbert space. The idea for converting a matrix element to an operator is to raise/lower the qubits differing between two states to convert one basis-state to the other. The qubits that are not negated must be checked to have the correct value (using an analogue of the counting operator) to not get extra terms (one could perhaps allow for extra terms and compensate for them later?). 0 = up 1 = down (1+Zi)/2 checks that qubit i is 0 (up) (1-Zi)/2 checks that qubit i is 1 (down) (Xi+1j*Yi)/2 lowers qubit from 1 (down) to 0 (up) (Xi-1j*Yi)/2 raises qubit from 0 (up) to 1 (down) @author: Joel :param H: An array (array-like) representing the hamiltonian. :return: Hamiltonian as PyQuil PauliSum. """ # Convert to sparse coo_matrix if not sparse.issparse(H): H = sparse.coo_matrix(H) elif H.getformat() != "coo": H = H.tocoo() # The main part of the function H_op = QubitOperator() for i, j, data in zip(H.row, H.col, H.data): new_term = QubitOperator(()) # = I for qubit in range(int.bit_length(H.shape[0] - 1)): if (i ^ j) & (1 << qubit): # lower/raise qubit new_term *= QubitOperator((qubit, "X"), 1 / 2) + \ QubitOperator((qubit, "Y"), 1j * (int( j & (1 << qubit) != 0) - 1 / 2)) else: # check that qubit has correct value (same as i and j) new_term *= QubitOperator((), 1 / 2) + \ QubitOperator((qubit, "Z"), 1 / 2 - int(j & (1 << qubit) != 0)) H_op += data * new_term return qubitop_to_pyquilpauli(H_op)
def meanFilterSparse(a: sp.coo_matrix, h: int): """Apply a mean filter to an input sparse matrix. This convolves the input with a kernel of size 2*h + 1 with constant entries and subsequently reshape the output to be of the same shape as input Args: a: `sp.coo_matrix`, Input matrix to be filtered h: `int` half-size of the filter Returns: `sp.coo_matrix` filterd matrix """ assert h > 0, "meanFilterSparse half-size must be greater than 0" assert sp.issparse(a) and a.getformat() == 'coo',\ "meanFilterSparse input matrix is not scipy.sparse.coo_matrix" assert a.shape[0] == a.shape[1],\ "meanFilterSparse cannot handle non-square matrix" fSize = 2 * h + 1 # filter is a square matrix of constant 1 of shape (fSize, fSize) shapeOut = np.array(a.shape) + fSize - 1 mToeplitz = sp.diags(np.ones(fSize), np.arange(-fSize + 1, 1), shape=(shapeOut[1], a.shape[1]), format='csr') ans = sp.coo_matrix((mToeplitz @ a) @ mToeplitz.T) # remove the edges since we don't care about them if we are smoothing # the matrix itself ansNoEdge = ans.tocsr()[h:(h + a.shape[0]), h:(h + a.shape[1])].tocoo() # Assign different number of neighbors to the edge to better # match what the original R implementation of HiCRep does rowDist2Edge = np.minimum(ansNoEdge.row, ansNoEdge.shape[0] - 1 - ansNoEdge.row) nDim1 = h + 1 + np.minimum(rowDist2Edge, h) colDist2Edge = np.minimum(ansNoEdge.col, ansNoEdge.shape[1] - 1 - ansNoEdge.col) nDim2 = h + 1 + np.minimum(colDist2Edge, h) nNeighbors = nDim1 * nDim2 ansNoEdge.data /= nNeighbors return ansNoEdge