Tensor network and its contractions

This page serves as documentation for our main tensor network contraction engine.

Overview

Tensor Valued Objects

A tensor is a multi-dimensional array of numbers. The number of dimensions associated to a tensor is called the rank of the tensor. For example, a tensor of rank 0 represent a scalar \(T\). A tensor of rank 1 is a vector \((T_i)_{i=0}^{d-1}\), and a tensor of rank 2 is a matrix \((T_{ij})_{(i,j)\in [d_0]\times [d_1]}\). The dimension corresponds to each of the indices are called bond dimensions associated to the indices.

A tensor network represents a multi-linear map of multiple tensors that results in a new tensor. For example:

  • The inner product of two vectors \(U, V\) can be expressed as \(T = \sum_i U_i\cdot V_i\).

  • The outer product of two vectors \(U, V\) can be expressed as \(T_{ij} = U_i\cdot V_j\).

  • The element-wise product of two vectors \(U, V\) can be expressed as \(T_i = U_i\cdot V_i\).

  • The matrix product of two matrices \(M, N\) can be expressed as \(T_{ij}=\sum_k U_{ik}\cdot V_{kj}\).

Explicit expressions like above are good for sake of demonstrations, but more complex tensor networks could arise from various scenarios, including many-body physics, machine learning and quantum computation. There are several equivalent ways of expressing a tensor network:

  • Einstein summation. An einstein summation takes the form [indices_0],[indices_1],…,[indices_k]->[indices_o]. Each term on the left hand side corresponds to the indices configuration of an operand, and the indices on the right hand side corresponds to the indices on the right hand side, also called the open indices. All matching indices are identified with each other, and the closed indices, i.e. the ones that do not appear on the right hand side, are being summed over. The four examples above, expressed in terms of the Einstein summation, are respectively i,i->, i,j->ij, i,i->i, ik,kj->ij. There is a more restrictive interpretation of the einstein summation that each index appears exactly twice in the expression and the right hand side is thus removed. We do not take such convention. Moreover, each edge can appear multiple times on the right hand side, and does not have to appear on the left hand side as long as each index is associated with a definite bond dimension.

  • Attributed Multi-hypergraph. A tensor network can be expressed as a multi-hypergraph, where each node corresponds to a tensor operand, and each hyperedge an index. This provides a graphical, intuitive representation of a tensor network.

Our package not only supports the definition and manipulation of tensors and tensor networks, but also unary functions acting on a tensor and summation of tensors with the same shape. These extensions help us handle different scenarios where tensors appear naturally in an easier manner.

class acqdp.tensor_network.TensorValued(*args, **kwargs)[source]

Interface for all TensorValued objects, including Tensor, TensorNetwork, TensorSum and TensorView.

Variables
  • identifier – unique identifier for each TensorValued object.

  • dtype – A TensorValued object is homogeneous, and contains elements described by a dtype object.

property shape

The common property of all TensorValued classes, indicating whether the bond dimensions for a tensor valued object. A tensor valued object is semantically a multi-dimensionally array, and its dimensions can be expressed as a tuple of integers. The tuple is called the shape of the tensor, whereas the length of the tuple is the rank of the tensor.

In ACQDP, undetermined tensors and undetermined dimensions are allowed. In the former case, the shape of the tensor will return None; in the latter case, some of the bond_dimensions appearing in the tuple could be None.

Returns

tuple or None

Raises

NotImplementedError, ValueError

property is_valid

The common property of all TensorValued classes, indicating whether the TensorValued object is valid or not. In every step of a program, all existing TensorValued object must be valid, otherwise an exception should be thrown out.

Returns

bool

Raises

NotImplementedError

property is_ready

The common property of all TensorValued classes, indicating whether the current TensorValued object is ready for contraction, i.e. whether it semantically represents a tensor with a definite value. A TensorValued object needs to be ready upon contraction, but needs not to be ready throught the construction.

Returns

bool

Raises

NotImplementedError()

fix_index(index, fix_to=0) → acqdp.tensor_network.tensor_valued.TensorValued[source]

Fix the given index to the given value. The result TensorValued object would have the same type as the original one, with rank 1 smaller than the original.

Parameters
  • index (int) – The index to fix.

  • fix_to (bool) – the value to assign to the given index.

Returns

TensorValued – The TensorValued object after fixing the given index.

Raises

NotImplementedError

contract(**kwargs) → numpy.ndarray[source]

Evaluate the TensorValued object to a numpy.ndarray.

Returns

numpy.ndarray

Raises

NotImplementedError

cast(dtype)[source]

Cast the tensor valued object to a new underlying dtype.

class acqdp.tensor_network.Tensor(*args, **kwargs)[source]

Bases: acqdp.tensor_network.tensor_valued.TensorValued

A Tensor is an array of numbers with multiple dimensions. The most basic examples of a Tensor are a vector (1-dimensional arrays of numbers) and a matrix (2-dimensional arrays).

In our implementation, Tensor is a subclass of TensorValued, where the value is stored in an numpy.ndarray. All other TensorValued represent operations over the Tensor objects.

Variables

_datanumpy.ndarray object representing the data corresponding to the tensor.

__init__(data: numpy.ndarray = None, dtype: type = <class 'complex'>)None[source]

Constructor of a Tensor object.

class acqdp.tensor_network.TensorSum(*args, **kwargs)[source]

Bases: acqdp.tensor_network.tensor_valued.TensorValued

A TensorSum object represents the summation of multiple tensors.

Variables

terms_by_name – a dictionary with key-value pairs, where the key is the name of a summand and the value is the corresponding summand TensorValued object.

__init__(terms=None, dtype: type = <class 'complex'>)None[source]

The constructor of a TensorSum object.

add_term(term=None, tensor=None)[source]

Add a term to the summation.

Parameters
  • term (hashable) – Name of the term to be added. If not given, an auto-assigned one will be given as the output.

  • tensor (TensorValued or None) – Value of the term to be added.

Returns

The name of the newly added term.

update_term(term, tensor=None)[source]

Update the value of a term in the summation.

Parameters
  • term (hashable) – Name of the term to be updated.

  • tensor (TensorValued) – New value of the term

Returns

Name of the term to be updated.

remove_term(term)[source]

Remove a term from the summation.

Parameters

term (hashable) – Name of the term to be removed.

Returns

TensorValued Value of the removed term

class acqdp.tensor_network.TensorView(*args, **kwargs)[source]

Bases: acqdp.tensor_network.tensor_valued.TensorValued

TensorView is a subclass of TensorValued representing unary operations over another TensorValued

object that preserves the shape of the tensor. Common examples include element-wise conjugation and normalization with respect to the frobenius norm.

Variables
  • tn – the underlying TensorValued object where the unary operation is performed onto.

  • func – the unary function to be applied.

  • homomorphism – indicator whether the unary function is homomorphic to the addition and multiplication of tensors. If so, the unary function can be broadcast to lower-level tensors, enabling potential simplification of the tensor network structure.

  • dtype – dtype for the tensor entries.

__init__(tn, func=<ufunc 'conjugate'>, homomorphism=False, dtype=<class 'complex'>)[source]

The constructor of a TensorView object.

class acqdp.tensor_network.TensorNetwork(*args, **kwargs)[source]

Bases: acqdp.tensor_network.tensor_valued.TensorValued

A TensorNetwork is a collection of Tensor, with indices from different tensors identified and summed up to present a new tensor. An example of tensor network is two 2-tensors with a common edge representing the matrix multiplication. A TensorNetwork is a graphical representation of an Einstein summation.

Variables
  • network – attributed networkx.Graph object, representing the attributed hypergraph of the tensor network as a tanner graph.

  • dtype – dtype of the TensorValued object.

  • open_edges – a list of edge names, indicating the outgoing wires of the tensor network.

contract(preset=None, config=None, **kwargs)[source]

Evaluate the TensorNetwork object as an numpy.ndarray.

Parameters
  • preset (“default”, “khp” or None.) – Select a preset mode. If set to default, will contract the tensor network with default ordering and no post-processing. If set to khp, will invoke advanced KaHyPar-based contraction order finding routine. If set to None, will read config file or input keyword arguments for order finding specifications.

  • config (str) – File name for the config file. If preset option is not given and config file is given, the keyword arguments will be ignored and the specification will be read from the config file.

  • kwargs (dict) – If neither the preset option nor the config file name is given, the program will read the keyword arguments for order finding specifications. See OrderFinder, Compiler, Contractor for individual specifications.

Returns

numpy.ndarray.

find_order(input_file=None, output_file=None, **kwargs)[source]

Find a contraction scheme of the TensorNetwork object. Equivalent to next(get_order_finder(**kwargs).find_order(self)). See OrderFinder.find_order().

Parameters
  • input_file (str, optional) – Input file name. When given, load the contraction scheme from the input file.

  • output_file (str, optional) – Output file name. When given, the contraction scheme found will be dumped into the file.

Returns

ContractionScheme

compile(order, **kwargs)[source]

Compile a ContractionScheme corresponding to the TensorNetwork object into a runtime executable contraction process as a ContractionTask. Equivalent to Compiler(**kwargs.get(‘compiler_params’, {})).compile(self, order) (See Compiler.compile()).

Returns

ContractionTask

add_node(node_name=None, edges=None, tensor=None, is_open=False)[source]

Add a node into the tensor network.

Parameters
  • node_name (hashable) – The name of the node to be added. If not provided, a new name will be assigned.

  • edges (List – list of edges in the tensor network corresponding to the open edges of the new node. If not given, defaults to edges [0, …, len(shape)]) – The edges the new tensor node is being connected to.

  • tensor (tensor_network.tensor_valued.TensorValued.) – The value of the newly added tensor.

  • is_open (bool) – Whether the new indices associated to the new node will be added to open_edges.

Returns

hashable – Name of the node added. If none is given as input, return the one automatically signed.

Raises

ValueError – An existing node in the tensor network is being added.

Raises

IndexError – A node is added with ambiguous connection to the tensor network. Happens when neither the shape of the tensor nor the connecting edges are given.

Raises

AssertionError – A mismatch in the bond dimensions.

pop_node(node_name)[source]

Pop a tensor node from the tensor network. This operation simply removes the node from the hypergraph.

Returns

dict – The dict containing all the information of the popped node, including its tensor and hyperedge connections.

Parameters

node_name (hashable) – Name of the node to be popped.

remove_node(node_name)[source]

Remove a tensor node from the tensor network. The difference between removing a node and popping anode is that popping a node does not change the output shape of the tensor network, while removing a node would result in a new tensor-valued object, where all edges connected to the removed node are appended to the end of the open edges list.

Returns

dict – The dict containing all the information of the removed node, including its tensor and hyperedge connections.

Parameters

node_name (hashable) – Name of the node to be removed.

update_node(node_name, tensor=None)[source]

Update an existing node of the tensor network by another tensor-valued object.

Parameters
  • node_name (hashable) – Name of the node to be updated.

  • tensor (TensorValued or None) – The new tensor to be put at the node. If None, the tensor must be updated with an actual value later in order for the tensor network to be ready for contraction.

Raises

AssertionError – Node update results in a bond dimension mismatch.

add_edge(edge_name=None, bond_dim=None)[source]

Generate an index which is not in this tensor network before.

Parameters
  • edge_name (hashable) – Name of the edge to be added. Will be automatically assigned if none is given.

  • bond_dim (int or None) – Bond dimension of the edge. If set to None, the edge bond dimension will be wildcard until set otherwise.

Returns

hashable – Name of the newly added edge.

open_edge(edge_name=None, bond_dim=None)[source]

Append an edge to the list of open edges. If the edge does not exist, it will be created.

Parameters
  • edge_name (hashable) – Name of the edge to be opened.

  • bond_dim (int) – Bond dimension of the edge. See add_edge.

close_edge(edge_name)[source]

Make an edge closed. All appearances of the edge will be removed from the open edges list.

Parameters

edge_name (hashable) – Edge to be closed.

fix_edge(edge_name, fix_to=0, change_fix=False)[source]

Fix an edge to a fixed value. The tensor network structure is not yet modified; this method only puts an attribute to the fixed hyperedges. The structure will be changed upon calling the fix method.

Parameters
  • edge_name (hashable) – Edge to be fixed to a specific value.

  • fix_to (int) – the value the edge is fixed to. Should be an integer ranging from 0 to bond_dim - 1.

  • change_fix (bool) – Mode of fix_edge. If change_fix is set to True, the edge will be fixed to the given value regardless of how it is fixed previously. If set to False, the fix will apply together with the previous fix, resulting in a zero tensor if the two fixes do not match.

merge_edges(edges, merge_to=None)[source]

Merge a list of edges as one single edge by identification.

Parameters
  • edges (List) – The list of edges to be merged into one.

  • merge_to (hashable) – The name of the edge all the edges are merged to. If set to None, the merged edges will appear as edges[0]

rewire(node_name, leg, rewire_to=None)[source]

Rewire an outgoing edge of a tensor node to another edge in the tensor network.

Parameters
  • node_name (hashable) – Name of the tensor node for whom an outgoing edge is to be rewired.

  • leg (int) – Index of the outgoing edge regarding the tensor node. Should be an integer ranging from 0 to rank(t) - 1, t being the corresponding tensor.

  • rewire_to (hashable) – The edge name in the tensor network to redirect the leg to. If None, it will be rewired to a newly created edge.