1 @c RECOMMEND REVISE TEXT THROUGHOUT TO LOSE NOTION OF TIME RELATIVE TO PRESENT
2 @c LOOK FOR "NOW", "OLD", "NEW", "RECENT", "EARLIER", DATES
4 @c RERUN EXAMPLES WITH ADDT'L WHITESPACE IN INPUT TO AID LEGIBILITY
7 * Introduction to itensor::
8 * Functions and Variables for itensor::
11 @c -----------------------------------------------------------------------------
12 @node Introduction to itensor, Functions and Variables for itensor, itensor, itensor
13 @section Introduction to itensor
14 @c -----------------------------------------------------------------------------
16 Maxima implements symbolic tensor manipulation of two distinct types:
17 component tensor manipulation (@code{ctensor} package) and indicial tensor
18 manipulation (@code{itensor} package).
20 Nota bene: Please see the note on 'new tensor notation' below.
22 Component tensor manipulation means that geometrical tensor
23 objects are represented as arrays or matrices. Tensor operations such
24 as contraction or covariant differentiation are carried out by
25 actually summing over repeated (dummy) indices with @code{do} statements.
26 That is, one explicitly performs operations on the appropriate tensor
27 components stored in an array or matrix.
29 Indicial tensor manipulation is implemented by representing
30 tensors as functions of their covariant, contravariant and derivative
31 indices. Tensor operations such as contraction or covariant
32 differentiation are performed by manipulating the indices themselves
33 rather than the components to which they correspond.
35 These two approaches to the treatment of differential, algebraic and
36 analytic processes in the context of Riemannian geometry have various
37 advantages and disadvantages which reveal themselves only through the
38 particular nature and difficulty of the user's problem. However, one
39 should keep in mind the following characteristics of the two
42 The representation of tensors and tensor operations explicitly in
43 terms of their components makes @code{ctensor} easy to use. Specification of
44 the metric and the computation of the induced tensors and invariants
45 is straightforward. Although all of Maxima's powerful simplification
46 capacity is at hand, a complex metric with intricate functional and
47 coordinate dependencies can easily lead to expressions whose size is
48 excessive and whose structure is hidden. In addition, many calculations
49 involve intermediate expressions which swell causing programs to
50 terminate before completion. Through experience, an user can avoid
51 many of these difficulties.
53 Because of the special way in which tensors and tensor operations
54 are represented in terms of symbolic operations on their indices,
55 expressions which in the component representation would be
56 unmanageable can sometimes be greatly simplified by using the special
57 routines for symmetrical objects in @code{itensor}. In this way the structure
58 of a large expression may be more transparent. On the other hand, because
59 of the special indicial representation in @code{itensor}, in some cases the
60 user may find difficulty with the specification of the metric, function
61 definition, and the evaluation of differentiated "indexed" objects.
63 The @code{itensor} package can carry out differentiation with respect to an indexed
64 variable, which allows one to use the package when dealing with Lagrangian
65 and Hamiltonian formalisms. As it is possible to differentiate a field
66 Lagrangian with respect to an (indexed) field variable, one can use Maxima
67 to derive the corresponding Euler-Lagrange equations in indicial form. These
68 equations can be translated into component tensor (@code{ctensor}) programs using
69 the @code{ic_convert} function, allowing us to solve the field equations in a
70 particular coordinate representation, or to recast the equations of motion
71 in Hamiltonian form. See @code{einhil.dem} and @code{bradic.dem} for two comprehensive
72 examples. The first, @code{einhil.dem}, uses the Einstein-Hilbert action to derive
73 the Einstein field tensor in the homogeneous and isotropic case (Friedmann
74 equations) and the spherically symmetric, static case (Schwarzschild
75 solution.) The second, @code{bradic.dem}, demonstrates how to compute the Friedmann
76 equations from the action of Brans-Dicke gravity theory, and also derives
77 the Hamiltonian associated with the theory's scalar field.
81 @category{Share packages}
82 @category{Package itensor}
85 @c -----------------------------------------------------------------------------
86 @subsection New tensor notation
87 @c -----------------------------------------------------------------------------
89 Earlier versions of the @code{itensor} package in Maxima used a notation that sometimes
90 led to incorrect index ordering. Consider the following, for instance:
95 (%i3) ishow(g([],[j,k])*g([],[i,l])*a([i,j],[]))$
99 (%i4) ishow(contract(%))$
104 This result is incorrect unless @code{a} happens to be a symmetric tensor.
105 The reason why this happens is that although @code{itensor} correctly maintains
106 the order within the set of covariant and contravariant indices, once an
107 index is raised or lowered, its position relative to the other set of
110 To avoid this problem, a new notation has been developed that remains fully
111 compatible with the existing notation and can be used interchangeably. In
112 this notation, contravariant indices are inserted in the appropriate
113 positions in the covariant index list, but with a minus sign prepended.
114 Functions like @mref{contract_Itensor} and @mref{ishow} are now aware of this
115 new index notation and can process tensors appropriately.
117 In this new notation, the previous example yields a correct result:
120 (%i5) ishow(g([-j,-k],[])*g([-i,-l],[])*a([i,j],[]))$
124 (%i6) ishow(contract(%))$
129 Presently, the only code that makes use of this notation is the @code{lc2kdt}
130 function. Through this notation, it achieves consistent results as it
131 applies the metric tensor to resolve Levi-Civita symbols without resorting
134 Since this code is brand new, it probably contains bugs. While it has been
135 tested to make sure that it doesn't break anything using the "old" tensor
136 notation, there is a considerable chance that "new" tensors will fail to
137 interoperate with certain functions or features. These bugs will be fixed
138 as they are encountered... until then, caveat emptor!
140 @c -----------------------------------------------------------------------------
141 @subsection Indicial tensor manipulation
142 @c -----------------------------------------------------------------------------
144 The indicial tensor manipulation package may be loaded by
145 @code{load("itensor")}. Demos are also available: try @code{demo("tensor")}.
147 In @code{itensor} a tensor is represented as an "indexed object" . This is a
148 function of 3 groups of indices which represent the covariant,
149 contravariant and derivative indices. The covariant indices are
150 specified by a list as the first argument to the indexed object, and
151 the contravariant indices by a list as the second argument. If the
152 indexed object lacks either of these groups of indices then the empty
153 list @code{[]} is given as the corresponding argument. Thus, @code{g([a,b],[c])}
154 represents an indexed object called @code{g} which has two covariant indices
155 @code{(a,b)}, one contravariant index (@code{c}) and no derivative indices.
157 The derivative indices, if they are present, are appended as
158 additional arguments to the symbolic function representing the tensor.
159 They can be explicitly specified by the user or be created in the
160 process of differentiation with respect to some coordinate variable.
161 Since ordinary differentiation is commutative, the derivative indices
162 are sorted alphanumerically, unless @code{iframe_flag} is set to @code{true},
163 indicating that a frame metric is being used. This canonical ordering makes it
164 possible for Maxima to recognize that, for example, @code{t([a],[b],i,j)} is
165 the same as @code{t([a],[b],j,i)}. Differentiation of an indexed object with
166 respect to some coordinate whose index does not appear as an argument
167 to the indexed object would normally yield zero. This is because
168 Maxima would not know that the tensor represented by the indexed
169 object might depend implicitly on the corresponding coordinate. By
170 modifying the existing Maxima function @code{diff} in @code{itensor}, Maxima now
171 assumes that all indexed objects depend on any variable of
172 differentiation unless otherwise stated. This makes it possible for
173 the summation convention to be extended to derivative indices. It
174 should be noted that @code{itensor} does not possess the capabilities of
175 raising derivative indices, and so they are always treated as
178 The following functions are available in the tensor package for
179 manipulating indexed objects. At present, with respect to the
180 simplification routines, it is assumed that indexed objects do not
181 by default possess symmetry properties. This can be overridden by
182 setting the variable @code{allsym[false]} to @code{true}, which will
183 result in treating all indexed objects completely symmetric in their
184 lists of covariant indices and symmetric in their lists of
185 contravariant indices.
187 The @code{itensor} package generally treats tensors as opaque objects. Tensorial
188 equations are manipulated based on algebraic rules, specifically symmetry
189 and contraction rules. In addition, the @code{itensor} package understands
190 covariant differentiation, curvature, and torsion. Calculations can be
191 performed relative to a metric of moving frame, depending on the setting
192 of the @code{iframe_flag} variable.
194 A sample session below demonstrates how to load the @code{itensor} package,
195 specify the name of the metric, and perform some simple calculations.
198 (%i1) load("itensor");
199 (%o1) /share/tensor/itensor.lisp
202 (%i3) components(g([i,j],[]),p([i,j],[])*e([],[]))$
203 (%i4) ishow(g([k,l],[]))$
206 (%i5) ishow(diff(v([i],[]),t))$
210 (%i7) ishow(diff(v([i],[]),t))$
214 (%i8) ishow(idiff(v([i],[]),j))$
217 (%i9) ishow(extdiff(v([i],[]),j))$
222 (%i10) ishow(liediff(v,w([i],[])))$
226 (%i11) ishow(covdiff(v([i],[]),j))$
230 (%i12) ishow(ev(%,ichr2))$
232 (%t12) v - (g v (e p + e p - e p - e p
233 i,j %4 j %5,i ,i j %5 i j,%5 ,%5 i j
237 (%i13) iframe_flag:true;
239 (%i14) ishow(covdiff(v([i],[]),j))$
243 (%i15) ishow(ev(%,icc2))$
247 (%i16) ishow(radcan(ev(%,ifc2,ifc1)))$
249 (%t16) - (ifg v ifb + ifg v ifb - 2 v
250 %6 j %7 i %6 i j %7 i,j
255 (%i17) ishow(canform(s([i,j],[])-s([j,i])))$
258 (%i18) decsym(s,2,0,[sym(all)],[]);
260 (%i19) ishow(canform(s([i,j],[])-s([j,i])))$
262 (%i20) ishow(canform(a([i,j],[])+a([j,i])))$
265 (%i21) decsym(a,2,0,[anti(all)],[]);
267 (%i22) ishow(canform(a([i,j],[])+a([j,i])))$
271 @c end concepts itensor
273 @c -----------------------------------------------------------------------------
274 @node Functions and Variables for itensor, , Introduction to itensor, itensor
275 @section Functions and Variables for itensor
276 @subsection Managing indexed objects
277 @c -----------------------------------------------------------------------------
279 @c -----------------------------------------------------------------------------
281 @deffn {Function} dispcon @
282 @fname{dispcon} (@var{tensor_1}, @var{tensor_2}, @dots{}) @
283 @fname{dispcon} (all)
285 Displays the contraction properties of its arguments as were given to
286 @code{defcon}. @code{dispcon (all)} displays all the contraction properties
290 @category{Display functions}
294 @c -----------------------------------------------------------------------------
296 @deffn {Function} entertensor (@var{name})
298 is a function which, by prompting, allows one to create an indexed
299 object called @var{name} with any number of tensorial and derivative
300 indices. Either a single index or a list of indices (which may be
301 null) is acceptable input (see the example under @mref{covdiff}).
304 @category{Package itensor}
308 @c -----------------------------------------------------------------------------
310 @deffn {Function} changename (@var{old}, @var{new}, @var{expr})
312 will change the name of all indexed objects called @var{old} to @var{new}
313 in @var{expr}. @var{old} may be either a symbol or a list of the form
314 @code{[@var{name}, @var{m}, @var{n}]} in which case only those indexed objects called
315 @var{name} with @var{m} covariant and @var{n} contravariant indices will be
316 renamed to @var{new}.
319 @category{Package itensor}
323 @c -----------------------------------------------------------------------------
324 @deffn {Function} listoftens
328 Lists all tensors in a tensorial expression, complete with their indices. E.g.,
332 (%i6) ishow(a([i,j],[k])*b([u],[],v)+c([x,y],[])*d([],[])*e)$
336 (%i7) ishow(listoftens(%))$
338 (%t7) [a , b , c , d]
344 @category{Package itensor}
348 @c -----------------------------------------------------------------------------
350 @deffn {Function} ishow (@var{expr})
352 displays @var{expr} with the indexed objects in it shown having their
353 covariant indices as subscripts and contravariant indices as
354 superscripts. The derivative indices are displayed as subscripts,
355 separated from the covariant indices by a comma (see the examples
356 throughout this document).
359 @category{Package itensor}
363 @c -----------------------------------------------------------------------------
365 @deffn {Function} indices (@var{expr})
367 Returns a list of two elements. The first is a list of the free
368 indices in @var{expr} (those that occur only once). The second is the
369 list of the dummy indices in @var{expr} (those that occur exactly twice)
370 as the following example demonstrates.
374 (%i1) load("itensor");
375 (%o1) /share/tensor/itensor.lisp
376 (%i2) ishow(a([i,j],[k,l],m,n)*b([k,o],[j,m,p],q,r))$
381 (%o3) [[l, p, i, n, o, q, r], [k, j, m]]
385 A tensor product containing the same index more than twice is syntactically
386 illegal. @code{indices} attempts to deal with these expressions in a
387 reasonable manner; however, when it is called to operate upon such an
388 illegal expression, its behavior should be considered undefined.
391 @category{Package itensor}
395 @c -----------------------------------------------------------------------------
397 @deffn {Function} rename @
398 @fname{rename} (@var{expr}) @
399 @fname{rename} (@var{expr}, @var{count})
401 Returns an expression equivalent to @var{expr} but with the dummy indices
402 in each term chosen from the set @code{[%1, %2,...]}, if the optional second
403 argument is omitted. Otherwise, the dummy indices are indexed
404 beginning at the value of @var{count}. Each dummy index in a product
405 will be different. For a sum, @code{rename} will operate upon each term in
406 the sum resetting the counter with each term. In this way @code{rename} can
407 serve as a tensorial simplifier. In addition, the indices will be
408 sorted alphanumerically (if @mref{allsym} is @code{true}) with respect to
409 covariant or contravariant indices depending upon the value of @mref{flipflag}.
410 If @code{flipflag} is @code{false} then the indices will be renamed according
411 to the order of the contravariant indices. If @code{flipflag} is @code{true}
412 the renaming will occur according to the order of the covariant
413 indices. It often happens that the combined effect of the two renamings will
414 reduce an expression more than either one by itself.
418 (%i1) load("itensor");
419 (%o1) /share/tensor/itensor.lisp
422 (%i3) g([],[%4,%5])*g([],[%6,%7])*ichr2([%1,%4],[%3])*
423 ichr2([%2,%3],[u])*ichr2([%5,%6],[%1])*ichr2([%7,r],[%2])-
424 g([],[%4,%5])*g([],[%6,%7])*ichr2([%1,%2],[u])*
425 ichr2([%3,%5],[%1])*ichr2([%4,%6],[%3])*ichr2([%7,r],[%2]),noeval$
428 %4 %5 %6 %7 %3 u %1 %2
429 (%t4) g g ichr2 ichr2 ichr2 ichr2
430 %1 %4 %2 %3 %5 %6 %7 r
432 %4 %5 %6 %7 u %1 %3 %2
433 - g g ichr2 ichr2 ichr2 ichr2
434 %1 %2 %3 %5 %4 %6 %7 r
438 (%i6) ishow(rename(expr))$
439 %2 %5 %6 %7 %4 u %1 %3
440 (%t6) g g ichr2 ichr2 ichr2 ichr2
441 %1 %2 %3 %4 %5 %6 %7 r
443 %4 %5 %6 %7 u %1 %3 %2
444 - g g ichr2 ichr2 ichr2 ichr2
445 %1 %2 %3 %4 %5 %6 %7 r
446 (%i7) flipflag:false;
448 (%i8) rename(%th(2));
450 (%i9) ishow(rename(expr))$
451 %1 %2 %3 %4 %5 %6 %7 u
452 (%t9) g g ichr2 ichr2 ichr2 ichr2
453 %1 %6 %2 %3 %4 r %5 %7
455 %1 %2 %3 %4 %6 %5 %7 u
456 - g g ichr2 ichr2 ichr2 ichr2
457 %1 %3 %2 %6 %4 r %5 %7
461 @category{Package itensor}
465 @c -----------------------------------------------------------------------------
467 @defvr {Option variable} flipflag
468 Default value: @code{false}
470 If @code{false} then the indices will be
471 renamed according to the order of the contravariant indices,
472 otherwise according to the order of the covariant indices.
474 If @code{flipflag} is @code{false} then @code{rename} forms a list
475 of the contravariant indices as they are encountered from left to right
476 (if @code{true} then of the covariant indices). The first dummy
477 index in the list is renamed to @code{%1}, the next to @code{%2}, etc.
478 Then sorting occurs after the @code{rename}-ing (see the example
479 under @code{rename}).
482 @category{Package itensor}
486 @c -----------------------------------------------------------------------------
488 @deffn {Function} defcon @
489 @fname{defcon} (@var{tensor_1}) @
490 @fname{defcon} (@var{tensor_1}, @var{tensor_2}, @var{tensor_3})
492 gives @var{tensor_1} the property that the
493 contraction of a product of @var{tensor_1} and @var{tensor_2} results in @var{tensor_3}
494 with the appropriate indices. If only one argument, @var{tensor_1}, is
495 given, then the contraction of the product of @var{tensor_1} with any indexed
496 object having the appropriate indices (say @code{my_tensor}) will yield an
497 indexed object with that name, i.e. @code{my_tensor}, and with a new set of
498 indices reflecting the contractions performed.
499 For example, if @code{imetric:g}, then @code{defcon(g)} will implement the
500 raising and lowering of indices through contraction with the metric
502 More than one @code{defcon} can be given for the same indexed object; the
503 latest one given which applies in a particular contraction will be
505 @code{contractions} is a list of those indexed objects which have been given
506 contraction properties with @code{defcon}.
509 @category{Package itensor}
513 @c -----------------------------------------------------------------------------
515 @deffn {Function} remcon @
516 @fname{remcon} (@var{tensor_1}, ..., @var{tensor_n}) @
519 Removes all the contraction properties
520 from the (@var{tensor_1}, ..., @var{tensor_n}). @code{remcon(all)} removes all contraction
521 properties from all indexed objects.
524 @category{Package itensor}
528 @c -----------------------------------------------------------------------------
529 @anchor{contract_Itensor}
530 @deffn {Function} contract (@var{expr})
532 Carries out the tensorial contractions in @var{expr} which may be any
533 combination of sums and products. This function uses the information
534 given to the @code{defcon} function. For best results, @code{expr}
535 should be fully expanded. @mref{ratexpand} is the fastest way to expand
536 products and powers of sums if there are no variables in the denominators
537 of the terms. The @mref{gcd} switch should be @code{false} if GCD
538 cancellations are unnecessary.
541 @category{Package itensor}
545 @c -----------------------------------------------------------------------------
546 @anchor{indexed_tensor}
547 @deffn {Function} indexed_tensor (@var{tensor})
549 Must be executed before assigning components to a @var{tensor} for which
550 a built in value already exists as with @code{ichr1}, @code{ichr2},
551 @code{icurvature}. See the example under @mref{icurvature}.
554 @category{Package itensor}
558 @c -----------------------------------------------------------------------------
560 @deffn {Function} components (@var{tensor}, @var{expr})
562 permits one to assign an indicial value to an expression
563 @var{expr} giving the values of the components of @var{tensor}. These
564 are automatically substituted for the tensor whenever it occurs with
565 all of its indices. The tensor must be of the form @code{t([...],[...])}
566 where either list may be empty. @var{expr} can be any indexed expression
567 involving other objects with the same free indices as @var{tensor}. When
568 used to assign values to the metric tensor wherein the components
569 contain dummy indices one must be careful to define these indices to
570 avoid the generation of multiple dummy indices. Removal of this
571 assignment is given to the function @mref{remcomps}.
573 It is important to keep in mind that @code{components} cares only about
574 the valence of a tensor, not about any particular index ordering. Thus
575 assigning components to, say, @code{x([i,-j],[])}, @code{x([-j,i],[])}, or
576 @code{x([i],[j])} all produce the same result, namely components being
577 assigned to a tensor named @code{x} with valence @code{(1,1)}.
579 Components can be assigned to an indexed expression in four ways, two
580 of which involve the use of the @code{components} command:
582 1) As an indexed expression. For instance:
585 (%i2) components(g([],[i,j]),e([],[i])*p([],[j]))$
586 (%i3) ishow(g([],[i,j]))$
596 (%i5) lg:-ident(4)$lg[1,1]:1$lg;
606 (%i6) components(g([i,j],[]),lg);
608 (%i7) ishow(g([i,j],[]))$
617 3) As a function. You can use a Maxima function to specify the
618 components of a tensor based on its indices. For instance, the following
619 code assigns @mref{kdelta} to @code{h} if @code{h} has the same number
620 of covariant and contravariant indices and no derivative indices, and
625 (%i4) h(l1,l2,[l3]):=if length(l1)=length(l2) and length(l3)=0
626 then kdelta(l1,l2) else apply(g,append([l1,l2], l3))$
627 (%i5) ishow(h([i],[j]))$
631 (%i6) ishow(h([i,j],[k],l))$
637 4) Using Maxima's pattern matching capabilities, specifically the
638 @mref{defrule} and @mref{applyb1} commands:
642 (%i1) load("itensor");
643 (%o1) /share/tensor/itensor.lisp
644 (%i2) matchdeclare(l1,listp);
646 (%i3) defrule(r1,m(l1,[]),(i1:idummy(),
647 g([l1[1],l1[2]],[])*q([i1],[])*e([],[i1])))$
649 (%i4) defrule(r2,m([],l1),(i1:idummy(),
650 w([],[l1[1],l1[2]])*e([i1],[])*q([],[i1])))$
652 (%i5) ishow(m([i,n],[])*m([],[i,m]))$
658 (%i6) ishow(rename(applyb1(%,r1,r2)))$
665 @category{Package itensor}
670 @deffn {Function} remcomps (@var{tensor})
672 Unbinds all values from @var{tensor} which were assigned with the
673 @mref{components} function.
676 @category{Package itensor}
680 @c NEED LIST OF ARGUMENTS HERE
682 @c -----------------------------------------------------------------------------
684 @deffn {Function} showcomps (@var{tensor})
686 Shows component assignments of a tensor, as made using the @mref{components}
687 command. This function can be particularly useful when a matrix is assigned
688 to an indicial tensor using @code{components}, as demonstrated by the
694 (%o1) /share/tensor/ctensor.mac
695 (%i2) load("itensor");
696 (%o2) /share/tensor/itensor.lisp
697 (%i3) lg:matrix([sqrt(r/(r-2*m)),0,0,0],[0,r,0,0],
698 [0,0,sin(theta)*r,0],[0,0,0,sqrt((r-2*m)/r)]);
700 [ sqrt(-------) 0 0 0 ]
705 [ 0 0 r sin(theta) 0 ]
708 [ 0 0 0 sqrt(-------) ]
710 (%i4) components(g([i,j],[]),lg);
712 (%i5) showcomps(g([i,j],[]));
714 [ sqrt(-------) 0 0 0 ]
719 i j [ 0 0 r sin(theta) 0 ]
722 [ 0 0 0 sqrt(-------) ]
728 The @code{showcomps} command can also display components of a tensor of
732 @category{Package itensor}
736 @c -----------------------------------------------------------------------------
738 @deffn {Function} idummy ()
740 Increments @mref{icounter} and returns as its value an index of the form
741 @code{%n} where n is a positive integer. This guarantees that dummy indices
742 which are needed in forming expressions will not conflict with indices
743 already in use (see the example under @mref{indices}).
746 @category{Package itensor}
751 @defvr {Option variable} idummyx
752 Default value: @code{%}
754 Is the prefix for dummy indices (see the example under @mref{indices}).
757 @category{Package itensor}
761 @c -----------------------------------------------------------------------------
763 @defvr {Option variable} icounter
764 Default value: @code{1}
766 Determines the numerical suffix to be used in
767 generating the next dummy index in the tensor package. The prefix is
768 determined by the option @mref{idummy} (default: @code{%}).
771 @category{Package itensor}
775 @c -----------------------------------------------------------------------------
777 @deffn {Function} kdelta (@var{L1}, @var{L2})
778 is the generalized Kronecker delta function defined in
779 the @code{itensor} package with @var{L1} the list of covariant indices and @var{L2}
780 the list of contravariant indices. @code{kdelta([i],[j])} returns the ordinary
781 Kronecker delta. The command @code{ev(@var{expr},kdelta)} causes the evaluation of
782 an expression containing @code{kdelta([],[])} to the dimension of the
785 In what amounts to an abuse of this notation, @code{itensor} also allows
786 @code{kdelta} to have 2 covariant and no contravariant, or 2 contravariant
787 and no covariant indices, in effect providing a co(ntra)variant "unit matrix"
788 capability. This is strictly considered a programming aid and not meant to
789 imply that @code{kdelta([i,j],[])} is a valid tensorial object.
792 @category{Package itensor}
796 @c -----------------------------------------------------------------------------
798 @deffn {Function} kdels (@var{L1}, @var{L2})
800 Symmetrized Kronecker delta, used in some calculations. For instance:
804 (%i1) load("itensor");
805 (%o1) /share/tensor/itensor.lisp
806 (%i2) kdelta([1,2],[2,1]);
808 (%i3) kdels([1,2],[2,1]);
810 (%i4) ishow(kdelta([a,b],[c,d]))$
812 (%t4) kdelta kdelta - kdelta kdelta
814 (%i4) ishow(kdels([a,b],[c,d]))$
816 (%t4) kdelta kdelta + kdelta kdelta
822 @category{Package itensor}
826 @c -----------------------------------------------------------------------------
828 @deffn {Function} levi_civita (@var{L})
829 is the permutation (or Levi-Civita) tensor which yields 1 if
830 the list @var{L} consists of an even permutation of integers, -1 if it
831 consists of an odd permutation, and 0 if some indices in @var{L} are
835 @category{Package itensor}
839 @c -----------------------------------------------------------------------------
841 @deffn {Function} lc2kdt (@var{expr})
842 Simplifies expressions containing the Levi-Civita symbol, converting these
843 to Kronecker-delta expressions when possible. The main difference between
844 this function and simply evaluating the Levi-Civita symbol is that direct
845 evaluation often results in Kronecker expressions containing numerical
846 indices. This is often undesirable as it prevents further simplification.
847 The @code{lc2kdt} function avoids this problem, yielding expressions that
848 are more easily simplified with @mref{rename} or @mref{contract}.
852 (%i1) load("itensor");
853 (%o1) /share/tensor/itensor.lisp
854 (%i2) expr:ishow('levi_civita([],[i,j])
855 *'levi_civita([k,l],[])*a([j],[k]))$
857 (%t2) levi_civita a levi_civita
859 (%i3) ishow(ev(expr,levi_civita))$
861 (%t3) kdelta a kdelta
863 (%i4) ishow(ev(%,kdelta))$
865 (%t4) (kdelta kdelta - kdelta kdelta ) a
869 (kdelta kdelta - kdelta kdelta )
871 (%i5) ishow(lc2kdt(expr))$
873 (%t5) a kdelta kdelta - a kdelta kdelta
875 (%i6) ishow(contract(expand(%)))$
881 The @code{lc2kdt} function sometimes makes use of the metric tensor.
882 If the metric tensor was not defined previously with @mref{imetric},
883 this results in an error.
887 (%i7) expr:ishow('levi_civita([],[i,j])
888 *'levi_civita([],[k,l])*a([j,k],[]))$
891 (%t7) levi_civita levi_civita a
894 (%i8) ishow(lc2kdt(expr))$
895 Maxima encountered a Lisp error:
897 Error in $IMETRIC [or a callee]:
898 $IMETRIC [or a callee] requires less than two arguments.
900 Automatically continuing.
901 To re-enable the Lisp debugger set *debugger-hook* to nil.
904 (%i10) ishow(lc2kdt(expr))$
905 %3 i k %4 j l %3 i l %4 j
906 (%t10) (g kdelta g kdelta - g kdelta g
911 (%i11) ishow(contract(expand(%)))$
919 @category{Package itensor}
923 @c HMM, WHICH CATEGORY DOES THIS FALL INTO -- FUNCTION, VARIABLE, OTHER ??
925 @c -----------------------------------------------------------------------------
927 @deffn {Function} lc_l
928 Simplification rule used for expressions containing the unevaluated Levi-Civita
929 symbol (@mref{levi_civita}). Along with @mref{lc_u}, it can be used to simplify
930 many expressions more efficiently than the evaluation of @code{levi_civita}.
935 (%i1) load("itensor");
936 (%o1) /share/tensor/itensor.lisp
937 (%i2) el1:ishow('levi_civita([i,j,k],[])*a([],[i])*a([],[j]))$
939 (%t2) a a levi_civita
941 (%i3) el2:ishow('levi_civita([],[i,j,k])*a([i])*a([j]))$
943 (%t3) levi_civita a a
945 (%i4) canform(contract(expand(applyb1(el1,lc_l,lc_u))));
947 (%i5) canform(contract(expand(applyb1(el2,lc_l,lc_u))));
953 @category{Package itensor}
957 @c HMM, WHICH CATEGORY DOES THIS FALL INTO -- FUNCTION, VARIABLE, OTHER ??
959 @c -----------------------------------------------------------------------------
961 @deffn {Function} lc_u
963 Simplification rule used for expressions containing the unevaluated Levi-Civita
964 symbol (@mref{levi_civita}). Along with @code{lc_u}, it can be used to simplify
965 many expressions more efficiently than the evaluation of @code{levi_civita}.
966 For details, see @mref{lc_l}.
969 @category{Package itensor}
973 @c -----------------------------------------------------------------------------
975 @deffn {Function} canten (@var{expr})
976 Simplifies @var{expr} by renaming (see @mref{rename})
977 and permuting dummy indices. @code{rename} is restricted to sums of tensor
978 products in which no derivatives are present. As such it is limited
979 and should only be used if @mref{canform} is not capable of carrying out the
980 required simplification.
982 The @code{canten} function returns a mathematically correct result only
983 if its argument is an expression that is fully symmetric in its indices.
984 For this reason, @code{canten} returns an error if @mref{allsym} is not
988 @category{Package itensor}
992 @c -----------------------------------------------------------------------------
994 @deffn {Function} concan (@var{expr})
995 Similar to @mref{canten} but also performs index contraction.
998 @category{Package itensor}
1002 @c -----------------------------------------------------------------------------
1003 @subsection Tensor symmetries
1004 @c -----------------------------------------------------------------------------
1006 @c -----------------------------------------------------------------------------
1008 @defvr {Option variable} allsym
1009 Default value: @code{false}
1011 If @code{true} then all indexed objects
1012 are assumed symmetric in all of their covariant and contravariant
1013 indices. If @code{false} then no symmetries of any kind are assumed
1014 in these indices. Derivative indices are always taken to be symmetric
1015 unless @code{iframe_flag} is set to @code{true}.
1018 @category{Package itensor}
1022 @c -----------------------------------------------------------------------------
1024 @deffn {Function} decsym (@var{tensor}, @var{m}, @var{n}, [@var{cov_1}, @var{cov_2}, ...], [@var{contr_1}, @var{contr_2}, ...])
1026 Declares symmetry properties for @var{tensor} of @var{m} covariant and
1027 @var{n} contravariant indices. The @var{cov_i} and @var{contr_i} are
1028 pseudofunctions expressing symmetry relations among the covariant and
1029 contravariant indices respectively. These are of the form
1030 @code{symoper(@var{index_1}, @var{index_2},...)} where @code{symoper} is one of
1031 @code{sym}, @code{anti} or @code{cyc} and the @var{index_i} are integers
1032 indicating the position of the index in the @var{tensor}. This will
1033 declare @var{tensor} to be symmetric, antisymmetric or cyclic respectively
1034 in the @var{index_i}. @code{symoper(all)} is also an allowable form which
1035 indicates all indices obey the symmetry condition. For example, given an
1036 object @code{b} with 5 covariant indices,
1037 @code{decsym(b,5,3,[sym(1,2),anti(3,4)],[cyc(all)])} declares @code{b}
1038 symmetric in its first and second and antisymmetric in its third and
1039 fourth covariant indices, and cyclic in all of its contravariant indices.
1040 Either list of symmetry declarations may be null. The function which
1041 performs the simplifications is @code{canform} as the example below
1046 (%i1) load("itensor");
1047 (%o1) /share/tensor/itensor.lisp
1048 (%i2) expr:contract( expand( a([i1, j1, k1], [])
1049 *kdels([i, j, k], [i1, j1, k1])))$
1052 (%t3) a + a + a + a + a + a
1053 k j i k i j j k i j i k i k j i j k
1055 (%i4) decsym(a,3,0,[sym(all)],[]);
1057 (%i5) ishow(canform(expr))$
1060 (%i6) remsym(a,3,0);
1062 (%i7) decsym(a,3,0,[anti(all)],[]);
1064 (%i8) ishow(canform(expr))$
1066 (%i9) remsym(a,3,0);
1068 (%i10) decsym(a,3,0,[cyc(all)],[]);
1070 (%i11) ishow(canform(expr))$
1073 (%i12) dispsym(a,3,0);
1074 (%o12) [[cyc, [[1, 2, 3]], []]]
1079 @category{Package itensor}
1083 @c -----------------------------------------------------------------------------
1085 @deffn {Function} remsym (@var{tensor}, @var{m}, @var{n})
1086 Removes all symmetry properties from @var{tensor} which has @var{m}
1087 covariant indices and @var{n} contravariant indices.
1090 @category{Package itensor}
1094 @c -----------------------------------------------------------------------------
1096 @deffn {Function} canform @
1097 @fname{canform} (@var{expr}) @
1098 @fname{canform} (@var{expr}, @var{rename})
1100 Simplifies @var{expr} by renaming dummy
1101 indices and reordering all indices as dictated by symmetry conditions
1102 imposed on them. If @code{allsym} is @code{true} then all indices are assumed
1103 symmetric, otherwise symmetry information provided by @code{decsym}
1104 declarations will be used. The dummy indices are renamed in the same
1105 manner as in the @mref{rename} function. When @code{canform} is applied to a large
1106 expression the calculation may take a considerable amount of time.
1107 This time can be shortened by calling @code{rename} on the expression first.
1108 Also see the example under @mref{decsym}. Note: @code{canform} may not be able to
1109 reduce an expression completely to its simplest form although it will
1110 always return a mathematically correct result.
1112 The optional second parameter @var{rename}, if set to @code{false}, suppresses renaming.
1115 @category{Package itensor}
1119 @c -----------------------------------------------------------------------------
1120 @subsection Indicial tensor calculus
1121 @c -----------------------------------------------------------------------------
1123 @c -----------------------------------------------------------------------------
1124 @anchor{itensor_diff}
1125 @deffn {Function} diff (@var{expr}, @var{v_1}, [@var{n_1}, [@var{v_2}, @var{n_2}] ...])
1127 is the usual Maxima differentiation function which has been expanded
1128 in its abilities for @code{itensor}. It takes the derivative of @var{expr} with
1129 respect to @var{v_1} @var{n_1} times, with respect to @var{v_2} @var{n_2}
1130 times, etc. For the tensor package, the function has been modified so
1131 that the @var{v_i} may be integers from 1 up to the value of the variable
1132 @code{dim}. This will cause the differentiation to be carried out with
1133 respect to the @var{v_i}th member of the list @code{vect_coords}. If
1134 @code{vect_coords} is bound to an atomic variable, then that variable
1135 subscripted by @var{v_i} will be used for the variable of
1136 differentiation. This permits an array of coordinate names or
1137 subscripted names like @code{x[1]}, @code{x[2]}, ... to be used.
1139 A further extension adds the ability to @code{diff} to compute derivatives
1140 with respect to an indexed variable. In particular, the tensor package knows
1141 how to differentiate expressions containing combinations of the metric tensor
1142 and its derivatives with respect to the metric tensor and its first and
1143 second derivatives. This capability is particularly useful when considering
1144 Lagrangian formulations of a gravitational theory, allowing one to derive
1145 the Einstein tensor and field equations from the action principle.
1148 @category{Package itensor}
1152 @c -----------------------------------------------------------------------------
1154 @deffn {Function} idiff (@var{expr}, @var{v_1}, [@var{n_1}, [@var{v_2}, @var{n_2}] ...])
1155 Indicial differentiation. Unlike @code{diff}, which differentiates
1156 with respect to an independent variable, @code{idiff)} can be used
1157 to differentiate with respect to a coordinate. For an indexed object,
1158 this amounts to appending the @var{v_i} as derivative indices.
1159 Subsequently, derivative indices will be sorted, unless @code{iframe_flag}
1160 is set to @code{true}.
1162 @code{idiff} can also differentiate the determinant of the metric
1163 tensor. Thus, if @code{imetric} has been bound to @code{G} then
1164 @code{idiff(determinant(g),k)} will return
1165 @code{2 * determinant(g) * ichr2([%i,k],[%i])} where the dummy index @code{%i}
1166 is chosen appropriately.
1169 @category{Package itensor}
1173 @c -----------------------------------------------------------------------------
1175 @deffn {Function} liediff (@var{v}, @var{ten})
1177 Computes the Lie-derivative of the tensorial expression @var{ten} with
1178 respect to the vector field @var{v}. @var{ten} should be any indexed
1179 tensor expression; @var{v} should be the name (without indices) of a vector
1184 (%i1) load("itensor");
1185 (%o1) /share/tensor/itensor.lisp
1186 (%i2) ishow(liediff(v,a([i,j],[])*b([],[k],l)))$
1188 (%t2) b (v a + v a + v a )
1189 ,l i j,%2 ,j i %2 ,i %2 j
1192 + (v b - b v + v b ) a
1193 ,%1 l ,l ,%1 ,l ,%1 i j
1198 @category{Package itensor}
1202 @c -----------------------------------------------------------------------------
1204 @deffn {Function} rediff (@var{ten})
1206 Evaluates all occurrences of the @mref{idiff} command in the tensorial
1207 expression @var{ten}.
1210 @category{Package itensor}
1214 @c -----------------------------------------------------------------------------
1216 @deffn {Function} undiff (@var{expr})
1218 Returns an expression equivalent to @var{expr} but with all derivatives
1219 of indexed objects replaced by the noun form of the @mref{idiff} function. Its
1220 arguments would yield that indexed object if the differentiation were
1221 carried out. This is useful when it is desired to replace a
1222 differentiated indexed object with some function definition resulting
1223 in @var{expr} and then carry out the differentiation by saying
1224 @code{ev(@var{expr}, idiff)}.
1227 @category{Package itensor}
1231 @c -----------------------------------------------------------------------------
1233 @deffn {Function} evundiff (@var{expr})
1235 Equivalent to the execution of @mref{undiff}, followed by @mref{ev} and
1238 The point of this operation is to easily evaluate expressions that cannot
1239 be directly evaluated in derivative form. For instance, the following
1243 (%i1) load("itensor");
1244 (%o1) /share/tensor/itensor.lisp
1245 (%i2) icurvature([i,j,k],[l],m);
1246 Maxima encountered a Lisp error:
1248 Error in $ICURVATURE [or a callee]:
1249 $ICURVATURE [or a callee] requires less than three arguments.
1251 Automatically continuing.
1252 To re-enable the Lisp debugger set *debugger-hook* to nil.
1255 However, if @mref{icurvature} is entered in noun form, it can be evaluated
1256 using @code{evundiff}:
1259 (%i3) ishow('icurvature([i,j,k],[l],m))$
1263 (%i4) ishow(evundiff(%))$
1265 (%t4) - ichr2 - ichr2 ichr2 - ichr2 ichr2
1266 i k,j m %1 j i k,m %1 j,m i k
1269 + ichr2 + ichr2 ichr2 + ichr2 ichr2
1270 i j,k m %1 k i j,m %1 k,m i j
1273 Note: In earlier versions of Maxima, derivative forms of the
1274 Christoffel-symbols also could not be evaluated. This has been fixed now,
1275 so @code{evundiff} is no longer necessary for expressions like this:
1280 (%i6) ishow(ichr2([i,j],[k],l))$
1283 j %3,i l i j,%3 l i %3,j l
1284 (%t6) -----------------------------------------
1289 ,l j %3,i i j,%3 i %3,j
1290 + -----------------------------------
1295 @category{Package itensor}
1299 @c -----------------------------------------------------------------------------
1301 @deffn {Function} flush (@var{expr}, @var{tensor_1}, @var{tensor_2}, ...)
1303 @var{expr}, all occurrences of the @var{tensor_i} that have no derivative indices.
1306 @category{Package itensor}
1310 @c -----------------------------------------------------------------------------
1312 @deffn {Function} flushd (@var{expr}, @var{tensor_1}, @var{tensor_2}, ...)
1314 @var{expr}, all occurrences of the @var{tensor_i} that have derivative indices.
1317 @category{Package itensor}
1321 @c -----------------------------------------------------------------------------
1323 @deffn {Function} flushnd (@var{expr}, @var{tensor}, @var{n})
1324 Set to zero, in @var{expr}, all
1325 occurrences of the differentiated object @var{tensor} that have @var{n} or more
1326 derivative indices as the following example demonstrates.
1329 (%i1) load("itensor");
1330 (%o1) /share/tensor/itensor.lisp
1331 (%i2) ishow(a([i],[J,r],k,r)+a([i],[j,r,s],k,r,s))$
1335 (%i3) ishow(flushnd(%,a,3))$
1342 @category{Package itensor}
1346 @c -----------------------------------------------------------------------------
1348 @deffn {Function} coord (@var{tensor_1}, @var{tensor_2}, ...)
1350 Gives @var{tensor_i} the coordinate differentiation property that the
1351 derivative of contravariant vector whose name is one of the
1352 @var{tensor_i} yields a Kronecker delta. For example, if @code{coord(x)} has
1353 been done then @code{idiff(x([],[i]),j)} gives @code{kdelta([i],[j])}.
1354 @code{coord} is a list of all indexed objects having this property.
1357 @category{Package itensor}
1361 @c -----------------------------------------------------------------------------
1363 @deffn {Function} remcoord @
1364 @fname{remcoord} (@var{tensor_1}, @var{tensor_2}, ...) @
1365 @fname{remcoord} (all)
1367 Removes the coordinate differentiation property from the @code{tensor_i}
1368 that was established by the function @code{coord}. @code{remcoord(all)}
1369 removes this property from all indexed objects.
1372 @category{Package itensor}
1376 @c -----------------------------------------------------------------------------
1378 @deffn {Function} makebox (@var{expr},@var{g})
1379 Display @var{expr} using the metric @var{g} such that
1380 any tensor d'Alembertian occurring in @var{expr} will be indicated using the
1381 symbol @code{[]}. For example, @code{[]p([m],[n])} represents
1382 @code{g([],[i,j])*p([m],[n],i,j)}.
1385 @category{Package itensor}
1389 @c -----------------------------------------------------------------------------
1390 @anchor{conmetderiv}
1391 @deffn {Function} conmetderiv (@var{expr}, @var{tensor})
1393 Simplifies expressions containing ordinary derivatives of
1394 both covariant and con@-tra@-va@-ri@-ant forms of the metric tensor (the
1395 current restriction). For example, @code{conmetderiv} can relate the
1396 derivative of the contravariant metric tensor with the Christoffel
1397 symbols as seen from the following:
1401 (%i1) load("itensor");
1402 (%o1) /share/tensor/itensor.lisp
1403 (%i2) ishow(g([],[a,b],c))$
1407 (%i3) ishow(conmetderiv(%,g))$
1409 (%t3) - g ichr2 - g ichr2
1414 @category{Package itensor}
1418 @c -----------------------------------------------------------------------------
1419 @anchor{simpmetderiv}
1420 @deffn {Function} simpmetderiv @
1421 @fname{simpmetderiv} (@var{expr}) @
1422 @fname{simpmetderiv} (@var{expr}[, @var{stop}])
1424 Simplifies expressions containing products of the derivatives of the
1425 metric tensor. Specifically, @code{simpmetderiv} recognizes two identities:
1430 g g + g g = (g g ) = (kdelta ) = 0
1431 ,d bc bc,d bc ,d c ,d
1454 which follows from the symmetries of the Christoffel symbols.
1456 The @code{simpmetderiv} function takes one optional parameter which, when
1457 present, causes the function to stop after the first successful
1458 substitution in a product expression. The @code{simpmetderiv} function
1459 also makes use of the global variable @mref{flipflag} which determines
1460 how to apply a ``canonical'' ordering to the product indices.
1462 Put together, these capabilities can be used to achieve powerful
1463 simplifications that are difficult or impossible to accomplish otherwise.
1464 This is demonstrated through the following example that explicitly uses the
1465 partial simplification features of @code{simpmetderiv} to obtain a
1466 contractible expression:
1470 (%i1) load("itensor");
1471 (%o1) /share/tensor/itensor.lisp
1474 (%i3) ishow(g([],[a,b])*g([],[b,c])*g([a,b],[],d)*g([b,c],[],e))$
1478 (%i4) ishow(canform(%))$
1480 errexp1 has improper indices
1481 -- an error. Quitting. To debug this try debugmode(true);
1482 (%i5) ishow(simpmetderiv(%))$
1486 (%i6) flipflag:not flipflag;
1488 (%i7) ishow(simpmetderiv(%th(2)))$
1492 (%i8) flipflag:not flipflag;
1494 (%i9) ishow(simpmetderiv(%th(2),stop))$
1498 (%i10) ishow(contract(%))$
1505 See also @code{weyl.dem} for an example that uses @mref{simpmetderiv}
1506 and @mref{conmetderiv} together to simplify contractions of the Weyl tensor.
1509 @category{Package itensor}
1513 @c -----------------------------------------------------------------------------}
1514 @anchor{flush1deriv}
1515 @deffn {Function} flush1deriv (@var{expr}, @var{tensor})
1517 Set to zero, in @code{expr}, all occurrences of @code{tensor} that have
1518 exactly one derivative index.
1521 @category{Package itensor}
1525 @c -----------------------------------------------------------------------------
1526 @subsection Tensors in curved spaces
1527 @c -----------------------------------------------------------------------------
1529 @c -----------------------------------------------------------------------------
1531 @deffn {Function} imetric (@var{g})
1532 @deffnx {System variable} imetric
1534 Specifies the metric by assigning the variable @code{imetric:@var{g}} in
1535 addition, the con@-trac@-tion properties of the metric @var{g} are set up by
1536 executing the commands @code{defcon(@var{g}), defcon(@var{g}, @var{g}, kdelta)}.
1537 The variable @code{imetric} (unbound by default), is bound to the metric, assigned by
1538 the @code{imetric(@var{g})} command.
1541 @category{Package itensor}
1545 @c -----------------------------------------------------------------------------
1547 @deffn {Function} idim (@var{n})
1548 Sets the dimensions of the metric. Also initializes the antisymmetry
1549 properties of the Levi-Civita symbols for the given dimension.
1552 @category{Package itensor}
1556 @c -----------------------------------------------------------------------------
1558 @deffn {Function} ichr1 ([@var{i}, @var{j}, @var{k}])
1559 Yields the Christoffel symbol of the first kind via the
1566 To evaluate the Christoffel symbols for a particular metric, the
1567 variable @code{imetric} must be assigned a name as in the example under @code{chr2}.
1570 @category{Package itensor}
1574 @c -----------------------------------------------------------------------------
1576 @deffn {Function} ichr2 ([@var{i}, @var{j}], [@var{k}])
1577 Yields the Christoffel symbol of the second kind
1578 defined by the relation
1581 ichr2([i,j],[k]) = g (g + g - g )/2
1586 @category{Package itensor}
1590 @c -----------------------------------------------------------------------------
1592 @deffn {Function} icurvature ([@var{i}, @var{j}, @var{k}], [@var{h}])
1594 curvature tensor in terms of the Christoffel symbols of the second
1595 kind (@code{ichr2}). The following notation is used:
1598 icurvature = - ichr2 - ichr2 ichr2 + ichr2
1599 i j k i k,j %1 j i k i j,k
1606 @category{Package itensor}
1610 @c -----------------------------------------------------------------------------
1612 @deffn {Function} covdiff (@var{expr}, @var{v_1}, @var{v_2}, ...)
1613 Yields the covariant derivative of @var{expr} with
1614 respect to the variables @var{v_i} in terms of the Christoffel symbols of the
1615 second kind (@code{ichr2}). In order to evaluate these, one should use
1616 @code{ev(@var{expr},ichr2)}.
1620 (%i1) load("itensor");
1621 (%o1) /share/tensor/itensor.lisp
1622 (%i2) entertensor()$
1623 Enter tensor name: a;
1624 Enter a list of the covariant indices: [i,j];
1625 Enter a list of the contravariant indices: [k];
1626 Enter a list of the derivative indices: [];
1630 (%i3) ishow(covdiff(%,s))$
1632 (%t3) - a ichr2 - a ichr2 + a
1633 i %1 j s %1 j i s i j,s
1640 (%i5) ishow(ev(%th(2),ichr2))$
1643 i %1 s %4,j j s,%4 j %4,s
1644 (%t5) - ------------------------------------------
1649 %1 j s %3,i i s,%3 i %3,s
1650 - ------------------------------------------
1654 i j s %2,%1 %1 s,%2 %1 %2,s k
1655 + ------------------------------------------- + a
1662 @category{Package itensor}
1666 @c -----------------------------------------------------------------------------
1668 @deffn {Function} lorentz_gauge (@var{expr})
1669 Imposes the Lorentz condition by substituting 0 for all
1670 indexed objects in @var{expr} that have a derivative index identical to a
1671 contravariant index.
1674 @category{Package itensor}
1678 @c -----------------------------------------------------------------------------
1679 @anchor{igeodesic_coords}
1680 @deffn {Function} igeodesic_coords (@var{expr}, @var{name})
1682 Causes undifferentiated Christoffel symbols and
1683 first derivatives of the metric tensor vanish in @var{expr}. The @var{name}
1684 in the @mref{igeodesic_coords} function refers to the metric @var{name}
1685 (if it appears in @var{expr}) while the connection coefficients must be
1686 called with the names @code{ichr1} and/or @code{ichr2}. The following example
1687 demonstrates the verification of the cyclic identity satisfied by the Riemann
1688 curvature tensor using the @code{igeodesic_coords} function.
1692 (%i1) load("itensor");
1693 (%o1) /share/tensor/itensor.lisp
1694 (%i2) ishow(icurvature([r,s,t],[u]))$
1696 (%t2) - ichr2 - ichr2 ichr2 + ichr2
1697 r t,s %1 s r t r s,t
1702 (%i3) ishow(igeodesic_coords(%,ichr2))$
1706 (%i4) ishow(igeodesic_coords(icurvature([r,s,t],[u]),ichr2)+
1707 igeodesic_coords(icurvature([s,t,r],[u]),ichr2)+
1708 igeodesic_coords(icurvature([t,r,s],[u]),ichr2))$
1710 (%t4) - ichr2 + ichr2 + ichr2 - ichr2
1711 t s,r t r,s s t,r s r,t
1722 @category{Package itensor}
1726 @c -----------------------------------------------------------------------------
1727 @subsection Moving frames
1728 @c -----------------------------------------------------------------------------
1730 Maxima now has the ability to perform calculations using moving frames.
1731 These can be orthonormal frames (tetrads, vielbeins) or an arbitrary frame.
1733 To use frames, you must first set @code{iframe_flag} to @code{true}. This
1734 causes the Christoffel-symbols, @code{ichr1} and @code{ichr2}, to be replaced
1735 by the more general frame connection coefficients @code{icc1} and @code{icc2}
1736 in calculations. Specifically, the behavior of @mref{covdiff} and
1737 @code{icurvature} is changed.
1739 The frame is defined by two tensors: the inverse frame field (@mref{ifri},
1740 the dual basis tetrad),
1741 and the frame metric @mref{ifg}. The frame metric is the identity matrix for
1742 orthonormal frames, or the Lorentz metric for orthonormal frames in Minkowski
1743 spacetime. The inverse frame field defines the frame base (unit vectors).
1744 Contraction properties are defined for the frame field and the frame metric.
1746 When @code{iframe_flag} is true, many @code{itensor} expressions use the frame
1747 metric @code{ifg} instead of the metric defined by @code{imetric} for
1748 raising and lowerind indices.
1750 IMPORTANT: Setting the variable @code{iframe_flag} to @code{true} does NOT
1751 undefine the contraction properties of a metric defined by a call to
1752 @code{defcon} or @code{imetric}. If a frame field is used, it is best to
1753 define the metric by assigning its name to the variable @code{imetric}
1754 and NOT invoke the @code{imetric} function.
1756 Maxima uses these two tensors to define the frame coefficients (@code{ifc1}
1757 and @code{ifc2}) which form part of the connection coefficients (@code{icc1}
1758 and @code{icc2}), as the following example demonstrates:
1762 (%i1) load("itensor");
1763 (%o1) /share/tensor/itensor.lisp
1764 (%i2) iframe_flag:true;
1766 (%i3) ishow(covdiff(v([],[i]),j))$
1770 (%i4) ishow(ev(%,icc2))$
1774 (%i5) ishow(ev(%,ifc2))$
1776 (%t5) v ifg ifc1 + v
1778 (%i6) ishow(ev(%,ifc1))$
1781 v ifg (ifb - ifb + ifb )
1782 j %2 %1 %2 %1 j %1 j %2 i
1783 (%t6) -------------------------------------------------- + v
1786 (%i7) ishow(ifb([a,b,c]))$
1788 (%t7) (ifri - ifri ) ifr ifr
1793 An alternate method is used to compute the frame bracket (@code{ifb}) if
1794 the @code{iframe_bracket_form} flag is set to @code{false}:
1798 (%i8) block([iframe_bracket_form:false],ishow(ifb([a,b,c])))$
1800 (%t8) ifri (ifr ifr - ifr ifr )
1805 @c -----------------------------------------------------------------------------}
1807 @deffn {Function} iframes ()
1809 Since in this version of Maxima, contraction identities for @mref{ifr} and
1810 @mref{ifri} are always defined, as is the frame bracket (@mref{ifb}), this
1811 function does nothing.
1814 @category{Package itensor}
1818 @c -----------------------------------------------------------------------------
1820 @defvr {Variable} ifb
1822 The frame bracket. The contribution of the frame metric to the connection
1823 coefficients is expressed using the frame bracket:
1829 ifc1 = --------------------------------
1834 The frame bracket itself is defined in terms of the frame field and frame
1835 metric. Two alternate methods of computation are used depending on the
1836 value of @code{frame_bracket_form}. If true (the default) or if the
1837 @code{itorsion_flag} is @code{true}:
1842 ifb = ifr ifr (ifri - ifri - ifri itr )
1843 abc b c a d,e a e,d a f d e
1853 ifb = (ifr ifr - ifr ifr ) ifri
1859 @category{Package itensor}
1863 @c -----------------------------------------------------------------------------
1865 @defvr {Variable} icc1
1867 Connection coefficients of the first kind. In @code{itensor}, defined as
1871 icc1 = ichr1 - ikt1 - inmc1
1876 In this expression, if @code{iframe_flag} is true, the Christoffel-symbol
1877 @code{ichr1} is replaced with the frame connection coefficient @code{ifc1}.
1878 If @code{itorsion_flag} is @code{false}, @mref{ikt1}
1879 will be omitted. It is also omitted if a frame base is used, as the
1880 torsion is already calculated as part of the frame bracket.
1881 Lastly, of @code{inonmet_flag} is @code{false},
1882 @mref{inmc1} will not be present.
1885 @category{Package itensor}
1889 @c -----------------------------------------------------------------------------
1891 @defvr {Variable} icc2
1893 Connection coefficients of the second kind. In @code{itensor}, defined as
1898 icc2 = ichr2 - ikt2 - inmc2
1903 In this expression, if @code{iframe_flag} is true, the Christoffel-symbol
1904 @code{ichr2} is replaced with the frame connection coefficient @code{ifc2}.
1905 If @code{itorsion_flag} is @code{false}, @code{ikt2}
1906 will be omitted. It is also omitted if a frame base is used, as the
1907 torsion is already calculated as part of the frame bracket.
1908 Lastly, of @code{inonmet_flag} is @code{false},
1909 @mref{inmc2} will not be present.
1912 @category{Package itensor}
1916 @c -----------------------------------------------------------------------------
1918 @defvr {Variable} ifc1
1920 Frame coefficient of the first kind (also known as Ricci-rotation
1921 coefficients.) This tensor represents the contribution
1922 of the frame metric to the connection coefficient of the first kind. Defined
1929 ifc1 = --------------------------------
1936 @category{Package itensor}
1940 @c -----------------------------------------------------------------------------
1942 @defvr {Variable} ifc2
1944 Frame coefficient of the second kind. This tensor represents the contribution
1945 of the frame metric to the connection coefficient of the second kind. Defined
1946 as a permutation of the frame bracket (@mref{ifb}) with the appropriate
1947 indices raised and lowered as necessary:
1958 @category{Package itensor}
1962 @c -----------------------------------------------------------------------------
1964 @defvr {Variable} ifr
1966 The frame field. Contracts with the inverse frame field (@mref{ifri}) to
1967 form the frame metric (@mref{ifg}).
1970 @category{Package itensor}
1974 @c -----------------------------------------------------------------------------
1976 @defvr {Variable} ifri
1978 The inverse frame field. Specifies the frame base (dual basis vectors). Along
1979 with the frame metric, it forms the basis of all calculations based on
1983 @category{Package itensor}
1987 @c -----------------------------------------------------------------------------
1989 @defvr {Variable} ifg
1991 The frame metric. Defaults to @mref{kdelta}, but can be changed using
1995 @category{Package itensor}
1999 @c -----------------------------------------------------------------------------
2001 @defvr {Variable} ifgi
2003 The inverse frame metric. Contracts with the frame metric (@mref{ifg})
2007 @category{Package itensor}
2011 @c -----------------------------------------------------------------------------
2012 @anchor{iframe_bracket_form}
2013 @defvr {Option variable} iframe_bracket_form
2014 Default value: @code{true}
2016 Specifies how the frame bracket (@mref{ifb}) is computed.
2019 @category{Package itensor}
2023 @c -----------------------------------------------------------------------------
2024 @subsection Torsion and nonmetricity
2025 @c -----------------------------------------------------------------------------
2027 Maxima can now take into account torsion and nonmetricity. When the flag
2028 @code{itorsion_flag} is set to @code{true}, the contribution of torsion
2029 is added to the connection coefficients. Similarly, when the flag
2030 @code{inonmet_flag} is true, nonmetricity components are included.
2032 @c -----------------------------------------------------------------------------
2034 @defvr {Variable} inm
2036 The nonmetricity vector. Conformal nonmetricity is defined through the
2037 covariant derivative of the metric tensor. Normally zero, the metric
2038 tensor's covariant derivative will evaluate to the following when
2039 @code{inonmet_flag} is set to @code{true}:
2049 @category{Package itensor}
2053 @c -----------------------------------------------------------------------------
2055 @defvr {Variable} inmc1
2057 Covariant permutation of the nonmetricity vector components. Defined as
2061 g inm - inm g - g inm
2063 inmc1 = ------------------------------
2068 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2071 @category{Package itensor}
2075 @c -----------------------------------------------------------------------------
2077 @defvr {Variable} inmc2
2079 Contravariant permutation of the nonmetricity vector components. Used
2080 in the connection coefficients if @code{inonmet_flag} is @code{true}. Defined
2086 -inm kdelta - kdelta inm + g inm g
2088 inmc2 = -------------------------------------------
2093 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2096 @category{Package itensor}
2100 @c -----------------------------------------------------------------------------
2102 @defvr {Variable} ikt1
2104 Covariant permutation of the torsion tensor (also known as contorsion).
2110 -g itr - g itr - itr g
2112 ikt1 = ----------------------------------
2117 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2120 @category{Package itensor}
2124 @c -----------------------------------------------------------------------------
2126 @defvr {Variable} ikt2
2128 Contravariant permutation of the torsion tensor (also known as contorsion).
2139 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2142 @category{Package itensor}
2146 @c -----------------------------------------------------------------------------
2148 @defvr {Variable} itr
2150 The torsion tensor. For a metric with torsion, repeated covariant
2151 differentiation on a scalar function will not commute, as demonstrated
2152 by the following example:
2156 (%i1) load("itensor");
2157 (%o1) /share/tensor/itensor.lisp
2160 (%i3) covdiff( covdiff( f( [], []), i), j)
2161 - covdiff( covdiff( f( [], []), j), i)$
2164 (%t4) f ichr2 - f ichr2
2168 (%i6) itorsion_flag:true;
2170 (%i7) covdiff( covdiff( f( [], []), i), j)
2171 - covdiff( covdiff( f( [], []), j), i)$
2174 (%t8) f icc2 - f icc2 - f + f
2175 ,%8 j i ,%6 i j ,j i ,i j
2176 (%i9) ishow(canform(%))$
2178 (%t9) f icc2 - f icc2
2180 (%i10) ishow(canform(ev(%,icc2)))$
2182 (%t10) f ikt2 - f ikt2
2184 (%i11) ishow(canform(ev(%,ikt2)))$
2186 (%t11) f g ikt1 - f g ikt1
2187 ,%2 i j %1 ,%2 j i %1
2188 (%i12) ishow(factor(canform(rename(expand(ev(%,ikt1))))))$
2192 (%t12) ------------------------------------
2194 (%i13) decsym(itr,2,1,[anti(all)],[]);
2196 (%i14) defcon(g,g,kdelta);
2198 (%i15) subst(g,nounify(g),%th(3))$
2199 (%i16) ishow(canform(contract(%)))$
2207 @category{Package itensor}
2211 @c -----------------------------------------------------------------------------
2212 @subsection Exterior algebra
2213 @c -----------------------------------------------------------------------------
2215 The @code{itensor} package can perform operations on totally antisymmetric
2216 covariant tensor fields. A totally antisymmetric tensor field of rank
2217 (0,L) corresponds with a differential L-form. On these objects, a
2218 multiplication operation known as the exterior product, or wedge product,
2221 Unfortunately, not all authors agree on the definition of the wedge
2222 product. Some authors prefer a definition that corresponds with the
2223 notion of antisymmetrization: in these works, the wedge product of
2224 two vector fields, for instance, would be defined as
2229 a /\ a = -----------
2233 More generally, the product of a p-form and a q-form would be defined as
2237 A /\ B = ------ D A B
2238 i1..ip j1..jq (p+q)! i1..ip j1..jq k1..kp l1..lq
2241 where @code{D} stands for the Kronecker-delta.
2243 Other authors, however, prefer a ``geometric'' definition that corresponds
2244 with the notion of the volume element:
2251 and, in the general case
2255 A /\ B = ----- D A B
2256 i1..ip j1..jq p! q! i1..ip j1..jq k1..kp l1..lq
2259 Since @code{itensor} is a tensor algebra package, the first of these two
2260 definitions appears to be the more natural one. Many applications, however,
2261 utilize the second definition. To resolve this dilemma, a flag has been
2262 implemented that controls the behavior of the wedge product: if
2263 @mref{igeowedge_flag} is @code{false} (the default), the first, "tensorial"
2264 definition is used, otherwise the second, "geometric" definition will
2270 @fnindex Wedge product
2273 The wedge product operator is denoted by the tilde @code{~}. This is
2274 a binary operator. Its arguments should be expressions involving scalars,
2275 covariant tensors of rank one, or covariant tensors of rank @code{l} that
2276 have been declared antisymmetric in all covariant indices.
2278 The behavior of the wedge product operator is controlled by the
2279 @mref{igeowedge_flag} flag, as in the following example:
2282 (%i1) load("itensor");
2283 (%o1) /share/tensor/itensor.lisp
2284 (%i2) ishow(a([i])~b([j]))$
2289 (%i3) decsym(a,2,0,[anti(all)],[]);
2291 (%i4) ishow(a([i,j])~b([k]))$
2294 (%t4) ---------------------------
2296 (%i5) igeowedge_flag:true;
2298 (%i6) ishow(a([i])~b([j]))$
2301 (%i7) ishow(a([i,j])~b([k]))$
2302 (%t7) a b + b a - a b
2307 @category{Package itensor}
2308 @category{Operators}
2312 @c -----------------------------------------------------------------------------
2316 @fnindex Contraction with a vector
2319 The vertical bar @code{|} denotes the "contraction with a vector" binary
2320 operation. When a totally antisymmetric covariant tensor is contracted
2321 with a contravariant vector, the result is the same regardless which index
2322 was used for the contraction. Thus, it is possible to define the
2323 contraction operation in an index-free manner.
2325 In the @code{itensor} package, contraction with a vector is always carried out
2326 with respect to the first index in the literal sorting order. This ensures
2327 better simplification of expressions involving the @code{|} operator. For instance:
2330 (%i1) load("itensor");
2331 (%o1) /share/tensor/itensor.lisp
2332 (%i2) decsym(a,2,0,[anti(all)],[]);
2334 (%i3) ishow(a([i,j],[])|v)$
2338 (%i4) ishow(a([j,i],[])|v)$
2344 Note that it is essential that the tensors used with the @code{|} operator be
2345 declared totally antisymmetric in their covariant indices. Otherwise,
2346 the results will be incorrect.
2349 @category{Package itensor}
2350 @category{Operators}
2354 @c -----------------------------------------------------------------------------
2356 @deffn {Function} extdiff (@var{expr}, @var{i})
2358 Computes the exterior derivative of @var{expr} with respect to the index
2359 @var{i}. The exterior derivative is formally defined as the wedge
2360 product of the partial derivative operator and a differential form. As
2361 such, this operation is also controlled by the setting of @mref{igeowedge_flag}.
2365 (%i1) load("itensor");
2366 (%o1) /share/tensor/itensor.lisp
2367 (%i2) ishow(extdiff(v([i]),j))$
2372 (%i3) decsym(a,2,0,[anti(all)],[]);
2374 (%i4) ishow(extdiff(a([i,j]),k))$
2377 (%t4) ------------------------
2379 (%i5) igeowedge_flag:true;
2381 (%i6) ishow(extdiff(v([i]),j))$
2384 (%i7) ishow(extdiff(a([i,j]),k))$
2385 (%t7) - (a - a + a )
2391 @category{Package itensor}
2395 @c -----------------------------------------------------------------------------
2397 @deffn {Function} hodge (@var{expr})
2399 Compute the Hodge-dual of @var{expr}. For instance:
2406 @c decsym(A,3,0,[anti(all)],[])$
2407 @c ishow(A([i,j,k],[]))$
2408 @c ishow(canform(hodge(%)))$
2409 @c ishow(canform(hodge(%)))$
2412 @c ishow(canform(contract(expand(%))))$
2416 (%i1) load("itensor");
2417 (%o1) /share/tensor/itensor.lisp
2424 (%i5) decsym(A,3,0,[anti(all)],[])$
2426 (%i6) ishow(A([i,j,k],[]))$
2429 (%i7) ishow(canform(hodge(%)))$
2433 (%t7) -----------------------------------------
2435 (%i8) ishow(canform(hodge(%)))$
2436 %1 %2 %3 %8 %4 %5 %6 %7
2437 (%t8) levi_civita levi_civita g
2440 %2 %107 %3 %108 %4 %8 %5 %6 %7
2445 (%i11) ishow(canform(contract(expand(%))))$
2452 @category{Package itensor}
2456 @c -----------------------------------------------------------------------------
2457 @anchor{igeowedge_flag}
2458 @defvr {Option variable} igeowedge_flag
2459 Default value: @code{false}
2461 Controls the behavior of the wedge product and exterior derivative. When
2462 set to @code{false} (the default), the notion of differential forms will
2463 correspond with that of a totally antisymmetric covariant tensor field.
2464 When set to @code{true}, differential forms will agree with the notion
2465 of the volume element.
2468 @category{Package itensor}
2472 @c -----------------------------------------------------------------------------
2473 @subsection Exporting TeX expressions
2474 @c -----------------------------------------------------------------------------
2476 The @code{itensor} package provides limited support for exporting tensor
2477 expressions to TeX. Since @code{itensor} expressions appear as function calls,
2478 the regular Maxima @mref{tex} command will not produce the expected
2479 output. You can try instead the @mref{tentex} command, which attempts
2480 to translate tensor expressions into appropriately indexed TeX objects.
2482 @c -----------------------------------------------------------------------------
2484 @deffn {Function} tentex (@var{expr})
2486 To use the @code{tentex} function, you must first load @code{tentex},
2487 as in the following example:
2493 @c ishow(icurvature([j,k,l],[i]))$
2497 (%i1) load("itensor");
2498 (%o1) /share/tensor/itensor.lisp
2500 (%o2) /share/tensor/tentex.lisp
2503 (%i4) ishow(icurvature([j,k,l],[i]))$
2505 (%t4) ichr2 ichr2 - ichr2 ichr2 - ichr2
2506 j k m1 l j l m1 k j l,k
2512 $$\Gamma_@{j\,k@}^@{m_1@}\,\Gamma_@{l\,m_1@}^@{i@}-\Gamma_@{j\,l@}^@{m_1@}\,
2513 \Gamma_@{k\,m_1@}^@{i@}-\Gamma_@{j\,l,k@}^@{i@}+\Gamma_@{j\,k,l@}^@{i@}$$
2516 Note the use of the @code{idummyx} assignment, to avoid the appearance
2517 of the percent sign in the TeX expression, which may lead to compile errors.
2519 NB: This version of the @code{tentex} function is somewhat experimental.
2522 @category{Package itensor}
2523 @category{TeX output}
2527 @c -----------------------------------------------------------------------------
2528 @subsection Interfacing with ctensor
2529 @c -----------------------------------------------------------------------------
2531 The @code{itensor} package has the ability to generate Maxima code that can
2532 then be executed in the context of the @code{ctensor} package. The function that performs
2533 this task is @mref{ic_convert}.
2535 @c -----------------------------------------------------------------------------
2537 @deffn {Function} ic_convert (@var{eqn})
2539 Converts the @code{itensor} equation @var{eqn} to a @code{ctensor} assignment statement.
2540 Implied sums over dummy indices are made explicit while indexed
2541 objects are transformed into arrays (the array subscripts are in the
2542 order of covariant followed by contravariant indices of the indexed
2543 objects). The derivative of an indexed object will be replaced by the
2544 noun form of @mref{diff} taken with respect to @mref{ct_coords} subscripted
2545 by the derivative index. The Christoffel symbols @mref{ichr1} and @mref{ichr2}
2546 will be translated to @code{lcs} and @code{mcs}, respectively and if
2547 @code{metricconvert} is @code{true} then all occurrences of the metric
2548 with two covariant (contravariant) indices will be renamed to @code{lg}
2549 (@code{ug}). In addition, @mref{do} loops will be introduced summing over
2550 all free indices so that the
2551 transformed assignment statement can be evaluated by just doing
2552 @mref{ev}. The following examples demonstrate the features of this
2555 @c Added some ===beg=== and ==end== pairs around some source code
2557 @c The tags used here are different. This prevents the Perl parser from
2558 @c interpreting this section, since the text-based rendering of the output
2559 @c is pretty much unreadable. The origin example is likely been hand-edited
2563 @c eqn:ishow(t([i,j],[k])=f([],[])*g([l,m],[])*a([],[m],j)
2567 @c metricconvert:true;
2571 (%i1) load("itensor");
2572 (%o1) /share/tensor/itensor.lisp
2573 (%i2) eqn:ishow(t([i,j],[k])=f([],[])*g([l,m],[])*a([],[m],j)
2578 (%i3) ic_convert(eqn);
2579 (%o3) for i thru dim do (for j thru dim do (
2581 t : f sum(sum(diff(a , ct_coords ) b
2584 g , l, 1, dim), m, 1, dim)))
2588 (%i5) metricconvert:true;
2590 (%i6) ic_convert(eqn);
2591 (%o6) for i thru dim do (for j thru dim do (
2593 t : f sum(sum(diff(a , ct_coords ) b
2596 lg , l, 1, dim), m, 1, dim)))
2601 @category{Package itensor}
2602 @category{Package ctensor}
2606 @c -----------------------------------------------------------------------------
2607 @subsection Reserved words
2608 @c -----------------------------------------------------------------------------
2610 The following Maxima words are used by the @code{itensor} package internally and
2611 should not be redefined:
2613 @c REFORMAT THIS TABLE USING TEXINFO MARKUP
2616 ------------------------------------------
2617 indices2() Internal version of indices()
2618 conti Lists contravariant indices
2619 covi Lists covariant indices of an indexed object
2620 deri Lists derivative indices of an indexed object
2621 name Returns the name of an indexed object