]> www.ginac.de Git - ginac.git/commitdiff
 author Christian Bauer Mon, 9 Apr 2001 21:33:17 +0000 (21:33 +0000) committer Christian Bauer Mon, 9 Apr 2001 21:33:17 +0000 (21:33 +0000)
(l/t)coeff() and collect()
- added examples for specialized expression output by tree-traversal and
with the aid of archives

@@ -800,7 +800,7 @@ for instance) will always reveal their difference.  Watch out, please.
Although symbols can be assigned expressions for internal reasons, you
should not do it (and we are not going to tell you how it is done).  If
you want to replace a symbol with something else in an expression, you
-can use the expression's @code{.subs()} method (@xref{Substituting Symbols},
+can use the expression's @code{.subs()} method (@xref{Substituting Expressions},
for more information).

@@ -1413,7 +1413,7 @@ variance. By using it you only have to define the index once.
Sometimes you will want to substitute one symbolic index with another
symbolic or numeric index, for example when calculating one specific element
of a tensor expression. This is done with the @code{.subs()} method, as it
-is done for symbols (see @ref{Substituting Symbols}).
+is done for symbols (see @ref{Substituting Expressions}).

You have two possibilities here. You can either substitute the whole index
by another index or expression:
@@ -1799,7 +1799,7 @@ avoided.

-* Substituting Symbols::
+* Substituting Expressions::
* Polynomial Arithmetic::           Working with polynomials.
* Rational Expressions::            Working with rational functions.
* Symbolic Differentiation::
@@ -1809,7 +1809,7 @@ avoided.

-@node Information About Expressions, Substituting Symbols, Methods and Functions, Methods and Functions
+@node Information About Expressions, Substituting Expressions, Methods and Functions, Methods and Functions
@c    node-name, next, previous, up

@@ -2010,12 +2010,13 @@ GiNaC to establish a canonical sort order for terms, and using it to compare
expressions will give very surprising results.

-@node Substituting Symbols, Polynomial Arithmetic, Information About Expressions, Methods and Functions
+@node Substituting Expressions, Polynomial Arithmetic, Information About Expressions, Methods and Functions
@c    node-name, next, previous, up
-@section Substituting symbols
+@section Substituting expressions
@cindex @code{subs()}

-Symbols can be replaced with expressions via the @code{.subs()} method:
+Algebraic objects inside expressions can be replaced with arbitrary
+expressions via the @code{.subs()} method:

@example
ex ex::subs(const ex & e);
@@ -2023,30 +2024,55 @@ ex ex::subs(const lst & syms, const lst & repls);
@end example

In the first form, @code{subs()} accepts a relational of the form
-@samp{symbol == expression} or a @code{lst} of such relationals. E.g.
+@samp{object == expression} or a @code{lst} of such relationals:

@example
@{
symbol x("x"), y("y");
+
ex e1 = 2*x^2-4*x+3;
cout << "e1(7) = " << e1.subs(x == 7) << endl;
+     // -> 73
+
ex e2 = x*y + x;
cout << "e2(-2, 4) = " << e2.subs(lst(x == -2, y == 4)) << endl;
+     // -> -10
@}
@end example

-will print @samp{73} and @samp{-10}, respectively.
+@code{subs()} performs syntactic substitution of any complete algebraic
+object; it does not try to match sub-expressions as is demonstrated by the
+following example:
+
+@example
+@{
+    symbol x("x"), y("y"), z("z");
+
+    ex e1 = pow(x+y, 2);
+    cout << e1.subs(x+y == 4) << endl;
+     // -> 16
+
+    ex e2 = sin(x)*cos(x);
+    cout << e2.subs(sin(x) == cos(x)) << endl;
+     // -> cos(x)^2
+
+    ex e3 = x+y+z;
+    cout << e3.subs(x+y == 4) << endl;
+     // -> x+y+z
+     // (and not 4+z as one might expect)
+@}
+@end example

If you specify multiple substitutions, they are performed in parallel, so e.g.
@code{subs(lst(x == y, y == x))} exchanges @samp{x} and @samp{y}.

-The second form of @code{subs()} takes two lists, one for the symbols and
-one for the expressions to be substituted (both lists must contain the same
-number of elements). Using this form, you would write @code{subs(lst(x, y), lst(y, x))}
-to exchange @samp{x} and @samp{y}.
+The second form of @code{subs()} takes two lists, one for the objects to be
+replaced and one for the expressions to be substituted (both lists must
+contain the same number of elements). Using this form, you would write
+@code{subs(lst(x, y), lst(y, x))} to exchange @samp{x} and @samp{y}.

-@node Polynomial Arithmetic, Rational Expressions, Substituting Symbols, Methods and Functions
+@node Polynomial Arithmetic, Rational Expressions, Substituting Expressions, Methods and Functions
@c    node-name, next, previous, up
@section Polynomial arithmetic

@@ -2158,6 +2184,29 @@ As always, the exact output may vary between different versions of GiNaC
or even from run to run since the internal canonical ordering is not
within the user's sphere of influence.

+@code{degree()}, @code{ldegree()}, @code{coeff()}, @code{lcoeff()},
+@code{tcoeff()} and @code{collect()} can also be used to a certain degree
+with non-polynomial expressions as they not only work with symbols but with
+constants, functions and indexed objects as well:
+
+@example
+@{
+    symbol a("a"), b("b"), c("c");
+    idx i(symbol("i"), 3);
+
+    ex e = pow(sin(x) - cos(x), 4);
+    cout << e.degree(cos(x)) << endl;
+     // -> 4
+    cout << e.expand().coeff(sin(x), 3) << endl;
+     // -> -4*cos(x)
+
+    e = indexed(a+b, i) * indexed(b+c, i);
+    e = e.expand(expand_options::expand_indexed);
+    cout << e.collect(indexed(b, i)) << endl;
+     // -> a.i*c.i+(a.i+c.i)*b.i+b.i^2
+@}
+@end example
+

@subsection Polynomial division
@cindex polynomial division
@@ -2747,6 +2796,50 @@ add, hash=0x0, flags=0x3, nops=2
This kind of output is also available in @command{ginsh} as the @code{print()}
function.

+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:
+
+@example
+static void my_print(const ex & e)
+@{
+    if (is_ex_of_type(e, function))
+        cout << ex_to_function(e).get_name();
+    else
+        cout << e.bp->class_name();
+    cout << "(";
+    unsigned n = e.nops();
+    if (n)
+        for (unsigned i=0; i<n; i++) @{
+            my_print(e.op(i));
+            if (i != n-1)
+                cout << ",";
+        @}
+    else
+        cout << e;
+    cout << ")";
+@}
+
+int main(void)
+@{
+    my_print(pow(3, x) - 2 * sin(y / Pi)); cout << endl;
+    return 0;
+@}
+@end example
+
+This will produce
+
+@example
+symbol(y))),numeric(-2)))
+@end example
+
+If you need an output format that makes it possible to accurately
+reconstruct an expression by feeding the output to a suitable parser or
+object factory, you should consider storing the expression in an
+@code{archive} object and reading the object properties from there.
+See the section on archiving for more information.
+

@subsection Expression input
@cindex input of expressions
@@ -2887,6 +2980,92 @@ have had no effect because the @code{x} in @code{ex1} would have been a
different symbol than the @code{x} which was defined at the beginning of
the program, altough both would appear as @samp{x} when printed.

+You can also use the information stored in an @code{archive} object to
+output expressions in a format suitable for exact reconstruction. The
+@code{archive} and @code{archive_node} classes have a couple of member
+functions that let you access the stored properties:
+
+@example
+static void my_print2(const archive_node & n)
+@{
+    string class_name;
+    n.find_string("class", class_name);
+    cout << class_name << "(";
+
+    vector<archive_node::property_info> p;
+    n.get_properties(p);
+
+    unsigned num = p.size();
+    for (unsigned i=0; i<num; i++) @{
+        const string &name = p[i].name;
+        if (name == "class")
+            continue;
+        cout << name << "=";
+
+        unsigned count = p[i].count;
+        if (count > 1)
+            cout << "@{";
+
+        for (unsigned j=0; j<count; j++) @{
+            switch (p[i].type) @{
+                case archive_node::PTYPE_BOOL: @{
+                    bool x;
+                    n.find_bool(name, x);
+                    cout << (x ? "true" : "false");
+                    break;
+                @}
+                case archive_node::PTYPE_UNSIGNED: @{
+                    unsigned x;
+                    n.find_unsigned(name, x);
+                    cout << x;
+                    break;
+                @}
+                case archive_node::PTYPE_STRING: @{
+                    string x;
+                    n.find_string(name, x);
+                    cout << '\"' << x << '\"';
+                    break;
+                @}
+                case archive_node::PTYPE_NODE: @{
+                    const archive_node &x = n.find_ex_node(name, j);
+                    my_print2(x);
+                    break;
+                @}
+            @}
+
+            if (j != count-1)
+                cout << ",";
+        @}
+
+        if (count > 1)
+            cout << "@}";
+
+        if (i != num-1)
+            cout << ",";
+    @}
+
+    cout << ")";
+@}
+
+int main(void)
+@{
+    ex e = pow(2, x) - y;
+    archive ar(e, "e");
+    my_print2(ar.get_top_node(0)); cout << endl;
+    return 0;
+@}
+@end example
+
+This will produce:
+
+@example