Ejemplo n.º 1
0
def density_matrix_fidelity(nn_state, target, v_space, **kwargs):
    r"""Calculate the fidelity of the reconstructed density matrix
    given the exact target density matrix

    :param nn_state: The neural network state (i.e. current density matrix)
    :type nn_state: qucumber.nn_states.DensityMatrix
    :param target: The true density matrix of the system
    :type target: torch.Tensor
    :param v_space: The basis elements of the visible space
    :type v_space: torch.Tensor
    :param \**kwargs: Extra keyword arguments that may be passed.
                      Will be ignored.
    :returns: The fidelity
    :rtype: float
    """
    rhoRBM_ = nn_state.rhoRBM(v_space, v_space)
    argReal = cplx.real(rhoRBM_).numpy()
    argIm = cplx.imag(rhoRBM_).numpy()

    rho_rbm_ = argReal + 1j * argIm

    argReal = cplx.real(target).numpy()
    argIm = cplx.imag(target).numpy()

    target_ = argReal + 1j * argIm

    sqrt_rho_rbm = sqrtm(rho_rbm_)

    arg = sqrtm(np.matmul(sqrt_rho_rbm, np.matmul(target_, sqrt_rho_rbm)))

    return np.trace(arg).real
Ejemplo n.º 2
0
    def rho(self, v, vp=None, expand=True):
        r"""Computes the matrix elements of the (unnormalized) density matrix.
        If `expand` is `True`, will return a complex matrix
        :math:`A_{ij} = \langle\sigma_i|\widetilde{\rho}|\sigma'_j\rangle`.
        Otherwise will return a complex vector
        :math:`A_{i} = \langle\sigma_i|\widetilde{\rho}|\sigma'_i\rangle`.

        :param v: One of the visible states, :math:`\sigma`.
        :type v: torch.Tensor
        :param vp: The other visible state, :math:`\sigma'`.
                   If `None`, will be set to `v`.
        :type vp: torch.Tensor
        :param expand: Whether to return a matrix (`True`) or a vector (`False`).
        :type expand: bool

        :returns: The elements of the current density matrix
                  :math:`\langle\sigma|\widetilde{\rho}|\sigma'\rangle`
        :rtype: torch.Tensor
        """
        if expand is False and vp is None:
            return cplx.make_complex(self.probability(v))
        elif vp is None:
            vp = v

        pi_ = self.pi(v, vp, expand=expand)
        amp = (self.rbm_am.gamma(v, vp, eta=+1, expand=expand) +
               cplx.real(pi_)).exp()
        phase = self.rbm_ph.gamma(v, vp, eta=-1,
                                  expand=expand) + cplx.imag(pi_)

        return cplx.make_complex(amp * phase.cos(), amp * phase.sin())
Ejemplo n.º 3
0
    def test_imag_part_of_tensor(self):
        x = torch.randn(3, 3, 3)
        y = torch.randn(3, 3, 3)
        z = cplx.make_complex(x, y)

        self.assertTensorsEqual(
            y, cplx.imag(z), msg="Imaginary part of rank-3 tensor failed!"
        )
Ejemplo n.º 4
0
    def test_imag_part_of_matrix(self):
        x = torch.tensor([[1, 2], [3, 4]])
        y = torch.tensor([[5, 6], [7, 8]])
        z = cplx.make_complex(x, y)

        self.assertTensorsEqual(y,
                                cplx.imag(z),
                                msg="Imaginary part of matrix failed!")
Ejemplo n.º 5
0
    def test_imag_part_of_vector(self):
        x = torch.tensor([1, 2])
        y = torch.tensor([5, 6])
        z = cplx.make_complex(x, y)

        self.assertTensorsEqual(y,
                                cplx.imag(z),
                                msg="Imaginary part of vector failed!")
Ejemplo n.º 6
0
def test_positive_wavefunction_psi():
    nn_state = PositiveWaveFunction(10, gpu=False)

    vis_state = torch.ones(10).to(dtype=torch.double)
    actual_psi_im = cplx.imag(nn_state.psi(vis_state)).to(vis_state)
    expected_psi_im = torch.zeros(1).squeeze().to(vis_state)

    msg = "PositiveWaveFunction is giving a non-zero imaginary part!"
    assert torch.equal(actual_psi_im, expected_psi_im), msg
Ejemplo n.º 7
0
    def pi_grad(self, v, vp, phase=False, expand=False):
        r"""Calculates the gradient of the :math:`\Pi` matrix with
            respect to the amplitude RBM parameters for two input states

        :param v: One of the visible states, :math:`\sigma`
        :type v: torch.Tensor
        :param vp: The other visible state, :math`\sigma'`
        :type vp: torch.Tensor
        :param phase: Whether to compute the gradients for the phase RBM (`True`)
                      or the amplitude RBM (`False`)
        :type phase: bool

        :returns: The matrix element of the gradient given by
                  :math:`\langle\sigma|\nabla_\lambda\Pi|\sigma'\rangle`
        :rtype: torch.Tensor
        """
        unsqueezed = v.dim() < 2 or vp.dim() < 2
        v = (v.unsqueeze(0) if v.dim() < 2 else v).to(self.rbm_am.weights_W)
        vp = (vp.unsqueeze(0) if vp.dim() < 2 else vp).to(
            self.rbm_am.weights_W)

        if expand:
            arg_real = 0.5 * (F.linear(v, self.rbm_am.weights_U,
                                       self.rbm_am.aux_bias).unsqueeze_(1) +
                              F.linear(vp, self.rbm_am.weights_U,
                                       self.rbm_am.aux_bias).unsqueeze_(0))
            arg_imag = 0.5 * (
                F.linear(v, self.rbm_ph.weights_U).unsqueeze_(1) -
                F.linear(vp, self.rbm_ph.weights_U).unsqueeze_(0))
        else:
            arg_real = self.rbm_am.mixing_term(v + vp)
            arg_imag = self.rbm_ph.mixing_term(v - vp)

        sig = cplx.sigmoid(arg_real, arg_imag)

        batch_sizes = ((v.shape[0], vp.shape[0], *v.shape[1:-1]) if expand else
                       (*v.shape[:-1], ))

        W_grad = torch.zeros_like(self.rbm_am.weights_W).expand(
            *batch_sizes, -1, -1)
        vb_grad = torch.zeros_like(self.rbm_am.visible_bias).expand(
            *batch_sizes, -1)
        hb_grad = torch.zeros_like(self.rbm_am.hidden_bias).expand(
            *batch_sizes, -1)

        if phase:
            temp = (v.unsqueeze(1) - vp.unsqueeze(0)) if expand else (v - vp)
            sig = cplx.scalar_mult(sig, cplx.I)

            ab_grad_real = torch.zeros_like(self.rbm_ph.aux_bias).expand(
                *batch_sizes, -1)
            ab_grad_imag = ab_grad_real.clone()
        else:
            temp = (v.unsqueeze(1) + vp.unsqueeze(0)) if expand else (v + vp)

            ab_grad_real = cplx.real(sig)
            ab_grad_imag = cplx.imag(sig)

        U_grad = 0.5 * torch.einsum("c...j,...k->c...jk", sig, temp)
        U_grad_real = cplx.real(U_grad)
        U_grad_imag = cplx.imag(U_grad)

        vec_real = [
            W_grad.view(*batch_sizes, -1),
            U_grad_real.view(*batch_sizes, -1),
            vb_grad,
            hb_grad,
            ab_grad_real,
        ]
        vec_imag = [
            W_grad.view(*batch_sizes, -1).clone(),
            U_grad_imag.view(*batch_sizes, -1),
            vb_grad.clone(),
            hb_grad.clone(),
            ab_grad_imag,
        ]

        if unsqueezed and not expand:
            vec_real = [grad.squeeze_(0) for grad in vec_real]
            vec_imag = [grad.squeeze_(0) for grad in vec_imag]

        return cplx.make_complex(torch.cat(vec_real, dim=-1),
                                 torch.cat(vec_imag, dim=-1))