home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 1
/
crawlyvol1.bin
/
apps
/
math
/
euler
/
doc
/
extend.doc
< prev
next >
Wrap
Text File
|
1992-05-08
|
9KB
|
278 lines
INTRODUCTION
------------
This document describes how to extend EULER with own functions. Of
course, you need a compiler capable of translating the source code.
And you might probably need some good programming experience in C.
Furthermore, it is necessary that you have some practice in using
EULER.
BASICS
------
EULER uses a stack for keeping the variables (local and global) and
the parameters of functions. This stack starts with the user defined
functions (udf). Next we have the global variables, and on top of them
the parameters and variables of running functions. The stack grows
from lower to higher memory. This description makes clear, why one
cannot change the size of a global variable from within a function.
The elements of the stack start with a header of data type
typedef struct { LONG size; char name[16]; int xor; stacktyp type; }
header;
consisting of the total size of the stack element, its name and an
index code of the name (to compare it easily), and the type of the
data, which an enum type
typedef enum { s_real,s_complex,s_matrix,s_cmatrix,
s_reference,s_command,s_submatrix,s_csubmatrix,s_string,s_udf }
stacktyp;
The different data types will be explaned in detail below. Every stack
element has a header, followed by a further description and the data.
s_real : A double value.
s_complex : Two double values (real and imaginary part).
s_matrix : A matrix, consisting of the dimension of type
typedef struct { int c,r; } dims;
followed by r rows of c double values.
s_cmatrix : A complex matrix, which differs from s_matrix by having r
rows of c times two double values.
s_reference : A reference to a variable, which consists of a pointer
to the header of this variable.
s_string : A string, which consists of the string followed by a 0.
All other types are of no interest here.
You can avoid to no many of the details, if you use the service
makros, which we will describe now. "hd" is always a pointer to a
header here.
#define realof(hd) ((double *)((hd)+1))
computes the address of the value of a header of type s_real or the
real part of a header of type s_complex. (note: it returns a
pointer to the double value!).
#define matrixof(hd) ((double *)((char *)((hd)+1)+sizeof(dims)))
Computes address the (0,0)-element of a matrix (real or complex).
#define dimsof(hd) ((dims *)((hd)+1))
Computes the addres of the dimension field of a matrix. I.e.,
dimsof(hd)->r is the number of rows.
#define referenceof(hd) (*((header **)((hd)+1)))
Computes a pointer to a pointer to a header for references.
#define imagof(hd) ((double *)((hd)+1)+1)
Gives a pointer to the imaginary part of a s_complex header.
#define stringof(hd) ((char *)((hd)+1))
Computes a pointer to the string for s_string headers.
#define nextof(hd) ((header *)((char *)(hd)+(hd)->size))
Computes the a pointer to the header of the next stack element.
With these functions, you might get pointers to the details of stack
elements. There are a few more functions and makros.
void getmatrix (header *hd, int *r, int *c, double **m);
Computes the size (rows and columns) and the start address of a
matrix (real or complex). This works also for real and complex
values.
#define mat(m,c,i,j) (m+(LONG)(c)*(i)+(j))
Computes the address of the (i,j)-th element of a matrix starting
at m. c is the number of rows of the matrix.
#define cmat(m,c,i,j) (m+2*((LONG)(c)*(i)+(j)))
The same for a complex matrix.
There are two important variables
char *newram,*ramend;
The pointer newram indicates the start of the unused area of the
stack. You may use the portion of memory between newram and ramend for
own purposes, as long as you do not allocate new stack elements.
DECLARING FUNCTIONS
-------------------
Each function must be declared in "extend.c". First of all, you need
to add a prototype to the long list of prototypes in that file. It
simply has the form
void myfunction (header *hd);
Next, you need to append the function to the builtin_list array. You
must add a line of the form
"myname",2,myfunction,
Here, "myname" is the name the function can be called in EULER. 2 (or
any other number) is the number of parameters the function accepts.
You may have two functions with the same name and a different number
of arguments. "myfunction" is the name of the function in the source
code. If the argument number is equal to 0, myname must be unique, and
the function is called without regard for the number of arguments.
Finally, you will have to program the function. You could simply add
the function to the file "extend.c".
FUNCTIONS OF ONE REAL OR COMPLEX VALUE
--------------------------------------
This is easy. You define a function for the real and a function for
the complex case.
double real_case (double x)
{ ...
return ...;
}
void complex_case (double *x, double *xi, double *z, double *zi)
{ *z=...;
*zi=...;
}
void myfunction (header *hd)
{ spread1(real_case,complex_case,hd);
}
If you pass a 0 pointer, instead of complex_case, the complex case is
undefined and a complex value issues an error message. Of course, the
function "myfunction" will work for a matrix element by element.
If the function has a real result for the complex case, you may use
the function "spread1r" instead. Of course the complex case is then to
be defined as
void complex_case (double *x, double *xi, double *r)
{ ...
}
FUNCTIONS OF TWO REAL OF COMPLEX VALUES
---------------------------------------
This is also easy. Again, you define a function for the real and the
complex case.
void complex_case (double *x, double *xi, double *y, double *yi,
double *z, double *zi)
{ ...
*z=...;
*zi=...;
}
void real_case (double *x, double *y, double *z)
{ ...
*z=...;
}
void myfunction (header *hd)
{ spread2(real_case,complex_case,hd);
}
There is also a function "spread2r".
THE GENERAL CASE
----------------
This is more difficult. First of all you need to collect all
parameters. Since some of them may be references, you need to compute
the values of these references. This is done by the following code
void myfunction (header *hd)
{ header *result,*hd1=hd,*hd2,*hd3,...;
hd2=nextof(hd1); hd3=nextof(hd2); ...
hd1=getvalue(hd1); hd2=getvalue(hd2); ...
if (error) return;
... /* computations */
moveresult(hd,result);
}
Of course, you may not use more arguments than specified in
builtin_list. If you specified 0 arguments, you need to test, if hd1,
hd2, are bigger than newram, like in
if ((char *)hd1 >= newram) ...
Since an error may occur in a reference to a non-existing variable,
you must check the variable error.
Having done this, you should check the types of the arguments.
if (hd1->type!=s_matrix) ...
If you do not support the specific type, you should set error to 10000
(a value, reserved for this purpose) and return. Finally, it is a good
idea to use getmatrix to get the size and address of any matrix
involved.
Now you have the parameters. You will need a place to put the return
value (or values, if your function returns multiple values). This can
be done with the "new_..." functions. All these functions have a
parameter name, which you can set to "" simply. If there is no
sufficient space, error is set to 1.
header *new_matrix (int c, int r, char *name);
Creates a matrix with r rows and c columns.
header *new_cmatrix (int c, int r, char *name);
The same for a complex matrix.
header *new_real (double x, char *name);
A real number with the value x.
header *new_complex (double x, double y, char *name);
A complex number with the value x+iy.
header *new_string (char *s, size_t size, char *name);
A string of size "size", to which s is copied.
For example
header *result;
result=new_matrix(10,10,"");
After you computed your result and copied it into the result variable,
you need to move the result to the stack using "moveresult" (see above).
In case of multiple results, use a code like
header *result1,*result2;
...
moveresult(hd,result1); hd=nextof(hd);
moveresult(hd,result2);
Lets give a simple example. We define a function, which flips a matrix
along the second diagonal (from lower left to upper right). The
changes in builtin_list are then
"tflip",1,tflip,
void tflip (header *hd)
{ header *st=hd,*result;
int i,j,c,r;
double *m1,*m2;
hd=getvalue(hd); if (error) return;
if (hd->type==s_real || hd->type==s_matrix)
{ getmatrix(hd,&r,&c,&m1);
result=new_matrix(c,r,""); if (error) return;
m2=matrixof(result);
for (i=0; i<r; i++)
for (j=0; j<c; j++)
*mat(m2,r,j,i)=*mat(m1,c,i,j);
}
else if (hd->type==s_complex || hd->type==s_cmatrix)
{ getmatrix(hd,&r,&c,&m1);
result=new_cmatrix(c,r,""); if (error) return;
m2=matrixof(result);
for (i=0; i<r; i++)
for (j=0; j<c; j++)
{ *cmat(m2,r,j,i)=*cmat(m1,c,i,j);
*(cmat(m2,r,j,i)+1)=*(cmat(m1,c,i,j)+1);
}
}
else
{ output("Error in tflip. Illegal argument.\n");
error=10000; return;
}
moveresult(st,result);
}
output(char *) is a means to produce an error message related to the
error.
PLEASE
------
If you have an interesting extension to EULER, please send me a copy.
I might encorporate it to the benefit of other users.
Dr. R. Grothmann
Kath. Univ. Eichstaett
8078 Eichstaett
Germany