Beispiel #1
0
    def _sp_op(self, i, mat, h_list, mod_term, err=1.e-6):
        if not h_list:
            return np.zeros((mat.shape))

        logging.debug(__('> OP on mat {}...', i))

        n, m = mat.shape
        partial_transform = self._partial_transform
        a = self.get_sub_vec(-1)
        a_h = np.conj(a)
        density = self._partial_product(i, a, a_h)
        inv_density = linalg.inv(density + np.identity(m) * err)
        sp = self.get_sub_vec(i)
        sp_h = np.conj(np.transpose(sp))
        projection = np.identity(n) - np.dot(sp, sp_h)

        tmp = partial_transform(i, a, mat)
        for mat_j in h_list:
            tmp = partial_transform(i, tmp, mat_j)
        for j, mat_j in mod_term:
            if j != i:
                tmp = partial_transform(j, tmp, mat_j)
        tmp = self._partial_product(i, tmp, a_h)
        ans = np.dot(projection, np.dot(tmp, inv_density))

        return ans
Beispiel #2
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
Beispiel #3
0
    def fbr2dvr_mat(self, mat):
        r"""Transform a matrix from FBR to DVR.

        Parameters
        ----------
        mat : (n, n) ndarray

        Returns
        -------
        (n, n) ndarray
        """
        return np.dot(np.transpose(self._u_mat), np.dot(mat, self._u_mat))
Beispiel #4
0
    def dvr2fbr_mat(self, mat):
        r"""Transform a matrix from DVR to FBR.

        Parameters
        ----------
        mat : (n, n) ndarray

        Returns
        -------
        (n, n) ndarray
        """
        return np.dot(self._u_mat, np.dot(mat, np.transpose(self._u_mat)))
Beispiel #5
0
    def partial_trace(array1, i, array2, j):
        r"""Partial trace of 2 tensors, return a matrix. 

                +----+
                |    |
            -i- 1 -- 2 -j-

        Parameters
        ----------
        array1 : ndarray
        i : {int, None}
            if i is None then j must be None.
        array2 : ndarray 
        j : {int, None}
            if j is None then i must be None.

        Returns
        -------
        ans : ndarray
            Of shape `(n, m)`
        """
        if i is not None and j is not None:
            shape_1, shape_2 = map(list, (array1.shape, array2.shape))
            n, m = shape_1[i], shape_2[j]
            array1 = np.moveaxis(array1, i, 0)
            array1 = np.reshape(array1, (n, -1))
            array2 = np.moveaxis(array2, j, -1)
            array2 = np.reshape(array2, (-1, m))
        elif i is None and j is None:
            array1 = np.reshape(array1, -1)
            array2 = np.reshape(array2, -1)
        else:
            raise TypeError('Invalid parameters i={} and j={}!'.format(i, j))
        ans = np.dot(array1, array2)
        return ans
Beispiel #6
0
 def _extend_space(self):
     head = len(self._search_space)
     self._search_space += self._trial_vecs
     self._column_space += list(map(self._matvec, self._trial_vecs))
     tail = len(self._search_space)
     v, a_v = self._search_space, self._column_space
     for i in range(head):
         for j in range(head, tail):
             self._submatrix[i, j] = np.dot(np.conj(v[i]), a_v[j])
             self._submatrix[j, i] = np.conj(self._submatrix[i, j])
     for i in range(head, tail):
         for j in range(head, i):
             self._submatrix[i, j] = np.dot(np.conj(v[i]), a_v[j])
             self._submatrix[j, i] = np.conj(self._submatrix[i, j])
         self._submatrix[i, i] = np.dot(np.conj(v[i]), a_v[i])
     return self._submatrix[:tail, :tail]
Beispiel #7
0
    def _partial_product(i, a, b):
        r"""
        Parameters
        ----------
        i : {int, None}
        a : (..., n, ...) ndarray
        b : (..., m, ...) ndarray

        Returns
        -------
        mat : (n, m) ndarray
            Or return a float if i is None.
        """
        if i is None:
            a = np.reshape(a, -1)
            b = np.reshape(b, -1)
        else:
            n = a.shape[i]
            m = b.shape[i]
            a = np.moveaxis(a, i, 0)
            a = np.reshape(a, (n, -1))
            b = np.moveaxis(b, i, -1)
            b = np.reshape(b, (-1, m))
        mat = np.dot(a, b)
        return mat
Beispiel #8
0
    def _calc_trial_vecs(self):
        if self._precondition is None:
            dim = len(self._search_space[0])
            self._precondition = self.davidson_precondition(
                dim, self._matvec
            )
        #     ritz_vecs = [None] * dim
        # else:
        #     ritz_vecs = list(self._get_ritz_vecs())

        self._trial_vecs = []
        precondition = self._precondition
        zipped = zip(
            self._residuals, self._residual_norms,
            self._get_ritz_vecs(), self._convergence
        )
        for residual, norm_, ritz_vec, conv in zipped:
            # remove linear dependency in self._residuals
            if norm_ ** 2 > self.lin_dep_lim and not conv:
                vec = precondition(
                    residual, self._ritz_vals[0], ritz_vec
                )
                vec *= 1. / norm(vec)
                for base in self._search_space:
                    vec -= np.dot(np.conj(base), vec) * base
                norm_ = norm(vec)
                # remove linear dependency between trial_vecs and
                # self._search_space
                if norm_ ** 2 > self.lin_dep_lim:
                    vec *= 1. / norm_
                    self._trial_vecs.append(vec)
        return self._trial_vecs
Beispiel #9
0
    def __partial_product(array1, i, array2, j):
        r"""Times a matrix to a tensor.

               |
            -- 1 -i--j- 2 --
               |

        Parameters
        ----------
        array1 : ndarray
        i : int
        array2 : 2-d ndarray 
        j : int

        Returns
        -------
        ans : ndarray
        """
        shape_1, shape_2 = map(list, (array1.shape, array2.shape))
        n, m = shape_1.pop(i), shape_2.pop(j)
        new_shape = shape_1[:i] + shape_2 + shape_1[i:]
        array1 = np.moveaxis(array1, i, -1)
        array1 = np.reshape(array1, (-1, n))
        array2 = np.moveaxis(array2, j, 0)
        array2 = np.reshape(array2, (m, -1))
        ans = np.dot(array1, array2)
        ans = np.reshape(ans, shape_1 + [-1])
        ans = np.moveaxis(ans, -1, i)
        ans = np.reshape(ans, new_shape)
        return ans
Beispiel #10
0
 def normalize(self, forced=False):
     """Normalize the array of self. Only work when self.normalized.
     Set `forced` to `True` to normalize any way.
     """
     array = self.array
     if array is None or (not self.normalized and not forced):
         return
     axis = self.axis
     if axis is None:
         norm = np.array(self.local_norm())
         self.set_array(array / norm)
         ans = norm
     else:
         norm = linalg.norm
         shape = self.shape
         dim = shape.pop(axis)
         array = np.reshape(np.moveaxis(array, axis, 0), (dim, -1))
         vecs = []
         norm_list = []
         for vec_i in array:
             for vec_j in vecs:
                 vec_i -= vec_j * np.dot(np.conj(vec_j), vec_i)
             norm_ = norm(vec_i)
             vecs.append(vec_i / norm_)
             norm_list.append(norm_)
         array = np.array(vecs)
         array = np.moveaxis(np.reshape(array, [-1] + shape), 0, axis)
         self.set_array(array)
         ans = norm_list
     return ans
Beispiel #11
0
 def energy_expection(self, vec=None):
     if vec is None:
         vec = self.vec
     a_tensor = self.get_sub_vec(-1, vec)
     mod_terms = self.update_mod_terms(vec=vec, write=False)
     ans = 0.
     for r, term in enumerate(mod_terms):
         h_a = self._coeff_op(a_tensor, term)
         h_a = np.reshape(h_a, -1)
         a_h = np.conj(np.reshape(a_tensor, -1))
         ans += np.dot(a_h, h_a)
     return ans
Beispiel #12
0
    def dvr2fbr_vec(self, vec):
        r"""Transform a vector from DVR to FBR.

        Parameters
        ----------
        mat : (n,) ndarray

        Returns
        -------
        (n,) ndarray
        """
        return np.dot(self._u_mat, vec)
Beispiel #13
0
    def fbr2dvr_vec(self, vec):
        r"""Transform a vector from FBR to DVR.

        Parameters
        ----------
        mat : (n,) ndarray

        Returns
        -------
        (n,) ndarray
        """
        vec = np.reshape(vec, -1)
        return np.dot(np.transpose(self._u_mat), vec)
Beispiel #14
0
def expection(op, vec):
    r"""Calculate the energy expection.
    Parameters
    ----------
    op : (n, n) ndarray or LinearOpearator
    vec : (n,) ndarray

    Returns
    -------
    expection : float
    """
    vec_h = np.conjugate(vec)
    e = np.dot(vec_h, op.dot(vec))
    return e
Beispiel #15
0
 def _orthonormalize(self, use_svd=True):
     if use_svd and self._trial_vecs:
         trial_mat = np.transpose(np.array(self._trial_vecs))
         trial_mat = orth(trial_mat)
         self._trial_vecs = list(np.transpose(trial_mat))
     elif self._trial_vecs:
         vecs = []
         for vec_i in self._trial_vecs:
             for vec_j in vecs:
                 vec_i -= vec_j * np.dot(vec_j.conj(), vec_i)
             norm_ = norm(vec_i)
             if norm_ > 1.e-7:
                 vecs.append(vec_i / norm_)
         self._trial_vecs = vecs
     return self._trial_vecs
Beispiel #16
0
    def projector(self, comp=False):
        """[Deprecated] Return the projector corresponding to self.

        Returns
        -------
        ans : ndarray
        """
        axis = self.axis
        if axis is not None:
            array = self.array
            shape = self.shape
            dim = shape.pop(self.axis)
            comp_dim = np.prod(shape)
            array = np.moveaxis(array, axis, -1)
            array = np.reshape(array, (-1, dim))
            array_h = np.conj(np.transpose(array))
            ans = np.dot(array, array_h)
            if comp:
                identity = np.identity(comp_dim)
                ans = identity - ans
            ans = np.reshape(ans, shape * 2)
            return ans
        else:
            raise RuntimeError('Need to specific the normalization axis!')
Beispiel #17
0
 def _eval(op, vec):
     vec_h = np.conj(np.transpose(vec))
     mod_op = np.dot(vec_h, np.dot(op, vec))
     return mod_op
Beispiel #18
0
 def matvec(vec, mat=h):
     vec = np.reshape(vec, h.shape)
     ans = np.dot(mat, vec)
     return np.reshape(ans, -1)
Beispiel #19
0
    def split(self, axis, indice=None, root=None, child=None, rank=None, err=None, normalized=False):
        """Split the root Tensor to a certain axis/certain axes.

        Parameters
        ----------
        axis : {int, [int]}
        rank : int
            Max rank in SVD
        err : float
            Max error in SVD
        indice : (int, int)
            Linkage between root and child
        root : Tensor
            Tensor to be a new root node. `None` to create a new Tensor.
        child : Tensor
            Tensor to be a new child node. `None` to create a new Tensor.

        Returns
        -------
        root : Tensor
            New root node in the same environment of self.
        child : Tensor
            New child node in the same environment of self.

        Notes
        -----
        When split a Tensor, this method should let root.unite(i) (i.e. unite
        with child) be a inversion in terms of the tensor network.
        """
        if self.axis is not None:
            raise RuntimeError('Can only split the root Tensor!')
        try:
            axes1 = list(sorted(axis))
        except TypeError:
            axes1 = [axis]
            default_indice = (0, axis)
        else:
            default_indice = (0, 0)
        axes2 = [i for i in range(self.order) if i not in axes1]
        index1, index2 = indice if indice is not None else default_indice

        # save all data needed in `self`
        a = self.array
        children = list(self.children(axis=None))
        name = self.name
        shape = self.shape
        shape1, shape2 = [shape[i] for i in axes1], [shape[i] for i in axes2]
        # name settings only for clarity..
        if '+' in name:
            name1, name2 = name.split('+')
        else:
            name1, name2 = name + '\'', name

        # Calculate arrays for new tensors
        for n, i in enumerate(axes1):
            a = np.moveaxis(a, i, n)
        a = np.reshape(a, (np.prod([1] + shape1), np.prod([1] + shape2)))
        u, s, vh = compressed_svd(a, rank=rank, err=err)
        root_array = np.reshape(np.dot(u, s), shape1 + [-1])
        root_array = np.moveaxis(root_array, -1, index1)
        child_array = np.reshape(vh, [-1] + shape2)
        child_array = np.moveaxis(child_array, 0, index2)
        # Create/write new tensors.
        cls = type(self)
        if root is None:
            root = cls(name=name1, array=root_array, axis=None, normalized=normalized)
        else:
            root.axis = None
            root.set_array(root_array)
        if child is None:
            child = cls(name=name2, array=child_array, axis=index2, normalized=normalized)
        else:
            child.axis = index2
            child.set_array(child_array)

        # Fix linkage info
        axes1.insert(index1, None)
        axes2.insert(index2, None)
        unlink = self.unlink
        link = self.link
        link_info = [(root, index1, child, index2)]
        for i, t, j in children:
            is_1 = i in axes1
            axes = axes1 if is_1 else axes2
            tensor = root if is_1 else child
            unlink(self, i, t, j)
            link_info.append((tensor, axes.index(i), t, j))
        for linkage in link_info:
            link(*linkage)
        return root, child