QXTns

QXTns is a Julia package with data structures and utilities for manipulating tensor networks. As well as generic tensor network data structure, it also contains specific data structures for handling tensor networks derived from quantum circuits. It was developed as part of the QuantEx project, one of the individual software projects of WP8 of PRACE 6IP.

It uses some features from ITensors and NDTensors for representing tensors and indices and performing contractions.

Installation

QXTns is a Julia package and can be installed using Julia's inbuilt package manager from the Julia REPL using.

import Pkg
Pkg.add("QXTns")

To ensure everything is working, the unittests can be run using

import Pkg; Pkg.test()

Example usage

An example of creating a simple tensor network and contracting.

using QXTns

tn = TensorNetwork()

a, b, c, d = Index(2), Index(3), Index(5), Index(4)

# add a 2x3x5 rank tensor
push!(tn, [a, b, c], rand(2, 3, 5))
# add a 5x4 matrix
push!(tn, [c, d], rand(5, 4))

# contract network
simple_contraction!(tn)

# number of tensors after contraction
@show length(tn)

# resulting tensor has dimensions should have dimensions 2x3x4
@show size(first(tn))

Contributing

Contributions from users are welcome and we encourage users to open issues and submit merge/pull requests for any problems or feature requests they have. The CONTRIBUTING.md on the top level of the source folder has further details of the contribution guidelines.

Building documentation

QXTns.jl uses Documenter.jl to generate documentation. To build the documentation locally run the following from the root folder.

The first time it is will be necessary to instantiate the environment to install dependencies

julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'

and then to build the documentation

julia --project=docs/ docs/make.jl

The generated document will be in the docs/build folder. To serve these locally one can use the LiveServer package as

julia --project -e 'import Pkg; Pkg.add("LiveServer");
julia --project -e  'using LiveServer; serve(dir="docs/build")'

Or with python3 using from the docs/build folder using

python3 -m http.server

The generated documentation should now be viewable locally in a browser at http://localhost:8000.

API Reference

QXTns.QXTensorType
QXTensor(indices::Vector{<:Index},
         hyper_indices::Union{Nothing, Vector{<:Vector{Int64}}},
         storage::Union{Nothing, <: AbstractArray}=nothing;
         diagonal_check::Bool=true)

QXTensor constructor creates a new instance of QXTensor with the given indices and hyper indices. If no storage data structure is given then a MockTensor of that shape is added as the storage. If diagonalcheck is true, it will automaticallly check which indices are hyper indices and record in the hyperindices field. If hyper_indices are given, then these are used.

source
QXTns.QXTensorMethod
QXTensor(a::T) where T <: Number

QXTensor constructor which creates a new instance of QXTensor corresponding to a scalar

source
QXTns.TensorNetworkMethod
TensorNetwork(array::Vector{<: QXTensor})

Outer constructor to create a tensor network object from an array of ITensor objects.

source
Base.copyMethod

Overload functions from base to make MockTensor usable

source
Base.copyMethod

Overload functions from base to make BlockTensor usable

source
Base.delete!Method
delete!(tn::TensorNetwork, tensor_id::Symbol)

Function to remove a tensor from a tensor network.

source
Base.delete!Method
delete!(tnc::TensorNetworkCircuit, tensor_id::Symbol)

Function to remove a tensor from a tensor network circuit.

source
Base.getindexMethod
Base.getindex(t::BlockTensor{T, N, M}, i...) where {T, N, M}

Overload the getindex function. Returns zero if the indiex on ranks identified as hyperindex groups differ and the relevant tensor index otherwise.

source
Base.mergeMethod
merge(a::TensorNetwork, b::TensorNetwork)

Join two networks together

source
Base.push!Method
push!(tn::TensorNetwork,
      tensor::QXTensor;
      tid::Union{Nothing, Symbol}=nothing)

Function to add a tensor to the tensor network.

Keywords

  • tid::Union{Nothing, Symbol}=nothing: the id for the new tensor in tn. An id is

generated if one is not set.

source
Base.push!Method
push!(tn::TensorNetwork,
      indices::Vector{Index},
      data::Array{T, N}
      tid::Union{Nothing, Symbol}=nothing) where {T, N}

Function to add a tensor to the tensor network.

Keywords

  • tid::Union{Nothing, Symbol}=nothing: the id for the new tensor in tn. An id is

generated if one is not set.

source
Base.push!Method
push!(tnc::TensorNetworkCircuit,
      qubits::Vector{Int64},
      data::Array{T, 2}) where T

Function to add a gate to the tensor network circuit given the qubits it acts on and an array of the matrix elements

source
QXTns.add_input!Function
add_input!(tnc::TensorNetworkCircuit; input::Union{String, Nothing}=nothing)

Function to add input tensors to the circuit

source
QXTns.add_output!Function
add_output!(tnc::TensorNetworkCircuit; output::Union{String, Nothing}=nothing)

Function to add output tensors to the circuit

source
QXTns.contract_pair!Function
contract_pair!(tn::TensorNetwork, a_sym::Symbol, b_sym::Symbol, c_sym::Symbol=:_; mock::Bool=false)

Contract the tensors in 'tn' with ids 'asym' and 'bsym'. If the mock flag is true then the new tensor will be a mock tensor with the right dimensions but without the actual data.

The resulting tensor is stored in tn under the symbol c_sym if one is provided, otherwise a new id is created for it.

source
QXTns.contract_pairMethod
contract_pair(tn::TensorNetwork, a_sym::Symbol, b_sym::Symbol; mock::Bool=false)

Contract the tensors in 'tn' with ids 'asym' and 'bsym'. If the mock flag is true then the new tensor will be a mock tensor with the right dimensions but without the actual data.

source
QXTns.contract_tensorsMethod
contract_tensors(a::QXTensor, b::QXTensor; mock::Bool=false)

Function to contract two QXTensors and return another QXTensor. If the mock flag is false or either of the input tensors use MockTensor then the storage for the final tensor will be of type MockTensor.

source
QXTns.contract_tn!Method
contract_tn!(tn::TensorNetwork, plan)

Contract the indices of 'tn' according to 'plan'.

source
QXTns.contraction_indicesMethod
contraction_indices((a::QXTensor,b::QXTensor)

Function to work out the contraction indices that would be used to contract the given tensors. Exptected indices in Einstein notation using positive integers

source
QXTns.contraction_indicesMethod
contraction_indices(tn::TensorNetwork, a_sym::Symbol, b_sym::Symbol)

Function to work out the contraction indices that would be used to contract the given tensors. Expected indices in Einstein notation using positive integers

source
QXTns.create_test_tncMethod
create_test_tnc(;input::Union{String, Nothing}=nothing,
                output::Union{String, Nothing}=nothing,
                no_input::Bool=false,
                no_output::Bool=false,
                kwargs...)

Create a tensor network circuit for a small example circuit, 3 qubit ghz preparation circuit in this case

source
QXTns.decompose_gateFunction
function decompose_gate!(gate_data::Array{<:Number, 4},
                         threshold::AbstractFloat=1e-15)

Function to decompose a tensor into two smaller tensors

source
QXTns.decompose_tensor!Method
decompose_tensor!(tn::TensorNetwork,
                  tensor_id::Symbol,
                  left_indices::Array{<:Index, 1};
                  contract_S_with::Symbol=:V,
                  kwargs...)

Function to decompose a tensor in a tensor network using svd.

Keywords

  • contract_S_with::Symbol=:V: the maxtrix which should absorb the matrix of singular values
  • maxdim::Int: the maximum number of singular values to keep.
  • mindim::Int: the minimum number of singular values to keep.
  • cutoff::Float64: set the desired truncation error of the SVD.
source
QXTns.disable_hyperindices!Method
disable_hyperindices!(t::QXTensor)

Function to disable use of hyper indices with this tensor by removing the hyper indices and reshaping storage

source
QXTns.expand_tensorMethod
expand_tensor(A::AbstractArray{Elt, N}, hyper_index_groups::Array{Int64, 1})

Function to expand the rank of the given tensor assuming the given hyper edge groups. Like a generalisation of Diagonal. For example if passed a vector and given hyperindex groups [1,2], it will return a matrix where non diagonal elements are zero. Returns a a BlockTensor object which does not store "off-diagonal" elements.

julia> expand_tensor([1, 2], [[1, 2]])
BlockTensor with dims (2, 2) and index map (1, 1)
source
QXTns.find_connected_indicesMethod
find_connected_indices(tn::TensorNetwork, bond::Index)

Given a tensor network and an index in the network, find all indices that are related via hyper edge relations. Involves recurisively checking bonds connected to neighbouring tensors of any newly related edges found. Returns an array of all edges in the group including the initial edge.

source
QXTns.find_hyper_edgesMethod
function find_hyper_edges(A::AbstractArray{Elt, N}) where {Elt, N}

Function to identify hyper edges of tensors. Returns an array of tuples of indices of the original tensor which can be identified

source
QXTns.get_hyperedgesMethod
get_hyperedges(tn::TensorNetwork)::Array{Array{Symbol, 1}, 1}

Return an array of hyperedges in the given tensornetwork tn.

Hyperedges are represented as arrays of tensor symbols.

source
QXTns.hyperindicesMethod
hyperindices(t::QXTensor)

Function to get the hyper indices as an array of Indices. If the all_indices flag is true, then all indices are returned, if false then just the groups of 2 or more are returned.

source
QXTns.hyperindicesMethod
hyperindices(tn::TensorNetwork, i::Symbol; global_hyperindices=true)

Find groups of hyper indices for the given tensor. When global_hyperindices is set to true, then indices which are identified as hyperindices because of groups of hyperindices in conneted tensors in the network are also included.

source
QXTns.indices2ranksMethod
indices2ranks(tensor::QXTensor, hi::Vector{<:Vector{<:Index}})

Function convert groups of indices to groups of index positions (ranks).

source
QXTns.isdiagonalMethod
isdiagonal(A::AbstractArray{Elt, 2}) where Elt

Function to check if the given matrix is diagonal

source
QXTns.isdiagonalMethod
isdiagonal(A::AbstractArray{Elt, N}, Pair{Int64, Int64}) where {Elt, N}

Function to check if the given matrix is diagonal along given axes

source
QXTns.neighboursMethod
neighbours(tn::TensorNetwork, tensor::Symbol)

Function get the symbols of the neighbouring tensors

source
QXTns.push_input!Method
push_input!(tnc::TensorNetworkCircuit, tensor::Array{Elt, 1}, pos::Int64) where Elt

Function to add a single input tensor to the tensor network circuit at the given position

source
QXTns.push_output!Method
push_output!(tnc::TensorNetworkCircuit, tensor::Array{Elt, 1}, pos::Int64) where Elt

Function to add a single output tensor to the tensor network circuit at the given position

source
QXTns.reduce_tensorMethod
reduce_tensor(A::AbstractArray{Elt, N}, hyper_index_groups::Array{Int64, 1})

Function to reduce the rank of the given tensor assuming the given hyper edge groups. For example a diagonal matrix will have a single hyper edge group with both indices [1, 2]. This function will reduce this to a vector containing only the diagonal elements. can be seen as a generalisation of the diag function.

julia> reduce_tensor([[1, 0] [0, 2]], [[1, 2]])
2-element Vector{Int64}:
 1
 2
source
QXTns.replace_tensor_symbol!Method
replace_tensor_symbol!(tn::TensorNetwork, orig_sym::Symbol, new_sym::Symbol)

Replace the given symbol with the given new symbol

source
QXTns.simple_contraction!Method
simple_contraction!(tn::TensorNetwork)

Function to perfrom a simple contraction, contracting all tensors in order. Only useful for very small networks for testing.

source
QXTns.simple_contractionMethod
simple_contraction(tn::TensorNetwork)

Function to perfrom a simple contraction, contracting all tensors in order. Only useful for very small networks for testing.

source
QXTns.tensor_dataMethod
tensor_data(tensor::QXTensor; consider_hyperindices::Bool=true)

Get the data associated with the given tensor. If the considerhyperindices flag is true then the rank is reduced to merge related indices. For example for a 5 rank tensor where the 2nd and 4th indices form a group of hyper indices, with this option set to true would return a rank 4 tensor where the 2nd index has been merged with the 4th. With `considerhyperindices` set to false a rank 5 tensor is returned.

source
QXTns.tensor_dataMethod
tensor_data(tn::TensorNetwork, i::Symbol; consider_hyperindices=true, global_hyperindices=true)

Retrieve the tensor data for the given tensor. If the considerhyperindices flag is true then then the data is reshaped to take into account the local hyperindices of the tensor. If the globalhyperindices index is also true then groups of hyperindices related via hyperindices for other tensors in the network are also considered.

source