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
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