The other day, someone asked a question: Can the itensor package in Maxima calculate the Laplace-Beltrami operator applied to a scalar field in the presence of torsion?
Well, it can. But I was very happy to get this question because it allowed me to uncover some long-standing, subtle bugs in the package that prevented some essential simplifications and in some cases, even produced nonsensical results.
With these fixes, Maxima now produces a beautiful result, as evidenced by this nice newly created demo, which I am about to add to the package:
(%i1) if get('itensor,'version) = false then load(itensor)
(%i2) "First, we set up the basic properties of the system"
(%i3) imetric(g)
(%i4) "Demo is faster in 3D but works for other values of dim, too"
(%i5) dim:3
(%i6) "We declare symmetries of the metric and other symbols"
(%i7) decsym(g,2,0,[sym(all)],[])
(%i8) decsym(g,0,2,[],[sym(all)])
(%i9) components(g([a],[b]),kdelta([a],[b]))
(%i10) decsym(levi_civita,0,dim,[],[anti(all)])
(%i11) decsym(itr,2,1,[anti(all)],[])
(%i12) "It is useful to set icounter to avoid indexing conflicts"
(%i13) icounter:100
(%i14) "We choose the appropriate convention for exterior algebra"
(%i15) igeowedge_flag:true
(%i16) "Now let us calculate the Laplacian of a scalar field and simplify"
(%i17) canform(hodge(extdiff(hodge(extdiff(f([],[]))))))
(%i18) contract(expand(lc2kdt(%)))
(%i19) ev(%,kdelta)
(%i20) D1:ishow(canform(%))
%1 %2 %3 %4 %1 %2 %1 %2
(%t20) (- f g g g ) + f g + f g
,%4 ,%3 %1 %2 ,%2 ,%1 ,%1 %2
(%i21) "We can re-express the result using Christoffel symbols, too"
(%i22) ishow(canform(conmetderiv(D1,g)))
%1 %4 %2 %5 %3 %1 %2 %3
(%t22) 2 f g g ichr2 g - f g ichr2
,%5 %1 %2 %3 %4 ,%3 %1 %2
%1 %3 %2 %1 %2
- f g ichr2 + f g
,%3 %1 %2 ,%1 %2
(%i23) "Nice. Now let us repeat the same calculation with torsion"
(%i24) itorsion_flag:true
(%i25) canform(hodge(extdiff(hodge(extdiff(f([],[]))))))
(%i26) "Additional simplifications are now needed"
(%i27) contract(expand(lc2kdt(%th(2))))
(%i28) ev(%,kdelta)
(%i29) canform(%)
(%i30) ev(%,ichr2)
(%i31) ev(%,ikt2)
(%i32) ev(%,ikt1)
(%i33) ev(%,g)
(%i34) ev(%,ichr1)
(%i35) contract(rename(expand(canform(%))))
(%i36) flipflag:not flipflag
(%i37) D2:ishow(canform(%th(2)))
%1 %2 %3 %4 %1 %2 %3 %1 %2
(%t37) (- f g g g ) + f g itr + f g
,%1 ,%2 %3 %4 ,%1 %2 %3 ,%1 ,%2
%1 %2
+ f g
,%1 %2
(%i38) "Another clean result; can also be expressed using Christoffel symbols"
(%i39) ishow(canform(conmetderiv(D2,g)))
%1 %2 %3 %4 %5 %1 %2 %3
(%t39) 2 f g g ichr2 g + f g itr
,%1 %2 %3 %4 %5 ,%1 %2 %3
%1 %2 %3 %2 %3 %1 %1 %2
- f g ichr2 - f g ichr2 + f g
,%1 %2 %3 ,%1 %2 %3 ,%1 %2
(%i40) "Finally, we see that the two results differ only by torsion"
(%i41) ishow(canform(D2-D1))
%1 %2 %3
(%t41) f g itr
,%1 %2 %3
(%i42) "Last but not least, d^2 is not nilpotent in the presence of torsion"
(%i43) extdiff(extdiff(f([],[])))
(%i44) ev(%,icc2,ikt2,ikt1)
(%i45) canform(%)
(%i46) ev(%,g)
(%i47) ishow(contract(%))
%3
(%t47) f itr
,%3 %275 %277
(%i48) "Reminder: when dim = 2n, the Laplacian is -1 times these results."
The learning curve is steep and there are many pitfalls, but itensor remains an immensely powerful package.