123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /* file asps.c */
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 6a193f20 08-Apr-2002 */
- #include <stdarg.h>
- #include <sys/types.h>
- #include "machine.h"
- #include "tags.h"
- #include "cslerror.h"
- #include "externs.h"
- #include "entries.h"
- #include "arith.h"
- #ifndef WINDOWS_NT
- #define __stdcall
- #endif
- /*
- * The overall design for the asps mechanism relies on the following facts:
- * 1. No NAG routine uses the same type of ASP more than once.
- * 2. We have a hard-coded limit of 10 Asps in use at any one time (in
- * theory we could make this 10 Asps per NAG routine by changing the
- * storage strategy for the code/environment pairs).
- * 3. If NAG routines call one another, they do it via the top-level AXIOM
- * interfaces (and so go through the setup/restore process.
- *
- * The code and environment are the values obtained by applying car and cdr
- * respectively to a spadclosure. They are used in calling funcall in lisp
- * as follows:
- * (FUNCALL code arg1 arg2 ... argn environment)
- *
- * When we call setup on an asp, we push the code part onto user_base_0 and
- * the environment onto user_base_1 (which we treat as Lisp lists), and then
- * store the index in user_base_0/user_base_1 into the appropriate variable
- * (this is the index counting from the base).
- *
- * When we call an asp we copy the appropriate code/environment portions onto
- * users_base_2 and user_base_3, and pass them as arguments to Lfuncall and
- * friends.
- *
- * When we call restore on an asp we pop user_base_0/user_base_1 (this is
- * dodgey in one sense, but we assume that we restore all the asps from a
- * NAG call at the same time so the order in which we pop the user_bases is
- * in fact immaterial). Finally we restore the old asp_n_pointer value.
- *
- */
- extern Lisp_Object user_base_0, user_base_1, user_base_2, user_base_3;
- #define CODE_STACK user_base_0
- #define ENVIRONMENT_STACK user_base_1
- #define CODE user_base_2
- #define ENVIRONMENT user_base_3
- /* The number of asps on the stacks at present. */
- int32 stack_depth=0;
- /*
- * The current location of an asp's code/environment is stored on a stack, so
- * that we can nest calls which use asps.
- *
- */
- typedef struct Asp_Loc {
- int32 loc;
- struct Asp_Loc *next;
- } Asp_Loc;
- Asp_Loc *asp1_index=NULL,*asp4_index=NULL,*asp6_index=NULL,*asp35_index=NULL;
- #define location(asp) \
- (asp == NULL) ? aerror0("Asp calling mechanism corrupted"): asp -> loc;
- Asp_Loc *push_asp_num(Asp_Loc *asp) {
- Asp_Loc *new;
- new = (Asp_Loc *)malloc(sizeof(Asp_Loc));
- new->next = asp;
- new->loc = stack_depth;
- return(new);
- }
- #define pop_asp_num(asp) asp->next
- void push_asp(Lisp_Object nil, Lisp_Object f_code, Lisp_Object f_env)
- {
- Lisp_Object w;
- if (stack_depth == 0) {
- push(f_env);
- w = ncons(f_code);
- pop(f_env);
- errexitv();
- f_code = w;
- push(f_code);
- w = ncons(f_env);
- pop(f_code);
- errexitv();
- f_env = w;
- CODE_STACK = f_code;
- ENVIRONMENT_STACK = f_env;
- }
- else {
- push(f_env);
- w = Lcons(nil,f_code,CODE_STACK);
- pop(f_env);
- errexitv();
- f_code = w;
- push(f_code);
- w = Lcons(nil,f_env,ENVIRONMENT_STACK);
- pop(f_code);
- errexitv();
- f_env = w;
- CODE_STACK = f_code;
- ENVIRONMENT_STACK = f_env;
- }
- ++ stack_depth;
- }
- void pop_asp(Lisp_Object nil)
- {
- CODE_STACK=qcdr(CODE_STACK);
- ENVIRONMENT_STACK=qcdr(ENVIRONMENT_STACK);
- -- stack_depth;
- }
- #define get_code(index) Lelt(C_nil,CODE_STACK,fixnum_of_int(stack_depth-index))
- #define get_env(index) Lelt(C_nil,ENVIRONMENT_STACK,fixnum_of_int(stack_depth-index))
- /*
- * This function restores the global variables which are used in calling asps
- * to their previous state.
- */
- Lisp_Object asp_restore(Lisp_Object nil, int32 asp)
- {
- pop_asp(nil);
- switch (int_of_fixnum(asp))
- {
- case 1:
- asp1_index = pop_asp_num(asp1_index);
- break;
- case 4:
- asp4_index = pop_asp_num(asp4_index);
- break;
- case 6:
- asp6_index = pop_asp_num(asp6_index);
- break;
- case 35:
- asp35_index = pop_asp_num(asp35_index);
- break;
- default:
- aerror1("asp_restore: Unknown asp type:",asp);
- break;
- }
- return onevalue(lisp_true);
- }
- /*
- * This function sets up the global variables which are needed in calling asps
- */
- Lisp_Object MS_CDECL asp_set(Lisp_Object nil, int nargs, ...)
- {
- int32 asp;
- va_list args;
- Lisp_Object aspnum, f_car, f_cdr;
- argcheck(nargs,3,"asp_set");
- va_start(args,nargs);
- aspnum = va_arg(args, Lisp_Object);
- f_car = va_arg(args, Lisp_Object);
- f_cdr = va_arg(args, Lisp_Object);
- va_end(args);
- asp = int_of_fixnum(aspnum);
- switch (asp)
- {
- case 1:
- push_asp(nil,f_car, f_cdr);
- errexit();
- asp1_index = push_asp_num(asp1_index);
- break;
- case 4:
- push_asp(nil,f_car, f_cdr);
- errexit();
- asp4_index = push_asp_num(asp4_index);
- break;
- case 6:
- push_asp(nil,f_car, f_cdr);
- errexit();
- asp6_index = push_asp_num(asp6_index);
- break;
- case 35:
- push_asp(nil,f_car, f_cdr);
- errexit();
- asp35_index = push_asp_num(asp35_index);
- break;
- default:
- aerror1("asp_set: Unknown asp type:",aspnum);
- break;
- }
- return onevalue(lisp_true);
- }
- /* Routines for converting between representations. */
- Lisp_Object mkAXIOMVectorDF(double *v, int32 dim)
- {
- Lisp_Object nil=C_nil;
- Lisp_Object new, Lflt;
- int32 i;
- new = getvector(TAG_VECTOR, TYPE_SIMPLE_VEC, 4*dim+4);
- errexit();
- /* vectors must pad to an even number of words */
- if ((dim & 1) == 0) elt(new,dim) = nil;
- for (i=0;i<dim;++i) {
- push(new);
- Lflt = make_boxfloat(*(v+i),TYPE_DOUBLE_FLOAT);
- pop(new);
- errexit();
- elt(new,i) = Lflt;
- }
- return onevalue(new);
- }
- void mkFortranVectorDouble(double *loc, Lisp_Object v, int32 dim)
- {
- int32 i;
- /*Lisp_Object nil=C_nil;*/
- for (i=0;i<dim;++i) {
- push(v);
- *(loc + i) = float_of_number(elt(v,i));
- pop(v);
- }
- }
- void mkFortran2DArrayDouble(double *loc, Lisp_Object v, int32 rows, int32 cols)
- {
- int32 i,j;
- /*Lisp_Object nil=C_nil;*/
- for (i=0;i<rows;++i)
- for (j=0;j<cols;++j) {
- push(v);
- *(loc + j*cols + i) = float_of_number(elt(v,i*cols+j));
- pop(v);
- }
- }
- /* Code for ASP1 */
- double __stdcall asp1 (double *x)
- {
- Lisp_Object arg = make_boxfloat(*x,TYPE_DOUBLE_FLOAT), result, code, env;
- Lisp_Object nil = C_nil;
- code = get_code(asp1_index->loc);
- env = get_env(asp1_index->loc);
- result = Lfuncalln(C_nil,3,code,arg,env);
- errexit();
- if (exception_pending()) aerror0("Error in evaluating function (ASP1)");
- return float_of_number(result);
- }
- #ifdef TEST_ASPS
- Lisp_Object test_asp1(Lisp_Object nil, Lisp_Object a)
- {
- double arg = float_of_number(a);
- arg=asp1(&arg);
- return make_boxfloat(arg,TYPE_DOUBLE_FLOAT);
- }
- #endif
- /* Code for ASP4 */
- double __stdcall asp4 (int32 *ndim, double *x)
- {
- Lisp_Object arg, result, code, env;
- arg = mkAXIOMVectorDF(x,*ndim);
- code = get_code(asp4_index->loc);
- env = get_env(asp4_index->loc);
- result = Lfuncalln(C_nil,3,code,arg,env);
- return float_of_number(result);
- }
- #ifdef TEST_ASPS
- Lisp_Object test_asp4(Lisp_Object nil, Lisp_Object v)
- {
- double *x;
- int ndim;
- Lisp_Object result;
- ndim = (length_of_header(vechdr(v)) - 4)/4;
- x = (double *)malloc(ndim*sizeof(double));
- mkFortranVectorDouble(x,v,ndim);
- result = make_boxfloat(asp4(&ndim,x),TYPE_DOUBLE_FLOAT);
- free(x);
- return(result);
- }
- #endif
- /* Code for ASP6 */
- void __stdcall asp6 (int32 *n, double *x, double *fvec, int32 *iflag)
- {
- Lisp_Object arg, code, env;
- arg = mkAXIOMVectorDF(x,*n);
- code = get_code(asp6_index->loc);
- env = get_env(asp6_index->loc);
- mkFortranVectorDouble(fvec,Lfuncalln(C_nil,3,code,arg,env),*n);
- }
- #ifdef TEST_ASPS
- Lisp_Object test_asp6(Lisp_Object nil, Lisp_Object v)
- {
- double *x, *fvec;
- int n,iflag;
- Lisp_Object result;
- n = (length_of_header(vechdr(v)) - 4)/4;
- x = (double *)malloc(n*sizeof(double));
- fvec = (double *)malloc(n*sizeof(double));
- mkFortranVectorDouble(x,v,n);
- asp6(&n,x,fvec,&iflag);
- result = mkAXIOMVectorDF(fvec,n);
- free(x);
- free(fvec);
- return(result);
- }
- #endif
- /* Code for ASP35 */
- void __stdcall asp35 (int32 *n, double *x, double *fvec, double *fjac,
- int32 *ldfjac, int32 *iflag)
- {
- Lisp_Object Lx, Liflag, Lresult, code, env;
- Lx = mkAXIOMVectorDF(x,*n);
- Liflag = fixnum_of_int(*iflag);
- code = get_code(asp35_index->loc);
- env = get_env(asp35_index->loc);
- Lresult = Lfuncalln(C_nil,4,code,Lx,Liflag,env);
- if (*iflag == 1)
- mkFortranVectorDouble(fvec,Lresult,*n);
- else
- mkFortran2DArrayDouble(fjac,Lresult,*ldfjac,*n);
- }
- #ifdef TEST_ASPS
- Lisp_Object test_asp35(Lisp_Object nil, Lisp_Object v, Lisp_Object flag)
- {
- double *x, *fvec, *fjac;
- int n, ldfjac, iflag;
- Lisp_Object result;
- n = (length_of_header(vechdr(v)) - 4)/4;
- ldfjac=n;
- x = (double *)malloc(n*sizeof(double));
- mkFortranVectorDouble(x,v,n);
- fjac = (double *)malloc(n*ldfjac*sizeof(double));
- fvec = (double *)malloc(n*sizeof(double));
- iflag=int_of_fixnum(flag);
- asp35(&n,x,fvec,fjac,&ldfjac,&iflag);
- if (iflag == 1)
- result = mkAXIOMVectorDF(fvec,n);
- else
- result = mkAXIOMVectorDF(fjac,n*ldfjac);
- free(x);
- free(fjac);
- free(fvec);
- return(result);
- }
- #endif
- #ifndef TEST_ASPS
- Lisp_Object asp_error1(Lisp_Object nil, Lisp_Object a1)
- {
- return aerror0("The Windows version of the NAG Link is not installed");
- }
- Lisp_Object asp_error2(Lisp_Object nil, Lisp_Object a1, Lisp_Object a2)
- {
- return aerror0("The Windows version of the NAG Link is not installed");
- }
- Lisp_Object MS_CDECL asp_error0(Lisp_Object nil, int32 nargs, ...)
- {
- return aerror0("The Windows version of the NAG Link is not installed");
- }
- #endif
- setup_type const asp_setup[] =
- {
- {"asp-setup", wrong_no_na, wrong_no_nb, asp_set},
- {"asp-restore", asp_restore, too_many_1, wrong_no_1},
- #ifdef TEST_ASPS
- {"asp1", test_asp1, too_many_1, wrong_no_1},
- {"asp4", test_asp4, too_many_1, wrong_no_1},
- {"asp6", test_asp6, too_many_1, wrong_no_1},
- {"asp35", too_few_2, test_asp35, wrong_no_2},
- #else
- {"asp1", asp_error1, asp_error2, asp_error0},
- {"asp4", asp_error1, asp_error2, asp_error0},
- {"asp6", asp_error1, asp_error2, asp_error0},
- {"asp35", asp_error1, asp_error2, asp_error0},
- #endif
- {NULL, 0, 0, 0}
- };
- /* end of file asps.c */
|