Пример #1
0
    def propagator(self, tau=0.1, method='Trotter'):
        r"""Construct the propagator

        Parameters
        ----------
        tau : float
            Time interval at each step.

        Returns
        -------
        p1 : (n, n) ndarray
            :math:`e^{-iV\tau/2}`
        p2 : (n, n) ndarray
            :math:`e^{-iV\tau}`
        p3 : (n, n) ndarray
            :math:`e^{-iT\tau}`
        """
        hbar = self.hbar
        if 'Trotter' in method:
            diag, v = scipy.linalg.eigh(self.t_mat())
            p3 = np.exp(-1.0j * hbar * tau * diag)
            p3 = np.dot(v, np.dot(np.diag(p3), np.transpose(v)))
            p2 = np.exp(-1.0j * hbar * tau * np.diag(self.v_mat()))
            p2 = np.diag(p2)
            p1 = np.exp(-1.0j * hbar * tau * np.diag(0.5 * self.v_mat()))
            p1 = np.diag(p1)
            return p1, p2, p3
Пример #2
0
    def gen_h_terms(self, extra=None, kinetic_only=False):
        r"""Use a simple seperated Hamiltonian operator::

            h_0 ... h_p-1
               \ | /
                \|/
                 + r

        Notice that r is a index rather than a tensor

        Parameters
        ----------
        extra : [[(int, float -> float)]]
        kinetic_only : bool

        Returns
        -------
        h_terms : [[(int, (n_i, n_i) ndarray)]]
            A list of Hamiltonian matrix. (with ``length == rank``)
        """
        dvr_list = self.dvr_list
        if kinetic_only:
            h_terms = [[(i, dvr.t_mat())] for i, dvr in enumerate(self.dvr_list)]
        else:
            h_terms = [[(i, dvr.h_mat())] for i, dvr in enumerate(self.dvr_list)]
        if extra is not None:
            for term in extra:
                t_i = [(i, np.diag(func(np.asarray(self.grid_points_list[i])))) for i, func in term]
                h_terms.append(t_i)
        self.h_terms = h_terms
        return h_terms
Пример #3
0
def fine_grain_mps(C, dims, direction, _trunc=False):
    """Fine-graining of one-site MPS into three site by SVD.::

            |st         |s    |t
        -i- C -k- = -i- A -m- B -k-

    Parameters
    ----------
    C : (st, i, k) ndarray
        A MPS matrix.
    dims : (int, int)
        [s, t].
    direction : {'>', '<'}
        '>': move to right; '<'  move to left
    _trunc : int, optional
        Set m in compress_svd to _trunc. Not compressed if not _trunc.

    Returns
    -------
    A : (s, i, m) ndarray
        A MPS matrix.
    B : (t, m, k) ndarray
        A MPS matrix.

    Notes
    -----
    If direction == '>', A is (left-)canonical;
    if direction == '<', B is (right-)canonical.
    """
    sh = dims + [C.shape[1], C.shape[2]]  # [s, t, i, k]
    mat = np.reshape(C, sh)
    mat = np.transpose(mat, (0, 2, 1, 3))  # mat[s, i, t, k]
    mat = np.reshape(mat, (sh[0] * sh[2], sh[1] * sh[3]))  # mat[si, tk]
    U, S, V = np.linalg.svd(mat, full_matrices=0)
    if _trunc:
        U, S, V, compress_error = compress_svd(U, S, V, _trunc)
    if direction == '>':
        A = U
        B = np.matmul(np.diag(S), V)  # [m, tk]
    elif direction == '<':
        A = np.matmul(U, np.diag(S))
        B = V
    A = np.reshape(A, (sh[0], sh[2], -1))  # [s, i, m]
    B = np.reshape(B, (-1, sh[1], sh[3]))  # [m, t, k]
    B = np.transpose(B, (1, 0, 2))  # [t, m, k]

    return A, B
Пример #4
0
    def number_operator(self):
        if self.dense:
            ans = np.diag(np.arange(self.dim))
        else:

            def matvec(x):
                return self.raising(self.lowering(x))

            ans = self.operator(matvec=matvec)
        return ans
Пример #5
0
    def hamiltonian(self):
        coeff = self.hbar * self.omega
        if self.dense:
            ans = np.diag(coeff * (0.5 + np.arange(self.dim)))
        else:

            def matvec(x):
                return coeff * (self.raising(self.lowering(x)) + 0.5 * x)

            ans = self.operator(matvec=matvec)
        return ans
Пример #6
0
    def v_mat(self):
        r"""Return the potential energy matrix with the given potential
        in DVR.

        Returns
        -------
        (n, n) np.ndarray
            A 2-d diagonal matrix.
        """
        v = self.v_func(self.grid_points)
        v_matrix = np.diag(v)
        return v_matrix
Пример #7
0
    def t_mat(self):
        """Return the kinetic energy matrix in DVR.

        Returns
        -------
        (n, n) np.ndarray
            A 2-d matrix.
        """
        factor = -self.hbar**2 / (2 * self.m_e)
        j = np.arange(1, self.n + 1)
        t_matrix = np.diag(-(j * np.pi / self.length)**2)
        t_matrix = factor * self.fbr2dvr_mat(t_matrix)
        return t_matrix
Пример #8
0
    def _move_right(mat, mat_next, _trunc):
        shape = np.shape(mat)
        # SVD on mat[si, j]
        mat = np.reshape(mat, (shape[0] * shape[1], shape[2]))
        U, S, V = np.linalg.svd(mat, full_matrices=0)

        # truncated to compress.
        U, S, V, compress_error = compress_svd(U, S, V, _trunc)
        mat = np.reshape(U, (shape[0], shape[1], -1))  # U[si, m]
        SV = np.matmul(np.diag(S), V)
        mat_next = np.einsum('mj,tjk->tmk', SV, mat_next)

        return mat, mat_next
Пример #9
0
 def _diff_n(self):
     if self.corr.exp_coeff.ndim == 1:
         gamma = np.diag(self.corr.exp_coeff)
     ans = []
     for i, j in product(range(self.k_max), repeat=2):
         g = gamma[i, j]
         if not np.allclose(g, 0.0):
             term = [(i, 0.5j * self.hbar * g * self.numberer(i))]
             if i != j:
                 at = self.creator(i)
                 a = self.annihilator(j)
                 term.extend([(i, at), (j, a)])
             ans.append(term)
     return ans
Пример #10
0
    def _move_left(mat, mat_prev, _trunc):
        shape = np.shape(mat)
        mat = np.reshape(
            np.transpose(mat, (1, 0, 2)),  # mat[i, s, j]
            (shape[1], shape[0] * shape[2]))  # SVD on mat[i, sj]
        U, S, V = np.linalg.svd(mat, full_matrices=0)

        # truncated to compress.
        U, S, V, compress_error = compress_svd(U, S, V, _trunc)
        mat = np.reshape(V, (-1, shape[0], shape[2]))  # V[m, sj]
        mat = np.transpose(mat, (1, 0, 2))  # mat[s, m, j]
        US = np.matmul(U, np.diag(S))
        mat_prev = np.einsum('rhi,im->rhm', mat_prev, US)

        return mat, mat_prev
Пример #11
0
 def _diff_n(self):
     if self.corr.exp_coeff.ndim == 1:
         gamma = np.diag(self.corr.exp_coeff)
     ans = []
     for i, j in product(range(self.k_max), repeat=2):
         g = gamma[i, j]
         if not np.allclose(g, 0.0):
             term = [(i, -g * self._numberer(i))]
             if i != j:
                 n_i = self._sqrt_numberer(i)
                 n_j = self._sqrt_numberer(j)
                 raiser = self._raiser(i)
                 lower = self._lower(j)
                 term.extend([(i, raiser @ n_i), (j, n_j @ lower)])
             ans.append(term)
     return ans
Пример #12
0
def compressed_svd(a, rank=None, err=None, **kwargs):
    u, s, vh = svd(a, full_matrices=False, **kwargs)
    if err is not None:
        total_error = 0.0
        for n, s_i in reversed(list(enumerate(s))):
            total_error += s_i
            if total_error > err:
                rank = n + 1
                break
        if rank is None:
            rank = 1
    if rank is not None and rank <= 0 :
        raise RuntimeError('The matrix must have positive rank!')
    if rank is not None and rank <= len(s):
        s = s[:rank]
        u = u[:, :rank]
        vh = vh[:rank,:]
    s = np.diag(s)
    return u, s, vh
Пример #13
0
 def creator(self, k):
     """Acting on 0-th index"""
     dim = self.n_dims[k]
     raiser = np.eye(dim, k=1)
     sqrt_n = np.diag(np.sqrt(np.arange(dim)))
     return raiser @ sqrt_n
Пример #14
0
 def _sqrt_numberer(self, k, start=0):
     return np.diag(
         np.sqrt(np.arange(start, start + self.n_dims[k], dtype=DTYPE)))
Пример #15
0
 def _lower(self, k):
     """Acting on 0-th index"""
     dim = self.n_dims[k]
     sqrt_n = np.diag(np.sqrt(np.arange(dim, dtype=DTYPE)))
     return sqrt_n @ np.eye(dim, k=-1, dtype=DTYPE)
Пример #16
0
    def autocomplete(self, n_bond_dict, max_entangled=False):
        """Autocomplete the tensors linked to `self.root` with suitable initial
        value.

        Parameters
        ----------
        n_bond_dict : {Leaf: int}
            A dictionary to specify the dimensions of each primary basis.
        max_entangled : bool
            Whether to use the max entangled state as initial value (for finite
            temperature and imaginary-time propagation).  Default is `False`.
        """
        for t in self.root.visitor(leaf=False):
            if t.array is None:
                axis = t.axis
                if max_entangled and not any(t.children(leaf=False)):
                    if len(list(t.children(leaf=True))) != 2 or axis is None:
                        raise RuntimeError('Not correct tensor graph for FT.')
                    for i, leaf, j in t.children():
                        if not leaf.name.endswith("'"):
                            n_leaf = n_bond_dict[(t, i, leaf, j)]
                            break
                    p, p_i = t[axis]
                    n_parent = n_bond_dict[(p, p_i, t, axis)]
                    vec_i = np.diag(np.ones((n_leaf, )) / np.sqrt(n_leaf))
                    vec_i = np.reshape(vec_i, -1)
                    init_vecs = [vec_i]
                    print(np.shape(init_vecs),
                          np.shape(self._local_matvec(leaf)))
                    da = DavidsonAlgorithm(self._local_matvec(leaf),
                                           init_vecs=init_vecs,
                                           n_vals=n_parent)
                    array = da.kernel(search_mode=True)
                    if len(array) >= n_parent:
                        array = array[:n_parent]
                    else:
                        for j in range(n_parent - len(array)):
                            v = np.zeros((n_leaf**2, ))
                            v[j] = 1.0
                            array.append(v)
                    assert len(array) == n_parent
                    assert np.allclose(array[0], vec_i)
                    array = np.reshape(array, (n_parent, n_leaf, n_leaf))
                else:
                    n_children = []
                    for i, child, j in t.children():
                        n_children.append(n_bond_dict[(t, i, child, j)])
                    if axis is not None:
                        p, p_i = t[axis]
                        n_parent = n_bond_dict[(p, p_i, t, axis)]
                        shape = [n_parent] + n_children
                    else:
                        n_parent = 1
                        shape = n_children
                    array = np.zeros((n_parent, np.prod(n_children)))
                    for n, v_i in zip(self.triangular(n_children), array):
                        v_i[n] = 1.
                    array = np.reshape(array, shape)
                    if axis is not None:
                        array = np.moveaxis(array, 0, axis)
                t.set_array(array)
                t.normalize(forced=True)
                assert (t.axis is None or np.linalg.matrix_rank(t.local_norm())
                        == t.shape[t.axis])
        if __debug__:
            for t in self.root.visitor():
                t.check_completness(strict=True)
        return
Пример #17
0
 def _numberer(self, k):
     return np.diag(np.arange(self.n_dims[k], dtype=DTYPE))
Пример #18
0
 def annihilator(self, k):
     """Acting on 0-th index"""
     dim = self.n_dims[k]
     lower = np.eye(dim, k=-1)
     sqrt_n = np.diag(np.sqrt(np.arange(dim)))
     return sqrt_n @ lower
Пример #19
0
 def numberer(self, k):
     """Acting on 0-th index"""
     return np.diag(np.arange(self.n_dims[k]))
Пример #20
0
 def annihilation_operator(self):
     if self.dense:
         ans = np.diag(np.sqrt(np.arange(1, self.dim)), 1)
     else:
         ans = self.operator(matvec=self.lowering, rmatvec=self.raising)
     return ans
Пример #21
0
 def _numberer(self, k, start=0):
     return np.diag(np.arange(start, start + self.n_dims[k]))