1 /* Copyright (C) 2003 Valerij Pipin <pip@iszf.irk.ru>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be
9 * useful, but WITHOUT ANY WARRANTY; without even the implied
10 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
14 * Its purpose is to extend the maxima's itensor ability to manage the
15 * exterior forms. We introduce the "~" operator for the exterior product,
16 * and "|" for the inner product of a form with a vector.
20 declare("~",additive);
21 declare("~",antisymmetric);
24 __iextdiff_flag:false;
28 [i,l1,l2,l11,l22,l1s,lk1,div,rp],
30 if length(first(indices(any)))>0 then rp:true,
33 if listp(cartan_basis) and not member(body,cartan_basis) and
34 member(any,cartan_basis) then -body~any
35 else if not atom(any) and op(any)="+" then
36 apply(op(any),[part(any,1)~body,rest(any)~body])
37 else if not atom(body) and op(body)="+" then
38 apply(op(body),[any~part(body,1),any~rest(body)])
39 else if not atom(any) and op(any)="-" then -((-any)~body)
40 else if not atom(body) and op(body)="-" then -(any~(-body))
41 else if not atom(any) and op(any)="*" then
43 if atom(first(any)) then first(any)*(rest(any)~body)
44 else if atom(last(any)) then last(any)*(rest(any,-1)~body)
45 else (first(any)~body)*rest(any)
47 else if not atom(body) and op(body)="*" then
49 if atom(first(body)) then first(body)*(any~rest(body))
50 else if atom(last(body)) then last(body)*(any~rest(body,-1))
51 else (any~first(body))*rest(body)
53 else if atom(any) or atom(body) then
56 else nounify("~")(any,body)
58 else if not atom(any) and nounify(op(any))=nounify("~") and
59 not atom(body) and nounify(op(body))=nounify("~") and
60 (intersect)(setify(args(any)),setify(args(body)))#[] then 0
61 else if not atom(any) and nounify(op(any))=nounify("~") then
63 if member(body, any) then 0
64 else nounify("~")(any,body)
66 else if not atom(body) and nounify(op(body))=nounify("~") then
68 if member(any, body) then 0
69 else nounify("~")(any,body)
71 else if atom(any) and nounify(op(body))=nounify("~") and
72 member(any,body) then 0
73 else if atom(body) and nounify(op(any))=nounify("~") and
74 member(body,any) then 0
79 l1:first(indices(any)),
80 l2:first(indices(body)),
81 if l1=[] then return(any*body)
82 else if l2=[] then return(any*body)
85 l11 : makelist(idummy(), i,1, length(l1)),
86 l22 : makelist(idummy(), i,1, length(l2)),
87 l1s:map("=",l1,l11), l2s:map("=",l2,l22),
88 lk1:append(l1,l2),lk2:append(l11,l22),
89 any:sublis(l1s,any), body:sublis(l2s,body),
90 div:if igeowedge_flag then length(l1)!*length(l2)! else length(lk1)!,
91 factor(canform(contract(expand(kdelta(lk1,lk2)*any*body)))/div)
96 contind(t):=if mapatom(t) then []
97 else if op(t)=nounify(determinant) then []
98 else if op(t)=sqrt then []
99 else if ?rpobj(t) then conti(t)
100 else if op(t)="+" then
105 else if op(t)="-" then contind(part(t,1))
106 else if op(t)="/" then append(contind(part(t,1)),covind(part(t,2)))
107 else if op(t)="*" then
111 map(lambda([x],l:append(l,contind(x))),args(t)),
114 else error("Cannot determine list of contravariant indices.");
116 covind(t):=if mapatom(t) then []
117 else if op(t)=nounify(determinant) then []
118 else if op(t)=sqrt then []
119 else if ?rpobj(t) then append(covi(t),deri(t))
120 else if op(t)="+" then
125 else if op(t)="-" then covind(part(t,1))
126 else if op(t)="/" then append(covind(part(t,1)),contind(part(t,2)))
127 else if op(t)="*" then
131 map(lambda([x],l:append(l,covind(x))),args(t)),
134 else error("Cannot determine list of covariant indices.");
136 extdiff(forma,[optind]):=if not mapatom(forma) and op(forma)=extdiff then 0
137 /* A misguided attempt to check for valid forms... DO NOT UNCOMMENT
138 * else if (?rpobj)(forma)#false and length(conti(forma))>0
139 * then error("A differential form cannot have a contravariant index")
140 * else if (?rpobj)(forma)#false and length(covi(forma))>1 and
141 * dispsym(forma,length(covi(forma)),0)#
142 * [[anti,[makelist(i,i,1,length(covi(forma)))],[]]]
143 * then error("Tensor not declared anti(all) in its covariant indices")
145 else if not mapatom(forma) and op(forma)="+" then
146 sum(apply(extdiff,cons(part(forma,%%i),optind)),%%i,1,length(forma))
147 /* Another misguided attempt to process products. Fails because it
148 * separates contractable products, yielding invalid results. DO NOT UNCOMMENT
149 * else if not mapatom(forma) and op(forma)="*" then block
151 * [d:(if length(optind)>0 then optind[1] else idummy())],
152 * extdiff(first(forma),d)*rest(forma)+
153 * first(forma)*extdiff(rest(forma),d)
158 [l1,l11,l1s,lk1,lk2,indd,res,l0:setify(first(indices(forma))),
159 /* l1:listify(intersect(setify(covi(forma)),setify(first(indices(forma))))),*/
160 div,ind1:if length(optind)>0 then optind[1] else idummy()],
161 l1:listify(intersect(setify(covind(forma)),l0)),
164 if itorsion_flag = true and length(l0)>0 then return (covdiff(forma,ind1))
165 else return(idiff(forma,ind1))
167 else if length(l1) >= dim then return(0)
170 l11:makelist(idummy(),i,1,length(l1)),
172 lk1:append([ind1],l1),
174 lk2:append(l11,[indd]),
175 res:sublis(l1s,forma),
176 if itorsion_flag=true then
177 res:contract(canform(ratexpand(kdelta(lk1,lk2)*covdiff(res,indd))))
178 else res:contract(canform(ratexpand(kdelta(lk1,lk2)*idiff(res,indd)))),
179 /* If a frame base is used, the contribution of ifb must be added */
180 if iframe_flag=true then
181 for i thru length(l1) do
183 l1s:map("=",[l1[i]],[indd]),
184 res:res+(if evenp(length(l1)) then 1 else -1)*
185 'ifb([l1[i],ind1],[indd])*sublis(l1s,forma)
187 div:if igeowedge_flag then (length(lk1)-1)! else length(lk1)!,
192 /* VTT: To ensure consistent application of the "first" index in | */
196 for i thru length(l)-1 do if orderlessp(l[i+1],l[i]) then
197 (temp:l[i+1],l[i+1]:l[i],l[i]:temp,i:0,result:-result),
202 declare("|",additive);
203 /* VTT: ADDITIVE doesn't always do the trick so we break up sums manually */
204 "|"(forma,vec):=block
207 forma:distrib(forma),
208 if not(atom(forma)) and (op(forma)="+" or op(forma)="=") then
209 apply(op(forma),[part(forma,1)|vec,rest(forma)|vec])
210 /* When I thought that I'd implement MACSYMA's Cartan package features
211 * as part of this package, I thought I needed this. But I don't.
212 * else if listp(forma) and listp(cartan_basis) then
214 * for i thru length(cartan_basis) do
215 * vec:subst(forma[i],cartan_basis[i],-vec),
221 /* We must not attempt to permute derivative indices. Non-derivative
222 indices are found as the intersection of free indices, and free
223 indices of the UNDIFF'd form of forma. However, we still do the
224 contraction with respect to the first free covariant index which
225 may be a derivative index. Urgh. */
226 /* perm:permutator((?intersect)(first(indices(forma)),
227 first(indices(undiff(forma))))),
228 if perm[2]=[] then perm:[1,first(indices(forma))],
230 else perm[1]*(contract(canform(expand(forma*
231 vec([],[first(sort(indices(forma)[1]))])))))*/
232 ind1:first(sort(first(indices(forma)))),
233 contract(canform(expand(forma*vec([],[ind1]))))