]> www.ginac.de Git - ginac.git/blobdiff - doc/tutorial/ginac.texi
- documented map(), find(), and new symmetry specifications for indexed objects
[ginac.git] / doc / tutorial / ginac.texi
index 730f277309be4b877b4d6351066d79186e73ae8e..6ed69023339a20a225bb1a9a48fbfca61da1a06e 100644 (file)
@@ -1543,7 +1543,7 @@ ex idx::get_dimension(void);
 return the value and dimension of an @code{idx} object. If you have an index
 in an expression, such as returned by calling @code{.op()} on an indexed
 object, you can get a reference to the @code{idx} object with the function
-@code{ex_to_idx()} on the expression.
+@code{ex_to<idx>()} on the expression.
 
 There are also the methods
 
@@ -1586,7 +1586,7 @@ bool varidx::is_covariant(void);
 bool varidx::is_contravariant(void);
 @end example
 
-allow you to check the variance of a @code{varidx} object (use @code{ex_to_varidx()}
+allow you to check the variance of a @code{varidx} object (use @code{ex_to<varidx>()}
 to get the object reference from an expression). There's also the very useful
 method
 
@@ -1630,7 +1630,7 @@ bool spinidx::is_undotted(void);
 @end example
 
 allow you to check whether or not a @code{spinidx} object is dotted (use
-@code{ex_to_spinidx()} to get the object reference from an expression).
+@code{ex_to<spinidx>()} to get the object reference from an expression).
 Finally, the two methods
 
 @example
@@ -1697,22 +1697,99 @@ expected:
 @end example
 
 @subsection Symmetries
+@cindex @code{symmetry} (class)
+@cindex @code{sy_none()}
+@cindex @code{sy_symm()}
+@cindex @code{sy_anti()}
+@cindex @code{sy_cycl()}
 
-Indexed objects can be declared as being totally symmetric or antisymmetric
-with respect to their indices. In this case, GiNaC will automatically bring
-the indices into a canonical order which allows for some immediate
-simplifications:
+Indexed objects can have certain symmetry properties with respect to their
+indices. Symmetries are specified as a tree of objects of class @code{symmetry}
+that is constructed with the helper functions
+
+@example
+symmetry sy_none(...);
+symmetry sy_symm(...);
+symmetry sy_anti(...);
+symmetry sy_cycl(...);
+@end example
+
+@code{sy_none()} stands for no symmetry, @code{sy_symm()} and @code{sy_anti()}
+specify fully symmetric or antisymmetric, respectively, and @code{sy_cycl()}
+represents a cyclic symmetry. Each of these functions accepts up to four
+arguments which can be either symmetry objects themselves or unsigned integer
+numbers that represent an index position (counting from 0). A symmetry
+specification that consists of only a single @code{sy_symm()}, @code{sy_anti()}
+or @code{sy_cycl()} with no arguments specifies the respective symmetry for
+all indices.
+
+Here are some examples of symmetry definitions:
 
 @example
     ...
-    cout << indexed(A, indexed::symmetric, i, j)
-          + indexed(A, indexed::symmetric, j, i) << endl;
+    // No symmetry:
+    e = indexed(A, i, j);
+    e = indexed(A, sy_none(), i, j);     // equivalent
+    e = indexed(A, sy_none(0, 1), i, j); // equivalent
+
+    // Symmetric in all three indices:
+    e = indexed(A, sy_symm(), i, j, k);
+    e = indexed(A, sy_symm(0, 1, 2), i, j, k); // equivalent
+    e = indexed(A, sy_symm(2, 0, 1), i, j, k); // same symmetry, but yields a
+                                               // different canonical order
+
+    // Symmetric in the first two indices only:
+    e = indexed(A, sy_symm(0, 1), i, j, k);
+    e = indexed(A, sy_none(sy_symm(0, 1), 2), i, j, k); // equivalent
+
+    // Antisymmetric in the first and last index only (index ranges need not
+    // be contiguous):
+    e = indexed(A, sy_anti(0, 2), i, j, k);
+    e = indexed(A, sy_none(sy_anti(0, 2), 1), i, j, k); // equivalent
+
+    // An example of a mixed symmetry: antisymmetric in the first two and
+    // last two indices, symmetric when swapping the first and last index
+    // pairs (like the Riemann curvature tensor):
+    e = indexed(A, sy_symm(sy_anti(0, 1), sy_anti(2, 3)), i, j, k, l);
+
+    // Cyclic symmetry in all three indices:
+    e = indexed(A, sy_cycl(), i, j, k);
+    e = indexed(A, sy_cycl(0, 1, 2), i, j, k); // equivalent
+
+    // The following examples are invalid constructions that will throw
+    // an exception at run time.
+
+    // An index may not appear multiple times:
+    e = indexed(A, sy_symm(0, 0, 1), i, j, k); // ERROR
+    e = indexed(A, sy_none(sy_symm(0, 1), sy_anti(0, 2)), i, j, k); // ERROR
+
+    // Every child of sy_symm(), sy_anti() and sy_cycl() must refer to the
+    // same number of indices:
+    e = indexed(A, sy_symm(sy_anti(0, 1), 2), i, j, k); // ERROR
+
+    // And of course, you cannot specify indices which are not there:
+    e = indexed(A, sy_symm(0, 1, 2, 3), i, j, k); // ERROR
+    ...
+@end example
+
+If you need to specify more than four indices, you have to use the
+@code{.add()} method of the @code{symmetry} class. For example, to specify
+full symmetry in the first six indices you would write
+@code{sy_symm(0, 1, 2, 3).add(4).add(5)}.
+
+If an indexed object has a symmetry, GiNaC will automatically bring the
+indices into a canonical order which allows for some immediate simplifications:
+
+@example
+    ...
+    cout << indexed(A, sy_symm(), i, j)
+          + indexed(A, sy_symm(), j, i) << endl;
      // -> 2*A.j.i
-    cout << indexed(B, indexed::antisymmetric, i, j)
-          + indexed(B, indexed::antisymmetric, j, j) << endl;
+    cout << indexed(B, sy_anti(), i, j)
+          + indexed(B, sy_anti(), j, i) << endl;
      // -> -B.j.i
-    cout << indexed(B, indexed::antisymmetric, i, j)
-          + indexed(B, indexed::antisymmetric, j, i) << endl;
+    cout << indexed(B, sy_anti(), i, j, k)
+          + indexed(B, sy_anti(), j, i, k) << endl;
      // -> 0
     ...
 @end example
@@ -2302,7 +2379,7 @@ QED:
            dirac_gamma(mu.toggle_variance()) *
            (dirac_slash(l, D) + m * dirac_ONE());   
     e = dirac_trace(e).simplify_indexed(sp);
-    e = e.collect(lst(l, ldotq, m), true);
+    e = e.collect(lst(l, ldotq, m));
     cout << e << endl;
      // -> (8-4*D)*l^2+(8-4*D)*ldotq+4*D*m^2
 @}
@@ -2477,6 +2554,7 @@ avoided.
 * Information About Expressions::
 * Substituting Expressions::
 * Pattern Matching and Advanced Substitutions::
+* Applying a Function on Subexpressions::
 * Polynomial Arithmetic::           Working with polynomials.
 * Rational Expressions::            Working with rational functions.
 * Symbolic Differentiation::
@@ -2492,41 +2570,42 @@ avoided.
 @section Getting information about expressions
 
 @subsection Checking expression types
-@cindex @code{is_ex_of_type()}
-@cindex @code{ex_to_numeric()}
-@cindex @code{ex_to_@dots{}}
-@cindex @code{Converting ex to other classes}
+@cindex @code{is_a<@dots{}>()}
+@cindex @code{is_exactly_a<@dots{}>()}
+@cindex @code{ex_to<@dots{}>()}
+@cindex Converting @code{ex} to other classes
 @cindex @code{info()}
 @cindex @code{return_type()}
 @cindex @code{return_type_tinfo()}
 
 Sometimes it's useful to check whether a given expression is a plain number,
 a sum, a polynomial with integer coefficients, or of some other specific type.
-GiNaC provides a couple of functions for this (the first one is actually a macro):
+GiNaC provides a couple of functions for this:
 
 @example
-bool is_ex_of_type(const ex & e, TYPENAME t);
+bool is_a<T>(const ex & e);
+bool is_exactly_a<T>(const ex & e);
 bool ex::info(unsigned flag);
 unsigned ex::return_type(void) const;
 unsigned ex::return_type_tinfo(void) const;
 @end example
 
-When the test made by @code{is_ex_of_type()} returns true, it is safe to
-call one of the functions @code{ex_to_@dots{}}, where @code{@dots{}} is
-one of the class names (@xref{The Class Hierarchy}, for a list of all
-classes). For example, assuming @code{e} is an @code{ex}:
+When the test made by @code{is_a<T>()} returns true, it is safe to call
+one of the functions @code{ex_to<T>()}, where @code{T} is one of the
+class names (@xref{The Class Hierarchy}, for a list of all classes). For
+example, assuming @code{e} is an @code{ex}:
 
 @example
 @{
     @dots{}
-    if (is_ex_of_type(e, numeric))
-        numeric n = ex_to_numeric(e);
+    if (is_a<numeric>(e))
+        numeric n = ex_to<numeric>(e);
     @dots{}
 @}
 @end example
 
-@code{is_ex_of_type()} allows you to check whether the top-level object of
-an expression @samp{e} is an instance of the GiNaC class @samp{t}
+@code{is_a<T>(e)} allows you to check whether the top-level object of
+an expression @samp{e} is an instance of the GiNaC class @samp{T}
 (@xref{The Class Hierarchy}, for a list of all classes). This is most useful,
 e.g., for checking whether an expression is a number, a sum, or a product:
 
@@ -2535,15 +2614,19 @@ e.g., for checking whether an expression is a number, a sum, or a product:
     symbol x("x");
     ex e1 = 42;
     ex e2 = 4*x - 3;
-    is_ex_of_type(e1, numeric);  // true
-    is_ex_of_type(e2, numeric);  // false
-    is_ex_of_type(e1, add);      // false
-    is_ex_of_type(e2, add);      // true
-    is_ex_of_type(e1, mul);      // false
-    is_ex_of_type(e2, mul);      // false
+    is_a<numeric>(e1);  // true
+    is_a<numeric>(e2);  // false
+    is_a<add>(e1);      // false
+    is_a<add>(e2);      // true
+    is_a<mul>(e1);      // false
+    is_a<mul>(e2);      // false
 @}
 @end example
 
+In contrast, @code{is_exactly_a<T>(e)} allows you to check whether the
+top-level object of an expression @samp{e} is an instance of the GiNaC
+class @samp{T}, not including parent classes.
+
 The @code{info()} method is used for checking certain attributes of
 expressions. The possible values for the @code{flag} argument are defined
 in @file{ginac/flags.h}, the most important being explained in the following
@@ -2553,7 +2636,7 @@ table:
 @multitable @columnfractions .30 .70
 @item @strong{Flag} @tab @strong{Returns true if the object is@dots{}}
 @item @code{numeric}
-@tab @dots{}a number (same as @code{is_ex_of_type(..., numeric)})
+@tab @dots{}a number (same as @code{is_<numeric>(...)})
 @item @code{real}
 @tab @dots{}a real integer, rational or float (i.e. is not complex)
 @item @code{rational}
@@ -2583,7 +2666,7 @@ table:
 @item @code{prime}
 @tab @dots{}a prime integer (probabilistic primality test)
 @item @code{relation}
-@tab @dots{}a relation (same as @code{is_ex_of_type(..., relational)})
+@tab @dots{}a relation (same as @code{is_a<relational>(...)})
 @item @code{relation_equal}
 @tab @dots{}a @code{==} relation
 @item @code{relation_not_equal}
@@ -2597,9 +2680,9 @@ table:
 @item @code{relation_greater_or_equal}
 @tab @dots{}a @code{>=} relation
 @item @code{symbol}
-@tab @dots{}a symbol (same as @code{is_ex_of_type(..., symbol)})
+@tab @dots{}a symbol (same as @code{is_a<symbol>(...)})
 @item @code{list}
-@tab @dots{}a list (same as @code{is_ex_of_type(..., lst)})
+@tab @dots{}a list (same as @code{is_a<lst>(...)})
 @item @code{polynomial}
 @tab @dots{}a polynomial (i.e. only consists of sums and products of numbers and symbols with positive integer powers)
 @item @code{integer_polynomial}
@@ -2750,7 +2833,7 @@ A more powerful form of substitution using wildcards is described in the
 next section.
 
 
-@node Pattern Matching and Advanced Substitutions, Polynomial Arithmetic, Substituting Expressions, Methods and Functions
+@node Pattern Matching and Advanced Substitutions, Applying a Function on Subexpressions, Substituting Expressions, Methods and Functions
 @c    node-name, next, previous, up
 @section Pattern matching and advanced substitutions
 @cindex @code{wildcard} (class)
@@ -2953,6 +3036,33 @@ Again some examples in @command{ginsh} for illustration (in @command{ginsh},
    contains a linear term you should use the coeff() function instead.)
 @end example
 
+@cindex @code{find()}
+The method
+
+@example
+bool ex::find(const ex & pattern, lst & found);
+@end example
+
+works a bit like @code{has()} but it doesn't stop upon finding the first
+match. Instead, it appends all found matches to the specified list. If there
+are multiple occurrences of the same expression, it is entered only once to
+the list. @code{find()} returns false if no matches were found (in
+@command{ginsh}, it returns an empty list):
+
+@example
+> find(1+x+x^2+x^3,x);
+@{x@}
+> find(1+x+x^2+x^3,y);
+@{@}
+> find(1+x+x^2+x^3,x^$1);
+@{x^3,x^2@}
+  (Note the absence of "x".)
+> expand((sin(x)+sin(y))*(a+b));
+sin(y)*a+sin(x)*b+sin(x)*a+sin(y)*b
+> find(",sin($1));
+@{sin(y),sin(x)@}
+@end example
+
 @cindex @code{subs()}
 Probably the most useful application of patterns is to use them for
 substituting expressions with the @code{subs()} method. Wildcards can be
@@ -2996,7 +3106,115 @@ The last example would be written in C++ in this way:
 @end example
 
 
-@node Polynomial Arithmetic, Rational Expressions, Pattern Matching and Advanced Substitutions, Methods and Functions
+@node Applying a Function on Subexpressions, Polynomial Arithmetic, Pattern Matching and Advanced Substitutions, Methods and Functions
+@c    node-name, next, previous, up
+@section Applying a Function on Subexpressions
+@cindex Tree traversal
+@cindex @code{map()}
+
+Sometimes you may want to perform an operation on specific parts of an
+expression while leaving the general structure of it intact. An example
+of this would be a matrix trace operation: the trace of a sum is the sum
+of the traces of the individual terms. That is, the trace should @dfn{map}
+on the sum, by applying itself to each of the sum's operands. It is possible
+to do this manually which usually results in code like this:
+
+@example
+ex calc_trace(ex e)
+@{
+    if (is_a<matrix>(e))
+        return ex_to<matrix>(e).trace();
+    else if (is_a<add>(e)) @{
+        ex sum = 0;
+        for (unsigned i=0; i<e.nops(); i++)
+            sum += calc_trace(e.op(i));
+        return sum;
+    @} else if (is_a<mul>)(e)) @{
+        ...
+    @} else @{
+        ...
+    @}
+@}
+@end example
+
+This is, however, slightly inefficient (if the sum is very large it can take
+a long time to add the terms one-by-one), and its applicability is limited to
+a rather small class of expressions. If @code{calc_trace()} is called with
+a relation or a list as its argument, you will probably want the trace to
+be taken on both sides of the relation or of all elements of the list.
+
+GiNaC offers the @code{map()} method to aid in the implementation of such
+operations:
+
+@example
+static ex ex::map(map_function & f) const;
+static ex ex::map(ex (*f)(const ex & e)) const;
+@end example
+
+In the first (preferred) form, @code{map()} takes a function object that
+is subclassed from the @code{map_function} class. In the second form, it
+takes a pointer to a function that accepts and returns an expression.
+@code{map()} constructs a new expression of the same type, applying the
+specified function on all subexpressions (in the sense of @code{op()}),
+non-recursively.
+
+The use of a function object makes it possible to supply more arguments to
+the function that is being mapped, or to keep local state information.
+The @code{map_function} class declares a virtual function call operator
+that you can overload. Here is a sample implementation of @code{calc_trace()}
+that uses @code{map()} in a recursive fashion:
+
+@example
+struct calc_trace : public map_function @{
+    ex operator()(const ex &e)
+    @{
+        if (is_a<matrix>(e))
+            return ex_to<matrix>(e).trace();
+        else if (is_a<mul>(e)) @{
+            ...
+        @} else
+            return e.map(*this);
+    @}
+@};
+@end example
+
+This function object could then be used like this:
+
+@example
+@{
+    ex M = ... // expression with matrices
+    calc_trace do_trace;
+    ex tr = do_trace(M);
+@}
+@end example
+
+@command{ginsh} offers a slightly different implementation of @code{map()}
+that allows applying algebraic functions to operands. The second argument
+to @code{map()} is an expression containing the wildcard @samp{$0} which
+acts as the placeholder for the operands:
+
+@example
+> map(a*b,sin($0));
+sin(a)*sin(b)
+> map(a+2*b,sin($0));
+sin(a)+sin(2*b)
+> map(@{a,b,c@},$0^2+$0);
+@{a^2+a,b^2+b,c^2+c@}
+@end example
+
+Note that it is only possible to use algebraic functions in the second
+argument. You can not use functions like @samp{diff()}, @samp{op()},
+@samp{subs()} etc. because these are evaluated immediately:
+
+@example
+> map(@{a,b,c@},diff($0,a));
+@{0,0,0@}
+  This is because "diff($0,a)" evaluates to "0", so the command is equivalent
+  to "map(@{a,b,c@},0)".
+@end example
+
+
+@node Polynomial Arithmetic, Rational Expressions, Applying a Function on Subexpressions, Methods and Functions
 @c    node-name, next, previous, up
 @section Polynomial arithmetic
 
@@ -3041,8 +3259,25 @@ case the result is either a recursively collected polynomial, or a polynomial
 in a distributed form with terms like @math{c*x1^e1*...*xn^en}, as specified
 by the @code{distributed} flag.
 
-Note that the original polynomial needs to be in expanded form in order
-for @code{collect()} to be able to find the coefficients properly.
+Note that the original polynomial needs to be in expanded form (for the
+variables concerned) in order for @code{collect()} to be able to find the
+coefficients properly.
+
+The following @command{ginsh} transcript shows an application of @code{collect()}
+together with @code{find()}:
+
+@example
+> a=expand((sin(x)+sin(y))*(1+p+q)*(1+d));
+d*p*sin(x)+p*sin(x)+q*d*sin(x)+q*sin(y)+d*sin(x)+q*d*sin(y)+sin(y)+d*sin(y)+q*sin(x)+d*sin(y)*p+sin(x)+sin(y)*p
+> collect(a,@{p,q@});
+d*sin(x)+(d*sin(x)+sin(y)+d*sin(y)+sin(x))*p+(d*sin(x)+sin(y)+d*sin(y)+sin(x))*q+sin(y)+d*sin(y)+sin(x)
+> collect(a,find(a,sin($1)));
+(1+q+d+q*d+d*p+p)*sin(y)+(1+q+d+q*d+d*p+p)*sin(x)
+> collect(a,@{find(a,sin($1)),p,q@});
+(1+(1+d)*p+d+q*(1+d))*sin(x)+(1+(1+d)*p+d+q*(1+d))*sin(y)
+> collect(a,@{find(a,sin($1)),d@});
+(1+q+d*(1+q+p)+p)*sin(y)+(1+q+d*(1+q+p)+p)*sin(x)
+@end example
 
 @subsection Degree and coefficients
 @cindex @code{degree()}
@@ -3799,6 +4034,7 @@ will print out:
     @{(-\ln(x))@}+@{(-\gamma_E)@} x+@{(1/12 \pi^2)@} x^@{2@}+\mathcal@{O@}(x^3)
 @end example
 
+@cindex Tree traversal
 If you need any fancy special output format, e.g. for interfacing GiNaC
 with other algebra systems or for producing code for different
 programming languages, you can always traverse the expression tree yourself:
@@ -3806,8 +4042,8 @@ programming languages, you can always traverse the expression tree yourself:
 @example
 static void my_print(const ex & e)
 @{
-    if (is_ex_of_type(e, function))
-        cout << ex_to_function(e).get_name();
+    if (is_a<function>(e))
+        cout << ex_to<function>(e).get_name();
     else
         cout << e.bp->class_name();
     cout << "(";
@@ -4154,7 +4390,7 @@ function that does so, in this case the one in class @code{numeric}:
 @example
 static ex cos_evalf(const ex & x)
 @{
-    return cos(ex_to_numeric(x));
+    return cos(ex_to<numeric>(x));
 @}
 @end example
 
@@ -4323,7 +4559,7 @@ private:
     string str;
 @};
 
-GIANC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
+GINAC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
 @end example
 
 The @code{GINAC_DECLARE_REGISTERED_CLASS} and @code{GINAC_IMPLEMENT_REGISTERED_CLASS}
@@ -4552,7 +4788,7 @@ strings in algebraic expressions. Let's confirm that the RTTI works:
 
 @example
 ex e = mystring("Hello, world!");
-cout << is_ex_of_type(e, mystring) << endl;
+cout << is_a<mystring>(e) << endl;
  // -> 1 (true)
 
 cout << e.bp->class_name() << endl;
@@ -4702,19 +4938,12 @@ implement for terminal classes like the described string class is
 which will allow GiNaC to compare and canonicalize expressions much more
 efficiently.
 
-You can, of course, also add your own new member functions. In this case you
-will probably want to define a little helper function like
-
-@example
-inline const mystring &ex_to_mystring(const ex &e)
-@{
-    return static_cast<const mystring &>(*e.bp);
-@}
-@end example
-
-that let's you get at the object inside an expression (after you have
-verified that the type is correct) so you can call member functions that are
-specific to the class.
+You can, of course, also add your own new member functions. Remember,
+that the RTTI may be used to get information about what kinds of objects
+you are dealing with (the position in the class hierarchy) and that you
+can always extract the bare object from an @code{ex} by stripping the
+@code{ex} off using the @code{ex_to<mystring>(e)} function when that
+should become a need.
 
 That's it. May the source be with you!