Basic examples
Initialization
To initialize the tensor, you can import it from either a numpy.ndarray
or sparse.COO
object. You can also choose your Grassmann tensor to be stored in a dense
or sparse
format
import numpy as np
import grassmanntn as gtn
A_coeff = np.arange(4096).reshape(8,8,8,8) # defining an 8x8x8x8 coefficient tensor
A_stats = (1,1,-1,-1) # -1 is a conjugated index,
# # +1 is a non-conjugated index.
# # 0 is a bosonic index
A_dense = gtn.dense(data=A_coeff, statistics=A_stats) # defining a dense grassmann tensor
A_sparse = gtn.sparse(data=A_coeff, statistics=A_stats) # defining a sparse grassmann tensor
The two formats can be switched at any time
A_dense = gtn.dense(A_sparse)
Every function in this package is agnostic to the tensor format.
Contraction
Typically, when two tensors are contracted, appropriate sign factor must be multiplied due to the Grassmann anti-commutativity; e.g., for \(\mathcal{A}_{\bar\psi\phi}=\sum_{I,J}A_{IJ}\bar\psi^I\phi^J\) and \(\mathcal{B}_{\eta\bar\phi}=\sum_{I,J}B_{IJ}\eta^I\bar\phi^J\), we have
where, for \(I=(i_1,i_2,\cdots i_m)\in\{0,1\}^m\), \(J=(j_1,j_2,\cdots j_n)\in\{0,1\}^n\), and \(K=(k_1,k_2,\cdots k_l)\in\{0,1\}^l\), we have to introduce the sign factor
In the coding, we have to write the sign factor down explicitly—hardcoded. This is not a good idea if your algorithm involves a lot of contractions with many indices.
In this package, the contraction can be as simple as writing
C = gtn.einsum('IJ,KJ->IK',A,B)
where A
, B
, and C
belong to a class of Grassmann tensor. A Grassmann tensor object contains every necessary information for the computation; e.g., the coefficient tensor and the statistic of the indices.
Tensor decompositions
Tensor decomposition can also be done in an equally simple way. For example, if we want to decompose \(\mathcal{A}_{\psi_1\psi_2\bar\psi_3\bar\psi_4}\) into \(\mathcal{X}_{\psi_1\psi_2\eta}\) and \(\mathcal{Y}_{\bar\eta\bar\psi_3\bar\psi_4}\), this can be done with a few lines of code
U, Λ, V = A_dense.svd('ij,kl')
X = gtn.einsum( 'ija,ab -> ijb', U, gtn.sqrt(Λ))
Y = gtn.einsum( 'ab,bkl -> akl', gtn.sqrt(Λ), V)
You can also use the method .eig()
instead of .svd()
if your tensor is a Hermitian Grassmann matrix.
Hermitian conjugation
Hermitian conjugate of a Grassmann tensor can be computed using the .hconjugate()
method
cU = U.hconjugate('ij,a')
Of course, you need to identify the index separation first (in this case, it is ij
and a
). Hermitian conjugate is only well-defined when the indices are separated into two groups, corresponding to the two matrix indices.
After the conjugation, the indices are now arranged as aij
.