Giac is a C++ library that has types for symbolic algebraic manipulations. Xcas is a GUI linked with Giac that provides the functionnalities of a general purpose computer algebra system. This documentation gives a short overview of Giac/Xcas 0.x features. Further Xcas information can be found in the tutorial bundled in Xcas distributions, and for French speakers in the extensive documentation by Renée De Graeve also bundled in Xcas binaries distribution.
The Giac project was started by Bernard Parisse, Institut Fourier, CNRS UMR 5582, Université de Grenoble I in year 2000. It's name derives from http://www.ginac.de, another C++ library for symbolic algebraic computations. It means Giac Is A Computer Algebra System.
If you want to use xcas/giac like another CAS and your OS is
Intel x86 GNU/Linux or Intel StrongARM GNU/Linux or Windows 9x, then
you don't need to worry about compilation. Instead you can install
precompiled binaries:
/usr/local/bin is in the PATH and
/usr/local/lib in /etc/ld.so.conf.
Unpack the archive from the / directory, and run ldconfig.
Unpack the archive with
tar xvfz xcas_user.tgz
then
cd xcas
and
./xcas
xcas from the desktop shortcut
or from the Start menu.
Get Giac source at ftp://ftp-fourier.ujf-grenoble.fr/linux/xcas/giac.tgz
or http://perso.wanadoo.fr/bernard.parisse/giac-0.6.1.tar.gz.
Check that your C++ compiler understand the C++ ANSI 3 norm. For
example gcc version 2.95 or later will work. If the GMP GNU Math
Precision Library is not installed on your system, install it:
http://www.gnu.org/directory/gnump.html. If you are using GNU/Linux,
the GMP library is most probably installed but the headers files
might not, check for a package named something like gmp-devel.
make clean ./configure NTL_GMP_LIP=on NTL_STD_CXX=on make make install
src/basemath/polarit2.c: remove the word
static from the declaration:
static GEN combine_factors(...)Replace
inflate and deflate by pari_inflate
and pari_deflate, to avoid linker conflict with the libz.
src/headers/paridecl.h: Add the line
GEN combine_factors(GEN a, GEN famod, GEN p, long klim, long hint);
in the * polarit2.c section.
make all) and reinstall PARI (make install)
and check that libpari.a has been updated or copy it explicitely
from the O<your_os> directory.
/usr/local/include/pari/pariinl.h labs
by std::abs otherwise you might get compiler errors.
long pari_mem_size=10000000;
INSTALL file).
gnuplot,
follow the compilation instructions
in the src/plot.cc file.
The ./configure shell-script recognizes the following options:
These options can be turned off using --disable-option-name instead of
--enable-option-name. By default configure will use these
options if the libraries are available on your system.
For full speed binaries, before calling configure do (with bash
as shell)
$ export CXXFLAGS="-O3 -fexpensive-optimizations -malign-loops=2 -malign-jumps=2 -malign-functions=2"
or (with tcsh as shell)
$ setenv CXXFLAGS "-O3 -fexpensive-optimizations -malign-loops=2 -malign-jumps=2 -malign-functions=2"
Like with any autoconfiguring GNU software, you can type :
./configure
[add options as needed: try ./configure -help for option info]
make
make check
[become root if necessary]
make install
Tips:
CXXFLAGS to -g before calling configure, with tcsh
setenv CXXFLAGS -g, with bash export CXXFLAGS=-g.
config.h defines HAVE_LIBFLTK and does not define
HAVE_LIBGSL and HAVE_LIBGSLCBLAS unless you have these libraries too, then
make -f Makefile.ipaq
Note that I never succeded to build with optimization for the iPaq.
./configure --disable-gui
make
You can compile the library version of giac like under Unix.
Or assuming you have the cygwin tools, gmp and FLTK installed (see
http://sources.redhat.com/cygwin for cygwin, run cygwin,
go in the giac directory, run
./configure
go in the src directory and run
make -f Makefile.win
After that, you may run xcas.exe standalone, provided that the
cygwin DLL's have been copied in the path (e.g. in the same
directory as xcas.exe)
make check,
please note that the answer assume PARI and NTL are enabled.
Otherwise you will get some errors because factoring will not
return the factors in the same order.
src/Makefile and if necessary replace the line :
CXXFLAGS = -g -O2
by :
CXXFLAGS = -g
autoheader: Symbol 'CONSTANT_DEBUG_SUPPORT' is not covered by ...
run
autoheader --localdir=.
modpoly.cc, it's most certainly
because you compiled NTL without namespaces. Recompile it (see section)
modfactor.o it's because you did not modify PARI correctly or
forgot to re-install the PARI libraries (see section)
cp libpari.a /usr/local/lib mkdir /usr/local/include/pari cp src/headers/*.h /usr/local/include/pari cp Ocygwin/*.h /usr/local/include/pariThen I got an error compiling
pari.cc that dispeared by commenting
the offending line in the header /usr/local/include/pari/paricom.h
After that all went OK.
xcas is an user-interface to giac that is similar to a calculator.
A readline interface named cas is also available.
You can use but you don't need a keyboard to use xcas since this interface is designed to be used on a PDA as well. Use the green shift button to get the button-keyboard.
The window is composed from left and up to right and down of:
The interface ressembles advanced graphing calculators (TI89, TI92, HP49G in algebraic mode): you write a command in the commandline with the help of the keyboard and/or the buttons, on-line help and menus. Then hitting Enter will evaluate your expression and return the answer in the history area. The interface can also be configured so that commands are entered directly in the history.
The on-line help gives a short description of all the CAS commands
with examples that can be pasted to the commandline. It is available
by default in xcas or by the cas_help command from a shell.
Advanced printing requires a working LaTeX
installation with pstricks.
A few commands of the CAS system.
The gcd and lcm commands apply to both argument types : they
return the greatest common divisor or the least common multiplicator.
Other arithmetic commands must begin with an i if you want
to use them with integers, otherwise the arguments will be considered
as constant polynomials.
Given two integers a and b, the euclidean integer division
is defined by the equality :
a=b*q+rwhere usually
r is taken between 0 and b-1, or
in the symmetric representation, between -b/2 and b/2.
The functions iquo(a,b) and irem(a,b) return respectively
q and r, or iquorem(a,b) return both in a vector.
The smod(a,b) function will return r using the symmetric
remainder convention.
The gcd(a,b) function returns the greatest common divisor
d of two integers a and b. If you need two integers
u and v such that:
a*u+b*v=dyou should call
egcd(a,b) instead, it will return [u,v,d].
The ichinrem([a,n],[b,m]) call where n and m
are prime together will return a vector [c,n*m] such that
c=a (mod n) and c=b (mod m).
The is_prime(a) function will return 0 if a is not prime.
If will return 2 if a is known to be prime, and 1 if a
is a (strong) pseudo-prime. If you have compiled xcas with PARI
support, you will get a prime certificate instead (see PARI documentation for
more information).
The nextprime(a) and prevprime(a) will return the next
or previous (pseudo-)prime, given an integer a.
The ifactor(a) function returns a factorization of a.
It is a good idea to compile with PARI support if you plan to factor
relatively large integers (with prime factors having more than 20 digits).
Additional integer functions provided by xcas are
jacobi(a,b)
and legendre(a,b), see the GMP documentation for more details.
pa2b2(p) return [a,b] so that p=a*a+b*b
if p=1 (mod 4) is prime.
Polynomials have two representations: symbolic representation or
by a vector of coefficients. In the symbolic representation you might
add the variable name as an additionnal parameter to the functions
you call, otherwise the default variable is used. For the vector
representation, it is recommended to use the right delimiter poly1[
instead of [ so that usual operations (addition, ...) behave
correctly (i.e. not like vectors or matrices).
quo(a,b) rem(a,b) and quorem(a,b)
return respectively q, r and [q,r] polynomials
so that a=b*q+r and degree(r)<degree(b)
gcd(a,b) return the greatest common divisor of two
polynomials
egcd(a,b) is the extended euclidean GCD algorithm, like for
integers it returns a list of 3 polynomials u,v,d such
that au+bv=d.
chinrem return the chinese remainder for polynomials written
as lists. The 2 arguments are two lists made of a polynomial modulo
another polynomial (where the modulo polynomials must be prime together).
The answer is the polynomial modulo the product of the modulo polynomials
that reduce to the original polynomials modulo the original modulo
polynomials
cyclotomic takes an integer n as argument and returns the
n-th cyclotomic polynomial.
The normal command rewrites a rational fraction as a ratio of two
coprime polynomials. If an expression is not rational, it is first
rationalized by substitution of transcendental expressions (e.g.
sin(x) by a temporary identifier. Algebraic expressions
(e.g. sqrt(x)) are normalized too.
The factor command factorize polynomials. Like above a non
polynomial expression is first rationalized. You can choose the main
variable with respect to which the polynomial will be factorized by
adding it as second argument of factor.
The texpand function is called to expand transcendental
expressions like exp(x+y)=exp(x)*exp(y) or similar rules
for trigonometric functions. The tlin function does
the reverse operation for trigonometric functions, as the lin
function does it for exponentials.
The halftan function rewrites trigonometric expressions
in terms of the tangent of the half angle. The hyp2exp
function rewrites hyperbolic functions in terms of exponentials.
The differentiation instruction is diff(expression,variable).
The undefined antiderivative is obtained using
integrate(expression,variable). If you need defined integration
between bounds a and b, choose
integrate(expression,variable,a,b) for exact integration
or romberg(expression,variable,a,b) for numeric integration.
Example of defined integration are Fourier coefficients of periodic
functions. They are provided using fourier_an and fourier_bn
for trigonometric coefficients or using fourier_cn for
complex exponentials coefficients.
Some discrete antiderivatives may be obtained using the
sum(variable,expression) call.
For a limit the syntax is
limit(expression,variable,limitpoint[,direction]).
For a series expansion
series(expression,variable,limitpoint,order[,direction]).
Note: giac implementation of limit and series is based
on the mrv algorithm.
The solve(expression,variable) call is used to find exact
solutions of (polynomial-)like equations. Use newton instead
for numeric solutions (of a wider range of equations).
Arithmetic operations on matrices and vectors are done using the usual
operators. The scalar product of two vectors is obtained using the *
operator.
Gaussian elimination (Gauss-Bareiss) over a matrix is performed
using rref(m). The kernel of a linear application with matrix
m is obtained with ker(m). A system of linear equations (written
symbolically in a vector) can be solved via
linsolve([equations],[variables]).
The determinant of a matrix may be obtained using two algorithms,
either Gauss-Bareiss invoking det(m), or by computing minors
det_minor(m). Actually, a last method is provided using the
computation of the constant coefficient of the characteristic polynomial
using Fadeev-Leverrier algorithm.
The characteristic polynomial of a matrix may be computed by Fadeev-Leverrier
algorithm calling pcar(m). For matrices withe coefficients in
a finite field, pcar_hessenberg(m) is a better choice (O(n^3)
complexity where n is the size of the matrix).
Eigenvalues and eigenvectors are computed using respectively egvl(m)
and egv(m). The Jordan normal form is obtained invoking
jordan(m).
Quadratic forms (written symbolically) can be reduced to sum and differences
of squares using gauss(expression,[variables]).
There is some support for isometries: mkisom may be used to
make an isometry from its proper elements as isom(m) return the
proper elements of an isometry.
As other objects, you can create geometrical objects analytically using the
commandline. Additionnally, if the graphic window is active (click
on the Geo button if necessary), you can create points and
segments with the mouse (or the stylus) or move a geometrical object.
To create a point just click. To create a line, push any button
of the mouse, move the mouse and release it at the second point.
To move an object, first select it by clicking near it. The commandline
should display the name of the object. You can drag it by pushing
the mouse near the object and moving. Release the mouse at the final
position. You can cancel a move by releasing the mouse out of the graphical
window. As with any dynamical geometry package, all objects depending
on an object will move when you move this object.
To print the current graph, you can use the graph2tex() instruction
either with no argument (then the LaTeX code will be inserted
at its place in the history) or with a string containing the name
of a file where you save a standalone version of the graph, for example
graph2tex("figure.tex") will create a file named figure.tex
that you can compile with latex figure.tex.
The xcas and cas program provide an interpreted language that is similar to
the popular other CAS programming language. This scripting language is
available in 4 flavours: C-like syntax (default) or compatibility
mode for simple Maple, Mupad or TI89-like programs. We describe only the C-like
syntax. Instructions must end with a semi-column ;. Groups of
instructions may be combined like in C with brackets.
The command maple_mode(0) or maple_mode(1) or
maple_mode(2) or maple_mode(3)
may be used to switch the language flavour
respectively from C-like to Maple-like, Mupad-like or TI89-like
mode. At startup, the mode is by default 0, but might be different
if you saved your preferred settings (in the ~/.xcasrc
file). The environment variable GIAC_MAPLE_MODE
will also affect the default mode, for example with
tcsh: setenv GIAC_MAPLE_MODE 1
or with bash export GIAC_MAPLE_MODE=1
will switch to the Maple-like language. Inside xcas you can run
the Import command of the File menu and select the mode
temporarily for a script file.
The Export command can be used to translate the current level
of the history inside xcas to a file, or the View as command
of the Edit menu to translate to the Help output window.
The language accept local and global variables, variables are not typed.
Global variables do not need to be declared, local variables must be declared
at the beginning of a function by the keyword local followed by
the names of the local variables separated by commas , with a final
semi-columns ;
The affectation sign is := like in popular CAS and unlike in C.
Other operations (e.g. {+ - * /}) and function calls are done like in C
or like in an interactive session.
As in C, the equality test is ==. The single equal sign =
is used to return an equation (this equation will be checked as a test
only in some situations where an equation can not be expected).
The other tests are != for non equal, < <= > >= for
real value comparisons. You can combine tests with && or and,
and || or or. The boolean negation is ! or not.
The loop keywoard is like in C:
for (initialization;while_condition;increment){ loop_block }
You can break a loop inside the loop block with break;.
You can skip immediately to the next iteration with continue;.
The conditionnal keywoard is like in C:
if (condition) { bloc_if_true } [ else { bloc_if_false } ]
Additionnaly, multiple-cases is translated like in C:
swith (variable){ case (value_1): ... break; default: ... ; }
Functions are declared and implemeted together like this
function_name(parameters):={ definition }
Parameters are like local variables with an additional initialization from the values of the parameters inside the calling instruction.
The return(return_value) should be used to return the value
of the function.
It is not possible to pass arguments by reference, only by value.
Functions might be written using your favorite editor, using
a filename ending with e.g. .cxx will give you mostly
meaningfull syntax highlighting. Inside xcas, you can
also use the prg yellow button to write your functions.
The read function will import the function in your session.
Inside prg mode, you can also test and copy to history
using the buttons bar.
If one of these variables GIAC_MAPLE, GIAC_MUPAD,
GIAC_C or GIAC_TI is defined, the corresponding
syntax mode will be in effect. If XCAS_RPN is defined,
then xcas will start in RPN mode.
The variable XCAS_ROOT may be used for a custom xcas installation,
it should point to the directory where xcas is installed. XCAS_LOCALE
should point to the directory where the locales are. XCAS_TMP
may be defined for temporary exchange files between xcas processes,
if not defined it will use the home directory.
The variable PARI_SIZE may be used to define the memory
available for pari.
The variable BROWSER may be used for the HTML documentation browser.
The variable LANG may be used for internationalization.
The variable GIAC_TIME and GIAC_TEX may be used
in giac readline interface to ask for timing and tex output.
GIAC_DEBUG will give some info on the internals used.
In this chapter we will first describe the generic data type of giac,
the gen class. Then we describe the most important data
types than gen dispatches to (polynomials, vectors, symbolic
objects and gen unary functions). At this point, the reader should be
able to code using giac, hence we describe how to integrate
code to giac by inclusion in the library or as a separate
runtime loadable library (called module). The last item describes
how you can add new mathematical objects, e.g. quaternions,
inside the gen type.
Giac uses the C++ language because it is easier to write algebraic
operations using usual operators, for example a+b*x is easier
to understand and modify than add(a,mul(b,x)), but it does not
require that you learn object oriented programming. In fact it is more
a C library using C++ features that makes programming easier (like the
I/O streams and the Standard Template Library). However you will need
a recent C++ compiler, e.g. gcc version 2.95 or later.
Future versions of Giac will use a mechanism for thread-safe executions
(suggested E. Kia and A. Thillosen). This will be achived by bundling
all the execution context (e.g. assigned Xcas-level variables, angle
mode, complex/real mode, etc.) in a pointer of type context *.
The null context (value of variable set to 0) will design a thread
common global execution context, as non zero pointers will be used
for independants threads. A part of the functions have been converted
to use this additionnal argument, other have not been converted yet.
In version 0.4 or above, it is recommended to use a 0 pointer for every call
to the already converted functions.
gen is the class used to represent mathematical objects
(#include <giac/gen.h>). It's a C union, made either of "direct"
objects like int or double
or of pointers to heap-allocated objects that are reference counted.
Memory allocation is handled by the class itself (except for
user-defined object types). You can check
the actual type of a variable of type gen, e.g. gen e;,
using it's type field (e.g. if (e.type==...)). This
type field of a gen is an int.
The gen might be:
e.type==_INT_, get value by
int i=e.val;
e.type==_DOUBLE_, get value by
double d=e._DOUBLE_val;
e.type==_ZINT,
get value by mpz_t * m=e._ZINTptr; (see GMP documentation
for more details on the underlying type).
e.type==_REAL),
e.type==_CINT), the
pointer value points to two objects of type gen
the real part gen realpart=*e._CINTptr; and the imaginary part
gen imagpart=*(e._CINTptr+1);
e.type==_VECT),
e._VECTptr is a pointer to the vecteur type
(a shortcut for std::vector<gen>). For example
e._VECTptr->size() will give the size of the vector object.
See the vector section above for more details.
e.type==_IDNT, with a pointer to an
identificateur type identificateur i=*e._IDNTptr; .
See giac/identificateur.h for more details.
e.type==_SYMB, with a pointer to
a symbolic type symbolic s=*e._SYMBptr;. See the
symbolic section below and giac/symbolic.h for more details.
e.type==_FUNC,
with a pointer to a unary_function_ptr type
unary_function_ptr u=*e._FUNCptr. See the unary function
section below and giac/unary.h for more details.
In addition to the main type, each gen has also a subtype.
This subtype is used sometimes to select different behaviour, e.g.
adding a constant to a vector might add the constant to all terms for
some geometric objects represented using vectors, only to the term of
the diagonal of a square matrix, or to the last term for dense polynomials.
Have a look at giac/dispatch.h for the description of types
and subtypes.
Note that a few other types are available (e.g. a pointer to gen_user
an object you can derive to make your own class), for a complete
description look at giac/gen.h (if you have installed giac
the path to the include files is /usr/local/include/giac unless you
override the default, if you did not install it, the path is the path
to the src directory of the source code distribution).
Polynomials types available inside giac:
polynome.
They are represented using a vector of monomials, each monomial is
a gen coefficient and a vector<int> representing
the powers of each variable.
Header files are gausspol.h, poly.h, monomial.h.
poly1
or modpoly for modular univariate polynomials. Both are alias
for vecteur, the type used for vectors of gen.
The coefficients are listed in decreasing order.
Header files are giac/vecteur.h, giac/modpoly.h
and giac/modfactor.h (for the modular factorization code).
A gen is a polynomials if it's type field is
respectively _POLY (for sparse) or _VECT (for dense).
Conversion functions to and from the symbolic representation with
respect to global names are declared in giac/sym2poly.cc.
Some sparse polynomial optimizations use the STL map
(or hash_map) types, some dense optimizations use vector<int>.
The type used for vectors and matrices is the same, it's a
std::vector<gen> (unless you have configured with
--enable-debug). The header file is giac/vecteur.h.
A gen is a vector if it's type field is
_VECT.
Basic functions for vectors come from the STL, most giac functions
are declared in giac/vecteur.h
A symbolic object
is made of two fields:
the function named sommet, type unary_function_ptr,
and the argument(s) named feuille, type gen.
For a non-unary function, the arguments are grouped in a
vecteur.
For example, if e.type==_SYMB, the arguments of e
are grouped in a vecteur if e._SYMBptr->feuille.type==_VECT.
For a unary function, e.g.
if (e._SYMBptr->sommet==at_sin), then the argument of
the sin operation is e._SYMBptr->feuille.
In the giac library, every function is viewed as a function taking one
argument and returning one argument. If a function should have more than one
argument, we pack these arguments in a vector. If you search for a Giac
function to make a symbolic computation, a good start is to search the
xcas function name if it exists, add a _ at the beginning and
try to call the giac function. For example for integration, the xcas
function name is integrate, hence
_integrate(makevecteur(f,x),0)
will integrate the expression f with respect to variable x
using global context. Most of the time, the _ function calls
a normal function with non-vector bundled arguments, e.g.
_integrate(f,x,0)
will do the same operation (a little faster since we won't bundle
f and x in a vecteur).
The files usual.cc/.h give examples of declaration e.g. for
exponential and trigonometric functions. Unary functions have the
following members~:
gen and returning an gen
which does the job
taylor_asin).
This is always the case if your function is defined at infinity.
Note that this function
is called at initialization so that you can include code in it for
example to add your function to the symbolic preprocessing step of the
limit/series algorithm.
input_lexer.ll
(see for example "sin") or you must register it (see below).
unary_function_unary is defined, you must construct
a unary_function_ptr to be able to use it inside symbolics.
If you define your own function,
you may give an optional argument to specify a behavior for the evaluation
of arguments (quoting). In this case, you may give a second optionnal argument
to register your function dynamically in the list of function names
recognized by the lexer, this second argument might be true (usual
syntax for the parser) or a token value (see input_parser.yy
for the grammar recognized by the parser and the appropriate token
value). Be sure to link the object file so that
initialization occurs after the initialization of input_lexer.ll,
it means you must put your object file before (or after with Mac OS X linker)
input_lexer.o
when linking (see for example the position of ti89.o in
the Makefile.am file, ti89
is one example where dynamic registering is done).
You have of course the option to declare the function name
statically in the file input_lexer.ll, but auto-registering
is the only way to share your new functions with other who do not
modify their version of the giac library.
Here is one example of a dynamically linkable function named
example which takes 2 arguments and returns the sum divided
by the product if the argument are integers and return itself otherwise.
The C++ header example.h code looks like
#ifndef __EXAMPLE_H
#define __EXAMPLE_H
#include <giac/gen.h>
#include <giac/unary.h>
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
gen example(const gen & a,const gen & b);
gen _example(const gen & args);
extern unary_function_ptr at_example ;
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC
#endif // __EXAMPLE_H
The C++ source code looks like:
using namespace std;
#include <giac/giac.h>
#include "example.h"
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
gen example(const gen & a,const gen & b){
if (is_integer(a) && is_integer(b))
return (a+b)/(a*b);
return symbolic(at_example,makevecteur(a,b));
}
gen _example(const gen & args){
if ( (args.type!=_VECT) || (args._VECTptr->size()!=2) )
setsizeerr(); // type checking : args must be a vector of size 2
vecteur & v=*args._VECTptr;
return example(v[0],v[1]);
}
const string _example_s("example");
unary_function_unary __example(&_example,_example_s);
unary_function_ptr at_example (&__example,0,true);
#ifndef NO_NAMESPACE_GIAC
}
#endif // ndef NO_NAMESPACE_GIAC
Compile it with
c++ -g -c example.cc
To test your code, you should write the following test.cc program
#include "example.h"
using namespace std;
using namespace giac;
int main(){
gen args;
cout << "Enter argument of example function";
cin >> args;
cout << "Result: " << _example(args) << endl;
}
Compile it with the command
c++ -g example.o test.cc -lgiac -lgmpYou might need to link to other libraries e.g.
-lreadline -lhistory -lcurses depedning on your installation.
Then run a.out. Here you would test e.g. with [1,2].
You can debug your program as usual, e.g. with
gdb a.out, it is recommended to create a .gdbinit file
in the current directory so that you can use the v command
to print giac data, the .gdbinit file should contain :
echo Defining v as print command for giac types\n define v print ($arg0).dbgprint() end
When your function is tested, you can add it to the library. Edit
the file Makefile.am of the src subdirectory
of giac : just add example.cc before input_lexer.cc
in the libgiac_la_SOURCES line and add example.h in the
giacinclude_HEADERS line.
To rebuild the library go in the giac directory and type
automake; make
If you want to share your function(s) with other people, you must
license it under the GPL (because it will be linked to GPL-ed code).
Add the GPL header to the files, and send them to the giac
contribution e-mail, currently mailto:parisse@fourier.ujf-grenoble.fr
/* * Copyright (C) 2002 Your name * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Another way to share your code could be to build a dynamic library
that can be loaded at runtime using facilities of <dlfcns.h>.
Warning: modules do not work with static binaries. Be sure
to have dynamic binaries (this is the default when you compile giac,
but the packaged xcas distributed as a binary is build static to
avoid incompatible libraries).
Let us define a function named mydll in the file mydll.cc like
this :
#include <giac/giac.h>
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
const string _mydll_s("mydll");
gen _mydll(const gen & args){
return sin(ln(args));
}
unary_function_unary __mydll(&giac::_mydll,_mydll_s);
unary_function_ptr at_mydll (&__mydll,0,true); // auto-register
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC
Compile it like this
c++ -fPIC -DPIC -g -c mydll.cc -o mydll.lo cc -shared mydll.lo -lc -Wl,-soname -Wl,libmydll.so.0 -o libmydll.so.0.0.0 rm -f libmydll.so.0 && ln -s libmydll.so.0.0.0 libmydll.so.0 rm -f libmydll.so && ln -s libmydll.so.0.0.0 libmydll.so
The library is loadable at runtime in a session using the command
insmod("libmydll.so") assuming it is stored in a directory available
from LD_LIBRARY_PATH or in /etc/ld.so.conf otherwise
you must put a path to the library file (beginning with ./ if
it is in the current directory).
A nice way to test your code is to add the following line in your
~/.xcasrc file :
insmod("path_to_libmydll/libmydll.so");
where you replace path_to_libmydll.so with the actual path to
libmydll.so for example /home/joe if your login name is
joe and mydll is in your home directory.
Then if you are using emacs as editor, put as first line of
the file mydll.cc
// -*- mode:C++ ; compile-command: "g++ -I.. -fPIC -DPIC -g -c mydll.cc -o mydll.lo && ln -sf mydll.lo mydll.o && gcc -shared mydll.lo -lc -Wl,-soname -Wl,libmydll.so.0 -o libmydll.so.0.0.0 && ln -sf libmydll.so.0.0.0 libmydll.so.0 && ln -sf libmydll.so.0.0.0 libmydll.so" -*-Now you can compile it with
Compile of the menu Tools
and the resulting code is automatically loaded when you launch a new
session with xcas or cas which makes testing a breath.
The class gen_user can be derived so that you can include
your own data inside gen. Look at the declaration of gen_user
in the file gen.h and at the example of the quaternions
in the files quater.h and quater.cc.
Type the following text with your favorite editor
#include <giac/giac.h>
using namespace std;
using namespace giac;
int main(){
gen e(string("x^2-1"));
cout << factor(e) << endl;
}
save it e.g. as tryit.cc and compile it with
c++ -g tryit.cc -lgiac -lgmp
If you get unresolved symbol, then readline is probably enabled
and you should compile like that
c++ -g tryit.cc -lgiac -lgmp -lreadline -lcurses
You can now run a.out which will print the factorisation of
x^2-1.
You can also run the program step by step using gdb. We
recommended that you copy the file .gdbinit from the src
directory of the giac distribution, because it enables using
v varname to print the variable varname of type gen.
Some explanations of the code:
#include <giac/giac.h>
directive includes all the headers of giac (which includes some STL
headers like string or vector).
using namespace
directive are not mandatory, if you don't use them, you need to modify
some of the code, e.g. use std::string instead of string
or giac::gen instead of gen.
gen
can be constructed from strings (using the parser), from some C types
(like int or double), from the STL type
std::complex<double> or from streams (using the parser).
+, -, * are defined on the gen type
but the division is not redefined to avoid confusion between integers
(use iquo) and double C division (use rdiv). For powers,
use pow as usual.
Type the following text with your favorite editor
#include <giac/giac.h>
using namespace std;
using namespace giac;
int main(){
gen e;
cout << "Enter an expression to integrate and a variable" << endl;
cout << "like this: sin(x),x ";
cin >> e;
e=eval(e);
if (e.type!=_VECT || e._VECTptr->size()!=2){
cerr << "Invalid syntax" << endl;
return 1;
}
vecteur & v = *e._VECTptr;
cout << "Antiderivative is " << integrate(v.front(),v[1],0) << endl;
return 0;
}
Compile it like above. This example demonstrates how to use vectors, and it shows one call of a function with a context pointer parameter (set to 0).