@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
ex HermitePoly(const symbol & x, int n)
// Trott's constant in scientific notation:
numeric trott("1.0841015122311136151E-2");
- cout << two*p << endl; // floating point 6.283...
+ std::cout << two*p << std::endl; // floating point 6.283...
@}
@end example
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
void foo()
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
// some very important constants:
in other CAS or like expressions involving numerical variables in C.
The necessary operators @code{+}, @code{-}, @code{*} and @code{/} have
been overloaded to achieve this goal. When you run the following
-program, the constructor for an object of type @code{mul} is
+code snippet, the constructor for an object of type @code{mul} is
automatically called to hold the product of @code{a} and @code{b} and
then the constructor for an object of type @code{add} is called to hold
the sum of that @code{mul} object and the number one:
@example
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-int main()
-@{
+ ...
symbol a("a"), b("b");
ex MyTerm = 1+a*b;
- // ...
-@}
+ ...
@end example
@cindex @code{pow()}
statement @code{pow(x,2);} to represent @code{x} squared. This direct
construction is necessary since we cannot safely overload the constructor
@code{^} in C++ to construct a @code{power} object. If we did, it would
-have several counterintuitive effects:
+have several counterintuitive and undesired effects:
@itemize @bullet
@item
instance, all trigonometric and hyperbolic functions are implemented
(@xref{Built-in Functions}, for a complete list).
-These functions are all objects of class @code{function}. They accept one
-or more expressions as arguments and return one expression. If the arguments
-are not numerical, the evaluation of the function may be halted, as it
-does in the next example:
+These functions are all objects of class @code{function}. They accept
+one or more expressions as arguments and return one expression. If the
+arguments are not numerical, the evaluation of the function may be
+halted, as it does in the next example, showing how a function returns
+itself twice and finally an expression that may be really useful:
@cindex Gamma function
@cindex @code{subs()}
@example
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-int main()
-@{
- symbol x("x"), y("y");
-
+ ...
+ symbol x("x"), y("y");
ex foo = x+y/2;
- cout << "tgamma(" << foo << ") -> " << tgamma(foo) << endl;
+ cout << tgamma(foo) << endl;
+ // -> tgamma(x+(1/2)*y)
ex bar = foo.subs(y==1);
- cout << "tgamma(" << bar << ") -> " << tgamma(bar) << endl;
+ cout << tgamma(bar) << endl;
+ // -> tgamma(x+1/2)
ex foobar = bar.subs(x==7);
- cout << "tgamma(" << foobar << ") -> " << tgamma(foobar) << endl;
-@}
-@end example
-
-This program shows how the function returns itself twice and finally an
-expression that may be really useful:
-
-@example
-tgamma(x+(1/2)*y) -> tgamma(x+(1/2)*y)
-tgamma(x+1/2) -> tgamma(x+1/2)
-tgamma(15/2) -> (135135/128)*Pi^(1/2)
+ cout << tgamma(foobar) << endl;
+ // -> (135135/128)*Pi^(1/2)
+ ...
@end example
Besides evaluation most of these functions allow differentiation, series
@itemize @bullet
+@cindex contravariant
+@cindex covariant
+@cindex variance
@item Index objects are of class @code{idx} or a subclass. Every index has
a @dfn{value} and a @dfn{dimension} (which is the dimension of the space
the index lives in) which can both be arbitrary expressions but are usually
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@end example
@cindex @code{get_free_indices()}
+@cindex Dummy index
@subsection Dummy indices
GiNaC treats certain symbolic index pairs as @dfn{dummy indices} meaning
@subsection Linear algebra
The @code{matrix} class can be used with indices to do some simple linear
-algebra (products of vectors and matrices, traces and scalar products):
+algebra (linear combinations and products of vectors and matrices, traces
+and scalar products):
@example
@{
idx i(symbol("i"), 2), j(symbol("j"), 2);
symbol x("x"), y("y");
- matrix A(2, 2), X(2, 1);
- A.set(0, 0, 1); A.set(0, 1, 2);
- A.set(1, 0, 3); A.set(1, 1, 4);
- X.set(0, 0, x); X.set(1, 0, y);
+ matrix A(2, 2, lst(1, 2, 3, 4)), X(2, 1, lst(x, y));
cout << indexed(A, i, i) << endl;
// -> 5
cout << e.simplify_indexed() << endl;
// -> [[ [[2*y+x]], [[4*y+3*x]] ]].i
- e = indexed(A, i, j) * indexed(X, i);
+ e = indexed(A, i, j) * indexed(X, i) + indexed(X, j) * 2;
cout << e.simplify_indexed() << endl;
- // -> [[ [[3*y+x,4*y+2*x]] ]].j
+ // -> [[ [[3*y+3*x,6*y+2*x]] ]].j
@}
@end example
-You can of course obtain the same results with the @code{matrix::mul()}
-and @code{matrix::trace()} methods but with indices you don't have to
-worry about transposing matrices.
+You can of course obtain the same results with the @code{matrix::add()},
+@code{matrix::mul()} and @code{matrix::trace()} methods but with indices you
+don't have to worry about transposing matrices.
Matrix indices always start at 0 and their dimension must match the number
of rows/columns of the matrix. Matrices with one row or one column are
vectors and can have one or two indices (it doesn't matter whether it's a
-row or a columnt vector). Other matrices must have two indices.
+row or a column vector). Other matrices must have two indices.
You should be careful when using indices with variance on matrices. GiNaC
doesn't look at the variance and doesn't know that @samp{F~mu~nu} and
example:
@example
-#include <ginac/ginac.h>
-using namespace GiNaC;
-
-int main()
-@{
- ex x = numeric(1.0);
-
- cout << "As method: " << sin(x).evalf() << endl;
- cout << "As function: " << evalf(sin(x)) << endl;
-@}
+ ...
+ cout << "As method: " << sin(1).evalf() << endl;
+ cout << "As function: " << evalf(sin(1)) << endl;
+ ...
@end example
@cindex @code{subs()}
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@end example
+@subsection Square-free decomposition
+@cindex square-free decomposition
+@cindex factorization
+@cindex @code{sqrfree()}
+
+GiNaC still lacks proper factorization support. Some form of
+factorization is, however, easily implemented by noting that factors
+appearing in a polynomial with power two or more also appear in the
+derivative and hence can easily be found by computing the GCD of the
+original polynomial and its derivatives. Any system has an interface
+for this so called square-free factorization. So we provide one, too:
+@example
+ex sqrfree(const ex & a, const lst & l = lst());
+@end example
+Here is an example that by the way illustrates how the result may depend
+on the order of differentiation:
+@example
+ ...
+ symbol x("x"), y("y");
+ ex BiVarPol = expand(pow(x-2*y*x,3) * pow(x+y,2) * (x-y));
+
+ cout << sqrfree(BiVarPol, lst(x,y)) << endl;
+ // -> (y+x)^2*(-1+6*y+8*y^3-12*y^2)*(y-x)*x^3
+
+ cout << sqrfree(BiVarPol, lst(y,x)) << endl;
+ // -> (1-2*y)^3*(y+x)^2*(-y+x)*x^3
+
+ cout << sqrfree(BiVarPol) << endl;
+ // -> depending on luck, any of the above
+ ...
+@end example
+
+
@node Rational Expressions, Symbolic Differentiation, Polynomial Arithmetic, Methods and Functions
@c node-name, next, previous, up
@section Rational expressions
symbol x("x");
ex t1 = (pow(x,2) + 2*x + 1)/(x + 1);
ex t2 = (pow(sin(x),2) + 2*sin(x) + 1)/(sin(x) + 1);
- cout << "t1 is " << t1.normal() << endl;
- cout << "t2 is " << t2.normal() << endl;
+ std::cout << "t1 is " << t1.normal() << std::endl;
+ std::cout << "t2 is " << t2.normal() << std::endl;
@}
@end example
int main()
@{
for (unsigned i=0; i<11; i+=2)
- cout << EulerNumber(i) << endl;
+ std::cout << EulerNumber(i) << std::endl;
return 0;
@}
@end example
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
int main()
@{
+ using std::cout; // just for fun, another way of...
+ using std::endl; // ...dealing with this namespace std.
ex pi_frac;
for (int i=2; i<12; i+=2) @{
pi_frac = mechain_pi(i);
#include <string>
#include <stdexcept>
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
expression a unique name:
@example
-#include <ginac/ginac.h>
#include <fstream>
+using namespace std;
+#include <ginac/ginac.h>
using namespace GiNaC;
int main()
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@example
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@example
#include <ginac/ginac.h>
-using namespace GiNaC;
int main(void)
@{
- symbol x("x");
- ex a = sin(x);
- cout << "Derivative of " << a << " is " << a.diff(x) << endl;
+ GiNaC::symbol x("x");
+ GiNaC::ex a = GiNaC::sin(x);
+ std::cout << "Derivative of " << a
+ << " is " << a.diff(x) << std::endl;
return 0;
@}
@end example