def rotate_rho(self, basis, space, Z, unitaries, rho=None): r"""Computes the density matrix rotated into some basis :param basis: The basis into which to rotate the density matrix :type basis: numpy.ndarray :param space: The Hilbert space of the system :type space: torch.Tensor :param unitaries: A dictionary of unitary matrices associated with rotation into each basis :type unitaries: dict[str, torch.Tensor] :returns: The rotated density matrix :rtype: torch.Tensor """ rho = self.rhoRBM(space, space) if rho is None else rho unitaries = {k: v for k, v in unitaries.items()} us = [unitaries[b] for b in basis] if len(us) == 0: return rho # After ensuring there is more than one measurement, compute the # composite unitary by repeated Kronecker products U = us[0] for index in range(len(us) - 1): U = cplx.kronecker_prod(U, us[index + 1]) U = U.to(rho) U_dag = cplx.conjugate(U) rot_rho = cplx.matmul(rho, U_dag) rot_rho_ = cplx.matmul(U, rot_rho) return rot_rho_
def test_rotate_rho(num_visible, state_type): nn_state = state_type(num_visible, gpu=False) basis = "X" * num_visible unitary_dict = create_dict() space = nn_state.generate_hilbert_space() rho = nn_state.rho(space, space) rho_r_fast = rotate_rho(nn_state, basis, space, unitary_dict, rho=rho) U = reduce(cplx.kronecker_prod, [unitary_dict[b] for b in basis]) rho_r_correct = cplx.matmul(U, rho) rho_r_correct = cplx.matmul(rho_r_correct, cplx.conjugate(U)) assertAlmostEqual(rho_r_fast, rho_r_correct, msg="Fast rho rotation failed!")
def test_matrix_matrix_matmul(self): matrix1 = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.double) matrix2 = torch.tensor([[[1, 0], [3, 0]], [[0, 6], [0, 8]]], dtype=torch.double) expect = torch.tensor( [[[7, -78], [15, -106]], [[23, 22], [31, 50]]], dtype=torch.double ) self.assertTensorsEqual( cplx.matmul(matrix1, matrix2), expect, msg="Matrix * Matrix multiplication failed!", )
def test_matrix_vector_matmul(self): matrix = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.double) vector = torch.tensor([[1, 2], [3, 4]], dtype=torch.double) expect = torch.tensor([[-34, -42], [28, 48]], dtype=torch.double) self.assertTensorsEqual( cplx.matmul(matrix, vector), expect, msg="Matrix * Vector multiplication failed!", )
def test_rotate_psi(num_visible, wvfn_type): nn_state = wvfn_type(num_visible, gpu=False) basis = "X" * num_visible unitary_dict = create_dict() space = nn_state.generate_hilbert_space() psi = nn_state.psi(space) psi_r_fast = rotate_psi(nn_state, basis, space, unitary_dict, psi=psi) U = reduce(cplx.kronecker_prod, [unitary_dict[b] for b in basis]) psi_r_correct = cplx.matmul(U, psi) assertAlmostEqual(psi_r_fast, psi_r_correct, msg="Fast psi rotation failed!")
def rotate_psi(nn_state, basis, space, unitaries, psi=None): r"""A function that rotates the reconstructed wavefunction to a different basis. :param nn_state: The neural network state (i.e. complex wavefunction or positive wavefunction). :type nn_state: qucumber.nn_states.WaveFunctionBase :param basis: The basis to rotate the wavefunction to. :type basis: str :param space: The basis elements of the Hilbert space of the system :math:`\mathcal{H}`. :type space: torch.Tensor :param unitaries: A dictionary of (2x2) unitary operators. :type unitaries: dict(str, torch.Tensor) :param psi: A wavefunction that the user can input to override the neural network state's wavefunction. :type psi: torch.Tensor :returns: A wavefunction in a new basis. :rtype: torch.Tensor """ psi = ( nn_state.psi(space) if psi is None else psi.to(dtype=torch.double, device=nn_state.device) ) unitaries = {k: v.to(device=nn_state.device) for k, v in unitaries.items()} us = [unitaries[b] for b in basis] n_u = [u.size()[0] for u in us] l, r = np.prod(n_u), 1 # noqa: E741 psi_r = psi.clone() for s in reversed(range(len(n_u))): l //= n_u[s] # noqa: E741 m = us[s] for k in range(l): for i in range(r): slc = slice(k * n_u[s] * r + i, (k + 1) * n_u[s] * r + i, r) U = psi_r[:, slc] psi_r[:, slc] = cplx.matmul(m, U) r *= n_u[s] return psi_r
def _kron_mult(matrices, x): n = [m.size()[0] for m in matrices] l, r = np.prod(n), 1 # noqa: E741 if l != x.shape[1]: # noqa: E741 raise ValueError("Incompatible sizes!") y = x.clone() for s in reversed(range(len(n))): l //= n[s] # noqa: E741 m = matrices[s] for k in range(l): for i in range(r): slc = slice(k * n[s] * r + i, (k + 1) * n[s] * r + i, r) temp = y[:, slc, ...] y[:, slc, ...] = cplx.matmul(m, temp) r *= n[s] return y
def rotate_psi_full(self, basis, full_unitary_dict, psi): U = full_unitary_dict[basis] Upsi = cplx.matmul(U, psi) return Upsi