Ondrej Certik wrote:
On Tue, Jun 8, 2010 at 6:28 AM, Andy Ray Terrel <[email protected]> wrote:
Hello Alan,
Do you have anymore details of how the tensor module will work? Way
back when I was coding more with Sympy we tried to do something based
on GiNaC's Indexed system. It would be good to have a more uniform
system such that vectors, matrices, and tensors were implemented in a
very similar manner.
Øyvind is working on code generation for quantum chemistry. This
requires tensors so we are definitely interested in your work.
Yes, I am interested as well. Here is ho ginac does it:
http://www.ginac.de/tutorial/Indexed-objects.html#Indexed-objects
http://www.ginac.de/tutorial/Non_002dcommutative-objects.html#Non_002dcommutative-objects
Ondrej
Ondrej
Try attached not ready for prime time code. Once I clean it up and
generate enough documentation (internal and external) to make it useful
I will submit it.
--
You received this message because you are subscribed to the Google Groups
"sympy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sympy?hl=en.
#!/bin/env python
import math,copy,sys,pyx,os,subprocess
from sympy import latex,Symbol,simplify,Function,diff,Rational
import numpy
global MAIN_PROGRAM
MAIN_PROGRAM = ''
ZERO = Rational(0,1)
ONE = Rational(1,1)
HALF = Rational(1,2)
even = True
odd = False
old = True
new = False
def set_main(main_program):
global MAIN_PROGRAM
MAIN_PROGRAM = main_program
return
set_main(sys.modules[__name__])
def perm_lst(str):
if len(str) <=1:
yield str
else:
for perm in perm_lst(str[1:]):
for i in range(len(perm)+1):
yield perm[:i] + str[0:1] + perm[i:]
def even_perm(perm):
"""Determine whether a permutation is even.
An even permutation is a permutation that can be produced by an even number
of exchanges.
Positional arguments :
perm -- permutation (tuple)
"""
dim = len(perm)
even = True
for i in xrange(dim):
for j in xrange(1 + i, dim):
if perm[j] < perm[i]:
even = not even
return even
def find_repeats(lst):
rlst = []
for i in range(len(lst)-1):
lst_i = lst[i]
if lst_i in lst[i+1:]:
if lst_i not in rlst:
rlst.append(lst_i)
return(rlst)
def separate_free_and_repeats(lst):
free_lst = []
repeat_lst = []
for i in range(len(lst)-1):
lst_i = lst[i]
if lst_i in lst[i+1:]:
if lst_i not in repeat_lst:
repeat_lst.append(lst_i)
else:
if lst_i not in repeat_lst:
free_lst.append(lst_i)
if lst[-1] not in repeat_lst:
free_lst.append(lst[-1])
return(free_lst,repeat_lst)
def cycle_list(lst,shift):
n = len(lst)
new_lst = n*[0]
for i in range(n):
new_lst[i] = lst[(i-shift)%n]
return(new_lst)
def compress_free_list(lst):
sort_lst = copy.copy(lst)
sort_lst.sort()
n_lst = len(lst)
comp_lst = n_lst*[0]
for i in range(n_lst):
comp_lst[lst.index(sort_lst[i])] = i+1
return(comp_lst)
def canonical_index(lst):
(free_lst,repeat_lst) = separate_free_and_repeats(lst)
reduced_lst = free_lst+repeat_lst
reduced_lst.sort()
can_lst = len(lst)*[0]
i = 1
for index in reduced_lst:
new_index = lst.index(index)
can_lst[new_index] = i
if index in repeat_lst:
new_index = lst.index(index,new_index+1)
can_lst[new_index] = i
i += 1
return(can_lst)
def minus(lst):
mlst = []
for x in lst:
mlst.append(-x)
return(mlst)
def make_tensor(tensorlst):
"""
make_tensor takes a string of tensor names separated by
blanks and converts them tensors separately
accessible by the main program and addition returns a list
of the symbols.
"""
global MAIN_PROGRAM
tensorlst = tensorlst.split()
tensor_lst = []
isym = 0
for name in tensorlst:
tmp = Tensor(name)
tensor_lst.append(tmp)
setattr(MAIN_PROGRAM,name,tmp)
isym += 1
return(tensor_lst)
class PDF:
mode = 'Pyx'
preamble = '\\documentclass[10pt,letter,fleqn]{report}\n'+\
'\\pagestyle{empty}\n'+\
'\\usepackage[latin1]{inputenc}\n'+\
'\\usepackage[pdftex,landscape,top=1cm,nohead,nofoot]{geometry}\n'+\
'\\usepackage{amsmath}\n'+\
'\\usepackage{bm}\n'+\
'\\usepackage{amsfonts}\n'+\
'\\usepackage{amssymb}\n'+\
'\\usepackage{tensor}\n'+\
'\\setlength{\\parindent}{0pt}\n'+\
'\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}\n'+\
'\\newcommand{\\lp}{\\left (}\n'+\
'\\newcommand{\\rp}{\\right )}\n'+\
'\\newcommand{\\half}{\\frac{1}{2}}\n'+\
'\\newcommand{\\llt}{\\left <}\n'+\
'\\newcommand{\\rgt}{\\right >}\n'+\
'\\newcommand{\\abs}[1]{\\left |{#1}\\right | }\n'+\
'\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}\n'+\
'\\newcommand{\\lbrc}{\\left \\{}\n'+\
'\\newcommand{\\rbrc}{\\right \\}}\n'+\
'\\newcommand{\\W}{\\wedge}\n'+\
"\\newcommand{\\prm}[1]{{#1}'}\n"+\
'\\newcommand{\\ddt}[1]{\\bfrac{d{#1}}{dt}}\n'+\
'\\newcommand{\\R}{\\dagger}\n'+\
'\\newcommand{\\be}{\\begin{equation*}}\n'+\
'\\newcommand{\\ee}{\\end{equation*}}\n'+\
'\\begin{document}\n'
postscript = '\\end{document}\n'
@staticmethod
def setup(mode=''):
PDF.mode = mode
if PDF.mode == '':
return
if PDF.mode == 'Pyx':
PDF.filename = 'trash'
PDF.old_filename = 'old_trash'
PDF.file_flg = True
pyx.text.set(mode='latex')
pyx.text.preamble(r'\usepackage{tensor}')
pyx.text.preamble(r'\usepackage{amsmath}')
pyx.text.preamble(r'\usepackage{amsfonts}')
pyx.text.preamble(r'\usepackage{amssymb}')
PDF.canvas = pyx.canvas.canvas()
PDF.vpos = 0.0
PDF.dvpos = 0.5
PDF.file = ''
if PDF.mode == 'latex':
PDF.latex = []
return
@staticmethod
def write(latex_str,inline=True):
if inline:
latex_str = '$'+latex_str+'$'
if PDF.mode == 'Pyx':
PDF.canvas.text(0,PDF.vpos,latex_str)
PDF.vpos -= PDF.dvpos
filename = ''
remove_filename = ''
if PDF.file_flg:
filename = PDF.filename
remove_filename = PDF.old_filename
else:
filename = PDF.old_filename
remove_filename = PDF.filename
PDF.file_flg = not PDF.file_flg
PDF.canvas.writePDFfile(filename)
subprocess.Popen('xpdf -g 500x750 -cont -z 150 -remote myserver '+filename+'.pdf',shell=True)
os.system('rm '+remove_filename+'.pdf')
if PDF.mode == 'latex':
PDF.latex.append(latex_str)
return
@staticmethod
def display(filename='pdflatex'):
if PDF.mode == 'latex':
latex_str = PDF.preamble
for line in PDF.latex:
line = line.replace('$','')
latex_str += '\\be\n\\hspace{-1.5in}'+line+'\n\\ee\n'
latex_str += PDF.postscript
latex_file = open(filename+'.tex','w')
latex_file.write(latex_str)
latex_file.close()
os.system('pdflatex '+filename+'.tex')
subprocess.Popen('xpdf -g 500x750 -cont -z 150 -remote myserver '+filename+'.pdf',shell=True)
return
class BasicTensor:
@staticmethod
def cat_shift(lst1,lst2):
lst = copy.copy(lst1)
n = len(lst1)
for i in lst2:
lst.append(i+n)
return(lst)
@staticmethod
def shift(n,lst1):
lst = []
for i in lst1:
lst.append(n+i)
return(lst)
@staticmethod
def minus(lst):
mlst = []
for x in lst:
mlst.append(-x)
return(mlst)
@staticmethod
def scale(sf,lst):
sflst = []
for x in lst:
sflst.append(sf*x)
return(sflst)
@staticmethod
def setup(pdfmode='latex',dim=2,offset=0):
BasicTensor.index_pool = 'abcdefhijklmnopquvwxyz'
BasicTensor.dim = dim
BasicTensor.offset = offset
BasicTensor.Pd = BasicTensor('Pd_a')
BasicTensor.Pd.op_flg = True
BasicTensor.Cd = BasicTensor('Cd_a')
BasicTensor.Cd.op_flg = True
BasicTensor.op_symbol = {'Pd':r'\partial','Cd':r'\nabla'}
PDF.setup(pdfmode)
return
@staticmethod
def free_indices(free_index,cntrct_index):
f = []
for i in free_index:
if i not in cntrct_index:
f.append(i)
return(f)
@staticmethod
def product_of_list(lst):
plst = lst[0]
for x in lst[1:]:
plst = plst*x
return(plst)
def __init__(self,Tstr,syms=None,sgns=None):
self.Tstr = Tstr #Basic Tensor indexed name
Tstr_lst = Tstr.split('_')
self.base = Tstr_lst[0] #Stem name
self.index = [] #Index list
self.sym = [] #Symmetry list
self.sgn = [] #Signs of symmetries
self.ccflg = [] #Covariant (True)/Contravariant (False) flag list
self.rank = [0,0] # [Contravariant rank,Contravariant rank]
self.cntrct = [] #List of contracted index pairs
self.op_flg = False #Is tensor a derivative operator
i = 1
sgn = -1
for chstr in Tstr_lst[1:]:
if chstr == '':
sgn = -sgn
else:
for ch in chstr:
self.index.append(i)
i += 1
if sgn == -1:
self.rank[0] += 1
self.ccflg.append(True)
else:
self.rank[1] += 1
self.ccflg.append(False)
sgn = -1
if syms != None:
self.add_symmetries(syms,sgns)
def rank(self):
return(self.rank)
def symmetries(self):
return(self.syms,self.sgns)
def add_symmetries(self,sym_lst,sgn_lst=None):
self.sym += sym_lst
if sgn_lst == None:
sgn_lst = len(sym_lst)*[1]
self.sgn += sgn_lst
return
def contract(self,a,b):
if self.ccflg[a-1] != self.ccflg[b-1]:
self.cntrct += [a,b]
self.rank[1] -= 1
self.rank[0] -= 1
return
else:
print 'Cannot contract indices',a,'and',b,'of',self
sys.exit(1)
def pderv(self):
return(BasicTensor.Pd*ProductTensor(self))
def cderv(self):
return(BasicTensor.Cd*ProductTensor(self))
def symbol(self):
Tstr = str(self)
Tsym = sympy.Symbol(Tstr)
return(Tsym)
class ProductTensor:
@staticmethod
def setup(pdfmode='latex',dim=2,offset=0):
BasicTensor.setup(pdfmode,dim,offset)
return
@staticmethod
def mul(T1,T2):
n = len(T1.index)
T1T2 = ProductTensor()
T1T2.plst = T1.plst+T2.plst
T1T2.index = BasicTensor.cat_shift(T1.index,T2.index)
T1T2.ccflg = T1.ccflg+T2.ccflg
T1T2.cntrct = BasicTensor.cat_shift(T1.cntrct,T2.cntrct)
T1T2.sym = copy.copy(T1.sym)
for sym in T2.sym:
T1T2.sym.append(BasicTensor.shift(n,sym))
T1T2.rank[0] = T1.rank[0]+T2.rank[0]
T1T2.rank[1] = T1.rank[1]+T2.rank[1]
return(T1T2)
@staticmethod
def derv(T,op):
dT = Tensor()
Tshft = copy.copy(T)
Tshft.index = BasicTensor.shift(1,Tshft.index)
Tshft.cntrct = BasicTensor.shift(1,Tshft.cntrct)
for i in range(len(T.sym)):
Tshft.sym[i] = BasicTensor.shift(1,Tshft.sym[i])
i = 0
for i_p in range(len(T.plst)):
s = ProductTensor()
s.plst = Tshft.plst[:i_p]+[op]+Tshft.plst[i_p:]
s.index = Tshft.index[:i]+[1]+Tshft.index[i:]
s.ccflg = Tshft.ccflg[:i]+[True]+Tshft.ccflg[i:]
s.cntrct = copy.copy(Tshft.cntrct)
s.sym = copy.copy(Tshft.cntrct)
s.rank[0] = Tshft.rank[0]+1
s.rank[1] = Tshft.rank[1]
dT = dT+Tensor(s)
i += len(T.plst[i_p].index)
dT.rank = dT.slst[0].rank
return(dT)
def __init__(self,Tstr=None):
if Tstr == None:
self.plst = []
self.cntrct = []
self.sym = []
self.ccflg = []
self.index = []
self.rank = [0,0]
else:
if isinstance(Tstr,BasicTensor):
self.plst = [Tstr]
else:
self.plst = [BasicTensor(Tstr)]
self.cntrct = self.plst[0].cntrct
self.sym = [self.plst[0].sym]
self.ccflg = self.plst[0].ccflg
self.index = self.plst[0].index
self.rank = self.plst[0].rank
def __mul__(self,T):
return(ProductTensor.mul(self,T))
def contract(self,a,b):
T = copy.copy(self)
if (T.ccflg[a-1] != T.ccflg[b-1]) and (a not in T.cntrct) and (b not in T.cntrct):
T.cntrct += [a,b]
T.rank[0] -= 1
T.rank[1] -= 1
return(T)
else:
print self,'contract('+str(a)+','+str(b)+') not allowed\n'
sys.exit(1)
def pderv(self):
return(ProductTensor.derv(self,BasicTensor.Pd))
def cderv(self):
return(ProductTensor.derv(self,BasicTensor.Cd))
def permute(self,perm_lst):
T = copy.copy(self)
tmp = copy.copy(T.index)
for i in range(len(perm_lst)):
j = perm_lst[i]-1
tmp[j] = T.index[i]
T.index = tmp
return(T)
def __str__(self):
Tstr = ''
i = 0
for p in self.plst:
j = i+len(p.index)
Tstr += p.base
old_ccflg = not self.ccflg[i]
while i < j:
new_ccflg = self.ccflg[i]
if old_ccflg != new_ccflg:
if new_ccflg:
Tstr += '_'
else:
Tstr += '__'
old_ccflg = new_ccflg
i1 = i+1
if i1 in self.cntrct:
cntrct_pos = self.cntrct.index(i1)
dummy_pos = -((cntrct_pos/2)+1)
Tstr += BasicTensor.index_pool[dummy_pos]
else:
Tstr += BasicTensor.index_pool[self.index[i]-1]
i += 1
Tstr += '*'
return(Tstr[:-1])
def latex(self):
Tstr = ''
i = 0
frst_flg = True
for p in self.plst:
j = i+len(p.index)
if p.op_flg:
Tstr += BasicTensor.op_symbol[p.base]
else:
Tstr += p.base
Tstr += r'\indices{'
old_ccflg = not self.ccflg[i]
while i < j:
new_ccflg = self.ccflg[i]
if old_ccflg != new_ccflg:
if new_ccflg:
Tstr += '_{'
else:
Tstr += '^{'
old_ccflg = new_ccflg
i1 = i+1
if i1 in self.cntrct:
cntrct_pos = self.cntrct.index(i1)
dummy_pos = -((cntrct_pos/2)+1)
Tstr += BasicTensor.index_pool[dummy_pos]
else:
Tstr += BasicTensor.index_pool[self.index[i]-1]
i += 1
Tstr += '}}'
return(Tstr)
def debug(self,i=-1):
if i < 0:
print 'Debug:'
else:
print 'Term:',i
print 'index =',self.index
print 'ccflg =',self.ccflg
print 'rank =',self.rank
print 'cntrct =',self.cntrct
print 'sym =',self.sym
return
class Tensor:
@staticmethod
def setup(pdfmode='latex',dim=2,offset=0):
ProductTensor.setup(pdfmode,dim,offset)
return
def __init__(self,Tstr=None):
self.coef = []
self.slst = []
self.rank = [0,0]
if Tstr != None:
if isinstance(Tstr,ProductTensor):
self.slst = [Tstr]
else:
self.slst = [ProductTensor(Tstr)]
self.coef = [ONE]
self.rank = self.slst[0].rank
@staticmethod
def add(T1,T2):
if T1.rank != T2.rank and T1.rank != [0,0] and T2.rank != [0,0]:
print 'In add '+str(T1)+' and '+str(T2)+' not equal in rank'
sys.exit(1)
T1pT2 = Tensor()
T1pT2.slst = T1.slst+T2.slst
T1pT2.coef = T1.coef+T2.coef
T1pT2.rank[0] = max(T1.rank[0],T2.rank[0])
T1pT2.rank[1] = max(T1.rank[1],T2.rank[1])
return(T1pT2)
@staticmethod
def sub(T1,T2):
if T1.rank != T2.rank and T1.rank != [0,0] and T2.rank != [0,0]:
print 'In sub '+str(T1)+' and '+str(T2)+' not equal in rank'
sys.exit(1)
T1sT2 = Tensor()
T1sT2.slst = T1.slst+T2.slst
T1sT2.coef = T1.coef+minus(T2.coef)
T1sT2.rank[0] = max(T1.rank[0],T2.rank[0])
T1sT2.rank[1] = max(T1.rank[1],T2.rank[1])
return(T1sT2)
@staticmethod
def mul(T1,T2):
T1T2 = Tensor()
for c1,s1 in zip(T1.coef,T1.slst):
for c2,s2 in zip(T2.coef,T2.slst):
T1T2.coef.append(c1*c2)
T1T2.slst.append(s1*s2)
T1T2.rank = T1T2.slst[0].rank
return(T1T2)
@staticmethod
def derv(T,op):
dT = Tensor()
for i in range(len(T.slst)):
dT = dT+ProductTensor.derv(T.slst[i],op)
dT.rank = dT.slst[0].rank
return(dT)
def pderv(self):
return(Tensor.derv(self,BasicTensor.Pd))
def cderv(self):
return(Tensor.derv(self,BasicTensor.Cd))
def __add__(self,T):
return(Tensor.add(self,T))
def __sub__(self,T):
return(Tensor.sub(self,T))
def __mul__(self,T):
if isinstance(T,Tensor):
return(Tensor.mul(self,T))
else:
selfT = Tensor()
selfT.slst = copy.copy(self.slst)
selfT.coef = BasicTensor.scale(T,self.coef)
selfT.rank = copy.cppy(self.rank)
return(selfT)
def __rmul__(self,T):
if isinstance(T,Tensor):
return(Tensor.mul(T,self))
else:
selfT = Tensor()
selfT.slst = copy.copy(self.slst)
selfT.coef = BasicTensor.scale(T,self.coef)
selfT.rank = copy.copy(self.rank)
return(selfT)
def __neg__(self):
T = copy.copy(self)
for i in range(len(T.coef)):
T.coef[i] = -self.coef[i]
return(T)
def contract(self,a,b):
T = copy.copy(self)
for i in range(len(T.slst)):
T.slst[i] = self.slst[i].contract(a,b)
T.rank[0] -= 1
T.rank[1] -= 1
return(T)
def permute(self,perm_lst):
permT = Tensor()
permT.coef = copy.copy(self.coef)
for pt in self.slst:
permT.slst.append(pt.permute(perm_lst))
permT.rank = copy.copy(self.rank)
return(permT)
def __str__(self):
Tsum = ZERO
for i in range(len(self.coef)):
dummy = Symbol('dummy'+str(i))
Tsum += self.coef[i]*dummy
Tstr = str(Tsum)
for i in range(len(self.coef)):
tstr = str(self.slst[i])
Tstr = Tstr.replace('dummy'+str(i),tstr)
return(Tstr)
def latex(self):
Tsum = ZERO
for i in range(len(self.coef)):
dummy = Symbol('dummy'+str(i))
Tsum += self.coef[i]*dummy
Tstr = latex(Tsum)
for i in range(len(self.coef)):
Tstr = Tstr.replace('dummy_{'+str(i)+'}',self.slst[i].latex())
return(Tstr)
def debug(self):
print 'Debug:'
for i in range(len(self.slst)):
self.slst[i].debug(i+1)
return
if __name__ == '__main__':
Tensor.setup()
g_dn = Tensor('g_ab')
g_up = Tensor('g__ab')
dg = g_dn.pderv()
f = HALF*((g_up*(dg+dg.permute([2,1]))).contract(2,5)-((g_up*dg.permute([2,3,1])).contract(2,3)))
PDF.write(f.latex())
PDF.display()