programming
In GP you can use up to 256 variable names. These names can be any standard identifier names, i.e. they must start with a letter and contain only alphanumeric characters. To avoid confusion with other symbols, you must not use non alphanumeric symbols like '_', '$', or '.'. In addition to the function names which you must not use (see the list with \c) there are exactly three special variable names which you are not allowed to use: pi and euler, which represent well known constants, but also i which is always equal to the square root of -1. Since usually you are not going to use the variable name pi for anything else but the number π, and similarly for euler, these two will not create any problems. On the other hand, you will have to get used to calling a loop control variable with a name different from i. We realize that this may initially be the cause for some confusion, but we do not have any replacement symbol for the square root of -1.
Now the main thing to understand is that PARI/GP is not a symbolic manipulation package, although it shares some of the functionalities. One of the main consequences of this fact is that all expressions are evaluated as soon as they are written, they never stay in a purely abstract form. As an important example, consider what happens when you use a variable name before assigning a value into it. This is perfectly acceptable to GP, who considers this variable in fact as a polynomial of degree 1, with coefficients 1 in degree 1, 0 in degree 0, whose variable is the variable name you used.
If later you assign a value to that variable, the objects which you have created before will still be considered as polynomials. If you want to obtain their value, use the function eval (see 3.6.6 above).
Another consequence is that the variables are numbered in the order that they appear, and the main variable of an expression is always the lowest numbered variable. Hence if you are working with expressions involving several variables and want to have them ordered in a specific manner in the internal representation, the simplest is just to write down the variables one after the other under GP before starting any real computations. If you already have started working and want to change the names of the variables in an object, use the function changevar (see 3.2.2). If you only want to have them ordered when the result is printed, you can also use the function reorder (see 3.9.4.6).
Finally, note that if x is a vector, you can assign a result to x[m] (i.e. write something like x[k] = expr). If x is a matrix, you can assign a result to x[m, n], but not to x[m], which is a vector.
An expression is formed by combining the GP operators, functions (including user-defined functions) and control statements. It may be preceded by an assignment statement '=' into a variable. It always has a value, which can be any PARI object.
Several expressions can be combined on a single line by separating them with semicolons (';') and also with colons (':') for those who are used to BASIC. Such an expression sequence will be called simply a seq. A seq also has a value, which is the value of the last nonempty expression in the sequence. Under GP, the value of the seq is always put on the stack (i.e. it will become the next object %n), and only that value. The values of the other expressions in the seq are discarded after the execution of the seq is complete, except of course if they were assigned into variables. In addition, the value of the seq (or of course of an expression if there is only one) is printed if the line does not end with a semicolon (';').
Control statements.
A number of control statements are available under GP. They are simpler and have a slightly different syntax than their C counterparts, but are quite powerful enough to write any kind of program. Some of them are specific to GP, since they are made for number theorists. They are as follows. As usual, X will denote any simple variable name, and seq will always denote a sequence of expressions, including the empty sequence.
for
(X = a, b, seq): the formal variable X going from a to b,
the seq is evaluated. Nothing is done if a > b. a and b must be in R.
fordiv(n, X, seq): the formal variable X ranging through the positive divisors of n, the sequence seq is evaluated. n must be of type integer.
forprime
(X = a, b, seq): the formal variable X ranging over the prime
numbers between a to b (including a and b if they are prime),
the seq is evaluated. Nothing is done if a > b. Note that a and b
must be in R.
forstep
(X = a, b, s, seq): the formal variable X going from a to
b, in increments of s, the seq is evaluated. Nothing is done if s > 0 and
a > b or if s < 0 and a < b. a, b and s must be in R, and s must
be nonzero.
if (a, seq1, seq2): if a is nonzero, the expression sequence seq1 is evaluated, otherwise the expression seq2 is evaluated. Of course, seq1 or seq2 may be empty, but the syntax must stay the same: if(a,seq,) evaluates seq if a is not equal to zero, does nothing otherwise; if(a„seq) evaluates seq if a is equal to zero, does nothing otherwise.
until(a, seq): evaluate expression sequence seq until a is not equal to 0 (i.e. until a is true). If a is initially not equal to 0, seq is evaluated once (more generally, the condition on a is tested after execution of the seq, not before as in while.
while(a, seq): while a is nonzero evaluate the expression sequence seq. The test is made before evaluating the seq, hence in particular if a is initially equal to zero the seq will not be evaluated at all.
Specific functions used in GP programming.In addition to the general PARI functions, it is necessary to have some functions which will be of use specificlly for GP. They are as follows:
kill(x): kills the present value of the variable or user-defined function x. After kill of a variable, since the variable does not have a value, as has been explained above it is again considered as a monic polynomial of degree 1 with no constant term.
For the following four printing functions, list represents a list (separated by commas) either of PARI objects or of character strings between double quotes '"', which are always printed as they are.
pprint(list): output list in prettyprint (beautified) format, ending with a newline.
pprint1(list): output list in prettyprint (beautified) format, without ending with a newline.
print(list): output list in raw format, ending with a newline.
print1(list): output list in raw format, without ending with a newline.
reorder(x): x must be a vector. If x is the empty vector, this gives the vector whose components are the existing variables in increasing order (i.e. in decreasing importance). If x is nonempty, it must be a permutation of variable names, and this permutation gives a new order of importance of the variables. For example, if the existing order is [x,y,z], then after reorder([z,x]) the order of importance of the variables will be [z,y,x].
texprint(list): outputs list in TEX format. This output can then be used in a TEX manuscript.
Warning: in the present version 1.35, the printing is done on the standard output, hence to be able to get the output into a file, you must be either in an emacs session or shell (see 3.10), in a windowing system (which enables you to grab the output with the mouse), under a UNIX script command, or with the logfile enabled (see the command \l). This will be improved.
User defined functions.
It is very easy to define a new function under GP, which can then be used like any other function. The syntax is as follows:
name(list of true formal variables, list of local variables)=seq
where name is the name that you want to give to your function (same syntactic restrictions as for variable names). list of true formal variables is the list of variables corresponding to those which you will actually use when calling your function, the variables being separated by commas, and the list being allowed to be empty. list of local variables is the list of the additional local variables which you will use in the definition of the function. If you omit some or all of these local variable declarations, the function will probably still work, but the nondeclared variables will become global, hence known outside of the function, and this may have undesirable side-effects. On the other hand, in some cases it may also be what you want. Finally, as usual seq is any expression sequence.
Once the function is defined using the above syntax, you can use it like any other function. In addition, you can also recall its definition exactly as you do for predefined functions, that is by writing ?name. One small difference with predefined functions is that you can never redefine such a function, while you can redefine a user-defined function as many times as you want, without using the kill instruction.
In a given session you can give any identifier name to a function, except those of predefined functions (of course) but also those of any variables that have been used, even if they have been killed. On the other hand, if you want to use as a variable name the name of a user-defined function, it is enough (and necessary) to kill this function name first.
An amusing example of a user-defined function is the following. It is intended
to illustrate both the use of
user-defined functions and the power of the sumalt function. Although
since version 1.34 the is included in the standard
functions, let us assume that this is not the case (or that we want another
implementation). One way to define it, which is probably the simplest
(but certainly not the most efficient), is as follows:
zeta function zet(s,j)=sumalt(j=1,(-1)ˆ(j-1)*jˆ(-s))/(1-2ˆ(1-s))
Then this gives reasonably good accuracy and speed as long as you are not too far from the domain of convergence. Try it for s integral between -5 and 5, say, or for s = 0.5 + i*t where t = 14.134... Of course, the call to the function is done by zet(s), the variable j must not be given.
Special s. A GP program can of course have more than
one line. Since GP executes your commands as soon as you have finished typing them, there
must be a way to tell it to wait for the next line or lines of input before doing
anything. There are two ways of doing this.
The first one is simply to use the '
\' at the end of the
line that you are typing, just before hitting <return>. This tells GP that what you
will write on the next line is the physical continuation of what you have just written.
In other words, it makes GP forget your newline character. For example if you use this
while defining a function, and if you ask for the definition of the function using
?name, you will see that your backslash has disappeared and that everything is on
the same line. You can type a
\ anywhere. It will be interpreted as above
only if it is immediately followed by a newline. For example, you can type
3+ \
4
instead of typing 3+4.
The second one cannot be used everywhere, but is in general more useful. It is the use brace characters of braces '{' and '}'. When GP sees an opening brace ('{`) at the beginning of a line, it understands that you are writing a program, and newlines will be ignored (but registered, contrary to when you use a backslash) until you type a closing brace '}'. However, there is an important (but easily obeyed) restriction: inside an open brace-close brace pair, all newlines must occur after a semicolon (';'), i.e. between two expressions forming a seq.
Of course you can combine the use of backslash and braces.
As we have seen, the GP calculator uses a primitive purely interpreted language. The structure of this language is in fact more reminiscent of LISP with a functional notation, f(x, y) rather than (f x y): all programming constructs, such as if, while, etc.) are functions, and the main loop does not really execute, but rather evaluates (sequences of) expressions.
Of course, it is by no means a true LISP. Function names are distinct from variable names: once a name has been used as a variable name, this cannot be changed in the same session. Predefined function names cannot be used for anything else, and the number of actual parameters must match the declaration given in the online help. Identifiers that are used for user-defined functions can be freely redefined for other functions, or totally forgotten (using kill) and later reused for a variable, for example.
Each variable has a stack of values, implemented as a linked list. When a new
scope is entered, during a function call,
the value of the actual parameter is pushed on the stack. If the parameter is not
supplied, a special 0 value called is pushed on the stack
(this value is not printed if it is
returned as the result of a GP expression sequence). Upon exit, the stack decreases.
You can kill a variable, decreasing the stack yourself. This should be used
only at the top level of GP, to undo the effect of an assignment,
not from a function. However, the stack has a bottom:
the value of a variable is the monomial of degre 1 in
this variable, as is natural for a mathematician.
Note that the iterative constructs which use a variable name (for, fordiv, forprime, prod, sum, vector, matrix, plot, etc.) also consider the given variable to be local to the construct. A value is pushed on entry and pulled on exit. So, it is not necessary for a function using such a construct to declare the variable as a dummy formal parameter. In particular, in our zet example above, the variable j need not be declared.
Otherwise, it is strongly recommended to declare in this way all other variables that are used inside a function: If a function accesses a variable which is not one of its formal parameters, the value used will be the one which happens to be on top of the stack at the time of the call. This could be a ``global'' value, or a local value belonging to any function higher in the call chain. So, be warned.
Implementation note. For the curious reader, here is how these stacks are
handled: a is computed from the identifer, and used as an
index in
, a table of pointers. Each of these pointers begins
a linked list of structures (type
). The linked list is searched
linearly for the identifer (each list will have less than 7 components or
so). When the correct entree is found, it points to the top of the
stack of values for that identifier if it is a variable, to the function
itself if it is a predefined function, and to a copy of the text of the
function if it is a user-defined function. When an error occurs, all of this
maze (rather a tree, in fact) is searched and (hopefully) replaced in the
situation preceding the last call of the main evaluator.