Removed show, updated makebox in Itensor docs. Fixes #3890.
[maxima.git] / doc / info / Itensor.texi
blobb924f1a8bcc6bf64d01addee4b32ed0dc046181a
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
6 @menu
7 * Introduction to itensor::
8 * Functions and Variables for itensor::
9 @end menu
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
40 implementations:
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.
79 @opencatbox
80 @category{Tensors}
81 @category{Share packages}
82 @category{Package itensor}
83 @closecatbox
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:
92 @example
93 (%i2) imetric(g);
94 (%o2)                                done
95 (%i3) ishow(g([],[j,k])*g([],[i,l])*a([i,j],[]))$
96                                  i l  j k
97 (%t3)                           g    g    a
98                                            i j
99 (%i4) ishow(contract(%))$
100                                       k l
101 (%t4)                                a
102 @end example
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
108 indices is lost.
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:
119 @example
120 (%i5) ishow(g([-j,-k],[])*g([-i,-l],[])*a([i,j],[]))$
121                                  i l       j k
122 (%t5)                           g    a    g
123                                       i j
124 (%i6) ishow(contract(%))$
125                                       l k
126 (%t6)                                a
127 @end example
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
132 to numeric indices.
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
176 covariant.
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.
197 @example
198 (%i1) load("itensor");
199 (%o1)      /share/tensor/itensor.lisp
200 (%i2) imetric(g);
201 (%o2)                                done
202 (%i3) components(g([i,j],[]),p([i,j],[])*e([],[]))$
203 (%i4) ishow(g([k,l],[]))$
204 (%t4)                               e p
205                                        k l
206 (%i5) ishow(diff(v([i],[]),t))$
207 (%t5)                                  0
208 (%i6) depends(v,t);
209 (%o6)                               [v(t)]
210 (%i7) ishow(diff(v([i],[]),t))$
211                                     d
212 (%t7)                               -- (v )
213                                     dt   i
214 (%i8) ishow(idiff(v([i],[]),j))$
215 (%t8)                                v
216                                       i,j
217 (%i9) ishow(extdiff(v([i],[]),j))$
218 (%t9)                             v    - v
219                                    j,i    i,j
220                                   -----------
221                                        2
222 (%i10) ishow(liediff(v,w([i],[])))$
223                                %3          %3
224 (%t10)                        v   w     + v   w
225                                    i,%3    ,i  %3
226 (%i11) ishow(covdiff(v([i],[]),j))$
227                                               %4
228 (%t11)                        v    - v   ichr2
229                                i,j    %4      i j
230 (%i12) ishow(ev(%,ichr2))$
231                 %4 %5
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
235                                          + e p       + e   p    ))/2
236                                               i %5,j    ,j  i %5
237 (%i13) iframe_flag:true;
238 (%o13)                               true
239 (%i14) ishow(covdiff(v([i],[]),j))$
240                                              %6
241 (%t14)                        v    - v   icc2
242                                i,j    %6     i j
243 (%i15) ishow(ev(%,icc2))$
244                                              %6
245 (%t15)                        v    - v   ifc2
246                                i,j    %6     i j
247 (%i16) ishow(radcan(ev(%,ifc2,ifc1)))$
248              %6 %7                    %6 %7
249 (%t16) - (ifg      v   ifb       + ifg      v   ifb       - 2 v
250                     %6    j %7 i             %6    i j %7      i,j
252                                              %6 %7
253                                         - ifg      v   ifb      )/2
254                                                     %6    %7 i j
255 (%i17) ishow(canform(s([i,j],[])-s([j,i])))$
256 (%t17)                            s    - s
257                                    i j    j i
258 (%i18) decsym(s,2,0,[sym(all)],[]);
259 (%o18)                               done
260 (%i19) ishow(canform(s([i,j],[])-s([j,i])))$
261 (%t19)                                 0
262 (%i20) ishow(canform(a([i,j],[])+a([j,i])))$
263 (%t20)                            a    + a
264                                    j i    i j
265 (%i21) decsym(a,2,0,[anti(all)],[]);
266 (%o21)                               done
267 (%i22) ishow(canform(a([i,j],[])+a([j,i])))$
268 (%t22)                                 0
269 @end example
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 -----------------------------------------------------------------------------
280 @anchor{dispcon}
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
287 which were defined.
289 @opencatbox
290 @category{Display functions}
291 @closecatbox
292 @end deffn
294 @c -----------------------------------------------------------------------------
295 @anchor{entertensor}
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}).
303 @opencatbox
304 @category{Package itensor}
305 @closecatbox
306 @end deffn
308 @c -----------------------------------------------------------------------------
309 @anchor{changename}
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}.
318 @opencatbox
319 @category{Package itensor}
320 @closecatbox
321 @end deffn
323 @c -----------------------------------------------------------------------------
324 @deffn {Function} listoftens
326 @anchor{listoftens}
328 Lists all tensors in a tensorial expression, complete with their indices. E.g.,
330 @example
332 (%i6) ishow(a([i,j],[k])*b([u],[],v)+c([x,y],[])*d([],[])*e)$
333                                          k
334 (%t6)                        d e c    + a    b
335                                   x y    i j  u,v
336 (%i7) ishow(listoftens(%))$
337                                k
338 (%t7)                        [a   , b   , c   , d]
339                                i j   u,v   x y
341 @end example
343 @opencatbox
344 @category{Package itensor}
345 @closecatbox
346 @end deffn
348 @c -----------------------------------------------------------------------------
349 @anchor{ishow}
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).
358 @opencatbox
359 @category{Package itensor}
360 @closecatbox
361 @end deffn
363 @c -----------------------------------------------------------------------------
364 @anchor{indices}
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.
372 @example
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))$
377                                 k l      j m p
378 (%t2)                          a        b
379                                 i j,m n  k o,q r
380 (%i3) indices(%);
381 (%o3)                 [[l, p, i, n, o, q, r], [k, j, m]]
383 @end example
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.
390 @opencatbox
391 @category{Package itensor}
392 @closecatbox
393 @end deffn
395 @c -----------------------------------------------------------------------------
396 @anchor{rename}
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.
416 @example
418 (%i1) load("itensor");
419 (%o1)      /share/tensor/itensor.lisp
420 (%i2) allsym:true;
421 (%o2)                                true
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$
426 (%i4) expr:ishow(%)$
427 @group
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
435 @end group
436 (%i5) flipflag:true;
437 (%o5)                                true
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;
447 (%o7)                                false
448 (%i8) rename(%th(2));
449 (%o8)                                  0
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
458 @end example
460 @opencatbox
461 @category{Package itensor}
462 @closecatbox
463 @end deffn
465 @c -----------------------------------------------------------------------------
466 @anchor{flipflag}
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}).
481 @opencatbox
482 @category{Package itensor}
483 @closecatbox
484 @end defvr
486 @c -----------------------------------------------------------------------------
487 @anchor{defcon}
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
501 tensor.
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
504 used.
505 @code{contractions} is a list of those indexed objects which have been given
506 contraction properties with @code{defcon}.
508 @opencatbox
509 @category{Package itensor}
510 @closecatbox
511 @end deffn
513 @c -----------------------------------------------------------------------------
514 @anchor{remcon}
515 @deffn {Function} remcon @
516 @fname{remcon} (@var{tensor_1}, ..., @var{tensor_n}) @
517 @fname{remcon} (all)
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.
523 @opencatbox
524 @category{Package itensor}
525 @closecatbox
526 @end deffn
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.
540 @opencatbox
541 @category{Package itensor}
542 @closecatbox
543 @end deffn
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}.
553 @opencatbox
554 @category{Package itensor}
555 @closecatbox
556 @end deffn
558 @c -----------------------------------------------------------------------------
559 @anchor{components}
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:
584 @example
585 (%i2) components(g([],[i,j]),e([],[i])*p([],[j]))$
586 (%i3) ishow(g([],[i,j]))$
587                                       i  j
588 (%t3)                                e  p
590 @end example
592 2) As a matrix:
594 @example
596 (%i5) lg:-ident(4)$lg[1,1]:1$lg;
597 @group
598                             [ 1   0    0    0  ]
599                             [                  ]
600                             [ 0  - 1   0    0  ]
601 (%o5)                       [                  ]
602                             [ 0   0   - 1   0  ]
603                             [                  ]
604                             [ 0   0    0   - 1 ]
605 @end group
606 (%i6) components(g([i,j],[]),lg);
607 (%o6)                                done
608 (%i7) ishow(g([i,j],[]))$
609 (%t7)                                g
610                                       i j
611 (%i8) g([1,1],[]);
612 (%o8)                                  1
613 (%i9) g([4,4],[]);
614 (%o9)                                 - 1
615 @end example
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
621 @code{g} otherwise:
623 @example
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]))$
628                                           j
629 (%t5)                               kdelta
630                                           i
631 (%i6) ishow(h([i,j],[k],l))$
632                                      k
633 (%t6)                               g
634                                      i j,l
635 @end example
637 4) Using Maxima's pattern matching capabilities, specifically the
638 @mref{defrule} and @mref{applyb1} commands:
640 @example
642 (%i1) load("itensor");
643 (%o1)      /share/tensor/itensor.lisp
644 (%i2) matchdeclare(l1,listp);
645 (%o2)                                done
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]))$
653 @group
654                                     i m
655 (%t5)                              m    m
656                                          i n
657 @end group
658 (%i6) ishow(rename(applyb1(%,r1,r2)))$
659                            %1  %2  %3 m
660 (%t6)                     e   q   w     q   e   g
661                                          %1  %2  %3 n
662 @end example
664 @opencatbox
665 @category{Package itensor}
666 @closecatbox
667 @end deffn
669 @anchor{remcomps}
670 @deffn {Function} remcomps (@var{tensor})
672 Unbinds all values from @var{tensor} which were assigned with the
673 @mref{components} function.
675 @opencatbox
676 @category{Package itensor}
677 @closecatbox
678 @end deffn
680 @c NEED LIST OF ARGUMENTS HERE
682 @c -----------------------------------------------------------------------------
683 @anchor{showcomps}
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
689 following example:
691 @example
693 (%i1) load(ctensor);
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)]);
699         [         r                                     ]
700         [ sqrt(-------)  0       0              0       ]
701         [      r - 2 m                                  ]
702         [                                               ]
703         [       0        r       0              0       ]
704 (%o3)   [                                               ]
705         [       0        0  r sin(theta)        0       ]
706         [                                               ]
707         [                                      r - 2 m  ]
708         [       0        0       0        sqrt(-------) ]
709         [                                         r     ]
710 (%i4) components(g([i,j],[]),lg);
711 (%o4)                                done
712 (%i5) showcomps(g([i,j],[]));
713              [         r                                     ]
714              [ sqrt(-------)  0       0              0       ]
715              [      r - 2 m                                  ]
716              [                                               ]
717              [       0        r       0              0       ]
718 (%t5) g    = [                                               ]
719        i j   [       0        0  r sin(theta)        0       ]
720              [                                               ]
721              [                                      r - 2 m  ]
722              [       0        0       0        sqrt(-------) ]
723              [                                         r     ]
724 (%o5)                                false
726 @end example
728 The @code{showcomps} command can also display components of a tensor of
729 rank higher than 2.
731 @opencatbox
732 @category{Package itensor}
733 @closecatbox
734 @end deffn
736 @c -----------------------------------------------------------------------------
737 @anchor{idummy}
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}).
745 @opencatbox
746 @category{Package itensor}
747 @closecatbox
748 @end deffn
750 @anchor{idummyx}
751 @defvr {Option variable} idummyx
752 Default value: @code{%}
754 Is the prefix for dummy indices (see the example under @mref{indices}).
756 @opencatbox
757 @category{Package itensor}
758 @closecatbox
759 @end defvr
761 @c -----------------------------------------------------------------------------
762 @anchor{icounter}
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{%}).
770 @opencatbox
771 @category{Package itensor}
772 @closecatbox
773 @end defvr
775 @c -----------------------------------------------------------------------------
776 @anchor{kdelta}
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
783 manifold.
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.
791 @opencatbox
792 @category{Package itensor}
793 @closecatbox
794 @end deffn
796 @c -----------------------------------------------------------------------------
797 @anchor{kdels}
798 @deffn {Function} kdels (@var{L1}, @var{L2})
800 Symmetrized Kronecker delta, used in some calculations. For instance:
802 @example
804 (%i1) load("itensor");
805 (%o1)      /share/tensor/itensor.lisp
806 (%i2) kdelta([1,2],[2,1]);
807 (%o2)                                 - 1
808 (%i3) kdels([1,2],[2,1]);
809 (%o3)                                  1
810 (%i4) ishow(kdelta([a,b],[c,d]))$
811                              c       d         d       c
812 (%t4)                  kdelta  kdelta  - kdelta  kdelta
813                              a       b         a       b
814 (%i4) ishow(kdels([a,b],[c,d]))$
815                              c       d         d       c
816 (%t4)                  kdelta  kdelta  + kdelta  kdelta
817                              a       b         a       b
819 @end example
821 @opencatbox
822 @category{Package itensor}
823 @closecatbox
824 @end deffn
826 @c -----------------------------------------------------------------------------
827 @anchor{levi_civita}
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
832 repeated.
834 @opencatbox
835 @category{Package itensor}
836 @closecatbox
837 @end deffn
839 @c -----------------------------------------------------------------------------
840 @anchor{lc2kdt}
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}.
850 @example
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]))$
856                                   i j  k
857 (%t2)                  levi_civita    a  levi_civita
858                                        j            k l
859 (%i3) ishow(ev(expr,levi_civita))$
860                                   i j  k       1 2
861 (%t3)                       kdelta    a  kdelta
862                                   1 2  j       k l
863 (%i4) ishow(ev(%,kdelta))$
864              i       j         j       i   k
865 (%t4) (kdelta  kdelta  - kdelta  kdelta ) a
866              1       2         1       2   j
868                                1       2         2       1
869                         (kdelta  kdelta  - kdelta  kdelta )
870                                k       l         k       l
871 (%i5) ishow(lc2kdt(expr))$
872                      k       i       j    k       j       i
873 (%t5)               a  kdelta  kdelta  - a  kdelta  kdelta
874                      j       k       l    j       k       l
875 (%i6) ishow(contract(expand(%)))$
876                                  i           i
877 (%t6)                           a  - a kdelta
878                                  l           l
879 @end example
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.
885 @example
887 (%i7) expr:ishow('levi_civita([],[i,j])
888                  *'levi_civita([],[k,l])*a([j,k],[]))$
889 @group
890                                  i j            k l
891 (%t7)                 levi_civita    levi_civita    a
892                                                      j k
893 @end group
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.
902 (%i9) imetric(g);
903 (%o9)                                done
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    
907                     %3             %4               %3
908               k
909         kdelta  ) a
910               %4   j k
911 (%i11) ishow(contract(expand(%)))$
912                                   l i    l i  j
913 (%t11)                           a    - g    a
914                                               j
915 @end example
918 @opencatbox
919 @category{Package itensor}
920 @closecatbox
921 @end deffn
923 @c HMM, WHICH CATEGORY DOES THIS FALL INTO -- FUNCTION, VARIABLE, OTHER ??
925 @c -----------------------------------------------------------------------------
926 @anchor{lc_l}
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}.
931 For example:
933 @example
935 (%i1) load("itensor");
936 (%o1)      /share/tensor/itensor.lisp
937 (%i2) el1:ishow('levi_civita([i,j,k],[])*a([],[i])*a([],[j]))$
938                              i  j
939 (%t2)                       a  a  levi_civita
940                                              i j k
941 (%i3) el2:ishow('levi_civita([],[i,j,k])*a([i])*a([j]))$
942                                        i j k
943 (%t3)                       levi_civita      a  a
944                                               i  j
945 (%i4) canform(contract(expand(applyb1(el1,lc_l,lc_u))));
946 (%t4)                                  0
947 (%i5) canform(contract(expand(applyb1(el2,lc_l,lc_u))));
948 (%t5)                                  0
950 @end example
952 @opencatbox
953 @category{Package itensor}
954 @closecatbox
955 @end deffn
957 @c HMM, WHICH CATEGORY DOES THIS FALL INTO -- FUNCTION, VARIABLE, OTHER ??
959 @c -----------------------------------------------------------------------------
960 @anchor{lc_u}
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}.
968 @opencatbox
969 @category{Package itensor}
970 @closecatbox
971 @end deffn
973 @c -----------------------------------------------------------------------------
974 @anchor{canten}
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
985 set to @code{true}.
987 @opencatbox
988 @category{Package itensor}
989 @closecatbox
990 @end deffn
992 @c -----------------------------------------------------------------------------
993 @anchor{concan}
994 @deffn {Function} concan (@var{expr})
995 Similar to @mref{canten} but also performs index contraction.
997 @opencatbox
998 @category{Package itensor}
999 @closecatbox
1000 @end deffn
1002 @c -----------------------------------------------------------------------------
1003 @subsection Tensor symmetries
1004 @c -----------------------------------------------------------------------------
1006 @c -----------------------------------------------------------------------------
1007 @anchor{allsym}
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}.
1017 @opencatbox
1018 @category{Package itensor}
1019 @closecatbox
1020 @end defvr
1022 @c -----------------------------------------------------------------------------
1023 @anchor{decsym}
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
1042 illustrates.
1044 @example
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])))$
1050 (%i3) ishow(expr)$
1051 @group
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
1054 @end group
1055 (%i4) decsym(a,3,0,[sym(all)],[]);
1056 (%o4)                                done
1057 (%i5) ishow(canform(expr))$
1058 (%t5)                              6 a
1059                                       i j k
1060 (%i6) remsym(a,3,0);
1061 (%o6)                                done
1062 (%i7) decsym(a,3,0,[anti(all)],[]);
1063 (%o7)                                done
1064 (%i8) ishow(canform(expr))$
1065 (%t8)                                  0
1066 (%i9) remsym(a,3,0);
1067 (%o9)                                done
1068 (%i10) decsym(a,3,0,[cyc(all)],[]);
1069 (%o10)                               done
1070 (%i11) ishow(canform(expr))$
1071 (%t11)                        3 a      + 3 a
1072                                  i k j      i j k
1073 (%i12) dispsym(a,3,0);
1074 (%o12)                     [[cyc, [[1, 2, 3]], []]]
1076 @end example
1078 @opencatbox
1079 @category{Package itensor}
1080 @closecatbox
1081 @end deffn
1083 @c -----------------------------------------------------------------------------
1084 @anchor{remsym}
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.
1089 @opencatbox
1090 @category{Package itensor}
1091 @closecatbox
1092 @end deffn
1094 @c -----------------------------------------------------------------------------
1095 @anchor{canform}
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.
1114 @opencatbox
1115 @category{Package itensor}
1116 @closecatbox
1117 @end deffn
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.
1147 @opencatbox
1148 @category{Package itensor}
1149 @closecatbox
1150 @end deffn
1152 @c -----------------------------------------------------------------------------
1153 @anchor{idiff}
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.
1168 @opencatbox
1169 @category{Package itensor}
1170 @closecatbox
1171 @end deffn
1173 @c -----------------------------------------------------------------------------
1174 @anchor{liediff}
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
1180 field. For example:
1182 @example
1184 (%i1) load("itensor");
1185 (%o1)      /share/tensor/itensor.lisp
1186 (%i2) ishow(liediff(v,a([i,j],[])*b([],[k],l)))$
1187        k    %2            %2          %2
1188 (%t2) b   (v   a       + v   a     + v   a    )
1189        ,l       i j,%2    ,j  i %2    ,i  %2 j
1191                           %1  k        %1  k      %1  k
1192                       + (v   b      - b   v    + v   b   ) a
1193                               ,%1 l    ,l  ,%1    ,l  ,%1   i j
1195 @end example
1197 @opencatbox
1198 @category{Package itensor}
1199 @closecatbox
1200 @end deffn
1202 @c -----------------------------------------------------------------------------
1203 @anchor{rediff}
1204 @deffn {Function} rediff (@var{ten})
1206 Evaluates all occurrences of the @mref{idiff} command in the tensorial
1207 expression @var{ten}.
1209 @opencatbox
1210 @category{Package itensor}
1211 @closecatbox
1212 @end deffn
1214 @c -----------------------------------------------------------------------------
1215 @anchor{undiff}
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)}.
1226 @opencatbox
1227 @category{Package itensor}
1228 @closecatbox
1229 @end deffn
1231 @c -----------------------------------------------------------------------------
1232 @anchor{evundiff}
1233 @deffn {Function} evundiff (@var{expr})
1235 Equivalent to the execution of @mref{undiff}, followed by @mref{ev} and
1236 @mref{rediff}.
1238 The point of this operation is to easily evaluate expressions that cannot
1239 be directly evaluated in derivative form. For instance, the following
1240 causes an error:
1242 @example
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.
1253 @end example
1255 However, if @mref{icurvature} is entered in noun form, it can be evaluated
1256 using @code{evundiff}:
1258 @example
1259 (%i3) ishow('icurvature([i,j,k],[l],m))$
1260                                          l
1261 (%t3)                          icurvature
1262                                          i j k,m
1263 (%i4) ishow(evundiff(%))$
1264              l              l         %1           l           %1
1265 (%t4) - ichr2        - ichr2     ichr2      - ichr2       ichr2
1266              i k,j m        %1 j      i k,m        %1 j,m      i k
1268              l              l         %1           l           %1
1269       + ichr2        + ichr2     ichr2      + ichr2       ichr2
1270              i j,k m        %1 k      i j,m        %1 k,m      i j
1271 @end example
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:
1277 @example
1278 (%i5) imetric(g);
1279 (%o5)                                done
1280 (%i6) ishow(ichr2([i,j],[k],l))$
1281        k %3
1282       g     (g         - g         + g        )
1283               j %3,i l    i j,%3 l    i %3,j l
1284 (%t6) -----------------------------------------
1285                           2
1287                          k %3
1288                         g     (g       - g       + g      )
1289                          ,l     j %3,i    i j,%3    i %3,j
1290                       + -----------------------------------
1291                                          2
1292 @end example
1294 @opencatbox
1295 @category{Package itensor}
1296 @closecatbox
1297 @end deffn
1299 @c -----------------------------------------------------------------------------
1300 @anchor{flush}
1301 @deffn {Function} flush (@var{expr}, @var{tensor_1}, @var{tensor_2}, ...)
1302 Set to zero, in
1303 @var{expr}, all occurrences of the @var{tensor_i} that have no derivative indices.
1305 @opencatbox
1306 @category{Package itensor}
1307 @closecatbox
1308 @end deffn
1310 @c -----------------------------------------------------------------------------
1311 @anchor{flushd}
1312 @deffn {Function} flushd (@var{expr}, @var{tensor_1}, @var{tensor_2}, ...)
1313 Set to zero, in
1314 @var{expr}, all occurrences of the @var{tensor_i} that have derivative indices.
1316 @opencatbox
1317 @category{Package itensor}
1318 @closecatbox
1319 @end deffn
1321 @c -----------------------------------------------------------------------------
1322 @anchor{flushnd}
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.
1327 @example
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))$
1332                                 J r      j r s
1333 (%t2)                          a      + a
1334                                 i,k r    i,k r s
1335 (%i3) ishow(flushnd(%,a,3))$
1336                                      J r
1337 (%t3)                               a
1338                                      i,k r
1339 @end example
1341 @opencatbox
1342 @category{Package itensor}
1343 @closecatbox
1344 @end deffn
1346 @c -----------------------------------------------------------------------------
1347 @anchor{coord}
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.
1356 @opencatbox
1357 @category{Package itensor}
1358 @closecatbox
1359 @end deffn
1361 @c -----------------------------------------------------------------------------
1362 @anchor{remcoord}
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.
1371 @opencatbox
1372 @category{Package itensor}
1373 @closecatbox
1374 @end deffn
1376 @c -----------------------------------------------------------------------------
1377 @anchor{makebox}
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)}.
1384 @opencatbox
1385 @category{Package itensor}
1386 @closecatbox
1387 @end deffn
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:
1399 @example
1401 (%i1) load("itensor");
1402 (%o1)      /share/tensor/itensor.lisp
1403 (%i2) ishow(g([],[a,b],c))$
1404                                       a b
1405 (%t2)                                g
1406                                       ,c
1407 (%i3) ishow(conmetderiv(%,g))$
1408                          %1 b      a       %1 a      b
1409 (%t3)                 - g     ichr2     - g     ichr2
1410                                    %1 c              %1 c
1411 @end example
1413 @opencatbox
1414 @category{Package itensor}
1415 @closecatbox
1416 @end deffn
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:
1427 @example
1429    ab        ab           ab                 a
1430   g   g   + g   g     = (g   g  )   = (kdelta )   = 0
1431    ,d  bc        bc,d         bc ,d          c ,d
1433 @end example
1435 hence
1437 @example
1439    ab          ab
1440   g   g   = - g   g
1441    ,d  bc          bc,d
1442 @end example
1446 @example
1448   ab          ab
1449  g   g     = g   g
1450   ,j  ab,i    ,i  ab,j
1452 @end example
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:
1468 @example
1470 (%i1) load("itensor");
1471 (%o1)      /share/tensor/itensor.lisp
1472 (%i2) imetric(g);
1473 (%o2)                                done
1474 (%i3) ishow(g([],[a,b])*g([],[b,c])*g([a,b],[],d)*g([b,c],[],e))$
1475                              a b  b c
1476 (%t3)                       g    g    g      g
1477                                        a b,d  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(%))$
1483                              a b  b c
1484 (%t5)                       g    g    g      g
1485                                        a b,d  b c,e
1486 (%i6) flipflag:not flipflag;
1487 (%o6)                                true
1488 (%i7) ishow(simpmetderiv(%th(2)))$
1489                                a b  b c
1490 (%t7)                         g    g    g    g
1491                                ,d   ,e   a b  b c
1492 (%i8) flipflag:not flipflag;
1493 (%o8)                                false
1494 (%i9) ishow(simpmetderiv(%th(2),stop))$
1495                                a b  b c
1496 (%t9)                       - g    g    g      g
1497                                     ,e   a b,d  b c
1498 (%i10) ishow(contract(%))$
1499                                     b c
1500 (%t10)                           - g    g
1501                                     ,e   c b,d
1503 @end example
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.
1508 @opencatbox
1509 @category{Package itensor}
1510 @closecatbox
1511 @end deffn
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.
1520 @opencatbox
1521 @category{Package itensor}
1522 @closecatbox
1523 @end deffn
1525 @c -----------------------------------------------------------------------------
1526 @subsection Tensors in curved spaces
1527 @c -----------------------------------------------------------------------------
1529 @c -----------------------------------------------------------------------------
1530 @anchor{imetric}
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.
1540 @opencatbox
1541 @category{Package itensor}
1542 @closecatbox
1543 @end deffn
1545 @c -----------------------------------------------------------------------------
1546 @anchor{idim}
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.
1551 @opencatbox
1552 @category{Package itensor}
1553 @closecatbox
1554 @end deffn
1556 @c -----------------------------------------------------------------------------
1557 @anchor{ichr1}
1558 @deffn {Function} ichr1 ([@var{i}, @var{j}, @var{k}])
1559 Yields the Christoffel symbol of the first kind via the
1560 definition
1561 @example
1562        (g      + g      - g     )/2 .
1563          ik,j     jk,i     ij,k
1564 @end example
1565 @noindent
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}.
1569 @opencatbox
1570 @category{Package itensor}
1571 @closecatbox
1572 @end deffn
1574 @c -----------------------------------------------------------------------------
1575 @anchor{ichr2}
1576 @deffn {Function} ichr2 ([@var{i}, @var{j}], [@var{k}])
1577 Yields the Christoffel symbol of the second kind
1578 defined by the relation
1579 @example
1580                        ks
1581    ichr2([i,j],[k]) = g    (g      + g      - g     )/2
1582                              is,j     js,i     ij,s
1583 @end example
1585 @opencatbox
1586 @category{Package itensor}
1587 @closecatbox
1588 @end deffn
1590 @c -----------------------------------------------------------------------------
1591 @anchor{icurvature}
1592 @deffn {Function} icurvature ([@var{i}, @var{j}, @var{k}], [@var{h}])
1593 Yields the Riemann
1594 curvature tensor in terms of the Christoffel symbols of the second
1595 kind (@code{ichr2}).  The following notation is used:
1596 @example
1597             h             h            h         %1         h
1598   icurvature     = - ichr2      - ichr2     ichr2    + ichr2
1599             i j k         i k,j        %1 j      i k        i j,k
1600                             h          %1
1601                      + ichr2      ichr2
1602                             %1 k       i j
1603 @end example
1605 @opencatbox
1606 @category{Package itensor}
1607 @closecatbox
1608 @end deffn
1610 @c -----------------------------------------------------------------------------
1611 @anchor{covdiff}
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)}.
1618 @example
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: [];
1627                                       k
1628 (%t2)                                a
1629                                       i j
1630 (%i3) ishow(covdiff(%,s))$
1631              k         %1     k         %1     k
1632 (%t3)     - a     ichr2    - a     ichr2    + a
1633              i %1      j s    %1 j      i s    i j,s
1635              k     %1
1636       + ichr2     a
1637              %1 s  i j
1638 (%i4) imetric:g;
1639 (%o4)                                  g
1640 (%i5) ishow(ev(%th(2),ichr2))$
1641          %1 %4  k
1642         g      a     (g       - g       + g      )
1643                 i %1   s %4,j    j s,%4    j %4,s
1644 (%t5) - ------------------------------------------
1645                             2
1646 @group
1647     %1 %3  k
1648    g      a     (g       - g       + g      )
1649            %1 j   s %3,i    i s,%3    i %3,s
1650  - ------------------------------------------
1651                        2
1652     k %2  %1
1653    g     a    (g        - g        + g       )
1654           i j   s %2,%1    %1 s,%2    %1 %2,s     k
1655  + ------------------------------------------- + a
1656                         2                         i j,s
1657 @end group
1658 (%i6)
1659 @end example
1661 @opencatbox
1662 @category{Package itensor}
1663 @closecatbox
1664 @end deffn
1666 @c -----------------------------------------------------------------------------
1667 @anchor{lorentz}
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.
1673 @opencatbox
1674 @category{Package itensor}
1675 @closecatbox
1676 @end deffn
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.
1690 @example
1692 (%i1) load("itensor");
1693 (%o1)      /share/tensor/itensor.lisp
1694 (%i2) ishow(icurvature([r,s,t],[u]))$
1695              u            u         %1         u     
1696 (%t2) - ichr2      - ichr2     ichr2    + ichr2      
1697              r t,s        %1 s      r t        r s,t 
1699                                               u         %1
1700                                        + ichr2     ichr2
1701                                               %1 t      r s
1702 (%i3) ishow(igeodesic_coords(%,ichr2))$
1703                                  u            u
1704 (%t3)                       ichr2      - ichr2
1705                                  r s,t        r t,s
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))$
1709              u            u            u            u
1710 (%t4) - ichr2      + ichr2      + ichr2      - ichr2
1711              t s,r        t r,s        s t,r        s r,t
1713                                              u            u
1714                                       - ichr2      + ichr2
1715                                              r t,s        r s,t
1716 (%i5) canform(%);
1717 (%o5)                                  0
1719 @end example
1721 @opencatbox
1722 @category{Package itensor}
1723 @closecatbox
1724 @end deffn
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:
1760 @example
1762 (%i1) load("itensor");
1763 (%o1)      /share/tensor/itensor.lisp
1764 (%i2) iframe_flag:true;
1765 (%o2)                                true
1766 (%i3) ishow(covdiff(v([],[i]),j))$
1767                                i        i     %1
1768 (%t3)                         v   + icc2     v
1769                                ,j       %1 j
1770 (%i4) ishow(ev(%,icc2))$
1771                                %1     i       i
1772 (%t4)                         v   ifc2     + v
1773                                       %1 j    ,j
1774 (%i5) ishow(ev(%,ifc2))$
1775                           %1    i %2                i
1776 (%t5)                    v   ifg     ifc1        + v
1777                                          %1 j %2    ,j
1778 (%i6) ishow(ev(%,ifc1))$
1779 @group
1780             %1    i %2
1781            v   ifg     (ifb        - ifb        + ifb       )
1782                            j %2 %1      %2 %1 j      %1 j %2     i
1783 (%t6)      -------------------------------------------------- + v
1784                                    2                             ,j
1785 @end group
1786 (%i7) ishow(ifb([a,b,c]))$
1787                                                    %3    %4
1788 (%t7)               (ifri        - ifri       ) ifr   ifr
1789                          a %3,%4       a %4,%3     b     c
1791 @end example
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}:
1796 @example
1798 (%i8) block([iframe_bracket_form:false],ishow(ifb([a,b,c])))$
1799                                 %6    %5        %5      %6
1800 (%t8)              ifri     (ifr   ifr     - ifr     ifr  )
1801                        a %5     b     c,%6      b,%6    c
1803 @end example
1805 @c -----------------------------------------------------------------------------}
1806 @anchor{iframes}
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.
1813 @opencatbox
1814 @category{Package itensor}
1815 @closecatbox
1816 @end deffn
1818 @c -----------------------------------------------------------------------------
1819 @anchor{ifb}
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:
1825 @example
1827           - ifb      + ifb      + ifb
1828                c a b      b c a      a b c
1829 ifc1    = --------------------------------
1830     abc                  2
1832 @end example
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}:
1839 @example
1841           d      e                                      f
1842 ifb =  ifr    ifr   (ifri      - ifri      - ifri    itr   )
1843    abc    b      c       a d,e       a e,d       a f    d e
1846 @end example
1848 Otherwise:
1850 @example
1852              e      d        d      e
1853 ifb    = (ifr    ifr    - ifr    ifr   ) ifri
1854    abc       b      c,e      b,e    c        a d
1856 @end example
1858 @opencatbox
1859 @category{Package itensor}
1860 @closecatbox
1861 @end defvr
1863 @c -----------------------------------------------------------------------------
1864 @anchor{icc1}
1865 @defvr {Variable} icc1
1867 Connection coefficients of the first kind. In @code{itensor}, defined as
1869 @example
1871 icc1    = ichr1    - ikt1    - inmc1
1872     abc        abc       abc        abc
1874 @end example
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.
1884 @opencatbox
1885 @category{Package itensor}
1886 @closecatbox
1887 @end defvr
1889 @c -----------------------------------------------------------------------------
1890 @anchor{icc2}
1891 @defvr {Variable} icc2
1893 Connection coefficients of the second kind. In @code{itensor}, defined as
1895 @example
1897     c         c        c         c
1898 icc2   = ichr2   - ikt2   - inmc2
1899     ab        ab       ab        ab
1901 @end example
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.
1911 @opencatbox
1912 @category{Package itensor}
1913 @closecatbox
1914 @end defvr
1916 @c -----------------------------------------------------------------------------
1917 @anchor{ifc1}
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
1925 @example
1927           - ifb      + ifb      + ifb
1928                c a b      b c a      a b c
1929 ifc1    = --------------------------------
1930     abc                   2
1933 @end example
1935 @opencatbox
1936 @category{Package itensor}
1937 @closecatbox
1938 @end defvr
1940 @c -----------------------------------------------------------------------------
1941 @anchor{ifc2}
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:
1949 @example
1951     c       cd
1952 ifc2   = ifg   ifc1
1953     ab             abd
1955 @end example
1957 @opencatbox
1958 @category{Package itensor}
1959 @closecatbox
1960 @end defvr
1962 @c -----------------------------------------------------------------------------
1963 @anchor{ifr}
1964 @defvr {Variable} ifr
1966 The frame field. Contracts with the inverse frame field (@mref{ifri}) to
1967 form the frame metric (@mref{ifg}).
1969 @opencatbox
1970 @category{Package itensor}
1971 @closecatbox
1972 @end defvr
1974 @c -----------------------------------------------------------------------------
1975 @anchor{ifri}
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
1980 frames.
1982 @opencatbox
1983 @category{Package itensor}
1984 @closecatbox
1985 @end defvr
1987 @c -----------------------------------------------------------------------------
1988 @anchor{ifg}
1989 @defvr {Variable} ifg
1991 The frame metric. Defaults to @mref{kdelta}, but can be changed using
1992 @mref{components}.
1994 @opencatbox
1995 @category{Package itensor}
1996 @closecatbox
1997 @end defvr
1999 @c -----------------------------------------------------------------------------
2000 @anchor{ifgi}
2001 @defvr {Variable} ifgi
2003 The inverse frame metric. Contracts with the frame metric (@mref{ifg})
2004 to @mref{kdelta}.
2006 @opencatbox
2007 @category{Package itensor}
2008 @closecatbox
2009 @end defvr
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.
2018 @opencatbox
2019 @category{Package itensor}
2020 @closecatbox
2021 @end defvr
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 -----------------------------------------------------------------------------
2033 @anchor{inm}
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}:
2041 @example
2043 g     =- g  inm
2044  ij;k     ij   k
2046 @end example
2048 @opencatbox
2049 @category{Package itensor}
2050 @closecatbox
2051 @end defvr
2053 @c -----------------------------------------------------------------------------
2054 @anchor{inmc1}
2055 @defvr {Variable} inmc1
2057 Covariant permutation of the nonmetricity vector components. Defined as
2059 @example
2061            g   inm  - inm  g   - g   inm
2062             ab    c      a  bc    ac    b
2063 inmc1    = ------------------------------
2064      abc                 2
2066 @end example
2068 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2070 @opencatbox
2071 @category{Package itensor}
2072 @closecatbox
2073 @end defvr
2075 @c -----------------------------------------------------------------------------
2076 @anchor{inmc2}
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
2083 @example
2085                       c         c         cd
2086           -inm  kdelta  - kdelta  inm  + g   inm  g
2087      c        a       b         a    b          d  ab
2088 inmc2   = -------------------------------------------
2089      ab                        2
2091 @end example
2093 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2095 @opencatbox
2096 @category{Package itensor}
2097 @closecatbox
2098 @end defvr
2100 @c -----------------------------------------------------------------------------
2101 @anchor{ikt1}
2102 @defvr {Variable} ikt1
2104 Covariant permutation of the torsion tensor (also known as contorsion).
2105 Defined as:
2107 @example
2109                   d           d       d
2110           -g   itr  - g    itr   - itr   g
2111             ad    cb    bd    ca      ab  cd
2112 ikt1    = ----------------------------------
2113     abc                   2
2115 @end example
2117 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2119 @opencatbox
2120 @category{Package itensor}
2121 @closecatbox
2122 @end defvr
2124 @c -----------------------------------------------------------------------------
2125 @anchor{ikt2}
2126 @defvr {Variable} ikt2
2128 Contravariant permutation of the torsion tensor (also known as contorsion).
2129 Defined as:
2131 @example
2133     c     cd
2134 ikt2   = g   ikt1
2135     ab           abd
2137 @end example
2139 (Substitute @mref{ifg} in place of @code{g} if a frame metric is used.)
2141 @opencatbox
2142 @category{Package itensor}
2143 @closecatbox
2144 @end defvr
2146 @c -----------------------------------------------------------------------------
2147 @anchor{itr}
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:
2154 @example
2156 (%i1) load("itensor");
2157 (%o1)      /share/tensor/itensor.lisp
2158 (%i2) imetric:g;
2159 (%o2)                                  g
2160 (%i3) covdiff( covdiff( f( [], []), i), j)
2161                       - covdiff( covdiff( f( [], []), j), i)$
2162 (%i4) ishow(%)$
2163                                    %4              %2
2164 (%t4)                    f    ichr2    - f    ichr2
2165                           ,%4      j i    ,%2      i j
2166 (%i5) canform(%);
2167 (%o5)                                  0
2168 (%i6) itorsion_flag:true;
2169 (%o6)                                true
2170 (%i7) covdiff( covdiff( f( [], []), i), j)
2171                       - covdiff( covdiff( f( [], []), j), i)$
2172 (%i8) ishow(%)$
2173                            %8             %6
2174 (%t8)             f    icc2    - f    icc2    - f     + f
2175                    ,%8     j i    ,%6     i j    ,j i    ,i j
2176 (%i9) ishow(canform(%))$
2177                                    %1             %1
2178 (%t9)                     f    icc2    - f    icc2
2179                            ,%1     j i    ,%1     i j
2180 (%i10) ishow(canform(ev(%,icc2)))$
2181                                    %1             %1
2182 (%t10)                    f    ikt2    - f    ikt2
2183                            ,%1     i j    ,%1     j i
2184 (%i11) ishow(canform(ev(%,ikt2)))$
2185                       %2 %1                    %2 %1
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))))))$
2189                            %3 %2            %1       %1
2190                      f    g      g      (itr    - itr   )
2191                       ,%3         %2 %1     j i      i j
2192 (%t12)               ------------------------------------
2193                                       2
2194 (%i13) decsym(itr,2,1,[anti(all)],[]);
2195 (%o13)                               done
2196 (%i14) defcon(g,g,kdelta);
2197 (%o14)                               done
2198 (%i15) subst(g,nounify(g),%th(3))$
2199 (%i16) ishow(canform(contract(%)))$
2200                                            %1
2201 (%t16)                           - f    itr
2202                                     ,%1    i j
2204 @end example
2206 @opencatbox
2207 @category{Package itensor}
2208 @closecatbox
2209 @end defvr
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,
2219 is defined.
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
2226 @example
2227             a a  - a a
2228              i j    j i
2229  a  /\ a  = -----------
2230   i     j        2
2231 @end example
2233 More generally, the product of a p-form and a q-form would be defined as
2235 @example
2236                        1     k1..kp l1..lq
2237 A       /\ B       = ------ D              A       B
2238  i1..ip     j1..jq   (p+q)!  i1..ip j1..jq  k1..kp  l1..lq
2239 @end example
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:
2246 @example
2247 a  /\ a  = a a  - a a
2248  i     j    i j    j i
2249 @end example
2251 and, in the general case
2253 @example
2254                        1    k1..kp l1..lq
2255 A       /\ B       = ----- D              A       B
2256  i1..ip     j1..jq   p! q!  i1..ip j1..jq  k1..kp  l1..lq
2257 @end example
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
2265 be applied.
2267 @anchor{~}
2268 @defvr {Operator} ~
2269 @ifinfo
2270 @fnindex Wedge product
2271 @end ifinfo
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:
2281 @example
2282 (%i1) load("itensor");
2283 (%o1)      /share/tensor/itensor.lisp
2284 (%i2) ishow(a([i])~b([j]))$
2285                                  a  b  - b  a
2286                                   i  j    i  j
2287 (%t2)                            -------------
2288                                        2
2289 (%i3) decsym(a,2,0,[anti(all)],[]);
2290 (%o3)                                done
2291 (%i4) ishow(a([i,j])~b([k]))$
2292                           a    b  + b  a    - a    b
2293                            i j  k    i  j k    i k  j
2294 (%t4)                     ---------------------------
2295                                        3
2296 (%i5) igeowedge_flag:true;
2297 (%o5)                                true
2298 (%i6) ishow(a([i])~b([j]))$
2299 (%t6)                            a  b  - b  a
2300                                   i  j    i  j
2301 (%i7) ishow(a([i,j])~b([k]))$
2302 (%t7)                     a    b  + b  a    - a    b
2303                            i j  k    i  j k    i k  j
2304 @end example
2306 @opencatbox
2307 @category{Package itensor}
2308 @category{Operators}
2309 @closecatbox
2310 @end defvr
2312 @c -----------------------------------------------------------------------------
2313 @anchor{|}
2314 @defvr {Operator} |
2315 @ifinfo
2316 @fnindex Contraction with a vector
2317 @end ifinfo
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:
2329 @example
2330 (%i1) load("itensor");
2331 (%o1)      /share/tensor/itensor.lisp
2332 (%i2) decsym(a,2,0,[anti(all)],[]);
2333 (%o2)                                done
2334 (%i3) ishow(a([i,j],[])|v)$
2335                                     %1
2336 (%t3)                              v   a
2337                                         %1 j
2338 (%i4) ishow(a([j,i],[])|v)$
2339                                      %1
2340 (%t4)                             - v   a
2341                                          %1 j
2342 @end example
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.
2348 @opencatbox
2349 @category{Package itensor}
2350 @category{Operators}
2351 @closecatbox
2352 @end defvr
2354 @c -----------------------------------------------------------------------------
2355 @anchor{extdiff}
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}.
2362 For instance:
2364 @example
2365 (%i1) load("itensor");
2366 (%o1)      /share/tensor/itensor.lisp
2367 (%i2) ishow(extdiff(v([i]),j))$
2368                                   v    - v
2369                                    j,i    i,j
2370 (%t2)                             -----------
2371                                        2
2372 (%i3) decsym(a,2,0,[anti(all)],[]);
2373 (%o3)                                done
2374 (%i4) ishow(extdiff(a([i,j]),k))$
2375                            a      - a      + a
2376                             j k,i    i k,j    i j,k
2377 (%t4)                      ------------------------
2378                                       3
2379 (%i5) igeowedge_flag:true;
2380 (%o5)                                true
2381 (%i6) ishow(extdiff(v([i]),j))$
2382 (%t6)                             v    - v
2383                                    j,i    i,j
2384 (%i7) ishow(extdiff(a([i,j]),k))$
2385 (%t7)                    - (a      - a      + a     )
2386                              k j,i    k i,j    j i,k
2388 @end example
2390 @opencatbox
2391 @category{Package itensor}
2392 @closecatbox
2393 @end deffn
2395 @c -----------------------------------------------------------------------------
2396 @anchor{hodge}
2397 @deffn {Function} hodge (@var{expr})
2399 Compute the Hodge-dual of @var{expr}. For instance:
2401 @c ===beg===
2402 @c load("itensor");
2403 @c imetric(g);
2404 @c idim(4);
2405 @c icounter:100;
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(%)))$
2410 @c lc2kdt(%)$
2411 @c %,kdelta$
2412 @c ishow(canform(contract(expand(%))))$
2413 @c ===end===
2414 @example
2416 (%i1) load("itensor");
2417 (%o1)      /share/tensor/itensor.lisp
2418 (%i2) imetric(g);
2419 (%o2)                            done
2420 (%i3) idim(4);
2421 (%o3)                            done
2422 (%i4) icounter:100;
2423 (%o4)                             100
2424 (%i5) decsym(A,3,0,[anti(all)],[])$
2426 (%i6) ishow(A([i,j,k],[]))$
2427 (%t6)                           A
2428                                  i j k
2429 (%i7) ishow(canform(hodge(%)))$
2430                           %1 %2 %3 %4
2431                levi_civita            g        A
2432                                        %1 %102  %2 %3 %4
2433 (%t7)          -----------------------------------------
2434                                    6
2435 (%i8) ishow(canform(hodge(%)))$
2436                  %1 %2 %3 %8            %4 %5 %6 %7
2437 (%t8) levi_civita            levi_civita            g       
2438                                                      %1 %106
2439                              g        g        g      A         /6
2440                               %2 %107  %3 %108  %4 %8  %5 %6 %7
2441 (%i9) lc2kdt(%)$
2443 (%i10) %,kdelta$
2445 (%i11) ishow(canform(contract(expand(%))))$
2446 (%t11)                     - A
2447                               %106 %107 %108
2449 @end example
2451 @opencatbox
2452 @category{Package itensor}
2453 @closecatbox
2454 @end deffn
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.
2467 @opencatbox
2468 @category{Package itensor}
2469 @closecatbox
2470 @end defvr
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 -----------------------------------------------------------------------------
2483 @anchor{tentex}
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:
2489 @c ===beg===
2490 @c load("itensor");
2491 @c load(tentex);
2492 @c idummyx:m;
2493 @c ishow(icurvature([j,k,l],[i]))$
2494 @c tentex(%)$
2495 @c ===end===
2496 @example
2497 (%i1) load("itensor");
2498 (%o1)      /share/tensor/itensor.lisp
2499 (%i2) load(tentex);
2500 (%o2)       /share/tensor/tentex.lisp
2501 (%i3) idummyx:m;
2502 (%o3)                                  m
2503 (%i4) ishow(icurvature([j,k,l],[i]))$
2504             m1       i           m1       i           i
2505 (%t4)  ichr2    ichr2     - ichr2    ichr2     - ichr2
2506             j k      m1 l        j l      m1 k        j l,k
2508                                                       i
2509                                                + ichr2
2510                                                       j k,l
2511 (%i5) tentex(%)$
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@}$$
2514 @end example
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.
2521 @opencatbox
2522 @category{Package itensor}
2523 @category{TeX output}
2524 @closecatbox
2525 @end deffn
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 -----------------------------------------------------------------------------
2536 @anchor{ic_convert}
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
2553 function.
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
2560 @c for readability.
2561 @c ===begx===
2562 @c load("itensor");
2563 @c eqn:ishow(t([i,j],[k])=f([],[])*g([l,m],[])*a([],[m],j)
2564 @c      *b([i],[l,k]))$
2565 @c ic_convert(eqn);
2566 @c imetric(g);
2567 @c metricconvert:true;
2568 @c ic_convert(eqn);
2569 @c ===endx===
2570 @example
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)
2574       *b([i],[l,k]))$
2575                              k        m   l k
2576 (%t2)                       t    = f a   b    g
2577                              i j      ,j  i    l m
2578 (%i3) ic_convert(eqn);
2579 (%o3) for i thru dim do (for j thru dim do (
2580        for k thru dim do
2581         t        : f sum(sum(diff(a , ct_coords ) b
2582          i, j, k                   m           j   i, l, k
2584  g    , l, 1, dim), m, 1, dim)))
2585   l, m
2586 (%i4) imetric(g);
2587 (%o4)                                done
2588 (%i5) metricconvert:true;
2589 (%o5)                                true
2590 (%i6) ic_convert(eqn);
2591 (%o6) for i thru dim do (for j thru dim do (
2592        for k thru dim do
2593         t        : f sum(sum(diff(a , ct_coords ) b
2594          i, j, k                   m           j   i, l, k
2596  lg    , l, 1, dim), m, 1, dim)))
2597    l, m
2598 @end example
2600 @opencatbox
2601 @category{Package itensor}
2602 @category{Package ctensor}
2603 @closecatbox
2604 @end deffn
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
2614 @example
2615   Keyword    Comments
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
2622   concan
2623   irpmon
2624   lc0
2625   _lc2kdt0
2626   _lcprod
2627   _extlc
2628 @end example