python binding for TAT(TAT is A Tensor library)
Project description
PyTAT
PyTAT is python binding for TAT, which is a c++ tensor library with support for symmetry and fermion tensor.
Install
You can build by yourself, see this for details. Or use pip
to obtain
built distribution: pip install PyTAT
.
Documents
Create tensor
To create a no symmetry tensor, pass names and dimension for each dimension of the tensor
from TAT.No.D import Tensor
A = Tensor(["i", "j"], [3, 4]).zero()
print(A)
{names:[i,j],edges:[3,4],blocks:[0,0,0,0,0,0,0,0,0,0,0,0]}
the code above create a rank-2 tensor named A
which two edges are i
and j
,
and their dimensions are 3
and 4
, then print tensor A
to std::cout
.
Please notice that TAT will NOT initialize content of tensor when create it
so remember to clear the value of tensor by calling method zero
.
To create a Z2 symmetry tensor, you need to describe the detail of each edge
from TAT.Z2.D import Tensor
A = Tensor(["i", "j"], [[(False, 2), (True, 4)], [(False, 3), (True, 1)]]).range()
print(A)
{names:[i,j],edges:[{0:2,1:4},{0:3,1:1}],blocks:{[0,0]:[0,1,2,3,4,5],[1,1]:[6,7,8,9]}}
It means this symmetric tensor have two block, one's symmetries is 0, 0 and the other's is 1, 1.
range
is a function to initialize the value of tensor for test.
from TAT.Z2.D import Tensor
A = Tensor(["i", "j"], [[(False, 2), (True, 4)], [(False, 3), (True, 1)]]).range()
B = A.clear_symmetry()
print(B)
{names:[i,j],edges:[6,4],blocks:[0,1,2,0,3,4,5,0,0,0,0,6,0,0,0,7,0,0,0,8,0,0,0,9]}
You can clear the symmetry and convert a symmetric tensor to a normal no symmetry tensor by method clear_symmetry
.
the U1 symmety edge can be more complex
from TAT.U1.D import Tensor
A = Tensor(["i", "j"], [[(0, 2), (2, 4), (1, 1)], [(0, 3), (-2, 1), (-1, 3)]]).range()
B = A.clear_symmetry()
print(A)
print(B)
{names:[i,j],edges:[{0:2,2:4,1:1},{0:3,-2:1,-1:3}],blocks:{[0,0]:[0,1,2,3,4,5],[2,-2]:[6,7,8,9],[1,-1]:[10,11,12]}}
{names:[i,j],edges:[7,7],blocks:[0,1,2,0,0,0,0,3,4,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,7,0,0,0,0,0,0,8,0,0,0,0,0,0,9,0,0,0,0,0,0,0,10,11,12]}
Please notice that the order of symmetry segment is important.
Access element of tensor
You can easily access elements of tensor by a map from name of edge to index
from TAT.No.D import Tensor
# Create a tensor and initialize it to zero
A = Tensor(["i", "j"], [3, 4]).zero()
# Set an element of tensor A to 3
A[{"i": 2, "j": 2}] = 3
# print tensor A
print(A)
# print the element set as 3
print(A[{"i": 2, "j": 2}])
{names:[i,j],edges:[3,4],blocks:[0,0,0,0,0,0,0,0,0,0,3,0]}
3.0
For symmetric tensor, you can specify the pair of symmetry and sub-index or the total index.
from TAT.U1.D import Tensor
A = Tensor(["i", "j"], [[(0, 2), (2, 4), (1, 1)], [(0, 3), (-2, 1), (-1, 3)]]).zero()
A[{"i": 1, "j": 2}] = 233
A[{"i": (2, 2), "j": (-2, 0)}] = 43
# print tensor A
print(A)
# print the element set
print(A[{"i": (0, 1), "j": (0, 2)}])
print(A[{"j": 3, "i": 4}])
B = A.clear_symmetry()
print(B[{"j": 3, "i": 4}])
{names:[i,j],edges:[{0:2,2:4,1:1},{0:3,-2:1,-1:3}],blocks:{[0,0]:[0,0,0,0,0,233],[2,-2]:[0,0,43,0],[1,-1]:[0,0,0]}}
233.0
43.0
43.0
Scalar operators
You can do scalar operators directly
from TAT.No.D import Tensor
# Create two rank-1 tensors
A = Tensor(["i"], [4])
B = Tensor(["i"], [4])
A[{"i": 0}] = 1
A[{"i": 1}] = 2
A[{"i": 2}] = 3
A[{"i": 3}] = 4
B[{"i": 0}] = 10
B[{"i": 1}] = 20
B[{"i": 2}] = 30
B[{"i": 3}] = 40
# Add two tensor
print(A + B)
# A number over a tensor
print(1 / A)
{names:[i],edges:[4],blocks:[11,22,33,44]}
{names:[i],edges:[4],blocks:[1,0.5,0.333333,0.25]}
It always requires two tensor share the same shape, but edge order is not important
from TAT.U1.D import Tensor
A = Tensor(["i", "j"], [[(0, 2), (2, 4), (1, 1)], [(0, 3), (-2, 1), (-1, 3)]]).range()
B = Tensor(["j", "i"], [[(0, 3), (-2, 1), (-1, 3)], [(0, 2), (2, 4), (1, 1)]]).range()
print(A + B)
{names:[i,j],edges:[{0:2,2:4,1:1},{0:3,-2:1,-1:3}],blocks:{[0,0]:[0,3,6,4,7,10],[2,-2]:[12,14,16,18],[1,-1]:[20,22,24]}}
For symmetry tensor, symmetry segment order is also important, if their order is different, an error will be thrown.
from TAT.U1.D import Tensor
A = Tensor(["i", "j"], [[(0, 2), (2, 4), (1, 1)], [(0, 3), (-2, 1), (-1, 3)]]).range()
B = Tensor(["j", "i"], [[(0, 3), (-2, 1), (-1, 3)], [(0, 2), (1, 1), (2, 4)]]).range()
try:
print(A + B)
except RuntimeError as error:
print(error)
{names:[i,j],edges:[{0:2,2:4,1:1},{0:3,-2:1,-1:3}],blocks:{[0,0]:[0,3,6,4,7,10],[2,-2]:[16,18,20,15],[1,-1]:[17,19,21]}}
Rank-0 tensor and number
You can convert between rank-0 tensor and number directly
import TAT
# Directly initialize a tensor with a number
A = TAT.No.D.Tensor(233)
# Convert rank-0 tensor to number
a = float(A)
print(a)
B = TAT.U1.D.Tensor(233)
print(B)
b = float(B)
print(b)
C = TAT.U1.Z.Tensor(233 + 666j, ["i", "j"], [2, -2])
print(C)
c = complex(C)
print(c)
233.0
{names:[],edges:[],blocks:{[]:[233]}}
233.0
{names:[i,j],edges:[{2:1},{-2:1}],blocks:{[2,-2]:[233+666i]}}
(233+666j)
You can also create a scalar like non-rank-0 tensor directly, it can also be converted into scalar directly.
Explicitly copy
from TAT.No.D import Tensor
# Due to python feature, assigning will not copy data, it would share the same data,
# So changing data in A will get tensor B changed.
A = Tensor(233)
B = A
A[{}] = 1
print(B)
# Copy tensor excplicitly, A and B is two tensor without data shared.
A = Tensor(233)
B = A.copy()
A[{}] = 1
print(B)
{names:[],edges:[],blocks:[1]}
{names:[],edges:[],blocks:[233]}
Create same shape tensor and some elementwise operator
Create a tensor with same shape to another can be achieve by method same_shape
.
from TAT.No.D import Tensor
A = Tensor(["i", "j"], [2, 2])
A[{"i": 0, "j": 0}] = 1
A[{"i": 0, "j": 1}] = 2
A[{"i": 1, "j": 0}] = 3
A[{"i": 1, "j": 1}] = 4
# tensor B copy the shape of A but not content of A
B = A.same_shape().zero()
print(B)
{names:[i,j],edges:[2,2],blocks:[0,0,0,0]}
map=/=transform
is outplace/inplace elementwise operator method.
from TAT.No.D import Tensor
A = Tensor(["i", "j"], [2, 2])
# Another easy test data setter for tensor
# which will fill meanless test data into tensor
A.range()
# Every element is transformed by a function inplacely
A.transform(lambda x: x * x)
print(A)
# Every element is transformed by a function outplacely
B = A.map(lambda x: x + 1)
print(B)
print(A)
{names:[i,j],edges:[2,2],blocks:[0,1,4,9]}
{names:[i,j],edges:[2,2],blocks:[1,2,5,10]}
{names:[i,j],edges:[2,2],blocks:[0,1,4,9]}
method to
is used for type conversion.
import TAT
A = TAT.No.D.Tensor(233)
print(type(A))
# Convert A to a complex tensor
B = A.to(complex)
print(type(B))
<class 'TAT.No.D.Tensor'>
<class 'TAT.No.Z.Tensor'>
Norm
from TAT.No.D import Tensor
A = Tensor(["i"], [10]).range()
# Get maximum norm
print(A.norm_max())
# Get 0 norm
print(A.norm_num())
# Get 1 norm
print(A.norm_sum())
# Get 2 norm
print(A.norm_2())
9.0
10.0
45.0
16.881943016134134
Contract
from TAT.No.D import Tensor
A = Tensor(["i", "j", "k"], [2, 3, 4]).range()
B = Tensor(["a", "b", "c", "d"], [2, 5, 3, 6]).range()
# Contract edge i of A and edge a of B, edge j of A and edge c of B
C = A.contract(B, {("i", "a"), ("j", "c")})
print(C)
{names:[k,b,d],edges:[4,5,6],blocks:[4776,4836,4896,4956,5016,5076,5856,5916,5976,6036,6096,6156,6936,6996,7056,7116,7176,7236,8016,8076,8136,8196,8256,8316,9096,9156,9216,9276,9336,9396,5082,5148,5214,5280,5346,5412,6270,6336,6402,6468,6534,6600,7458,7524,7590,7656,7722,7788,8646,8712,8778,8844,8910,8976,9834,9900,9966,10032,10098,10164,5388,5460,5532,5604,5676,5748,6684,6756,6828,6900,6972,7044,7980,8052,8124,8196,8268,8340,9276,9348,9420,9492,9564,9636,10572,10644,10716,10788,10860,10932,5694,5772,5850,5928,6006,6084,7098,7176,7254,7332,7410,7488,8502,8580,8658,8736,8814,8892,9906,9984,10062,10140,10218,10296,11310,11388,11466,11544,11622,11700]}
from TAT.U1.D import Tensor
a = Tensor(["A", "B", "C", "D"], [
[(-1, 1), (0, 1), (-2, 1)],
[(0, 1), (1, 2)],
[(0, 2), (1, 2)],
[(-2, 2), (-1, 1), (0, 2)],
]).range()
b = Tensor(["E", "F", "G", "H"], [
[(0, 2), (1, 1)],
[(-2, 1), (-1, 1), (0, 2)],
[(0, 1), (-1, 2)],
[(2, 2), (1, 1), (0, 2)],
]).range()
print(a)
print(b)
print(Tensor.contract(a, b, {("B", "G"), ("D", "H")}))
print(Tensor.contract(a.transpose(["A", "C", "B", "D"]), b.transpose(["G", "H", "E", "F"]), {("B", "G"), ("D", "H")}))
c = a.clear_symmetry()
d = b.clear_symmetry()
e = Tensor.contract(a, b, {("B", "G"), ("D", "H")}).clear_symmetry()
f = type(c).contract(c, d, {("B", "G"), ("D", "H")})
print(e)
print(f)
{names:[A,B,C,D],edges:[{-1:1,0:1,-2:1},{0:1,1:2},{0:2,1:2},{-2:2,-1:1,0:2}],blocks:{[-1,0,1,0]:[0,1,2,3],[-1,1,0,0]:[4,5,6,7,8,9,10,11],[-1,1,1,-1]:[12,13,14,15],[0,0,0,0]:[16,17,18,19],[0,0,1,-1]:[20,21],[0,1,0,-1]:[22,23,24,25],[0,1,1,-2]:[26,27,28,29,30,31,32,33],[-2,1,1,0]:[34,35,36,37,38,39,40,41]}}
{names:[E,F,G,H],edges:[{0:2,1:1},{-2:1,-1:1,0:2},{0:1,-1:2},{2:2,1:1,0:2}],blocks:{[0,-2,0,2]:[0,1,2,3],[0,-1,0,1]:[4,5],[0,-1,-1,2]:[6,7,8,9,10,11,12,13],[0,0,0,0]:[14,15,16,17,18,19,20,21],[0,0,-1,1]:[22,23,24,25,26,27,28,29],[1,-2,0,1]:[30],[1,-2,-1,2]:[31,32,33,34],[1,-1,0,0]:[35,36],[1,-1,-1,1]:[37,38],[1,0,-1,0]:[39,40,41,42,43,44,45,46]}}
{names:[A,C,E,F],edges:[{-1:1,0:1,-2:1},{0:2,1:2},{0:2,1:1},{-2:1,-1:1,0:2}],blocks:{[-1,0,1,0]:[1062,1166,1386,1522],[-1,1,0,0]:[601,655,709,763,704,770,836,902],[-1,1,1,-1]:[1012,1229],[0,0,0,0]:[1515,1673,1831,1989,1618,1788,1958,2128],[0,0,1,-1]:[2898,3115],[0,1,0,-1]:[944,1420,1008,1517],[0,1,1,-2]:[4314,4604],[-2,1,1,0]:[5922,6506,6246,6862]}}
{names:[A,C,E,F],edges:[{-1:1,0:1,-2:1},{0:2,1:2},{0:2,1:1},{-2:1,-1:1,0:2}],blocks:{[-1,0,1,0]:[1062,1166,1386,1522],[-1,1,0,0]:[601,655,709,763,704,770,836,902],[-1,1,1,-1]:[1012,1229],[0,0,0,0]:[1515,1673,1831,1989,1618,1788,1958,2128],[0,0,1,-1]:[2898,3115],[0,1,0,-1]:[944,1420,1008,1517],[0,1,1,-2]:[4314,4604],[-2,1,1,0]:[5922,6506,6246,6862]}}
{names:[A,C,E,F],edges:[3,4,3,4],blocks:[0,0,0,0,0,0,0,0,0,0,1062,1166,0,0,0,0,0,0,0,0,0,0,1386,1522,0,0,601,655,0,0,709,763,0,1012,0,0,0,0,704,770,0,0,836,902,0,1229,0,0,0,0,1515,1673,0,0,1831,1989,0,2898,0,0,0,0,1618,1788,0,0,1958,2128,0,3115,0,0,0,944,0,0,0,1420,0,0,4314,0,0,0,0,1008,0,0,0,1517,0,0,4604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5922,6506,0,0,0,0,0,0,0,0,0,0,6246,6862]}
{names:[A,C,E,F],edges:[3,4,3,4],blocks:[0,0,0,0,0,0,0,0,0,0,1062,1166,0,0,0,0,0,0,0,0,0,0,1386,1522,0,0,601,655,0,0,709,763,0,1012,0,0,0,0,704,770,0,0,836,902,0,1229,0,0,0,0,1515,1673,0,0,1831,1989,0,2898,0,0,0,0,1618,1788,0,0,1958,2128,0,3115,0,0,0,944,0,0,0,1420,0,0,4314,0,0,0,0,1008,0,0,0,1517,0,0,4604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5922,6506,0,0,0,0,0,0,0,0,0,0,6246,6862]}
Since edge "B" and edge "G", edge "D" and edge "H" have the compatible order, the contract result of clearsymmetry equals to clearsymmetry of contract result.
Merge and split edge
from TAT.No.D import Tensor
A = Tensor(["i", "j", "k"], [2, 3, 4]).range()
# Merge edge i and edge j into a single edge a,
# and Merge no edge to get a trivial edge b
B = A.merge_edge({"a": ["i", "j"], "b": []})
print(B)
# Split edge a back to edge i and edge j, and split
# trivial edge b to no edge
C = B.split_edge({"b": [], "a": [("i", 2), ("j", 3)]})
print(C)
{names:[b,a,k],edges:[1,6,4],blocks:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]}
{names:[i,j,k],edges:[2,3,4],blocks:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]}
Edge rename and transpose
from TAT.No.D import Tensor
A = Tensor(["i", "j", "k"], [2, 3, 4]).range()
# Rename edge i to edge x
B = A.edge_rename({"i": "x"})
print(B)
# =edge_rename= is an outplace operator
print(A)
# Transpose tensor A with specific order
C = A.transpose(["k", "j", "i"])
print(C)
{names:[x,j,k],edges:[2,3,4],blocks:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]}
{names:[i,j,k],edges:[2,3,4],blocks:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]}
{names:[k,j,i],edges:[4,3,2],blocks:[0,12,4,16,8,20,1,13,5,17,9,21,2,14,6,18,10,22,3,15,7,19,11,23]}
SVD and QR decomposition
-
QR decomposition
def f_edge(*args): return (args, False) def t_edge(*args): return (args, True) from TAT.Fermi.D import Tensor A = Tensor(["i", "j", "k"], [ t_edge((-1, 2), (0, 2), (-2, 2)), f_edge((0, 2), (1, 2)), f_edge((0, 2), (1, 2)), ]).range() # Do QR decomposition, specify Q matrix edge is edge k # You can also write is as =Q, R = A.qr('r', {"i", "j"}, "Q", "R")= # The last two argument is the name of new edges generated # by QR decomposition Q, R = A.qr('q', {"k"}, "Q", "R") # Q is an unitary matrix, which edge name is Q and k print(Q.conjugate().edge_rename({"Q": "Q1"}).contract(Q.edge_rename({"Q": "Q2"}), {("k", "k")})) # Q R - A is 0 print((Q.contract(R, {("Q", "R")}) - A).norm_max()) {names:[Q1,Q2],edges:[{arrow:0,segment:{1:2,0:2}},{arrow:1,segment:{-1:2,0:2}}],blocks:{[1,-1]:[1,-0,-0,1],[0,0]:[1,5.55112e-17,5.55112e-17,1]}} 3.552713678800501e-15
-
SVD decomposition
def f_edge(*args): return (args, False) def t_edge(*args): return (args, True) from TAT.Fermi.D import Tensor A = Tensor(["i", "j", "k"], [ t_edge((-1, 2), (0, 2), (-2, 2)), f_edge((0, 2), (1, 2)), f_edge((0, 2), (1, 2)), ]).range() # Do SVD decomposition with cut=3, if cut not specified, # svd will not cut the edge. # The first argument is edge set of matrix U, SVD does not # supply function to specify edge set of matrix V like what # is done in QR since SVD is symmetric between U and V. # The later two argument is new edges generated in tensor U # and tensor V. The later two argument is new edges of tensor # S. and the last argument is dimension cut. U, S, V = A.svd({"k"}, "U", "V", "SU", "SV") # U is an rank-3 unitary matrix print(U.conjugate().edge_rename({"U": "U1"}).contract(U.edge_rename({"U": "U2"}), {("k", "k")})) # U S V - A is a small value print((U.contract(S, {("U", "SU")}).contract(V, {("SV", "V")}) - A).norm_max()) {names:[U1,U2],edges:[{arrow:0,segment:{1:2,0:2}},{arrow:1,segment:{-1:2,0:2}}],blocks:{[1,-1]:[1,-0,-0,1],[0,0]:[1,0,0,1]}} 7.105427357601002e-15
Identity, exponential and trace
from TAT.No.D import Tensor
# Please notice that identity is INPLACE operator
# For any i, j, k, l, we have
# =A[{"i":i, "j":j, "k":k, "l":l}] = delta(i,l) * delta(j,k)=
A = Tensor(["i", "j", "k", "l"], [2, 3, 3, 2]).identity({("i", "l"), ("j", "k")})
# calculate matrix exponential B = exp(A)
# second argument is iteration steps, with default value 2
B = A.exponential({("i", "l"), ("j", "k")}, 4)
print(B)
# Calculate trace or partial trace of a tenso
# Here it calculate =A[{"i":i, "j":j, "k":k, "l":l}] * delta(i,l) * delta(j,k)=
C = A.trace({("i", "l"), ("j", "k")})
print(C)
{names:[j,i,k,l],edges:[3,2,3,2],blocks:[2.71828,0,0,0,0,0,0,2.71828,0,0,0,0,0,0,2.71828,0,0,0,-0,-0,-0,2.71828,-0,-0,0,0,0,0,2.71828,0,0,0,0,0,0,2.71828]}
{names:[],edges:[],blocks:[6]}
from TAT.U1.D import Tensor
A = Tensor(["i", "j", "k", "l", "m"], [
[(-1, 2), (0, 2), (+1, 2)],
[(0, 2), (1, 2)],
[(0, 2), (-1, 2)],
[(0, 2), (2, 3)],
[(0, 2), (-2, 3)],
]).range()
identity = Tensor(["k", "j", "m", "l"], [
[(0, 2), (1, 2)],
[(0, 2), (-1, 2)],
[(0, 2), (2, 3)],
[(0, 2), (-2, 3)],
]).identity({("j", "k"), ("m", "l")})
print(A.trace({("j", "k"), ("l", "m")}))
print(A.contract(identity, {("j", "j"), ("k", "k"), ("l", "l"), ("m", "m")}))
{names:[i],edges:[{-1:2,0:2,1:2}],blocks:{[0]:[4734,5294]}}
{names:[i],edges:[{-1:2,0:2,1:2}],blocks:{[0]:[4734,5294]}}
IO
You can pickle load/dump a tensor directly, and even read data from str
printed by a tensor.
import pickle
from TAT.No.D import Tensor
A = Tensor(["i", "j", "k", "l"], [2, 3, 3, 2]).identity({("i", "l"), ("j", "k")})
B = pickle.loads(pickle.dumps(A))
C = Tensor(str(B))
print(A)
print(B)
print(C)
{names:[i,j,k,l],edges:[2,3,3,2],blocks:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1]}
{names:[i,j,k,l],edges:[2,3,3,2],blocks:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1]}
{names:[i,j,k,l],edges:[2,3,3,2],blocks:[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1]}
Fill random number into tensor
PyTAT contains a random generator inside.
import TAT
# Sed random seed
TAT.random.seed(2333)
# Generate normal distributed random variables into a tensor.
A = TAT.No.D.Tensor(["i"], [10]).randn()
print(A)
# Generate uniform distributed random variables into a tensor.
B = TAT.No.Z.Tensor(["i"], [10]).randn()
print(B)
{names:[i],edges:[10],blocks:[0.465246,0.529748,1.17368,0.544866,1.13411,0.611783,0.7999,-0.9954,0.9015,-1.69905]}
{names:[i],edges:[10],blocks:[-0.263321+0.872706i,0.340596+0.75738i,-1.00095+0.630635i,1.24853-1.67437i,-0.352834+0.158421i,0.0561893-1.15738i,-0.579757-0.761532i,-2.13231-1.00284i,-0.118861+1.90261i,-0.271529-0.554287i]}
PyTAT also provide function to generate single random number.
import TAT
# Sed random seed
TAT.random.seed(6666)
# Generate uniform distributed random int in =[0, 9]=.
generator = TAT.random.uniform_int(0, 4)
print([generator() for _ in range(10)])
# Generate uniform distributed random real in =[-1, +1]=.
generator = TAT.random.uniform_real(-1, +1)
print([generator() for _ in range(10)])
# And normal distribution with $\mu=0, \sigma=2$.
generator = TAT.random.normal(0, 2)
print([generator() for _ in range(10)])
[0, 4, 4, 1, 2, 2, 2, 1, 0, 3]
[-0.14092759016536094, -0.08462244818883502, 0.9629775447195736, -0.3677814327981205, 0.14071059784799678, -0.9461988098776835, -0.42065228922511544, 0.014462778869043236, -0.952394632542909, -0.7269948652715256]
[-0.8028506463569831, 2.467669174703166, 2.646095074776552, -2.238083341719702, 0.14214106921890585, 2.1826114150031, -2.0435554117053156, -0.22644183616582628, 2.4731844087444723, 5.112734591946305]
Import from and export to numpy array
TAT can use buffer protocol to transfer data from and to numpy.
import numpy as np
from TAT.No.D import Tensor
A = Tensor(["i", "j"], [3, 4]).zero()
# Export tensor to numpy array, which shape is [4, 3], because the
# dimension order is set as =["j", "i"]=, where "i" correspond to an
# edge with dimension 3 and "j" correspond to an edge with dimension
# 4, so the result shape is =(4, 3)=.
data_A = A.blocks[["j", "i"]]
print(data_A.shape)
# You can directly modify numpy array =data_A= to change data of tensor A,
# namely, numpy array and TAT tensor share the data.
data_A[1, 2] = 233
print(A)
# You can also direcly set =A.blocks[...]= to a numpy array.
A.blocks[["j", "i"]] = np.arange(3 * 4).reshape([4, 3])
print(A)
(4, 3)
{names:[i,j],edges:[3,4],blocks:[0,0,0,0,0,0,0,0,0,233,0,0]}
{names:[i,j],edges:[3,4],blocks:[0,3,6,9,1,4,7,10,2,5,8,11]}
FAQ
I get error message like this when import TAT
mca_base_component_repository_open: unable to open mca_patcher_overwrite: /usr/lib/x86_64-linux-gnu/openmpi/lib/openmpi/mca_patcher_overwrite.so: undefined symbol: mca_patcher_base_patch_t_class (ignored)
mca_base_component_repository_open: unable to open mca_shmem_posix: /usr/lib/x86_64-linux-gnu/openmpi/lib/openmpi/mca_shmem_posix.so: undefined symbol: opal_shmem_base_framework (ignored)
mca_base_component_repository_open: unable to open mca_shmem_mmap: /usr/lib/x86_64-linux-gnu/openmpi/lib/openmpi/mca_shmem_mmap.so: undefined symbol: opal_show_help (ignored)
mca_base_component_repository_open: unable to open mca_shmem_sysv: /usr/lib/x86_64-linux-gnu/openmpi/lib/openmpi/mca_shmem_sysv.so: undefined symbol: opal_show_help (ignored)
It is a problem for some old mpi version(for example, openmpi 2.1.1 in ubuntu 18.04 LTS) if you compile mpi
support into PyTAT, you need to load mpi dynamic shared library manually before import TAT
,
The way to load it manually is import ctypes
and ctypes.CDLL("libmpi.so", mode=ctypes.RTLD_GLOBAL)
.
It is recommended to use mpi4py
instead, not to compile mpi into PyTAT.
I get error message like this when import TAT
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: /home/hzhangxyz/.local/lib/python3.10/site-packages/TAT.cpython-310-x86_64-linux-gnu.so: undefined symbol: cgesv_
It happens because you forgot to link lapack
and blas
when compile the library. You need to recompile it
with correct compiling flags, OR add lapack/blas library path to environment variables LD_PRELOAD
, just
like export LD_PRELOAD=/lib64/liblapack.so.3
, before running python directly.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Hashes for PyTAT-0.3.2-cp311-cp311-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c8ddf5180d2aa022bb8485c687bc4edc82385b3e9be4ce7a424ae6596dd79527 |
|
MD5 | 9874082b0885d888fb20f78ff6c2e50e |
|
BLAKE2b-256 | 0d710aa357749f151b1c4b8ea11533f125d324d45d4cacbcb37f07aa75e1084f |
Hashes for PyTAT-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bc37265ea6d168a7bbaf7ab23fcb92ec1050624f418523920a243a6a6fed09e7 |
|
MD5 | 8b71a375eef4101b380f530a9cce8e96 |
|
BLAKE2b-256 | 10aa962a28c7ca8c6796cc257bc42bfcd1e2700c6190200b620a6df3df69519c |
Hashes for PyTAT-0.3.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 665e13243bbc2da723c5276fce681786a5cd5bac27e1f810812cfd4fe7352194 |
|
MD5 | 17382dc2bf02325dfe8ede7ad609b6cf |
|
BLAKE2b-256 | 94f0c5f43fff0caf4a7c17cd4da8c8ad3f0ea8dbb3778027821035fa02f4604f |
Hashes for PyTAT-0.3.2-cp311-cp311-macosx_10_14_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 20bb37e1ee6909117fc8aed52472cbad4dadb8f828fe32ed9540e6f171e4b10c |
|
MD5 | 53771b042090fc05a79b29ae1114d499 |
|
BLAKE2b-256 | b0ba44307ce9fb9a16a85eda3b9ff76ff47a6d871cb526fc6f4644a1ef49c11f |
Hashes for PyTAT-0.3.2-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 73477eb8757052949f2b3bf5fe9c4a6572ebc218955a0895c5c34a79a3ea28cb |
|
MD5 | d3533739f17b10ca5b7b180e88b4fd77 |
|
BLAKE2b-256 | b104f55e1e92abc1b70e5bbb600ab89dd9f075b1e9f7966e405ce0fb856c6855 |
Hashes for PyTAT-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e204f578d140014c405cab3f5e6a6e0914639deeb6755c9cf3a9cfb5639ecc72 |
|
MD5 | 7d50f3525ccea92c4a14a3932fe988b6 |
|
BLAKE2b-256 | 207646eeef89da12af6fc90ddf33eaebbdc9449e219f50ee9026bcd2323db1ac |
Hashes for PyTAT-0.3.2-cp310-cp310-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b3cc6d2100000ec75818b513351775f5c680a29e332d95f0ef3500ef4b994b62 |
|
MD5 | bd06416d7bb86a78469573365c0df3e4 |
|
BLAKE2b-256 | a9db6ddbdb6fe82f58e4497efd847b67516edc8509b907b17f6e874b4c73797b |
Hashes for PyTAT-0.3.2-cp310-cp310-macosx_10_14_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d31c90a669cca1eaa783759e7f87ce430511bc680881ff1d50a7d686612be2e4 |
|
MD5 | 41e29ab292ba4b86439badc6f93d866d |
|
BLAKE2b-256 | 668e74fb6dce22167e71e325b2dd57d6f5801e5d050f072fc1091b21cb2a3b75 |
Hashes for PyTAT-0.3.2-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ba2a652feabfa3f73c9881cfecc394b313c39cefed914a92fe54dcbdf161d7b9 |
|
MD5 | 96bab15c953bcb42e200440767f14ceb |
|
BLAKE2b-256 | b3352671cb48441d95b162b6163af4533391c7a9985c3c58fa79783c3e62dd38 |
Hashes for PyTAT-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d13867b731b3a497d757ab8c76b02e7629178540bce75aac127e5f6cc30e45de |
|
MD5 | d01499f4d8bcf5125ee80d6b4fc4679d |
|
BLAKE2b-256 | 7fab1d703208eb21f3ef35ce4517392248cfc4b2b10090b30c7b5166f0fc6797 |
Hashes for PyTAT-0.3.2-cp39-cp39-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 094731f947bc48255ac39f9d9a2d1d9075bfec6be65f063af88f3f31aa198c7b |
|
MD5 | 22194a3042a543614afc667d34f23526 |
|
BLAKE2b-256 | 42932c0d298fa05bd828b4aa351616add868fb731890e2a0b19b70d79ebad7fa |
Hashes for PyTAT-0.3.2-cp39-cp39-macosx_10_14_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d270f4d432ef95f36190478abe7bd06a472935c87fb7677557bda52cb9313e6c |
|
MD5 | 53aa3bbeb1ee64479f426a8e4a6741aa |
|
BLAKE2b-256 | cfa4a310a184362eb2c695e5deadda0e7a3df5cd117d00dba32ea6f9ce20e670 |
Hashes for PyTAT-0.3.2-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 22bfbec79cfc0194d6a0193698514554d7a7e900cb9189aeb085fdb5d76cba88 |
|
MD5 | 3c4e08461ee6eb76b9d9457d3723d25b |
|
BLAKE2b-256 | bfb781d8fb1c181a7f752fb4b70856aa4de975f35092dc88deb8e003a7ea2608 |
Hashes for PyTAT-0.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9b2c40a640ec0b509ab8fbb252ed46c05e6a946a5b22e7fb97bf0a0e2bf00781 |
|
MD5 | 7b49e82baf69059f0216b941f2ebcd79 |
|
BLAKE2b-256 | f777eae11422ea36187e2b21d0c21efc73b1a1b7553b9f669cf00df456b4ed5f |
Hashes for PyTAT-0.3.2-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0cf2ab52eee45c75e317b19f58099b96e1b67196e50cf7df950875cc6fb93a73 |
|
MD5 | 314dc890d540c07c3e5036a056342042 |
|
BLAKE2b-256 | c6b00f8426b051f7292e13a6dbd65de0c94214dcd37ca3e99998969d32725c84 |
Hashes for PyTAT-0.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b1a9504fedecbec10e7f4ffbe5096c98b83f1b90a2559fcc22f5d78147e2fb39 |
|
MD5 | 421c391f751326e8c5408fd37e731521 |
|
BLAKE2b-256 | 9963aff787d5063391a2935178c465593db514a540214d369a2a881a6d245aeb |