This is a tutorial that documents GiNaC @value{VERSION}, an open
framework for symbolic computation within the C++ programming language.
-Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
+Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1999-2000 Johannes Gutenberg University Mainz, Germany
+Copyright @copyright{} 1999-2001 Johannes Gutenberg University Mainz, Germany
@sp 2
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@section License
The GiNaC framework for symbolic computation within the C++ programming
-language is Copyright @copyright{} 1999-2000 Johannes Gutenberg
+language is Copyright @copyright{} 1999-2001 Johannes Gutenberg
University Mainz, Germany.
This program is free software; you can redistribute it and/or
ex MyEx5 = MyEx4 + 1; // similar to above
@end example
-Expressions are handles to other more fundamental objects, that many
-times contain other expressions thus creating a tree of expressions
+Expressions are handles to other more fundamental objects, that often
+contain other expressions thus creating a tree of expressions
(@xref{Internal Structures}, for particular examples). Most methods on
@code{ex} therefore run top-down through such an expression tree. For
example, the method @code{has()} scans recursively for occurrences of
helpers) are internally derived from one abstract base class called
@code{basic}. You do not have to deal with objects of class
@code{basic}, instead you'll be dealing with symbols, numbers,
-containers of expressions and so on. You'll soon learn in this chapter
-how many of the functions on symbols are really classes. This is
-because simple symbolic arithmetic is not supported by languages like
-C++ so in a certain way GiNaC has to implement its own arithmetic.
+containers of expressions and so on.
@cindex container
@cindex atom
To get an idea about what kinds of symbolic composits may be built we
-have a look at the most important classes in the class hierarchy. The
-oval classes are atomic ones and the squared classes are containers.
-The dashed line symbolizes a `points to' or `handles' relationship while
-the solid lines stand for `inherits from' relationship in the class
-hierarchy:
+have a look at the most important classes in the class hierarchy and
+some of the relations among the classes:
@image{classhierarchy}
-Some of the classes shown here (the ones sitting in white boxes) are
-abstract base classes that are of no interest at all for the user. They
-are used internally in order to avoid code duplication if two or more
-classes derived from them share certain features. An example would be
-@code{expairseq}, which is a container for a sequence of pairs each
-consisting of one expression and a number (@code{numeric}). What
-@emph{is} visible to the user are the derived classes @code{add} and
-@code{mul}, representing sums of terms and products, respectively.
-@xref{Internal Structures}, where these two classes are described in
-more detail.
-
-At this point, we only summarize what kind of mathematical objects are
-stored in the different classes in above diagram in order to give you a
-overview:
+The abstract classes shown here (the ones without drop-shadow) are of no
+interest for the user. They are used internally in order to avoid code
+duplication if two or more classes derived from them share certain
+features. An example is @code{expairseq}, a container for a sequence of
+pairs each consisting of one expression and a number (@code{numeric}).
+What @emph{is} visible to the user are the derived classes @code{add}
+and @code{mul}, representing sums and products. @xref{Internal
+Structures}, where these two classes are described in more detail. The
+following table shortly summarizes what kinds of mathematical objects
+are stored in the different classes:
@cartouche
@multitable @columnfractions .22 .78
@math{Pi}
@end ifnottex
@item @code{numeric} @tab All kinds of numbers, @math{42}, @math{7/3*I}, @math{3.14159}@dots{}
-@item @code{add} @tab Sums like @math{x+y} or @math{a+(2*b)+3}
-@item @code{mul} @tab Products like @math{x*y} or @math{a*(x+y+z)*b*2}
+@item @code{add} @tab Sums like @math{x+y} or @math{a-(2*b)+3}
+@item @code{mul} @tab Products like @math{x*y} or @math{2*a^2*(x+y+z)/b}
@item @code{power} @tab Exponentials such as @math{x^2}, @math{a^b},
@tex
$\sqrt{2}$
@code{sqrt(}@math{2}@code{)}
@end ifnottex
@dots{}
-@item @code{pseries} @tab Power Series, e.g. @math{x+1/6*x^3+1/120*x^5+O(x^7)}
+@item @code{pseries} @tab Power Series, e.g. @math{x-1/6*x^3+1/120*x^5+O(x^7)}
@item @code{function} @tab A symbolic function like @math{sin(2*x)}
@item @code{lst} @tab Lists of expressions [@math{x}, @math{2*y}, @math{3+z}]
@item @code{matrix} @tab @math{n}x@math{m} matrices of expressions
@item @code{relational} @tab A relation like the identity @math{x}@code{==}@math{y}
-@item @code{color} @tab Element of the @math{SU(3)} Lie-algebra
+@item @code{color}, @code{coloridx} @tab Element and index of the @math{SU(3)} Lie-algebra
@item @code{isospin} @tab Element of the @math{SU(2)} Lie-algebra
-@item @code{idx} @tab Index of a tensor object
-@item @code{coloridx} @tab Index of a @math{SU(3)} tensor
+@item @code{idx} @tab Index of a general tensor object
@end multitable
@end cartouche
They are created by simply using the C++ operators @code{==}, @code{!=},
@code{<}, @code{<=}, @code{>} and @code{>=} between two expressions.
-@xref{Mathematical functions}, for examples where various applications of
-the @code{.subs()} method show how objects of class relational are used
-as arguments. There they provide an intuitive syntax for substitutions.
-They can also used for creating systems of equations that are to be
-solved for unknown variables. More applications of this class will
-appear throughout the next chapters.
-
+@xref{Mathematical functions}, for examples where various applications
+of the @code{.subs()} method show how objects of class relational are
+used as arguments. There they provide an intuitive syntax for
+substitutions. They are also used as arguments to the @code{ex::series}
+method, where the left hand side of the relation specifies the variable
+to expand in and the right hand side the expansion point. They can also
+be used for creating systems of equations that are to be solved for
+unknown variables. But the most common usage of objects of this class
+is rather inconspicuous in statements of the form @code{if
+(expand(pow(a+b,2))==a*a+2*a*b+b*b) @{...@}}. Here, an implicit
+conversion from @code{relational} to @code{bool} takes place. Note,
+however, that @code{==} here does not perform any simplifications, hence
+@code{expand()} must be called explicitly.
@node Methods and Functions, Information About Expressions, Relations, Top
@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{info()}
Sometimes it's useful to check whether a given expression is a plain number,
bool ex::info(unsigned flag);
@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}:
+
+@example
+@{
+ @dots{}
+ if (is_ex_of_type(e, numeric))
+ 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}
(@xref{The Class Hierarchy}, for a list of all classes). This is most useful,
@item @code{crational_polynomial}
@tab @dots{}a polynomial with (possibly complex) rational coefficients (such as @math{2/3+7/2*I})
@item @code{rational_function}
-@tab @dots{}a rational function
+@tab @dots{}a rational function (@math{x+y}, @math{z/(x+y)})
+@item @code{algebraic}
+@tab @dots{}an algebraic object (@math{sqrt(2)}, @math{sqrt(x)-1})
@end multitable
@end cartouche
for checking whether one expression is equal to another, or equal to zero,
respectively.
-@strong{Warning:} You will also find a @code{ex::compare()} method in the
+@strong{Warning:} You will also find an @code{ex::compare()} method in the
GiNaC header files. This method is however only to be used internally by
GiNaC to establish a canonical sort order for terms, and using it to compare
expressions will give very surprising results.
@cindex simplification
@cindex temporary replacement
-Some basic from of simplification of expressions is called for frequently.
+Some basic form of simplification of expressions is called for frequently.
GiNaC provides the method @code{.normal()}, which converts a rational function
into an equivalent rational function of the form @samp{numerator/denominator}
where numerator and denominator are coprime. If the input expression is already
@tab exponential function
@item @code{log(x)}
@tab natural logarithm
+@item @code{Li2(x)}
+@tab Dilogarithm
@item @code{zeta(x)}
@tab Riemann's zeta function
@item @code{zeta(n, x)}
@cindex branch cut
For functions that have a branch cut in the complex plane GiNaC follows
-the conventions for C++ as defined in the ANSI standard. In particular:
-the natural logarithm (@code{log}) and the square root (@code{sqrt})
-both have their branch cuts running along the negative real axis where
-the points on the axis itself belong to the upper part.
+the conventions for C++ as defined in the ANSI standard as far as
+possible. In particular: the natural logarithm (@code{log}) and the
+square root (@code{sqrt}) both have their branch cuts running along the
+negative real axis where the points on the axis itself belong to the
+upper part (i.e. continuous with quadrant II). The inverse
+trigonometric and hyperbolic functions are not defined for complex
+arguments by the C++ standard, however. In GiNaC we follow the
+conventions used by CLN, which in turn follow the carefully designed
+definitions in the Common Lisp standard. It should be noted that this
+convention is identical to the one used by the C99 standard and by most
+serious CAS. It is to be expected that future revisions of the C++
+standard incorporate these functions in the complex domain in a manner
+compatible with C99.
@node Input/Output, Extending GiNaC, Built-in Functions, Methods and Functions
@menu
* What does not belong into GiNaC:: What to avoid.
* Symbolic functions:: Implementing symbolic functions.
+* Adding classes:: Defining new algebraic classes.
@end menu
provided by @acronym{CLN} are much better suited.
-@node Symbolic functions, A Comparison With Other CAS, What does not belong into GiNaC, Extending GiNaC
+@node Symbolic functions, Adding classes, What does not belong into GiNaC, Extending GiNaC
@c node-name, next, previous, up
@section Symbolic functions
The easiest and most instructive way to start with is probably to
-implement your own function. Objects of class @code{function} are
-inserted into the system via a kind of `registry'. They get a serial
-number that is used internally to identify them but you usually need not
-worry about this. What you have to care for are functions that are
-called when the user invokes certain methods. These are usual
+implement your own function. GiNaC's functions are objects of class
+@code{function}. The preprocessor is then used to convert the function
+names to objects with a corresponding serial number that is used
+internally to identify them. You usually need not worry about this
+number. New functions may be inserted into the system via a kind of
+`registry'. It is your responsibility to care for some functions that
+are called when the user invokes certain methods. These are usual
C++-functions accepting a number of @code{ex} as arguments and returning
one @code{ex}. As an example, if we have a look at a simplified
implementation of the cosine trigonometric function, we first need a
implement does have a pole somewhere in the complex plane, you need to
write another method for Laurent expansion around that point.
-Now that all the ingrediences for @code{cos} have been set up, we need
+Now that all the ingredients for @code{cos} have been set up, we need
to tell the system about it. This is done by a macro and we are not
going to descibe how it expands, please consult your preprocessor if you
are curious:
assure you that functions are GiNaC's most macro-intense classes. We
have done our best to avoid macros where we can.)
+
+@node Adding classes, A Comparison With Other CAS, Symbolic functions, Extending GiNaC
+@c node-name, next, previous, up
+@section Adding classes
+
+If you are doing some very specialized things with GiNaC you may find that
+you have to implement your own algebraic classes to fit your needs. This
+section will explain how to do this by giving the example of a simple
+'string' class. After reading this section you will know how to properly
+declare a GiNaC class and what the minimum required member functions are
+that you have to implement. We only cover the implementation of a 'leaf'
+class here (i.e. one that doesn't contain subexpressions). Creating a
+container class like, for example, a class representing tensor products is
+more involved but this section should give you enough information so you can
+consult the source to GiNaC's predefined classes if you want to implement
+something more complicated.
+
+@subsection GiNaC's run-time type information system
+
+@cindex hierarchy of classes
+@cindex RTTI
+All algebraic classes (that is, all classes that can appear in expressions)
+in GiNaC are direct or indirect subclasses of the class @code{basic}. So a
+@code{basic *} (which is essentially what an @code{ex} is) represents a
+generic pointer to an algebraic class. Occasionally it is necessary to find
+out what the class of an object pointed to by a @code{basic *} really is.
+Also, for the unarchiving of expressions it must be possible to find the
+@code{unarchive()} function of a class given the class name (as a string). A
+system that provides this kind of information is called a run-time type
+information (RTTI) system. The C++ language provides such a thing (see the
+standard header file @file{<typeinfo>}) but for efficiency reasons GiNaC
+implements its own, simpler RTTI.
+
+The RTTI in GiNaC is based on two mechanisms:
+
+@itemize @bullet
+
+@item
+The @code{basic} class declares a member variable @code{tinfo_key} which
+holds an unsigned integer that identifies the object's class. These numbers
+are defined in the @file{tinfos.h} header file for the built-in GiNaC
+classes. They all start with @code{TINFO_}.
+
+@item
+By means of some clever tricks with static members, GiNaC maintains a list
+of information for all classes derived from @code{basic}. The information
+available includes the class names, the @code{tinfo_key}s, and pointers
+to the unarchiving functions. This class registry is defined in the
+@file{registrar.h} header file.
+
+@end itemize
+
+The disadvantage of this proprietary RTTI implementation is that there's
+a little more to do when implementing new classes (C++'s RTTI works more
+or less automatic) but don't worry, most of the work is simplified by
+macros.
+
+@subsection A minimalistic example
+
+Now we will start implementing a new class @code{mystring} that allows
+placing character strings in algebraic expressions (this is not very useful,
+but it's just an example). This class will be a direct subclass of
+@code{basic}. You can use this sample implementation as a starting point
+for your own classes.
+
+The code snippets given here assume that you have included some header files
+as follows:
+
+@example
+#include <iostream>
+#include <string>
+#include <stdexcept>
+using namespace std;
+
+#include <ginac/ginac.h>
+using namespace GiNaC;
+@end example
+
+The first thing we have to do is to define a @code{tinfo_key} for our new
+class. This can be any arbitrary unsigned number that is not already taken
+by one of the existing classes but it's better to come up with something
+that is unlikely to clash with keys that might be added in the future. The
+numbers in @file{tinfos.h} are modeled somewhat after the class hierarchy
+which is not a requirement but we are going to stick with this scheme:
+
+@example
+const unsigned TINFO_mystring = 0x42420001U;
+@end example
+
+Now we can write down the class declaration. The class stores a C++
+@code{string} and the user shall be able to construct a @code{mystring}
+object from a C or C++ string:
+
+@example
+class mystring : public basic
+@{
+ GINAC_DECLARE_REGISTERED_CLASS(mystring, basic)
+
+public:
+ mystring(const string &s);
+ mystring(const char *s);
+
+private:
+ string str;
+@};
+
+GIANC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
+@end example
+
+The @code{GINAC_DECLARE_REGISTERED_CLASS} and @code{GINAC_IMPLEMENT_REGISTERED_CLASS}
+macros are defined in @file{registrar.h}. They take the name of the class
+and its direct superclass as arguments and insert all required declarations
+for the RTTI system. The @code{GINAC_DECLARE_REGISTERED_CLASS} should be
+the first line after the opening brace of the class definition. The
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS} may appear anywhere else in the
+source (at global scope, of course, not inside a function).
+
+@code{GINAC_DECLARE_REGISTERED_CLASS} contains, among other things the
+declarations of the default and copy constructor, the destructor, the
+assignment operator and a couple of other functions that are required. It
+also defines a type @code{inherited} which refers to the superclass so you
+don't have to modify your code every time you shuffle around the class
+hierarchy. @code{GINAC_IMPLEMENT_REGISTERED_CLASS} implements the copy
+constructor, the destructor and the assignment operator.
+
+Now there are nine member functions we have to implement to get a working
+class:
+
+@itemize
+
+@item
+@code{mystring()}, the default constructor.
+
+@item
+@code{void destroy(bool call_parent)}, which is used in the destructor and the
+assignment operator to free dynamically allocated members. The @code{call_parent}
+specifies whether the @code{destroy()} function of the superclass is to be
+called also.
+
+@item
+@code{void copy(const mystring &other)}, which is used in the copy constructor
+and assignment operator to copy the member variables over from another
+object of the same class.
+
+@item
+@code{void archive(archive_node &n)}, the archiving function. This stores all
+information needed to reconstruct an object of this class inside an
+@code{archive_node}.
+
+@item
+@code{mystring(const archive_node &n, const lst &sym_lst)}, the unarchiving
+constructor. This constructs an instance of the class from the information
+found in an @code{archive_node}.
+
+@item
+@code{ex unarchive(const archive_node &n, const lst &sym_lst)}, the static
+unarchiving function. It constructs a new instance by calling the unarchiving
+constructor.
+
+@item
+@code{int compare_same_type(const basic &other)}, which is used internally
+by GiNaC to establish a canonical sort order for terms. It returns 0, +1 or
+-1, depending on the relative order of this object and the @code{other}
+object. If it returns 0, the objects are considered equal.
+@strong{Note:} This has nothing to do with the (numeric) ordering
+relationship expressed by @code{<}, @code{>=} etc (which cannot be defined
+for non-numeric classes). For example, @code{numeric(1).compare_same_type(numeric(2))}
+may return +1 even though 1 is clearly smaller than 2. Every GiNaC class
+must provide a @code{compare_same_type()} function, even those representing
+objects for which no reasonable algebraic ordering relationship can be
+defined.
+
+@item
+And, of course, @code{mystring(const string &s)} and @code{mystring(const char *s)}
+which are the two constructors we declared.
+
+@end itemize
+
+Let's proceed step-by-step. The default constructor looks like this:
+
+@example
+mystring::mystring() : inherited(TINFO_mystring)
+@{
+ // dynamically allocate resources here if required
+@}
+@end example
+
+The golden rule is that in all constructors you have to set the
+@code{tinfo_key} member to the @code{TINFO_*} value of your class. Otherwise
+it will be set by the constructor of the superclass and all hell will break
+loose in the RTTI. For your convenience, the @code{basic} class provides
+a constructor that takes a @code{tinfo_key} value, which we are using here
+(remember that in our case @code{inherited = basic}). If the superclass
+didn't have such a constructor, we would have to set the @code{tinfo_key}
+to the right value manually.
+
+In the default constructor you should set all other member variables to
+reasonable default values (we don't need that here since our @code{str}
+member gets set to an empty string automatically). The constructor(s) are of
+course also the right place to allocate any dynamic resources you require.
+
+Next, the @code{destroy()} function:
+
+@example
+void mystring::destroy(bool call_parent)
+@{
+ // free dynamically allocated resources here if required
+ if (call_parent)
+ inherited::destroy(call_parent);
+@}
+@end example
+
+This function is where we free all dynamically allocated resources. We don't
+have any so we're not doing anything here, but if we had, for example, used
+a C-style @code{char *} to store our string, this would be the place to
+@code{delete[]} the string storage. If @code{call_parent} is true, we have
+to call the @code{destroy()} function of the superclass after we're done
+(to mimic C++'s automatic invocation of superclass destructors where
+@code{destroy()} is called from outside a destructor).
+
+The @code{copy()} function just copies over the member variables from
+another object:
+
+@example
+void mystring::copy(const mystring &other)
+@{
+ inherited::copy(other);
+ str = other.str;
+@}
+@end example
+
+We can simply overwrite the member variables here. There's no need to worry
+about dynamically allocated storage. The assignment operator (which is
+automatically defined by @code{GINAC_IMPLEMENT_REGISTERED_CLASS}, as you
+recall) calls @code{destroy()} before it calls @code{copy()}. You have to
+explicitly call the @code{copy()} function of the superclass here so
+all the member variables will get copied.
+
+Next are the three functions for archiving. You have to implement them even
+if you don't plan to use archives, but the minimum required implementation
+is really simple. First, the archiving function:
+
+@example
+void mystring::archive(archive_node &n) const
+@{
+ inherited::archive(n);
+ n.add_string("string", str);
+@}
+@end example
+
+The only thing that is really required is calling the @code{archive()}
+function of the superclass. Optionally, you can store all information you
+deem necessary for representing the object into the passed
+@code{archive_node}. We are just storing our string here. For more
+information on how the archiving works, consult the @file{archive.h} header
+file.
+
+The unarchiving constructor is basically the inverse of the archiving
+function:
+
+@example
+mystring::mystring(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+@{
+ n.find_string("string", str);
+@}
+@end example
+
+If you don't need archiving, just leave this function empty (but you must
+invoke the unarchiving constructor of the superclass). Note that we don't
+have to set the @code{tinfo_key} here because it is done automatically
+by the unarchiving constructor of the @code{basic} class.
+
+Finally, the unarchiving function:
+
+@example
+ex mystring::unarchive(const archive_node &n, const lst &sym_lst)
+@{
+ return (new mystring(n, sym_lst))->setflag(status_flags::dynallocated);
+@}
+@end example
+
+You don't have to understand how exactly this works. Just copy these four
+lines into your code literally (replacing the class name, of course). It
+calls the unarchiving constructor of the class and unless you are doing
+something very special (like matching @code{archive_node}s to global
+objects) you don't need a different implementation.
+
+Our @code{compare_same_type()} function uses a provided function to compare
+the string members:
+
+@example
+int mystring::compare_same_type(const basic &other) const
+@{
+ const mystring &o = static_cast<const mystring &>(other);
+ int cmpval = str.compare(o.str);
+ if (cmpval == 0)
+ return 0;
+ else if (cmpval < 0)
+ return -1;
+ else
+ return 1;
+@}
+@end example
+
+Although this function takes a @code{basic &}, it will always be a reference
+to an object of exactly the same class (objects of different classes are not
+comparable), so the cast is safe. If this function returns 0, the two objects
+are considered equal (in the sense that @math{A-B=0}), so you should compare
+all relevant member variables.
+
+Now the only thing missing is our two new constructors:
+
+@example
+mystring::mystring(const string &s) : inherited(TINFO_mystring), str(s)
+@{
+ // dynamically allocate resources here if required
+@}
+
+mystring::mystring(const char *s) : inherited(TINFO_mystring), str(s)
+@{
+ // dynamically allocate resources here if required
+@}
+@end example
+
+No surprises here. We set the @code{str} member from the argument and
+remember to pass the right @code{tinfo_key} to the @code{basic} constructor.
+
+That's it! We now have a minimal working GiNaC class that can store
+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;
+ // -> 1 (true)
+
+cout << e.bp->class_name() << endl;
+ // -> mystring
+@end example
+
+Obviously it does. Let's see what the expression @code{e} looks like:
+
+@example
+cout << e << endl;
+ // -> [mystring object]
+@end example
+
+Hm, not exactly what we expect, but of course the @code{mystring} class
+doesn't yet know how to print itself. This is done in the @code{print()}
+member function. Let's say that we wanted to print the string surrounded
+by double quotes:
+
+@example
+class mystring : public basic
+@{
+ ...
+public:
+ void print(ostream &os, unsigned upper_precedence) const;
+ ...
+@};
+
+void mystring::print(ostream &os, unsigned upper_precedence) const
+@{
+ os << '\"' << str << '\"';
+@}
+@end example
+
+The @code{upper_precedence} argument is only required for container classes
+to correctly parenthesize the output. Let's try again to print the expression:
+
+@example
+cout << e << endl;
+ // -> "Hello, world!"
+@end example
+
+Much better. The @code{mystring} class can be used in arbitrary expressions:
+
+@example
+e += mystring("GiNaC rulez");
+cout << e << endl;
+ // -> "GiNaC rulez"+"Hello, world!"
+@end example
+
+(note that GiNaC's automatic term reordering is in effect here), or even
+
+@example
+e = pow(mystring("One string"), 2*sin(Pi-mystring("Another string")));
+cout << e << endl;
+ // -> "One string"^(2*sin(-"Another string"+Pi))
+@end example
+
+Whether this makes sense is debatable but remember that this is only an
+example. At least it allows you to implement your own symbolic algorithms
+for your objects.
+
+Note that GiNaC's algebraic rules remain unchanged:
+
+@example
+e = mystring("Wow") * mystring("Wow");
+cout << e << endl;
+ // -> "Wow"^2
+
+e = pow(mystring("First")-mystring("Second"), 2);
+cout << e.expand() << endl;
+ // -> -2*"First"*"Second"+"First"^2+"Second"^2
+@end example
+
+There's no way to, for example, make GiNaC's @code{add} class perform string
+concatenation. You would have to implement this yourself.
+
+@subsection Automatic evaluation
+
+@cindex @code{hold()}
+@cindex evaluation
+When dealing with objects that are just a little more complicated than the
+simple string objects we have implemented, chances are that you will want to
+have some automatic simplifications or canonicalizations performed on them.
+This is done in the evaluation member function @code{eval()}. Let's say that
+we wanted all strings automatically converted to lowercase with
+non-alphabetic characters stripped, and empty strings removed:
+
+@example
+class mystring : public basic
+@{
+ ...
+public:
+ ex eval(int level = 0) const;
+ ...
+@};
+
+ex mystring::eval(int level) const
+@{
+ string new_str;
+ for (int i=0; i<str.length(); i++) @{
+ char c = str[i];
+ if (c >= 'A' && c <= 'Z')
+ new_str += tolower(c);
+ else if (c >= 'a' && c <= 'z')
+ new_str += c;
+ @}
+
+ if (new_str.length() == 0)
+ return _ex0();
+ else
+ return mystring(new_str).hold();
+@}
+@end example
+
+The @code{level} argument is used to limit the recursion depth of the
+evaluation. We don't have any subexpressions in the @code{mystring} class
+so we are not concerned with this. If we had, we would call the @code{eval()}
+functions of the subexpressions with @code{level - 1} as the argument if
+@code{level != 1}. The @code{hold()} member function sets a flag in the
+object that prevents further evaluation. Otherwise we might end up in an
+endless loop. When you want to return the object unmodified, use
+@code{return this->hold();}.
+
+Let's confirm that it works:
+
+@example
+ex e = mystring("Hello, world!") + mystring("!?#");
+cout << e << endl;
+ // -> "helloworld"
+
+e = mystring("Wow!") + mystring("WOW") + mystring(" W ** o ** W");
+cout << e << endl;
+ // -> 3*"wow"
+@end example
+
+@subsection Other member functions
+
+We have implemented only a small set of member functions to make the class
+work in the GiNaC framework. For a real algebraic class, there are probably
+some more functions that you will want to re-implement, such as
+@code{evalf()}, @code{series()} or @code{op()}. Have a look at @file{basic.h}
+or the header file of the class you want to make a subclass of to see
+what's there. 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.
+
That's it. May the source be with you!
-@node A Comparison With Other CAS, Advantages, Symbolic functions, Top
+@node A Comparison With Other CAS, Advantages, Adding classes, Top
@c node-name, next, previous, up
@chapter A Comparison With Other CAS
@cindex advocacy
AC_PROG_INSTALL
AC_LANG_CPLUSPLUS
-AM_PATH_GINAC(0.4.0, [
+AM_PATH_GINAC(0.7.0, [
LIBS="$LIBS $GINACLIB_LIBS"
- CPPFLAGS="$CFLAGS $GINACLIB_CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $GINACLIB_CPPFLAGS"
], AC_MSG_ERROR([need to have GiNaC installed]))
AC_OUTPUT(Makefile)
The only command in this which is not standard for automake
is the @samp{AM_PATH_GINAC} macro.
-That command does the following:
-
-@display
-If a GiNaC version greater than 0.4.0 is found, adds @env{$GINACLIB_LIBS} to
-@env{$LIBS} and @env{$GINACLIB_CPPFLAGS} to @env{$CPPFLAGS}. Otherwise, dies
-with the error message `need to have GiNaC installed'
-@end display
+That command does the following: If a GiNaC version greater or equal
+than 0.7.0 is found, then it adds @env{$GINACLIB_LIBS} to @env{$LIBS}
+and @env{$GINACLIB_CPPFLAGS} to @env{$CPPFLAGS}. Otherwise, it dies with
+the error message `need to have GiNaC installed'
And the @file{Makefile.am}, which will be used to build the Makefile.
@printindex cp
@bye
-