Common Functions

tensornetwork.norm(tensor: tensornetwork.tensor.Tensor) → tensornetwork.tensor.Tensor

Calculate the L2-norm of the elements of tensor

tensornetwork.conj(tensor: tensornetwork.tensor.Tensor) → tensornetwork.tensor.Tensor

Return the complex conjugate of Tensor :param Tensor: A Tensor.

Returns:The complex conjugated Tensor.
tensornetwork.copy(nodes: Iterable[tensornetwork.network_components.AbstractNode], conjugate: bool = False) → Tuple[dict, dict]

Copy the given nodes and their edges.

This will return a tuple linking original nodes/edges to their copies. If nodes A and B are connected but only A is passed in to be copied, the edge between them will become a dangling edge.

Parameters:
  • nodes – An Iterable (Usually a list or set) of nodes.
  • conjugate – Boolean. Whether to conjugate all of the nodes (useful for calculating norms and reduced density matrices).
Returns:

node_dict:

A dictionary mapping the nodes to their copies.

edge_dict:

A dictionary mapping the edges to their copies.

Return type:

A tuple containing

tensornetwork.transpose(tensor: tensornetwork.tensor.Tensor, perm: Optional[Sequence[int]] = None) → tensornetwork.tensor.Tensor

Return a new Tensor transposed according to the permutation set by axes. By default the axes are reversed. :param axes: The permutation. If None (default) the index order is reversed.

Returns:The transposed Tensor.
tensornetwork.remove_node(node: tensornetwork.network_components.AbstractNode) → Tuple[Dict[str, tensornetwork.network_components.Edge], Dict[int, tensornetwork.network_components.Edge]]

Remove a node from the network.

Parameters:node – The node to be removed.
Returns:
disconnected_edges_by_name:
A Dictionary mapping node’s axis names to the newly broken edges.
disconnected_edges_by_axis:
A Dictionary mapping node’s axis numbers to the newly broken edges.
Return type:A tuple of
tensornetwork.split_node(node: tensornetwork.network_components.AbstractNode, left_edges: List[tensornetwork.network_components.Edge], right_edges: List[tensornetwork.network_components.Edge], max_singular_values: Optional[int] = None, max_truncation_err: Optional[float] = None, relative: Optional[bool] = False, left_name: Optional[str] = None, right_name: Optional[str] = None, edge_name: Optional[str] = None) → Tuple[tensornetwork.network_components.AbstractNode, tensornetwork.network_components.AbstractNode, Any]

Split a node using Singular Value Decomposition.

Let \(M\) be the matrix created by flattening left_edges and right_edges into 2 axes. Let \(U S V^* = M\) be the SVD of \(M\). This will split the network into 2 nodes. The left node’s tensor will be \(U \sqrt{S}\) and the right node’s tensor will be \(\sqrt{S} V^*\) where \(V^*\) is the adjoint of \(V\).

The singular value decomposition is truncated if max_singular_values or max_truncation_err is not None.

The truncation error is the 2-norm of the vector of truncated singular values. If only max_truncation_err is set, as many singular values will be truncated as possible while maintaining: norm(truncated_singular_values) <= max_truncation_err. If relative is set True then max_truncation_err is understood relative to the largest singular value.

If only max_singular_values is set, the number of singular values kept will be min(max_singular_values, number_of_singular_values), so that max(0, number_of_singular_values - max_singular_values) are truncated.

If both max_truncation_err and max_singular_values are set, max_singular_values takes priority: The truncation error may be larger than max_truncation_err if required to satisfy max_singular_values.

Parameters:
  • node – The node you want to split.
  • left_edges – The edges you want connected to the new left node.
  • right_edges – The edges you want connected to the new right node.
  • max_singular_values – The maximum number of singular values to keep.
  • max_truncation_err – The maximum allowed truncation error.
  • relative – Multiply max_truncation_err with the largest singular value.
  • left_name – The name of the new left node. If None, a name will be generated automatically.
  • right_name – The name of the new right node. If None, a name will be generated automatically.
  • edge_name – The name of the new Edge connecting the new left and right node. If None, a name will be generated automatically. The new axis will get the same name as the edge.
Returns:

left_node:

A new node created that connects to all of the left_edges. Its underlying tensor is \(U \sqrt{S}\)

right_node:

A new node created that connects to all of the right_edges. Its underlying tensor is \(\sqrt{S} V^*\)

truncated_singular_values:

The vector of truncated singular values.

Return type:

A tuple containing

Raises:

AttributeError – If node has no backend attribute

tensornetwork.split_node_qr(node: tensornetwork.network_components.AbstractNode, left_edges: List[tensornetwork.network_components.Edge], right_edges: List[tensornetwork.network_components.Edge], left_name: Optional[str] = None, right_name: Optional[str] = None, edge_name: Optional[str] = None) → Tuple[tensornetwork.network_components.AbstractNode, tensornetwork.network_components.AbstractNode]

Split a node using QR decomposition.

Let \(M\) be the matrix created by flattening left_edges and right_edges into 2 axes. Let \(QR = M\) be the QR Decomposition of \(M\). This will split the network into 2 nodes. The left node’s tensor will be \(Q\) (an orthonormal matrix) and the right node’s tensor will be \(R\) (an upper triangular matrix)

Parameters:
  • node – The node you want to split.
  • left_edges – The edges you want connected to the new left node.
  • right_edges – The edges you want connected to the new right node.
  • left_name – The name of the new left node. If None, a name will be generated automatically.
  • right_name – The name of the new right node. If None, a name will be generated automatically.
  • edge_name – The name of the new Edge connecting the new left and right node. If None, a name will be generated automatically.
Returns:

left_node:

A new node created that connects to all of the left_edges. Its underlying tensor is \(Q\)

right_node:

A new node created that connects to all of the right_edges. Its underlying tensor is \(R\)

Return type:

A tuple containing

Raises:

AttributeError – If node has no backend attribute

tensornetwork.split_node_rq(node: tensornetwork.network_components.AbstractNode, left_edges: List[tensornetwork.network_components.Edge], right_edges: List[tensornetwork.network_components.Edge], left_name: Optional[str] = None, right_name: Optional[str] = None, edge_name: Optional[str] = None) → Tuple[tensornetwork.network_components.AbstractNode, tensornetwork.network_components.AbstractNode]

Split a node using RQ (reversed QR) decomposition.

Let \(M\) be the matrix created by flattening left_edges and right_edges into 2 axes.

Let \(QR = M^*\) be the QR Decomposition of \(M^*\). This will split the network into 2 nodes.

The left node’s tensor will be \(R^*\) (a lower triangular matrix) and the right node’s tensor will be \(Q^*\) (an orthonormal matrix)

Parameters:
  • node – The node you want to split.
  • left_edges – The edges you want connected to the new left node.
  • right_edges – The edges you want connected to the new right node.
  • left_name – The name of the new left node. If None, a name will be generated automatically.
  • right_name – The name of the new right node. If None, a name will be generated automatically.
  • edge_name – The name of the new Edge connecting the new left and right node. If None, a name will be generated automatically.
Returns:

left_node:

A new node that connects to all of the left_edges. Its underlying tensor is \(R^*\)

right_node:

A new node that connects to all of the right_edges. Its underlying tensor is \(Q^*\)

Return type:

A tuple containing

Raises:

AttributeError – If node has no backend attribute

tensornetwork.split_node_full_svd(node: tensornetwork.network_components.AbstractNode, left_edges: List[tensornetwork.network_components.Edge], right_edges: List[tensornetwork.network_components.Edge], max_singular_values: Optional[int] = None, max_truncation_err: Optional[float] = None, relative: Optional[bool] = False, left_name: Optional[str] = None, middle_name: Optional[str] = None, right_name: Optional[str] = None, left_edge_name: Optional[str] = None, right_edge_name: Optional[str] = None) → Tuple[tensornetwork.network_components.AbstractNode, tensornetwork.network_components.AbstractNode, tensornetwork.network_components.AbstractNode, Any]

Split a node by doing a full singular value decomposition.

Let \(M\) be the matrix created by flattening left_edges and right_edges into 2 axes. Let \(U S V^* = M\) be the Singular Value Decomposition of \(M\).

The left most node will be \(U\) tensor of the SVD, the middle node is the diagonal matrix of the singular values, ordered largest to smallest, and the right most node will be the \(V*\) tensor of the SVD.

The singular value decomposition is truncated if max_singular_values or max_truncation_err is not None.

The truncation error is the 2-norm of the vector of truncated singular values. If only max_truncation_err is set, as many singular values will be truncated as possible while maintaining: norm(truncated_singular_values) <= max_truncation_err. If relative is set True then max_truncation_err is understood relative to the largest singular value.

If only max_singular_values is set, the number of singular values kept will be min(max_singular_values, number_of_singular_values), so that max(0, number_of_singular_values - max_singular_values) are truncated.

If both max_truncation_err and max_singular_values are set, max_singular_values takes priority: The truncation error may be larger than max_truncation_err if required to satisfy max_singular_values.

Parameters:
  • node – The node you want to split.
  • left_edges – The edges you want connected to the new left node.
  • right_edges – The edges you want connected to the new right node.
  • max_singular_values – The maximum number of singular values to keep.
  • max_truncation_err – The maximum allowed truncation error.
  • relative – Multiply max_truncation_err with the largest singular value.
  • left_name – The name of the new left node. If None, a name will be generated automatically.
  • middle_name – The name of the new center node. If None, a name will be generated automatically.
  • right_name – The name of the new right node. If None, a name will be generated automatically.
  • left_edge_name – The name of the new left Edge connecting the new left node (\(U\)) and the new central node (\(S\)). If None, a name will be generated automatically.
  • right_edge_name – The name of the new right Edge connecting the new central node (\(S\)) and the new right node (\(V*\)). If None, a name will be generated automatically.
Returns:

left_node:

A new node created that connects to all of the left_edges. Its underlying tensor is \(U\)

singular_values_node:

A new node that has 2 edges connecting left_node and right_node. Its underlying tensor is \(S\)

right_node:

A new node created that connects to all of the right_edges. Its underlying tensor is \(V^*\)

truncated_singular_values:

The vector of truncated singular values.

Return type:

A tuple containing

Raises:

AttributeError – If node has no backend attribute

tensornetwork.split_edge(edge: tensornetwork.network_components.Edge, shape: Tuple[int, ...], new_edge_names: Optional[List[str]] = None) → List[tensornetwork.network_components.Edge]

Split an Edge into multiple edges according to shape. Reshapes the underlying tensors connected to the edge accordingly.

This method acts as the inverse operation of flattening edges and distinguishes between the following edge cases when adding new edges:

  1. standard edge connecting two different nodes: reshape node dimensions
  2. dangling edge (node2 is None): reshape node1 dimension
  3. trace edge (node1 is node2): reshape node1 dimension
Parameters:
  • edge – Edge to split.
  • shape – Tuple of integers used to split edge into multiple edges.
Returns:

A list of new edges where the product of the dimensions of the new edges corresponds to the dimension of the edge before splitting.

Raises:
  • ValueError – If the edge dimension mismatches with the split shape.
  • ValueError – If the edge is connecting nodes with different backends.
tensornetwork.slice_edge(edge: tensornetwork.network_components.Edge, start_index: int, length: int) → tensornetwork.network_components.Edge

Slices an edge and the connected tensors beginning at start_index for length length, along the axis determined by edge.

This method modifies the tensors stored in the two nodes connected by edge to corresponding tensor slices (along the axis determined by edge) and returns an updated edge connecting the two nodes along the same axis as the original edge.

Parameters:
  • edge – The edge to slice.
  • start_index – Integer specifying the beginning of the slice.
  • length – Integer specifying the length of the slice.
Returns:

The updated edge after slicing.

Raises:
  • ValueError – If the length of the slice is negative.
  • ValueError – If the slice is incompatible with the edge dimension.
  • ValueError – If the edge is connecting nodes with different backends.
tensornetwork.reachable(inputs: Union[tensornetwork.network_components.AbstractNode, Iterable[tensornetwork.network_components.AbstractNode], tensornetwork.network_components.Edge, Iterable[tensornetwork.network_components.Edge]]) → Set[tensornetwork.network_components.AbstractNode]

Computes all nodes reachable from node or edge.node1 by connected edges.

Parameters:inputs – A AbstractNode/Edge or collection of AbstractNodes/Edges
Returns:A set of AbstractNode objects that can be reached from node via connected edges.
Raises:TypeError – If inputs contains other then Edge or Node.
tensornetwork.check_connected(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → None

Check if all nodes in nodes are connected.

Parameters:nodes – A list of nodes.
Returns:None
Raises:ValueError – If not all nodes in nodes are connected.
tensornetwork.check_correct(nodes: Iterable[tensornetwork.network_components.AbstractNode], check_connections: Optional[bool] = True) → None

Check if the network defined by nodes fulfills necessary consistency relations.

Parameters:
  • nodes – A list of AbstractNode objects.
  • check_connections – Check if the network is connected.
Returns:

None

Raises:

ValueError – If the network defined by nodes is not correctly structured.

tensornetwork.get_all_nodes(edges: Iterable[tensornetwork.network_components.Edge]) → Set[tensornetwork.network_components.AbstractNode]

Return the set of nodes connected to edges.

tensornetwork.get_all_edges(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → Set[tensornetwork.network_components.Edge]

Return the set of edges of all nodes.

tensornetwork.get_subgraph_dangling(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → Set[tensornetwork.network_components.Edge]

Get all of the edges that are “relatively dangling” to the given nodes.

A “relatively dangling” edge is an edge that is either actually dangling or is connected to another node that is outside of the given collection of nodes.

Parameters:nodes – A set of nodes.
Returns:The set of “relatively dangling” edges.
tensornetwork.reduced_density(traced_out_edges: Iterable[tensornetwork.network_components.Edge]) → Tuple[dict, dict]

Constructs the tensor network for a reduced density matrix, if it is pure.

The tensor network connected to traced_out_edges is assumed to be a pure quantum state (a state vector). This modifies the network so that it describes the reduced density matrix obtained by “tracing out” the specified edges.

This is done by making a conjugate copy of the original network and connecting each edge in traced_out_edges with its conjugate counterpart.

The edges in edge_dict corresponding to traced_out_edges will be the new non-dangling edges connecting the state with its conjugate.

Parameters:traced_out_edges – A list of dangling edges.
Returns:
node_dict: A dictionary mapping the nodes in the original network to
their conjugate copies.
edge_dict: A dictionary mapping edges in the original network to their
conjugate copies.
Return type:A tuple containing
tensornetwork.switch_backend(nodes: Iterable[tensornetwork.network_components.AbstractNode], new_backend: str) → None

Change the backend of the nodes.

This will convert all node’s tensors to the new_backend’s Tensor type.

Parameters:
  • nodes – iterable of nodes
  • new_backend (str) – The new backend.
  • dtype (datatype) – The dtype of the backend. If None, a defautl dtype according to config.py will be chosen.
Returns:

None

tensornetwork.contract_trace_edges(node: tensornetwork.network_components.AbstractNode) → tensornetwork.network_components.AbstractNode

contract all trace edges of node.

Parameters:node – A AbstractNode object.
Returns:A new AbstractNode obtained from contracting all trace edges.
tensornetwork.contract(edge: tensornetwork.network_components.Edge, name: Optional[str] = None, axis_names: Optional[List[str]] = None) → tensornetwork.network_components.AbstractNode

Contract an edge connecting two nodes.

All edges of node1 and node2 are passed on to the new node, and node1 and node2 get a new set of dangling edges. edge is disabled before returning.

Parameters:
  • edge – The edge to contract.
  • 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.

tensornetwork.contract_copy_node(copy_node: tensornetwork.network_components.CopyNode, name: Optional[str] = None) → tensornetwork.network_components.AbstractNode

Contract all edges incident on given copy node.

Parameters:
  • copy_node – Copy tensor node to be contracted.
  • name – Name of the new node created.
Returns:

New node representing contracted tensor.

Raises:

ValueError – If copy_node has dangling edge(s).

tensornetwork.contract_between(node1: tensornetwork.network_components.AbstractNode, node2: tensornetwork.network_components.AbstractNode, name: Optional[str] = None, allow_outer_product: bool = False, output_edge_order: Optional[Sequence[tensornetwork.network_components.Edge]] = None, axis_names: Optional[List[str]] = None) → tensornetwork.network_components.AbstractNode

Contract all of the edges between the two given nodes.

If output_edge_order is not set, the output axes will be ordered as: [...free axes of node1..., ...free axes of node2...]. Within the axes of each node, the input order is preserved.

Parameters:
  • node1 – The first node.
  • node2 – The second node.
  • name – Name to give to the new node created.
  • allow_outer_product – Optional boolean. If two nodes do not share any edges and allow_outer_product is set to True, then we return the outer product of the two nodes. Else, we raise a ValueError.
  • output_edge_order – Optional sequence of Edges. When not None, must contain all edges belonging to, but not shared by node1 and node2. The axes of the new node will be permuted (if necessary) to match this ordering of Edges.
  • axis_names – An optional list of names for the axis of the new node in order of the output axes.
Returns:

The new node created.

Raises:

ValueError – If no edges are found between node1 and node2 and allow_outer_product is set to False.

tensornetwork.outer_product(node1: tensornetwork.network_components.AbstractNode, node2: tensornetwork.network_components.AbstractNode, name: Optional[str] = None, axis_names: Optional[List[str]] = None) → tensornetwork.network_components.AbstractNode

Calculates an outer product of the two nodes.

This causes the nodes to combine their edges and axes, so the shapes are combined. For example, if a had a shape (2, 3) and b had a shape :math`(4, 5, 6)`, then the node net.outer_product(a, b) will have shape \((2, 3, 4, 5, 6)\). All edges of node1 and node2 are passed on to the new node, and node1 and node2 get a new set of dangling edges.

Parameters:
  • node1 – The first node. The axes on this node will be on the left side of the new node.
  • node2 – The second node. The axes on this node will be on the right side of the new node.
  • name – Optional name to give the new node created.
  • axis_names – An optional list of names for the axis of the new node.
Returns:

A new node. Its shape will be node1.shape + node2.shape.

Raises:

TypeError – If node1 and node2 have wrong types.

tensornetwork.outer_product_final_nodes(nodes: Iterable[tensornetwork.network_components.AbstractNode], edge_order: List[tensornetwork.network_components.Edge]) → tensornetwork.network_components.AbstractNode

Get the outer product of nodes

For example, if there are 3 nodes remaining in nodes with shapes \((2, 3)\), \((4, 5, 6)\), and \((7)\) respectively, the newly returned node will have shape \((2, 3, 4, 5, 6, 7)\).

Parameters:
  • nodes – A collection of nodes.
  • edge_order – Edge order for the final node.
Returns:

The outer product of the remaining nodes.

Raises:

ValueError – If any of the remaining nodes are not fully contracted.

tensornetwork.contract_parallel(edge: tensornetwork.network_components.Edge) → tensornetwork.network_components.AbstractNode

Contract all edges parallel to this edge.

This method calls contract_between with the nodes connected by the edge.

Parameters:edge – The edge to contract.
Returns:The new node created after contraction.
tensornetwork.flatten_edges(edges: List[tensornetwork.network_components.Edge], new_edge_name: Optional[str] = None) → tensornetwork.network_components.Edge

Flatten edges into single edge.

If two nodes have multiple edges connecting them, it may be beneficial to flatten these edges into a single edge to avoid having several unnecessary trace edges. This can speed up computation time and reduce memory cost.

Warning: This will remove all axes names.

Parameters:
  • edges – A list of edges to flatten.
  • new_edge_name – Optional name to give to the newly created edge.
Returns:

The new flattened edge.

Raises:
  • ValueError – If edges is an empty list.
  • ValueError – If not all of the edges connect to the same node(s).
  • ValueError – If one of the nodes connecting to these edges does not have edge definitions for all of its axes.
tensornetwork.get_all_nondangling(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → Set[tensornetwork.network_components.Edge]

Return the set of all non-dangling edges.

tensornetwork.get_all_dangling(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → List[tensornetwork.network_components.Edge]

Return the set of all dangling edges.

tensornetwork.flatten_all_edges(nodes: Iterable[tensornetwork.network_components.AbstractNode]) → List[tensornetwork.network_components.Edge]

Flatten all edges that belong to the nodes.

Returns:A list of all the flattened edges. If there was only one edge between two given nodes, that original edge is included in this list.
tensornetwork.flatten_edges_between(node1: tensornetwork.network_components.AbstractNode, node2: tensornetwork.network_components.AbstractNode) → Optional[tensornetwork.network_components.Edge]

Flatten all of the edges between the given two nodes.

Parameters:
  • node1 – The first node.
  • node2 – The second node.
Returns:

The flattened Edge object. If there was only one edge between the two

nodes, then the original edge is returned. If there were no edges between the nodes, a None is returned.

tensornetwork.get_parallel_edges(edge: tensornetwork.network_components.Edge) → Set[tensornetwork.network_components.Edge]

Get all of the edges parallel to the given edge. :param edge: The given edge.

Returns:A set of all of the edges parallel to the given edge (including the given edge).
tensornetwork.get_shared_edges(node1: tensornetwork.network_components.AbstractNode, node2: tensornetwork.network_components.AbstractNode) → Set[tensornetwork.network_components.Edge]

Get all edges shared between two nodes.

Parameters:
  • node1 – The first node.
  • node2 – The second node.
Returns:

A (possibly empty) set of `Edge`s shared by the nodes.

tensornetwork.get_neighbors(node: tensornetwork.network_components.AbstractNode) → List[tensornetwork.network_components.AbstractNode]

Get all of the neighbors that are directly connected to the given node.

Note: node will never be in the returned list, even if node has a trace edge.

Parameters:node – A node.
Returns:All of the neighboring edges that share an Edge with node.
tensornetwork.kron(tensorA: tensornetwork.tensor.Tensor, tensorB: tensornetwork.tensor.Tensor) → tensornetwork.tensor.Tensor

Compute the (tensor) kronecker product between tensorA and tensorB. tensorA and tensorB can be tensors of any even order (i.e. tensorA.ndim % 2 == 0, tensorB.ndim % 2 == 0). The returned tensor has index ordering such that when reshaped into a matrix with pivot =t ensorA.ndim//2 + tensorB.ndim//2, the resulting matrix is identical to the result of numpy’s np.kron(matrixA, matrixB), with matrixA, matrixB matrices obtained from reshaping tensorA and tensorB into matrices with pivotA = tensorA.ndim//2, pivotB = tensorB.ndim//2

Example: tensorA.shape = (2,3,4,5), tensorB.shape(6,7) -> kron(tensorA, tensorB).shape = (2, 3, 6, 4, 5, 7)

Parameters:
  • tensorA – A Tensor.
  • tensorB – A Tensor.
Returns:

The kronecker product.

Return type:

Tensor

Raises:

ValueError – - If backends, are not matching. - If ndims of the input tensors are not even.