asps.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /* file asps.c */
  2. /* Signature: 3637adcc 27-Jan-1997 */
  3. #include <stdarg.h>
  4. #include <sys/types.h>
  5. #include "machine.h"
  6. #include "tags.h"
  7. #include "cslerror.h"
  8. #include "externs.h"
  9. #include "entries.h"
  10. #include "arith.h"
  11. #ifndef WINDOWS_NT
  12. #define __stdcall
  13. #endif
  14. /*
  15. * The overall design for the asps mechanism relies on the following facts:
  16. * 1. No NAG routine uses the same type of ASP more than once.
  17. * 2. We have a hard-coded limit of 10 Asps in use at any one time (in
  18. * theory we could make this 10 Asps per NAG routine by changing the
  19. * storage strategy for the code/environment pairs).
  20. * 3. If NAG routines call one another, they do it via the top-level AXIOM
  21. * interfaces (and so go through the setup/restore process.
  22. *
  23. * The code and environment are the values obtained by applying car and cdr
  24. * respectively to a spadclosure. They are used in calling funcall in lisp
  25. * as follows:
  26. * (FUNCALL code arg1 arg2 ... argn environment)
  27. *
  28. * When we call setup on an asp, we push the code part onto user_base_0 and
  29. * the environment onto user_base_1 (which we treat as Lisp lists), and then
  30. * store the index in user_base_0/user_base_1 into the appropriate variable
  31. * (this is the index counting from the base).
  32. *
  33. * When we call an asp we copy the appropriate code/environment portions onto
  34. * users_base_2 and user_base_3, and pass them as arguments to Lfuncall and
  35. * friends.
  36. *
  37. * When we call restore on an asp we pop user_base_0/user_base_1 (this is
  38. * dodgey in one sense, but we assume that we restore all the asps from a
  39. * NAG call at the same time so the order in which we pop the user_bases is
  40. * in fact immaterial). Finally we restore the old asp_n_pointer value.
  41. *
  42. */
  43. extern Lisp_Object user_base_0, user_base_1, user_base_2, user_base_3;
  44. #define CODE_STACK user_base_0
  45. #define ENVIRONMENT_STACK user_base_1
  46. #define CODE user_base_2
  47. #define ENVIRONMENT user_base_3
  48. /* The number of asps on the stacks at present. */
  49. int32 stack_depth=0;
  50. /*
  51. * The current location of an asp's code/environment is stored on a stack, so
  52. * that we can nest calls which use asps.
  53. *
  54. */
  55. typedef struct Asp_Loc {
  56. int32 loc;
  57. struct Asp_Loc *next;
  58. } Asp_Loc;
  59. Asp_Loc *asp1_index=NULL,*asp4_index=NULL,*asp6_index=NULL,*asp35_index=NULL;
  60. #define location(asp) \
  61. (asp == NULL) ? aerror0("Asp calling mechanism corrupted"): asp -> loc;
  62. Asp_Loc *push_asp_num(Asp_Loc *asp) {
  63. Asp_Loc *new;
  64. new = (Asp_Loc *)malloc(sizeof(Asp_Loc));
  65. new->next = asp;
  66. new->loc = stack_depth;
  67. return(new);
  68. }
  69. #define pop_asp_num(asp) asp->next
  70. void push_asp(Lisp_Object nil, Lisp_Object f_code, Lisp_Object f_env)
  71. {
  72. Lisp_Object w;
  73. if (stack_depth == 0) {
  74. push(f_env);
  75. w = ncons(f_code);
  76. pop(f_env);
  77. errexitv();
  78. f_code = w;
  79. push(f_code);
  80. w = ncons(f_env);
  81. pop(f_code);
  82. errexitv();
  83. f_env = w;
  84. CODE_STACK = f_code;
  85. ENVIRONMENT_STACK = f_env;
  86. }
  87. else {
  88. push(f_env);
  89. w = Lcons(nil,f_code,CODE_STACK);
  90. pop(f_env);
  91. errexitv();
  92. f_code = w;
  93. push(f_code);
  94. w = Lcons(nil,f_env,ENVIRONMENT_STACK);
  95. pop(f_code);
  96. errexitv();
  97. f_env = w;
  98. CODE_STACK = f_code;
  99. ENVIRONMENT_STACK = f_env;
  100. }
  101. ++ stack_depth;
  102. }
  103. void pop_asp(Lisp_Object nil)
  104. {
  105. CODE_STACK=qcdr(CODE_STACK);
  106. ENVIRONMENT_STACK=qcdr(ENVIRONMENT_STACK);
  107. -- stack_depth;
  108. }
  109. #define get_code(index) Lelt(C_nil,CODE_STACK,fixnum_of_int(stack_depth-index))
  110. #define get_env(index) Lelt(C_nil,ENVIRONMENT_STACK,fixnum_of_int(stack_depth-index))
  111. /*
  112. * This function restores the global variables which are used in calling asps
  113. * to their previous state.
  114. */
  115. Lisp_Object asp_restore(Lisp_Object nil, int32 asp)
  116. {
  117. pop_asp(nil);
  118. switch (int_of_fixnum(asp))
  119. {
  120. case 1:
  121. asp1_index = pop_asp_num(asp1_index);
  122. break;
  123. case 4:
  124. asp4_index = pop_asp_num(asp4_index);
  125. break;
  126. case 6:
  127. asp6_index = pop_asp_num(asp6_index);
  128. break;
  129. case 35:
  130. asp35_index = pop_asp_num(asp35_index);
  131. break;
  132. default:
  133. aerror1("asp_restore: Unknown asp type:",asp);
  134. break;
  135. }
  136. return onevalue(lisp_true);
  137. }
  138. /*
  139. * This function sets up the global variables which are needed in calling asps
  140. */
  141. Lisp_Object MS_CDECL asp_set(Lisp_Object nil, int nargs, ...)
  142. {
  143. int32 asp;
  144. va_list args;
  145. Lisp_Object aspnum, f_car, f_cdr;
  146. argcheck(nargs,3,"asp_set");
  147. va_start(args,nargs);
  148. aspnum = va_arg(args, Lisp_Object);
  149. f_car = va_arg(args, Lisp_Object);
  150. f_cdr = va_arg(args, Lisp_Object);
  151. va_end(args);
  152. asp = int_of_fixnum(aspnum);
  153. switch (asp)
  154. {
  155. case 1:
  156. push_asp(nil,f_car, f_cdr);
  157. errexit();
  158. asp1_index = push_asp_num(asp1_index);
  159. break;
  160. case 4:
  161. push_asp(nil,f_car, f_cdr);
  162. errexit();
  163. asp4_index = push_asp_num(asp4_index);
  164. break;
  165. case 6:
  166. push_asp(nil,f_car, f_cdr);
  167. errexit();
  168. asp6_index = push_asp_num(asp6_index);
  169. break;
  170. case 35:
  171. push_asp(nil,f_car, f_cdr);
  172. errexit();
  173. asp35_index = push_asp_num(asp35_index);
  174. break;
  175. default:
  176. aerror1("asp_set: Unknown asp type:",aspnum);
  177. break;
  178. }
  179. return onevalue(lisp_true);
  180. }
  181. /* Routines for converting between representations. */
  182. Lisp_Object mkAXIOMVectorDF(double *v, int32 dim)
  183. {
  184. Lisp_Object nil=C_nil;
  185. Lisp_Object new, Lflt;
  186. int32 i;
  187. new = getvector(TAG_VECTOR, TYPE_SIMPLE_VEC, 4*dim+4);
  188. errexit();
  189. /* vectors must pad to an even number of words */
  190. if ((dim & 1) == 0) elt(new,dim) = nil;
  191. for (i=0;i<dim;++i) {
  192. push(new);
  193. Lflt = make_boxfloat(*(v+i),TYPE_DOUBLE_FLOAT);
  194. pop(new);
  195. errexit();
  196. elt(new,i) = Lflt;
  197. }
  198. return onevalue(new);
  199. }
  200. void mkFortranVectorDouble(double *loc, Lisp_Object v, int32 dim)
  201. {
  202. int32 i;
  203. Lisp_Object nil=C_nil;
  204. for (i=0;i<dim;++i) {
  205. push(v);
  206. *(loc + i) = float_of_number(elt(v,i));
  207. pop(v);
  208. }
  209. }
  210. void mkFortran2DArrayDouble(double *loc, Lisp_Object v, int32 rows, int32 cols)
  211. {
  212. int32 i,j;
  213. Lisp_Object nil=C_nil;
  214. for (i=0;i<rows;++i)
  215. for (j=0;j<cols;++j) {
  216. push(v);
  217. *(loc + j*cols + i) = float_of_number(elt(v,i*cols+j));
  218. pop(v);
  219. }
  220. }
  221. /* Code for ASP1 */
  222. double __stdcall asp1 (double *x)
  223. {
  224. Lisp_Object arg = make_boxfloat(*x,TYPE_DOUBLE_FLOAT), result, code, env;
  225. Lisp_Object nil = C_nil;
  226. code = get_code(asp1_index->loc);
  227. env = get_env(asp1_index->loc);
  228. result = Lfuncalln(C_nil,3,code,arg,env);
  229. errexit();
  230. if (exception_pending()) aerror0("Error in evaluating function (ASP1)");
  231. return float_of_number(result);
  232. }
  233. #ifdef TEST_ASPS
  234. Lisp_Object test_asp1(Lisp_Object nil, Lisp_Object a)
  235. {
  236. double arg = float_of_number(a);
  237. arg=asp1(&arg);
  238. return make_boxfloat(arg,TYPE_DOUBLE_FLOAT);
  239. }
  240. #endif
  241. /* Code for ASP4 */
  242. double __stdcall asp4 (int32 *ndim, double *x)
  243. {
  244. Lisp_Object arg, result, code, env;
  245. arg = mkAXIOMVectorDF(x,*ndim);
  246. code = get_code(asp4_index->loc);
  247. env = get_env(asp4_index->loc);
  248. result = Lfuncalln(C_nil,3,code,arg,env);
  249. return float_of_number(result);
  250. }
  251. #ifdef TEST_ASPS
  252. Lisp_Object test_asp4(Lisp_Object nil, Lisp_Object v)
  253. {
  254. double *x;
  255. int ndim;
  256. Lisp_Object result;
  257. ndim = (length_of_header(vechdr(v)) - 4)/4;
  258. x = (double *)malloc(ndim*sizeof(double));
  259. mkFortranVectorDouble(x,v,ndim);
  260. result = make_boxfloat(asp4(&ndim,x),TYPE_DOUBLE_FLOAT);
  261. free(x);
  262. return(result);
  263. }
  264. #endif
  265. /* Code for ASP6 */
  266. void __stdcall asp6 (int32 *n, double *x, double *fvec, int32 *iflag)
  267. {
  268. Lisp_Object arg, code, env;
  269. arg = mkAXIOMVectorDF(x,*n);
  270. code = get_code(asp6_index->loc);
  271. env = get_env(asp6_index->loc);
  272. mkFortranVectorDouble(fvec,Lfuncalln(C_nil,3,code,arg,env),*n);
  273. }
  274. #ifdef TEST_ASPS
  275. Lisp_Object test_asp6(Lisp_Object nil, Lisp_Object v)
  276. {
  277. double *x, *fvec;
  278. int n,iflag;
  279. Lisp_Object result;
  280. n = (length_of_header(vechdr(v)) - 4)/4;
  281. x = (double *)malloc(n*sizeof(double));
  282. fvec = (double *)malloc(n*sizeof(double));
  283. mkFortranVectorDouble(x,v,n);
  284. asp6(&n,x,fvec,&iflag);
  285. result = mkAXIOMVectorDF(fvec,n);
  286. free(x);
  287. free(fvec);
  288. return(result);
  289. }
  290. #endif
  291. /* Code for ASP35 */
  292. void __stdcall asp35 (int32 *n, double *x, double *fvec, double *fjac,
  293. int32 *ldfjac, int32 *iflag)
  294. {
  295. Lisp_Object Lx, Liflag, Lresult, code, env;
  296. Lx = mkAXIOMVectorDF(x,*n);
  297. Liflag = fixnum_of_int(*iflag);
  298. code = get_code(asp35_index->loc);
  299. env = get_env(asp35_index->loc);
  300. Lresult = Lfuncalln(C_nil,4,code,Lx,Liflag,env);
  301. if (*iflag == 1)
  302. mkFortranVectorDouble(fvec,Lresult,*n);
  303. else
  304. mkFortran2DArrayDouble(fjac,Lresult,*ldfjac,*n);
  305. }
  306. #ifdef TEST_ASPS
  307. Lisp_Object test_asp35(Lisp_Object nil, Lisp_Object v, Lisp_Object flag)
  308. {
  309. double *x, *fvec, *fjac;
  310. int n, ldfjac, iflag;
  311. Lisp_Object result;
  312. n = (length_of_header(vechdr(v)) - 4)/4;
  313. ldfjac=n;
  314. x = (double *)malloc(n*sizeof(double));
  315. mkFortranVectorDouble(x,v,n);
  316. fjac = (double *)malloc(n*ldfjac*sizeof(double));
  317. fvec = (double *)malloc(n*sizeof(double));
  318. iflag=int_of_fixnum(flag);
  319. asp35(&n,x,fvec,fjac,&ldfjac,&iflag);
  320. if (iflag == 1)
  321. result = mkAXIOMVectorDF(fvec,n);
  322. else
  323. result = mkAXIOMVectorDF(fjac,n*ldfjac);
  324. free(x);
  325. free(fjac);
  326. free(fvec);
  327. return(result);
  328. }
  329. #endif
  330. #ifndef TEST_ASPS
  331. Lisp_Object asp_error1(Lisp_Object nil, Lisp_Object a1)
  332. {
  333. return aerror0("The Windows version of the NAG Link is not installed");
  334. }
  335. Lisp_Object asp_error2(Lisp_Object nil, Lisp_Object a1, Lisp_Object a2)
  336. {
  337. return aerror0("The Windows version of the NAG Link is not installed");
  338. }
  339. Lisp_Object MS_CDECL asp_error0(Lisp_Object nil, int32 nargs, ...)
  340. {
  341. return aerror0("The Windows version of the NAG Link is not installed");
  342. }
  343. #endif
  344. setup_type const asp_setup[] =
  345. {
  346. {"asp-setup", wrong_no_na, wrong_no_nb, asp_set},
  347. {"asp-restore", asp_restore, too_many_1, wrong_no_1},
  348. #ifdef TEST_ASPS
  349. {"asp1", test_asp1, too_many_1, wrong_no_1},
  350. {"asp4", test_asp4, too_many_1, wrong_no_1},
  351. {"asp6", test_asp6, too_many_1, wrong_no_1},
  352. {"asp35", too_few_2, test_asp35, wrong_no_2},
  353. #else
  354. {"asp1", asp_error1, asp_error2, asp_error0},
  355. {"asp4", asp_error1, asp_error2, asp_error0},
  356. {"asp6", asp_error1, asp_error2, asp_error0},
  357. {"asp35", asp_error1, asp_error2, asp_error0},
  358. #endif
  359. {NULL, 0, 0, 0}
  360. };
  361. /* end of file asps.c */