Esempio n. 1
0
    def position(self,
                 site: int,
                 normalize: Optional[bool] = True) -> np.number:
        """
    Shift FiniteMPS.center_position to `site`.
    Args:
      site: The site to which FiniteMPS.center_position should be shifted
      normalize: If `True`, normalize matrices when shifting.
    Returns:
      Tensor: The norm of the tensor at FiniteMPS.center_position
    """
        #`site` has to be between 0 and len(mps) - 1
        if site >= len(self.nodes) or site < 0:
            raise ValueError('site = {} not between values'
                             ' 0 < site < N = {}'.format(site, len(self)))
        #nothing to do
        if site == self.center_position:
            return self.backend.norm(self.nodes[self.center_position].tensor)

        #shift center_position to the right using QR decomposition
        if site > self.center_position:
            n = self.center_position
            for n in range(self.center_position, site):
                Q, R = split_node_qr(
                    self.nodes[n],
                    left_edges=[self.nodes[n][0], self.nodes[n][1]],
                    right_edges=[self.nodes[n][2]],
                    left_name=self.nodes[n].name)

                self.nodes[n] = Q  #Q is a left-isometric tensor of rank 3
                self.nodes[n + 1] = contract(R[1], name=self.nodes[n + 1].name)
                Z = norm(self.nodes[n + 1])

                # for an mps with > O(10) sites one needs to normalize to avoid
                # over or underflow errors; this takes care of the normalization
                if normalize:
                    self.nodes[n + 1].tensor /= Z

            self.center_position = site

        #shift center_position to the left using RQ decomposition
        elif site < self.center_position:
            for n in reversed(range(site + 1, self.center_position + 1)):
                R, Q = split_node_rq(
                    self.nodes[n],
                    left_edges=[self.nodes[n][0]],
                    right_edges=[self.nodes[n][1], self.nodes[n][2]],
                    right_name=self.nodes[n].name)

                # for an mps with > O(10) sites one needs to normalize to avoid
                # over or underflow errors; this takes care of the normalization
                self.nodes[n] = Q  #Q is a right-isometric tensor of rank 3
                self.nodes[n - 1] = contract(R[0], name=self.nodes[n - 1].name)
                Z = norm(self.nodes[n - 1])
                if normalize:
                    self.nodes[n - 1].tensor /= Z

            self.center_position = site
        #return the norm of the last R tensor (useful for checks)
        return Z
Esempio n. 2
0
    def contract(self,
                 edge: network_components.Edge,
                 name: Optional[Text] = None) -> network_components.BaseNode:
        """Contract an edge connecting two nodes in the TensorNetwork.

    Args:
      edge: The edge contract next.
      name: Name of the new node created.

    Returns:
      The new node created after the contraction.

    Raises:
      ValueError: When edge is a dangling edge or if it already has been
        contracted.
    """
        #contract disables contracted edges; if we have to access them, we need
        #to do it beforehand.
        trace_edge = edge.node1 is edge.node2
        node1 = edge.node1
        node2 = edge.node2
        new_node = self.add_node(
            network_components.contract(edge, name, axis_names=None))
        # disable nodes
        if trace_edge:
            self.nodes_set.remove(node1)
            node1.disable()
        else:
            self.nodes_set.remove(node1)
            self.nodes_set.remove(node2)
            node1.disable()
            node2.disable()
        return new_node