There are several functions in REDTEN whose intention is to make the usage of the system more convenient for the user. Of these functions, dir() has been previously introduced. The function dir() displays the indexed objects in the system, showing the full name of the object, its type and number of explicit elements (components), the protection flags, the coordinates and the index structure. For example, after the Ricci tensor of the Kerr metric is simplified, a directory shows the following:
#: dir(!*); name type comp prot coordinates indextype x coordinates 4 w (t r th ph) (1)Notice that the Ricci tensor has no components, as it should for a vacuum solution. The current metric and its inverse are flagged by a leading * on the display line. Objects that are implicit have a + symbol following the number of components to indicate that there are more values than are explicitly stored. Ordinary derivatives (which are not normally displayed, see §4.1) may have a ? following the number of components to indicate that there are undefined components. Objects that are write-protected will have a W in the protection column, if they are kill-protected there will be a K, and if they are write- and kill-protected then there will be a KW. If there are no objects in the system, the message no objects is displayed.*
g1 metric 5 w (t r th ph) (-1 -1)*
g1_inv metric 5 w (t r th ph) (1 1) g1_ric ricci 5 w (t r th ph) (-1 -1) g1_R riemann 13 w (t r th ph) (-1 -1 -1 -1) g1_c1 christoffel1 20 w (t r th ph) (-1 -1 -1) g1_DF odf 10 (t r th ph) (-1 -1 -1) g1_c2 christoffel2 20 w (t r th ph) (1 -1 -1) g1_c1_DF odf 133? (t r th ph) (-1 -1 -1 -1) 9 objects, Total components: 215 t
With no arguments dir() shows all objects in order of creation, any arguments are taken as the names of objects to display alone. If the switch reversedir is turned off, the display proceeds in the reverse order, with the most recently created objects displayed first. The function nodir() flags objects so that they do not appear in a directory listing, the flag can be cleared by calling dir() with the object name as an argument. Some objects created by the system, such as the delta-functions, are hidden from dir() and are never displayed. If the keyword all is the single argument to dir(), then all objects are displayed regardless of the nodir flags. Scalar objects are not displayed in line with the other objects, their names are displayed at the end of the listing.
A rudimentary pattern matcher is used by dir() to expand names containing certain special characters. A !* matches any number of characters (including none), while a !? matches exactly one character. Thus, the pattern !* matches all names and is equivalent to the keyword all. The user can display the family of a given object with the pattern <name>!* or find all objects of a certain type, such as the Riemann tensor, with !*R. Objects selected in this way are displayed regardless of the nodir flags.
For metrics, the setmetric() function uses nodir() to hide the metric that was previously the current-metric, dir() will not display that metric or any of its family until it is again the current-metric or it appears as an explicit argument to dir(). This is intended to keep the directory listing short and concise, rather than being cluttered by objects that are not currently in use.
iprop()Each indexed object carries a large number of properties describing the objects' structure and characteristics, these are described in §2.2.6. The function iprop() will display those properties named in the iprop!*!* variable, the defaults are specially marked in §2.2.6. If the switch iprop is on, then iprop() is called whenever the user has requested a display of the object's values.
rem(), remi()The rem() functions are used to remove indexed objects from the system, deleting all of their properties and values. With rem() the user can delete specified objects, remi() deletes objects interactively. Both functions will accept the same patterns as dir(), as well as the keyword all which is a synonym for the pattern !*. Once an object is deleted there is no way to recover its values, hence the need for the protect() function (qv).
To use rem(), the user simply types the names of the objects to delete as the arguments, so, for example,
#: rem(c1,c2,R); (g2_R g2_c2 g2_c1)will remove the Christoffel symbols and the Riemann tensor. Notice that generic names were used as arguments to rem() but the correct target objects were deleted, as shown by the displayed list of deleted objects. If a name that was requested be deleted does not appear in this list, then the object is kill-protected and cannot be removed until the protection is cleared with protect(). If a name not of an indexed object is included in the arguments to rem() it will be ignored.
In the interactive mode, remi() presents each indexed object specified to the user an asks if is to be deleted. Valid responses are y to delete and move on to the next object, n to keep the object, g to go on and delete all remaining objects and q to quit out of rem(). Each reponse must be followed by a carriage return; the g response will cause a further query to ensure the user really wants to delete everything.
Removing certain objects causes the rem() functions to remove others as well, so as not to leave orphaned objects in the system. Specifically, removing a metric also removes its entire family of objects, while removing a parent object causes all of its offspring to be removed. If an indexed scalar is removed and it had a value, that value is placed as a normal algebraic value on the now non-indexed name.
protect()The function protect() sets or clears an objects' protection flags. The only protections available are write-protection, kill-protection, or both. The first argument to protect() is the name the object whose protections are being modifed, and the second argument sets the new protections (a missing second argument is equivalent to nil). The values for the second argument may be one of the following:
The protection flags are displayed by dir() and by iprop(), however, the output from iprop() will show the internal format of the protection flags, which are simply the numbers 2, 3, or 6 for write-protection, kill-protection, or both, respectively.
icopy()icopy() The function icopy() copies its first argument to a new object whose name is the second argument. The new objects' name should be unused; however, if it is an unprotected indexed object it will be removed, but its properties are saved and can be restored by an immediate call to restoreobj(). The shift property of the restoreobj() output will no longer refer to the offspring of the input, but all other properties are copied exactly. A more complete copy is offered by the function copyfam(), described below.
copyfam(), getfam()The copyfam() function allows the user to copy an object and its entire family (either metric or shifted offspring) to another parent. This routine rebuilds the family structures of each member so that they all correctly refer to new objects. Usually the family of the first named argument is copied to the second argument, but, in the case of a metric, the second argument may be omitted and the default is the next metric name in the sequence used by metric(). The copied metric is not made the current-metric.
A family of objects is primarily a relation such that the offspring objects are derived in some manner from the parent, either by shifting indices, taking derivatives, or more complicated relations such as among the tensor metric and various GR quantities. In REDTEN a family is defined by the construction of object names. A family member has the parent name, a separating underscore ``_'', and some further identifying name. These constructions can be carried out repeatedly, yielding a family tree of related objects. For example, in the dir() listing on page one can see that g1 is the parent of many objects, while c1 is itself the parent of an object, namely g1_c1_DF. The function getfam() will return a lisp list of all objects in the family of its argument, including the parent. Thus,
#: getfam('g); (g1_inv g1_ric g1_R g1_c1 g1_DF g1_c2 g1_c1_DF g1) #: getfam('c1); (g1_c1_DF g1_c1)and observe that the argument must be quoted to ensure the command line is parsed in symbolic mode. Also note that the argument may be either a generic name or the true name.
A common use of copyfam() and getfam() is to copy a metric family and then apply a consitent set of substitutions to the family without disturbing the original set of objects. For example, if g1 is a general spherically symmetric metric with a parameter , and with a family of computed objects, then the following will copy the family and substitute for :
#: %create g1 and family #: copyfam(g1); g2 #: lisp foreach x in getfam(g2) do write algebraic mapfi(sub(f=1-2*m/r,x)); <output> #: lisp foreach x in getfam(g2) do if get (x, 'itype) eq 'odf then write algebraic mapfi (x); <output>The first foreach can be used to apply a substitution to all objects in the family, note the use of the write command to ensure that the mapfi() output is seen, and the use of the algebraic command to change mode partway along the command line. The second foreach command demonstrates the application of mapfi() to a specific class of objects, in this case ordinary derivatives. It is also possible to use these constructs with other list generating functions or with the indexed!-names list directly, to access all objects in the system.
describe()The describe() function is used to retrieve or set a string containing a description an object. Most generating functions put a description string on their output specifying what kind of object has been created, and from what object it was derived. A string supplied as the second argument will replace the description on the object whose name is the first argument to describe().
help()The REDTEN help() function implements a rudimentary help utility to remind the user of the correct number and types of arguments to various REDTEN functions. help() takes any number of arguments, which may be patterns of the sort described on page ; a !* pattern will show all help strings, while, for example, the pattern !*env will give help for all the functions that deal with the REDUCE environment. With no arguments, help() prints a list of the names of functions and switches for which help is available.
defindextype()The defindextype() function allows the user to define new types of indices or to modify the range of the pre-defined index-types. See §2.2.2 for a description of the pre-defined index-types and table 2.1 for their properties. The call to defindextype() takes the form:
defindextype ('range:int-list, index-type-val:int, {'name:id}, {'format:string}, {'chsymgen:func});where range is a list of two ordered non-negative integers representing the range of the indices of type index-type-val (the range must consist of non-negative numbers ). For example, the default range is '(0 3) for the tensor indices, which have index-type-val 1. For the pre-defined index-types only the range may be changed, other arguments after index-type-val are ignored. For new index-types (index-type-val ), the remaining arguments are: the name by which the new index-type is to be known (eg. tensor, spinor, etc.), the format in which indices are to be printed, and a function that will generate a Christoffel symbol for this index-type for use by cov().
The name argument is used by mkobj() to determine the indexed property of a new object, different index-types may have the same name (such as the spinor or dyad types) so that an apparently mixed object will be given a meaningful property. The format is a string which must include a '%' mark to indicate the placement of the corresponding index element, any other characters are printed literally, so for example, the format for the frame indices is ``(%)''. The Christoffel symbol generation function is used by cov() to determine the appropriate Christoffel symbol to use, some index-types do not have a Christoffel symbol, in which case chsymgen is 'nil. In other cases the function is of the form
'(lambda nil (car christoffel2!* '(nil)))where christoffel2!* may be replaced by whatever is the correct lisp function. This complicated form is required since the function, following the usual convention, has a return value of the form '(name . 1). It is not really intended that the casual user be concerned with this.
defindextype() calls the delta function generator delta() to create or modify the system delta functions for the new or updated index-type. If no arguments are given, defindextype() prints out the currently defined index-types, which are stored in the variable defindextype!*.
restrict()The indices property of an indexed object are derived from the range parameter to defindextype() and specify the inclusive group range of the entire index of the object. The restrict() function allows the user to narrow this range, so that indexed references apply to only a part of the full range. A new property, restricted, is placed on the indexed object that is the first argument to restrict() (the name must be quoted to ensure parsing in symbolic mode). The next two arguments are the lower and upper bounds of the group range, these are lists of integers. If either of these arguments is left out, the default is the original group range obtained from the indices property on the object. Leaving both bounds off returns the group range to that present when the object was created, but the restricted property is not removed, just set to the new values.
For most object types, the restricted ranges must be contained within the original range. For array type objects, the user can reset the bounds to any desired values. Attempting to access components of the object outside the currently defined range, even if they are present, will yield 0 from a read or write operation. Indexed assignments will apply only to the current range, as will applications of mapfi(). The user can therefore work with a restricted section of an indexed object, without disturbing the remaining portion of the object.
saveobj()If the user is about to modify an object, the value of that object can be saved by a call to saveobj(). If something goes wrong, the object's value can be recovered by calling restoreobj(). Only one object at a time can be saved, and the system also saves objects during indexed asignments and when mapfi() is used.
mclear()The REDTEN hooks in the REDUCE parser in some places make use of global variables that control the parsing action. If an error has occured or the user has aborted an operation, these variables may be left in an inconsistent state. It may then be impossible to correctly enter indexed objects and output may be distorted. The function mclear() should always be called if the user suspects a parsing problem or has forced an abort.
If a directory listing shows objects with names of the form #tmp1 etc, then an abort has been made, but mclear() still
needs to be called. These object are the temporaries used by the
system during the evaluation of an indexed expression.