1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
/* Copyright (C) 2004 Viktor T. Toth <http://www.vttoth.com/>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* Algebraic tensor manipulation
*
*/
if get('atensor,'version)#false then error("ATENSOR already loaded!")$
alg_type: 'universal;
asymbol:v;
adim:0;
aform:diagmatrix(3,1);
dotscrules:true;
dotdistrib:true;
dotexptsimp:false;
abasep(v):=if not atom(v) and mapatom(v) and op(v)=asymbol and length(v)=1
and part(v,1)>0 and part(v,1)<=adim then true else false;
/* declare(..,scalarp) doesn't work on function names, which is why
we need some special rules here. */
scalarfunp(x):=if not atom(x) and (op(x)=nounify(sf) or op(x)=nounify(af))
then true else scalarp(x);
nonscfunp(x):=if atom(x) or (op(x)#nounify(sf) and op(x)#nounify(af))
then not scalarp(x) else false;
matchdeclare([nonsc1,nonsc2], nonscfunp());
matchdeclare([scalarf],scalarfunp());
matchdeclare([abasev1,abasev2],abasep());
defrule(scalarfun1,nonsc1.scalarf,nonsc1*scalarf);
defrule(scalarfun2,scalarf.nonsc2,nonsc2*scalarf);
defrule(grassmann1,nonsc1.nonsc1,0);
defrule(grassmann2,nonsc1.nonsc2,
if ordergreatp(nonsc1,nonsc2) then -nonsc2.nonsc1 else nonsc1.nonsc2);
defrule(clifford1,nonsc1.nonsc1,sf(nonsc1,nonsc1));
defrule(clifford2,nonsc1.nonsc2,
if ordergreatp(nonsc1,nonsc2) then -nonsc2.nonsc1+2*sf(nonsc2,nonsc1) else nonsc1.nonsc2);
defrule(symmetric,nonsc1.nonsc2,
if ordergreatp(nonsc1,nonsc2) then nonsc2.nonsc1 else nonsc1.nonsc2);
defrule(symplectic,nonsc1.nonsc2,
if ordergreatp(nonsc1,nonsc2) then nonsc2.nonsc1-2*af(nonsc2,nonsc1)
else nonsc1.nonsc2);
defrule(lie_envelop,nonsc1.nonsc2,
if ordergreatp(nonsc1,nonsc2) then nonsc2.nonsc1-2*av(nonsc2,nonsc1)
else nonsc1.nonsc2);
defrule(complex1,abasev1.abasev1,-1);
atenrules:[
[grassmann,[grassmann1,grassmann2]],
[clifford,[clifford1,clifford2]],
[symmetric,[symmetric]],
[symplectic,[symplectic]],
[lie_envelop,[lie_envelop]]
];
/* Recursively simplify an atensor expression, with special attention
paid to the fact that mnctimes can have multiple arguments;
furthermore, we don't want dot products to end up as arguments
to av(), af(), or sf(). The counter j is to ensure that the function
always terminates. Admittedly, this is not a very efficient
implementation and can use improvements, but it does provide results
that are compatible with commercial MACSYMA. */
atensimp(exp):=block
(
[i,j,exp1,exp2,exp3,done],
if not mapatom(exp) then exp:map(atensimp,exp),
for j thru 10 do
(
done:false,
exp1:exp,
while not done do
(
done:true,
if not atom(exp1) and op(exp1)="." and length(args(exp1))>2 then block
(
[argv:args(exp1)],
for i thru length(argv)-1 do
(
exp2:"."(argv[i],argv[i+1]),
exp3:atensimp(exp2),
if exp2#exp3 then
(
exp1:apply(".",append(rest(argv,-length(argv)+i-1),[exp3],
rest(argv,i+1))),
exp1:ev(exp1,simp),
i:length(argv),
done:false
)
)
)
),
if exp#exp1 then exp:atensimp(exp1) else
for i thru length(atenrules) do
if atenrules[i][1]=alg_type then
(
exp2:apply('applyb1,cons(exp,atenrules[i][2])),
exp2:ev(exp2,simp),
exp2:applyb1(exp2,scalarfun1,scalarfun2),
exp2:ev(exp2,simp),
if exp=exp2 then j:10
else exp:(if mapatom(exp2) then exp2 else map(atensimp,exp2))
)
),
exp
);
init_atensor(algname, [optdims]):=
(
if algname='universal or algname='grassmann or algname='clifford or
algname='symmetric or algname='symplectic or algname='lie_envelop then
(
alg_type:algname,
if alg_type='symplectic then
(
adim:0,
kill(aform),
if length(optdims)>0 then
(
adim:optdims[1],
aform:zeromatrix(optdims[1],optdims[1]),
for i thru adim do
for j thru i-1 do
(
aform[i,j]:if evenp(i+j) then 1 else -1,
aform[j,i]:-aform[i,j]
),
if length(optdims)>1 then
(
for i thru optdims[2] do
aform:addrow(aform,makelist(0,j,1,adim)),
adim:adim+optdims[2],
for i thru optdims[2] do
aform:addcol(aform,makelist(0,j,1,adim))
),
if length(optdims)>2 then error("Invalid optional dimensions"),
optdims:[]
)
)
else if alg_type='clifford then block
(
[p:0,z:0,n:0],
if length(optdims)>0 then p:optdims[1],
if length(optdims)>1 then z:optdims[2],
if length(optdims)>2 then n:optdims[3],
if length(optdims)>3 then error("Invalid optional dimensions"),
adim:p+z+n,
if adim>0 then
(
aform:ident(adim),
for i from p+1 thru p+z do aform[i,i]:0,
for i from p+z+1 thru adim do aform[i,i]:-1
)
else kill(aform),
optdims:[]
)
else if length(optdims)>0 then
(
if length(optdims)>1 then error("Invalid optional dimensions"),
adim:optdims[1],
aform:ident(adim),
if alg_type='lie_envelop then
(
for i thru adim do for j thru i do
if i=j then aform[i,j]:0
else aform[i,j]:-(aform[j,i]:(remainder(2*adim+2-i-j,adim)+1)*
signum(i-j)*(if oddp(i+j) then 1 else -1))
),
optdims:[]
)
else
(
kill(aform),
adim:0
)
)
else if algname='complex then init_atensor(clifford,0,0,1)
else if algname='quaternion then init_atensor(clifford,0,0,2)
else if algname='pauli then init_atensor(clifford,3)
else if algname='dirac then init_atensor(clifford,3,0,1)
else error("Unknown algebra name"),
if optdims#[] then error("No optional dimensions permitted for this algebra"),
done
);
af(u,v):=if abasep(u) and abasep(v) then aform[part(u,1),part(v,1)]
else 'af(u,v);
sf(u,v):=if abasep(u) and abasep(v) then aform[part(u,1),part(v,1)]
else 'sf(u,v);
av(%u,%v):=if abasep(%u) and abasep(%v) then block
(
[i:aform[part(%u,1),part(%v,1)]],
if abs(i)>0 and abs(i)<=adim then asymbol[abs(i)]*signum(i) else 0
)
else 'av(%u,%v);
put('atensor,'v20081223,'version)$
|