home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / apps / math / euler / doc / extend.doc < prev    next >
Text File  |  1992-05-08  |  9KB  |  278 lines

  1.  
  2. INTRODUCTION
  3. ------------
  4.  
  5. This document describes how to extend EULER with own functions. Of
  6. course, you need a compiler capable of translating the source code.
  7. And you might probably need some good programming experience in C.
  8. Furthermore, it is necessary that you have some practice in using
  9. EULER.
  10.  
  11.  
  12. BASICS
  13. ------
  14.  
  15. EULER uses a stack for keeping the variables (local and global) and
  16. the parameters of functions. This stack starts with the user defined
  17. functions (udf). Next we have the global variables, and on top of them
  18. the parameters and variables of running functions. The stack grows
  19. from lower to higher memory. This description makes clear, why one
  20. cannot change the size of a global variable from within a function.
  21.  
  22. The elements of the stack start with a header of data type
  23.     typedef struct { LONG size; char name[16]; int xor; stacktyp type; }
  24.         header;
  25. consisting of the total size of the stack element, its name and an
  26. index code of the name (to compare it easily), and the type of the
  27. data, which an enum type
  28.     typedef enum { s_real,s_complex,s_matrix,s_cmatrix,
  29.         s_reference,s_command,s_submatrix,s_csubmatrix,s_string,s_udf }
  30.         stacktyp;
  31. The different data types will be explaned in detail below. Every stack
  32. element has a header, followed by a further description and the data.
  33.  
  34. s_real : A double value.
  35. s_complex : Two double values (real and imaginary part).
  36. s_matrix : A matrix, consisting of the dimension of type
  37.         typedef struct { int c,r; } dims;
  38.     followed by r rows of c double values.
  39. s_cmatrix : A complex matrix, which differs from s_matrix by having r
  40.     rows of c times two double values.
  41. s_reference : A reference to a variable, which consists of a pointer
  42.     to the header of this variable.
  43. s_string : A string, which consists of the string followed by a 0.
  44.  
  45. All other types are of no interest here.
  46.  
  47. You can avoid to no many of the details, if you use the service
  48. makros, which we will describe now. "hd" is always a pointer to a
  49. header here.
  50.  
  51. #define realof(hd) ((double *)((hd)+1))
  52.     computes the address of the value of a header of type s_real or the
  53.     real part of a header of type s_complex. (note: it returns a
  54.     pointer to the double value!).
  55. #define matrixof(hd) ((double *)((char *)((hd)+1)+sizeof(dims)))
  56.     Computes address the (0,0)-element of a matrix (real or complex).
  57. #define dimsof(hd) ((dims *)((hd)+1))
  58.     Computes the addres of the dimension field of a matrix. I.e.,
  59.     dimsof(hd)->r is the number of rows.
  60. #define referenceof(hd) (*((header **)((hd)+1)))
  61.     Computes a pointer to a pointer to a header for references.
  62. #define imagof(hd) ((double *)((hd)+1)+1)
  63.     Gives a pointer to the imaginary part of a s_complex header.
  64. #define stringof(hd) ((char *)((hd)+1))
  65.     Computes a pointer to the string for s_string headers.
  66. #define nextof(hd) ((header *)((char *)(hd)+(hd)->size))
  67.     Computes the a pointer to the header of the next stack element.
  68.  
  69. With these functions, you might get pointers to the details of stack
  70. elements. There are a few more functions and makros.
  71.  
  72. void getmatrix (header *hd, int *r, int *c, double **m);
  73.     Computes the size (rows and columns) and the start address of a
  74.     matrix (real or complex). This works also for real and complex
  75.     values.
  76. #define mat(m,c,i,j) (m+(LONG)(c)*(i)+(j))
  77.     Computes the address of the (i,j)-th element of a matrix starting
  78.     at m. c is the number of rows of the matrix.
  79. #define cmat(m,c,i,j) (m+2*((LONG)(c)*(i)+(j)))
  80.     The same for a complex matrix.
  81.  
  82. There are two important variables
  83.     char *newram,*ramend;
  84. The pointer newram indicates the start of the unused area of the
  85. stack. You may use the portion of memory between newram and ramend for
  86. own purposes, as long as you do not allocate new stack elements.
  87.  
  88.  
  89. DECLARING FUNCTIONS
  90. -------------------
  91.  
  92. Each function must be declared in "extend.c". First of all, you need
  93. to add a prototype to the long list of prototypes in that file. It
  94. simply has the form
  95.     void myfunction (header *hd);
  96. Next, you need to append the function to the builtin_list array. You
  97. must add a line of the form
  98.     "myname",2,myfunction,
  99. Here, "myname" is the name the function can be called in EULER. 2 (or
  100. any other number) is the number of parameters the function accepts.
  101. You may have two functions with the same name and a different number
  102. of arguments. "myfunction" is the name of the function in the source
  103. code. If the argument number is equal to 0, myname must be unique, and
  104. the function is called without regard for the number of arguments.
  105.  
  106. Finally, you will have to program the function. You could simply add
  107. the function to the file "extend.c".
  108.  
  109.  
  110. FUNCTIONS OF ONE REAL OR COMPLEX VALUE
  111. --------------------------------------
  112.  
  113. This is easy. You define a function for the real and a function for
  114. the complex case.
  115.  
  116. double real_case (double x)
  117. {    ...
  118.     return ...;
  119. }
  120.  
  121. void complex_case (double *x, double *xi, double *z, double *zi)
  122. {    *z=...;
  123.     *zi=...;
  124. }
  125.  
  126. void myfunction (header *hd)
  127. {    spread1(real_case,complex_case,hd);
  128. }
  129.  
  130. If you pass a 0 pointer, instead of complex_case, the complex case is
  131. undefined and a complex value issues an error message. Of course, the
  132. function "myfunction" will work for a matrix element by element.
  133.  
  134. If the function has a real result for the complex case, you may use
  135. the function "spread1r" instead. Of course the complex case is then to
  136. be defined as
  137.  
  138. void complex_case (double *x, double *xi, double *r)
  139. { ...
  140. }
  141.  
  142.  
  143. FUNCTIONS OF TWO REAL OF COMPLEX VALUES
  144. ---------------------------------------
  145.  
  146. This is also easy. Again, you define a function for the real and the
  147. complex case.
  148.  
  149. void complex_case (double *x, double *xi, double *y, double *yi,
  150.     double *z, double *zi)
  151. {    ...
  152.     *z=...;
  153.     *zi=...;
  154. }
  155.  
  156. void real_case (double *x, double *y, double *z)
  157. {    ...
  158.     *z=...;
  159. }
  160.  
  161. void myfunction (header *hd)
  162. {    spread2(real_case,complex_case,hd);
  163. }
  164.  
  165. There is also a function "spread2r".
  166.  
  167.  
  168. THE GENERAL CASE
  169. ----------------
  170.  
  171. This is more difficult. First of all you need to collect all
  172. parameters. Since some of them may be references, you need to compute
  173. the values of these references. This is done by the following code
  174.  
  175. void myfunction (header *hd)
  176. {    header *result,*hd1=hd,*hd2,*hd3,...;
  177.     hd2=nextof(hd1); hd3=nextof(hd2); ...
  178.     hd1=getvalue(hd1); hd2=getvalue(hd2); ...
  179.     if (error) return;
  180.     ... /* computations */
  181.     moveresult(hd,result);
  182. }
  183.  
  184. Of course, you may not use more arguments than specified in
  185. builtin_list. If you specified 0 arguments, you need to test, if hd1,
  186. hd2, are bigger than newram, like in
  187.     if ((char *)hd1 >= newram) ...
  188. Since an error may occur in a reference to a non-existing variable,
  189. you must check the variable error.
  190.  
  191. Having done this, you should check the types of the arguments.
  192.     if (hd1->type!=s_matrix) ...
  193. If you do not support the specific type, you should set error to 10000
  194. (a value, reserved for this purpose) and return. Finally, it is a good
  195. idea to use getmatrix to get the size and address of any matrix
  196. involved.
  197.  
  198. Now you have the parameters. You will need a place to put the return
  199. value (or values, if your function returns multiple values). This can
  200. be done with the "new_..." functions. All these functions have a
  201. parameter name, which you can set to "" simply. If there is no
  202. sufficient space, error is set to 1.
  203.  
  204. header *new_matrix (int c, int r, char *name);
  205.     Creates a matrix with r rows and c columns.
  206. header *new_cmatrix (int c, int r, char *name);
  207.     The same for a complex matrix.
  208. header *new_real (double x, char *name);
  209.     A real number with the value x.
  210. header *new_complex (double x, double y, char *name);
  211.     A complex number with the value x+iy.
  212. header *new_string (char *s, size_t size, char *name);
  213.     A string of size "size", to which s is copied.
  214.  
  215. For example
  216.     header *result;
  217.     result=new_matrix(10,10,"");
  218.  
  219. After you computed your result and copied it into the result variable,
  220. you need to move the result to the stack using "moveresult" (see above).
  221. In case of multiple results, use a code like
  222.     header *result1,*result2;
  223.     ...
  224.     moveresult(hd,result1); hd=nextof(hd);
  225.     moveresult(hd,result2);
  226.  
  227. Lets give a simple example. We define a function, which flips a matrix
  228. along the second diagonal (from lower left to upper right). The
  229. changes in builtin_list are then
  230.     "tflip",1,tflip,
  231.  
  232. void tflip (header *hd)
  233. {    header *st=hd,*result;
  234.     int i,j,c,r;
  235.     double *m1,*m2;
  236.     hd=getvalue(hd); if (error) return;
  237.     if (hd->type==s_real || hd->type==s_matrix)
  238.     {    getmatrix(hd,&r,&c,&m1);
  239.         result=new_matrix(c,r,""); if (error) return;
  240.         m2=matrixof(result);
  241.         for (i=0; i<r; i++)
  242.             for (j=0; j<c; j++)
  243.                 *mat(m2,r,j,i)=*mat(m1,c,i,j);
  244.     }
  245.     else if (hd->type==s_complex || hd->type==s_cmatrix)
  246.     {    getmatrix(hd,&r,&c,&m1);
  247.         result=new_cmatrix(c,r,""); if (error) return;
  248.         m2=matrixof(result);
  249.         for (i=0; i<r; i++)
  250.             for (j=0; j<c; j++)
  251.             {    *cmat(m2,r,j,i)=*cmat(m1,c,i,j);
  252.                 *(cmat(m2,r,j,i)+1)=*(cmat(m1,c,i,j)+1);
  253.             }
  254.     }
  255.     else
  256.     {    output("Error in tflip. Illegal argument.\n");
  257.         error=10000; return;
  258.     }
  259.     moveresult(st,result);
  260. }
  261.  
  262. output(char *) is a means to produce an error message related to the
  263. error.
  264.  
  265.  
  266. PLEASE
  267. ------
  268.  
  269. If you have an interesting extension to EULER, please send me a copy.
  270. I might encorporate it to the benefit of other users.
  271.  
  272.  
  273. Dr. R. Grothmann
  274. Kath. Univ. Eichstaett
  275. 8078 Eichstaett
  276. Germany
  277.  
  278.