minpack.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. /* This file interfaces to some non-linear optimization functions from
  2. minpack. It needs the minpack c header file, which might be Debian
  3. specific because the upstream source is in Fortran, or else the
  4. configuration script will disable it. Best to get the header from
  5. somewhere and try recompiling if necessary.
  6. Copyright (C) 2006 Dennis Furey
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software Foundation,
  17. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #include <avm/common.h>
  20. #include <avm/error.h>
  21. #include <avm/lists.h>
  22. #include <avm/compare.h>
  23. #include <avm/listfuns.h>
  24. #include <avm/apply.h>
  25. #include <avm/matcon.h>
  26. #include <avm/chrcodes.h>
  27. #include <avm/minpack.h>
  28. #if HAVE_MINPACK
  29. #include <math.h>
  30. #include <minpack.h>
  31. #endif
  32. /* points to a stack of function specifications */
  33. typedef struct spec_stack_node *spec_stack;
  34. /* a stack of these is needed for re-entrancy */
  35. struct spec_stack_node
  36. {
  37. list fcn; /* computes the function being optimized */
  38. list jac; /* computes the jacobian */
  39. int fault;
  40. list message;
  41. double *origin;
  42. list *row_number;
  43. int number_of_outputs; /* the output vector length of fcn, in case it's less than the input length */
  44. spec_stack other_specs;
  45. };
  46. /* non-zero means static variables are initialized */
  47. static int initialized = 0;
  48. /* error messages as lists of lists of character representations */
  49. static list minpack_error = NULL;
  50. static list memory_overflow = NULL;
  51. static list bad_minpack_spec = NULL;
  52. static list unrecognized_function_name = NULL;
  53. /* the stack of function specifications whose top is referenced globally by minpack functions */
  54. static spec_stack top = NULL;
  55. /* function names as lists of lists of character representations */
  56. static list wild = NULL;
  57. static list funs = NULL;
  58. #if HAVE_MINPACK
  59. static list avm_lmder (list, int *);
  60. static list avm_lmdif (list, int *);
  61. static list avm_lmstr (list, int *);
  62. static list avm_hybrd (list, int *);
  63. static list avm_hybrj (list, int *);
  64. /* the tightest tolerance worth trying */
  65. #define MINIMUM_TOLERANCE 1E-15
  66. /* the number of retries at bigger tolerances before giving up due to slow convergence */
  67. #define TIME_LIMIT 25
  68. /* the factor by which the tolerance is increased on each attempt */
  69. #define MAGNIFIER 4.64158883361278
  70. #define freeif(x) if (x) \
  71. free (x)
  72. static spec_stack
  73. new_top()
  74. /* returns a pointer to the new top of the stack if it can be allocated */
  75. {
  76. spec_stack next_top;
  77. if (!(next_top = (spec_stack) malloc (sizeof(*next_top))))
  78. return NULL;
  79. memset (next_top, 0, sizeof(*next_top));
  80. next_top->other_specs = top;
  81. return (top = next_top);
  82. }
  83. static void
  84. pop_spec()
  85. /* gets rid of the spec on the top of the stack */
  86. {
  87. spec_stack previous_top;
  88. if (!top)
  89. avm_internal_error (2);
  90. top = (previous_top = top)->other_specs;
  91. free (previous_top);
  92. }
  93. static void
  94. lmder_fcn(m,n,x,fvec,fjac,ldfjac,iflag)
  95. int *m;
  96. int *n;
  97. double *x;
  98. double *fvec;
  99. double *fjac;
  100. int *ldfjac;
  101. int *iflag;
  102. /* the c function to be passed to the minpack lmder function;
  103. evaluates the function in the global variable top->fcn which
  104. is expected to take a list of n reals to a list of m reals, or
  105. evaluates the function in the global variable top->jac, which
  106. expected to take a list of n reals to a matrix with m rows and
  107. n columns */
  108. {
  109. list operand,result,row,col;
  110. int i,j;
  111. double *item;
  112. operand = (top->fault ? NULL : avm_list_of_vector((void *) x,*n,sizeof(double),&(top->fault)));
  113. if (top->fault)
  114. {
  115. top->message = (top->message ? top->message : operand);
  116. *iflag = -1;
  117. return;
  118. }
  119. row = result = avm_recoverable_apply(avm_copied((*iflag == 1) ? top->fcn : top->jac),operand,&(top->fault));
  120. if (top->fault)
  121. {
  122. top->message = result;
  123. *iflag = -1;
  124. return;
  125. }
  126. i = 0;
  127. operand = NULL;
  128. while (top->fault ? 0 : (i < *m))
  129. {
  130. if (*iflag == 1)
  131. {
  132. item = ((top->fault = !row) ? NULL : (double *) avm_value_of_list(row->head,&operand,&(top->fault)));
  133. fvec[i] = ((top->fault) ? 0.0 : (*item - top->origin[i]));
  134. }
  135. else if (!((top->fault) = !row))
  136. {
  137. j = 0;
  138. col = row->head;
  139. while ((top->fault) ? 0 : (j < *n))
  140. {
  141. item = ((top->fault = !col) ? NULL : (double *) avm_value_of_list(col->head,&operand,&(top->fault)));
  142. fjac[(j++ * *m) + i] = (top->fault ? 0.0 : *item);
  143. col = (top->fault ? col : col->tail);
  144. }
  145. top->fault = (top->fault ? 1 : !!col);
  146. }
  147. row = (top->fault ? row : row->tail);
  148. i++;
  149. }
  150. avm_dispose (result);
  151. if (!(top->fault = (top->fault ? 1 : !!row)))
  152. return;
  153. top->message = (operand ? operand : avm_copied(bad_minpack_spec));
  154. *iflag = -1;
  155. return;
  156. }
  157. static list
  158. avm_lmder (operand, fault)
  159. list operand;
  160. int *fault;
  161. /* the operand represents ((f,j),x,y) where f and j are functions
  162. and x and y are lists of reals of length n and m respectively.
  163. y is the preferred output of f, not necessarily 0, and x is
  164. the initial estimate of the input. j is a function that takes
  165. a list of reals to the jacobian of f represented as a list of
  166. rows. The jacobian is a matrix whose ith row is the list of
  167. partial derivatives of the ith output component of f with
  168. respect to each input component. The result returned is a more
  169. accurate estimate of the input if one is found, but is empty
  170. otherwise. Although a different algorithm is used, this
  171. interface is the same as that of avm_hybrj except that the
  172. output list may be longer than the input. If the output is
  173. shorter than the input, (i.e., m < n), this function calls
  174. avm_hybrj instead. */
  175. {
  176. int m;
  177. int n;
  178. double *x;
  179. double *fvec;
  180. double *fjac;
  181. int ldfjac;
  182. double ftol;
  183. double xtol;
  184. double gtol;
  185. int maxfev;
  186. double *diag;
  187. int mode;
  188. double factor;
  189. int nprint;
  190. int info;
  191. int nfev;
  192. int njev;
  193. int *ipvt;
  194. double *qtf;
  195. double *wa1;
  196. double *wa2;
  197. double *wa3;
  198. double *wa4;
  199. list result;
  200. int tries;
  201. spec_stack top;
  202. if (*fault)
  203. return NULL;
  204. result = NULL;
  205. if (*fault = !(operand ? (operand->head ? (operand->head->head ? (operand->head->tail ? !!(operand->tail):0):0):0):0))
  206. return avm_copied (bad_minpack_spec);
  207. m = (int) avm_length(operand->tail->tail);
  208. n = (int) avm_length(operand->tail->head);
  209. if (*fault = !(m ? n : 0))
  210. return avm_copied (bad_minpack_spec);
  211. if (n > m)
  212. return avm_hybrj (operand, fault);
  213. if (!(top = new_top()))
  214. return avm_copied (memory_overflow);
  215. top->fcn = operand->head->head;
  216. top->jac = operand->head->tail;
  217. x = (double *) avm_vector_of_list(operand->tail->head,sizeof(double),&result,fault);
  218. fvec = (double *) malloc(sizeof(double) * m);
  219. fjac = (double *) malloc(sizeof(double) * m * n);
  220. ldfjac = m;
  221. ftol = MINIMUM_TOLERANCE;
  222. xtol = MINIMUM_TOLERANCE;
  223. gtol = 0.0;
  224. maxfev = 100 * (n + 1);
  225. diag = (double *) malloc(sizeof(double) * n);
  226. mode = 1;
  227. factor = 100.0;
  228. nprint = 0;
  229. ipvt = (int *) malloc(sizeof(int) * n);
  230. qtf = (double *) malloc(sizeof(double) * n);
  231. wa1 = (double *) malloc(sizeof(double) * n);
  232. wa2 = (double *) malloc(sizeof(double) * n);
  233. wa3 = (double *) malloc(sizeof(double) * n);
  234. wa4 = (double *) malloc(sizeof(double) * m);
  235. top->origin = (*fault ? NULL : (double *) avm_vector_of_list(operand->tail->tail,sizeof(double),&result,fault));
  236. if (!*fault)
  237. *fault = !(x? (fvec? (fjac? (diag? (ipvt? (qtf? (wa1? (wa2? (wa3? (wa4 ? !!(top->origin):0):0):0):0):0):0):0):0):0):0);
  238. top->message = NULL;
  239. tries = info = top->fault = 0;
  240. while (*fault ? 0 : (!((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))) ? (tries++ < TIME_LIMIT) : 0))
  241. {
  242. lmder_ (&lmder_fcn, &m, &n, x, fvec, fjac, &ldfjac, &ftol, &xtol, &gtol, &maxfev, diag, &mode, &factor, &nprint, &info,
  243. &nfev, &njev, ipvt, qtf, wa1, wa2, wa3, wa4);
  244. if (!info)
  245. avm_internal_error (102);
  246. if (*fault = (top->fault ? 1 : !!(top->message)))
  247. {
  248. if (result ? top->message : NULL)
  249. avm_dispose (top->message);
  250. else
  251. result = (top->message ? top->message : avm_copied(bad_minpack_spec));
  252. }
  253. ftol = ftol * MAGNIFIER;
  254. xtol = xtol * MAGNIFIER;
  255. }
  256. freeif (fvec);
  257. freeif (fjac);
  258. freeif (diag);
  259. freeif (ipvt);
  260. freeif (qtf);
  261. freeif (wa1);
  262. freeif (wa2);
  263. freeif (wa3);
  264. freeif (wa4);
  265. freeif (top->origin);
  266. pop_spec ();
  267. if (*fault ? 0 : ((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))))
  268. result = avm_list_of_vector((void *) x,n,sizeof(double),fault);
  269. freeif (x);
  270. return (*fault ? (result ? result : avm_copied(memory_overflow)) : result);
  271. }
  272. static void
  273. lmstr_fcn(m,n,x,fvec,fjrow,iflag)
  274. int *m;
  275. int *n;
  276. double *x;
  277. double *fvec;
  278. double *fjrow;
  279. int *iflag;
  280. /* the c function to be passed to the minpack lmstr function;
  281. evaluates the function in the global variable top->fcn, which
  282. is expected to take a list of n reals to a list of m reals, or
  283. evaluates the function in the global variable top->jac, which
  284. is expected to take a pair (i,<x1..xn>) of a natural in the
  285. range 0..m-1 and a list of n reals to a list of n reals; also
  286. assumes the global variable top->row_number has been
  287. initialized at least to size m */
  288. {
  289. list operand,result,row;
  290. int i;
  291. double *item;
  292. if (top->fault = (top->fault ? 1 : ((*iflag <= 0) ? 1 : (*iflag > (*m + 1)))))
  293. {
  294. top->message = (top->message ? top->message : avm_copied(minpack_error));
  295. *iflag = -1;
  296. return;
  297. }
  298. operand = avm_list_of_vector((void *) x,*n,sizeof(double),&(top->fault));
  299. if (top->fault ? 0 : (*iflag > 1))
  300. operand = avm_recoverable_join(avm_copied(top->row_number[(*iflag) - 2]),operand);
  301. if (top->fault = (top->fault ? 1 : !operand))
  302. {
  303. top->message = (operand ? operand : avm_copied(memory_overflow));
  304. *iflag = -1;
  305. return;
  306. }
  307. row = result = avm_recoverable_apply(avm_copied((*iflag == 1) ? top->fcn : top->jac), operand, &(top->fault));
  308. if (top->fault)
  309. {
  310. top->message = result;
  311. *iflag = -1;
  312. return;
  313. }
  314. i = 0;
  315. operand = NULL;
  316. while (top->fault ? 0 : (i < ((*iflag == 1) ? *m : *n)))
  317. {
  318. item = ((top->fault = !row) ? NULL : (double *) avm_value_of_list(row->head,&operand,&(top->fault)));
  319. if (*iflag == 1)
  320. fvec[i] = (top->fault ? 0.0 : (*item - top->origin[i]));
  321. else
  322. fjrow[i] = (top->fault ? 0.0 : *item);
  323. row = (top->fault ? row : row->tail);
  324. i++;
  325. }
  326. avm_dispose (result);
  327. if (!(top->fault = (top->fault ? 1 : !!row)))
  328. return;
  329. top->message = (operand ? operand : avm_copied(bad_minpack_spec));
  330. *iflag = -1;
  331. return;
  332. }
  333. static list
  334. avm_lmstr (operand, fault)
  335. list operand;
  336. int *fault;
  337. /* the operand represents ((f,j),x,y) where f and j are functions
  338. and x and y are lists of reals of length n and m respectively.
  339. y is the preferred output of f, not necessarily 0, and x is
  340. the initial estimate of the input. j is a function that takes
  341. row number and a list of reals to the corresponding row of the
  342. jacobian of f. The jacobian is a matrix whose ith row is the
  343. list of partial derivatives of the ith output component of f
  344. with respect to each input component. The result returned is a
  345. more accurate estimate of the input if one is found, but is
  346. empty otherwise. This interface is the same as that of lmder
  347. except that jacobian function has a different calling
  348. convention allowing less memory to be used, appropriately for
  349. problems with a very large output vector and a moderate sized
  350. input vector. It's an error for m to be less than n. */
  351. {
  352. int m;
  353. int n;
  354. double *x;
  355. double *fvec;
  356. double *fjac;
  357. int ldfjac;
  358. double ftol;
  359. double xtol;
  360. double gtol;
  361. int maxfev;
  362. double *diag;
  363. int mode;
  364. double factor;
  365. int nprint;
  366. int info;
  367. int nfev;
  368. int njev;
  369. int *ipvt;
  370. double *qtf;
  371. double *wa1;
  372. double *wa2;
  373. double *wa3;
  374. double *wa4;
  375. list result;
  376. int tries;
  377. int i;
  378. spec_stack top;
  379. if (*fault)
  380. return NULL;
  381. result = NULL;
  382. if (*fault = !(operand ? (operand->head ? (operand->head->head ? (operand->head->tail ? !!(operand->tail):0):0):0):0))
  383. return avm_copied (bad_minpack_spec);
  384. m = (int) avm_length(operand->tail->tail);
  385. n = (int) avm_length(operand->tail->head);
  386. if (*fault = !(m ? (n ? (n <= m) : 0) : 0))
  387. return avm_copied (bad_minpack_spec);
  388. if (!(top = new_top()))
  389. return avm_copied (memory_overflow);
  390. top->fcn = operand->head->head;
  391. top->jac = operand->head->tail;
  392. x = (double *) avm_vector_of_list(operand->tail->head,sizeof(double),&result,fault);
  393. fvec = (double *) malloc(sizeof(double) * m);
  394. fjac = (double *) malloc(sizeof(double) * m * n);
  395. ldfjac = m;
  396. ftol = MINIMUM_TOLERANCE;
  397. xtol = MINIMUM_TOLERANCE;
  398. gtol = 0.0;
  399. maxfev = 100 * (n + 1);
  400. diag = (double *) malloc(sizeof(double) * n);
  401. mode = 1;
  402. factor = 100.0;
  403. nprint = 0;
  404. ipvt = (int *) malloc(sizeof(int) * n);
  405. qtf = (double *) malloc(sizeof(double) * n);
  406. wa1 = (double *) malloc(sizeof(double) * n);
  407. wa2 = (double *) malloc(sizeof(double) * n);
  408. wa3 = (double *) malloc(sizeof(double) * n);
  409. wa4 = (double *) malloc(sizeof(double) * m);
  410. top->origin = (*fault ? NULL : (double *) avm_vector_of_list(operand->tail->tail,sizeof(double),&result,fault));
  411. top->row_number = (*fault ? NULL : avm_row_number_array(m,fault));
  412. if (!(*fault = (*fault ? 1 : !(top->origin ? top->row_number : NULL))))
  413. *fault = !(x ? (fvec ? (fjac ? (diag ? (ipvt ? (qtf ? (wa1 ? (wa2 ? (wa3 ? !!wa4 : 0):0):0):0):0):0):0):0):0);
  414. top->message = NULL;
  415. tries = info = top->fault = 0;
  416. while (*fault ? 0 : (!((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))) ? (tries++ < TIME_LIMIT) : 0))
  417. {
  418. top->fault = 0;
  419. top->message = NULL;
  420. lmstr_ (&lmstr_fcn, &m, &n, x, fvec, fjac, &ldfjac, &ftol, &xtol, &gtol, &maxfev, diag, &mode, &factor, &nprint, &info,
  421. &nfev, &njev, ipvt, qtf, wa1, wa2, wa3, wa4);
  422. if (!info)
  423. avm_internal_error (103);
  424. if (*fault = (top->fault ? 1 : !!(top->message)))
  425. {
  426. if (result ? top->message : NULL)
  427. avm_dispose (top->message);
  428. else
  429. result = (top->message ? top->message : avm_copied(bad_minpack_spec));
  430. }
  431. xtol = xtol * MAGNIFIER;
  432. ftol = ftol * MAGNIFIER;
  433. }
  434. if(top->row_number)
  435. avm_dispose_rows(m,top->row_number);
  436. freeif (fvec);
  437. freeif (fjac);
  438. freeif (diag);
  439. freeif (ipvt);
  440. freeif (qtf);
  441. freeif (wa1);
  442. freeif (wa2);
  443. freeif (wa3);
  444. freeif (wa4);
  445. freeif (top->origin);
  446. pop_spec ();
  447. if (*fault ? 0 : ((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))))
  448. result = avm_list_of_vector((void *) x,n,sizeof(double),fault);
  449. freeif (x);
  450. return (*fault ? (result ? result : avm_copied(memory_overflow)) : result);
  451. }
  452. static void
  453. lmdif_fcn(m,n,x,fvec,iflag)
  454. int *m;
  455. int *n;
  456. double *x;
  457. double *fvec;
  458. int *iflag;
  459. /* the c function to be passed to the minpack lmdif function;
  460. evaluates the function in the global variable top->fcn, which is
  461. expected to take a list of n reals to a list of m reals */
  462. {
  463. list operand,result,row;
  464. int i;
  465. double *item;
  466. operand = (top->fault ? NULL : avm_list_of_vector((void *) x,*n,sizeof(double),&(top->fault)));
  467. if (top->fault)
  468. {
  469. top->message = (top->message ? top->message : operand);
  470. *iflag = -1;
  471. return;
  472. }
  473. row = result = avm_recoverable_apply(avm_copied(top->fcn),operand,&(top->fault));
  474. if (top->fault)
  475. {
  476. top->message = result;
  477. *iflag = -1;
  478. return;
  479. }
  480. operand = NULL;
  481. i = 0;
  482. while (top->fault ? 0 : (i < *m))
  483. {
  484. item = ((top->fault = !row) ? NULL : (double *) avm_value_of_list(row->head,&operand,&(top->fault)));
  485. fvec[i] = (top->fault ? 0.0 : (*item - top->origin[i]));
  486. row = (top->fault ? row : row->tail);
  487. i++;
  488. }
  489. avm_dispose (result);
  490. if (!(top->fault = (top->fault ? 1 : !!row)))
  491. return;
  492. top->message = (operand ? operand : avm_copied(bad_minpack_spec));
  493. *iflag = -1;
  494. return;
  495. }
  496. static list
  497. avm_lmdif (operand, fault)
  498. list operand;
  499. int *fault;
  500. /* the operand represents (f,x,y) where f is a function and x and
  501. y are lists of reals of length n and m respectively. y is the
  502. preferred output of f, not necessarily 0, and x is the initial
  503. estimate of the input. The result returned is a more accurate
  504. estimate of the input if one is found, but is empty otherwise.
  505. This function differs from lmder because no jacobian is
  506. specified, which may make it less efficient or less accurate.
  507. If y is shorter than x (i.e., m < n), this function calls
  508. avm_hybrd instead. */
  509. {
  510. int m;
  511. int n;
  512. double *x;
  513. double *fvec;
  514. double ftol;
  515. double xtol;
  516. double gtol;
  517. int maxfev;
  518. double epsfcn;
  519. double *diag;
  520. int mode;
  521. double factor;
  522. int nprint;
  523. int info;
  524. int nfev;
  525. double *fjac;
  526. int ldfjac;
  527. int *ipvt;
  528. double *qtf;
  529. double *wa1;
  530. double *wa2;
  531. double *wa3;
  532. double *wa4;
  533. list result;
  534. int tries;
  535. spec_stack top;
  536. if (*fault)
  537. return NULL;
  538. result = NULL;
  539. if (*fault = !(operand ? (operand->head ? !!(operand->tail) : 0) : 0))
  540. return avm_copied (bad_minpack_spec);
  541. m = (int) avm_length(operand->tail->tail);
  542. n = (int) avm_length(operand->tail->head);
  543. if (*fault = !(m ? n : 0))
  544. return avm_copied (bad_minpack_spec);
  545. if (n > m)
  546. return avm_hybrd (operand, fault);
  547. if (!(top = new_top()))
  548. return avm_copied (memory_overflow);
  549. top->fcn = operand->head;
  550. x = (double *) avm_vector_of_list(operand->tail->head,sizeof(double),&result,fault);
  551. fvec = (double *) malloc(sizeof(double) * m);
  552. ftol = MINIMUM_TOLERANCE;
  553. xtol = MINIMUM_TOLERANCE;
  554. gtol = 0.0;
  555. maxfev = 100 * (n + 1);
  556. epsfcn = 0.0;
  557. diag = (double *) malloc(sizeof(double) * n);
  558. mode = 1;
  559. factor = 100.0;
  560. nprint = 0;
  561. fjac = (double *) malloc(sizeof(double) * n * m);
  562. ldfjac = m;
  563. ipvt = (int *) malloc(sizeof(int) * n);
  564. qtf = (double *) malloc(sizeof(double) * n);
  565. wa1 = (double *) malloc(sizeof(double) * n);
  566. wa2 = (double *) malloc(sizeof(double) * n);
  567. wa3 = (double *) malloc(sizeof(double) * n);
  568. wa4 = (double *) malloc(sizeof(double) * m);
  569. top->origin = (*fault ? NULL : (double *) avm_vector_of_list(operand->tail->tail,sizeof(double),&result,fault));
  570. if (!*fault)
  571. *fault = !(x? (fvec? (diag? (fjac? (ipvt? (qtf? (wa1? (wa2? (wa3? (wa4? !!(top->origin):0):0):0):0):0):0):0):0):0):0);
  572. top->message = NULL;
  573. tries = info = top->fault = 0;
  574. while (*fault ? 0 : (!((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))) ? (tries++ < TIME_LIMIT) : 0))
  575. {
  576. lmdif_ (&lmdif_fcn, &m, &n, x, fvec, &ftol, &xtol, &gtol, &maxfev, &epsfcn,diag, &mode, &factor, &nprint, &info, &nfev,
  577. fjac, &ldfjac, ipvt, qtf, wa1, wa2, wa3, wa4);
  578. if (!info)
  579. avm_internal_error (104);
  580. if (*fault = (top->fault ? 1 : !!(top->message)))
  581. {
  582. if (result ? top->message : NULL)
  583. avm_dispose (top->message);
  584. else
  585. result = (top->message ? top->message : avm_copied(bad_minpack_spec));
  586. }
  587. xtol = xtol * MAGNIFIER;
  588. ftol = ftol * MAGNIFIER;
  589. }
  590. freeif (fvec);
  591. freeif (fjac);
  592. freeif (diag);
  593. freeif (ipvt);
  594. freeif (qtf);
  595. freeif (wa1);
  596. freeif (wa2);
  597. freeif (wa3);
  598. freeif (wa4);
  599. freeif (top->origin);
  600. pop_spec ();
  601. if (*fault ? 0 : ((info == 1) ? 1 : ((info == 2) ? 1 : (info == 3))))
  602. result = avm_list_of_vector((void *) x,n,sizeof(double),fault);
  603. freeif (x);
  604. return (*fault ? (result ? result : avm_copied(memory_overflow)) : result);
  605. }
  606. static void
  607. hybrd_fcn(n,x,fvec,iflag)
  608. int *n;
  609. double *x;
  610. double *fvec;
  611. int *iflag;
  612. /* the c function to be passed to the minpack hybrd function;
  613. evaluates the function described by the global variable
  614. top->fcn, which is expected to take a list of n reals to a
  615. list of at most n reals, and passes the difference between
  616. that result and the global variable top->origin to minpack. If
  617. the output length is less than n, the vector passed to minpack
  618. is padded with zeros. The global variable
  619. top->number_of_outputs must match the actual output list
  620. length. */
  621. {
  622. list operand,result,row;
  623. int i;
  624. double *item;
  625. operand = (top->fault ? NULL : avm_list_of_vector((void *) x,*n,sizeof(double),&(top->fault)));
  626. if (top->fault)
  627. {
  628. top->message = (top->message ? top->message : operand);
  629. *iflag = -1;
  630. return;
  631. }
  632. row = result = avm_recoverable_apply(avm_copied(top->fcn),operand,&(top->fault));
  633. if (top->fault)
  634. {
  635. top->message = result;
  636. *iflag = -1;
  637. return;
  638. }
  639. operand = NULL;
  640. i = 0;
  641. while (top->fault ? 0 : (i < top->number_of_outputs))
  642. {
  643. item = ((top->fault = !row) ? NULL : (double *) avm_value_of_list(row->head,&operand,&(top->fault)));
  644. fvec[i] = (top->fault ? 0.0 : (*item - top->origin[i]));
  645. row = (top->fault ? row : row->tail);
  646. i++;
  647. }
  648. avm_dispose (result);
  649. while (i < *n)
  650. fvec[i++] = 0.0;
  651. if (!(top->fault = (top->fault ? 1 : !!row)))
  652. return;
  653. top->message = (operand ? operand : avm_copied(bad_minpack_spec));
  654. *iflag = -1;
  655. return;
  656. }
  657. static list
  658. avm_hybrd (operand, fault)
  659. list operand;
  660. int *fault;
  661. /* the operand represents (f,x,y) where f is a function and x and
  662. y are lists of reals. y is the preferred output of f, not
  663. necessarily 0, and x is the initial estimate of the input. The
  664. result returned is a more accurate estimate of the input
  665. consistent with the given output if one is found, but is empty
  666. otherwise. If the output list is longer than the input list,
  667. avm_lmdif is called instead, and if it's shorter, it's
  668. padded automatically. */
  669. {
  670. int n;
  671. double *x;
  672. double *fvec;
  673. double xtol;
  674. int maxfev;
  675. int ml;
  676. int mu;
  677. double epsfcn;
  678. double *diag;
  679. int mode;
  680. double factor;
  681. int nprint;
  682. int info;
  683. int nfev;
  684. double *fjac;
  685. int ldfjac;
  686. double *r;
  687. int lr;
  688. double *qtf;
  689. double *wa1;
  690. double *wa2;
  691. double *wa3;
  692. double *wa4;
  693. list result;
  694. int tries;
  695. spec_stack top;
  696. int number_of_outputs;
  697. if (*fault)
  698. return NULL;
  699. result = NULL;
  700. if (*fault = !(operand ? (operand->head ? operand->tail : NULL) : NULL))
  701. return avm_copied (bad_minpack_spec);
  702. n = (int) avm_length (operand->tail->head);
  703. if (n < (number_of_outputs = (int) avm_length (operand->tail->tail)))
  704. return avm_lmdif (operand, fault);
  705. if (!(top = new_top()))
  706. return avm_copied (memory_overflow);
  707. top->number_of_outputs = number_of_outputs;
  708. top->fcn = operand->head;
  709. x = (double *) avm_vector_of_list(operand->tail->head,sizeof(double),&result,fault);
  710. fvec = (double *) malloc(sizeof(double) * n);
  711. xtol = MINIMUM_TOLERANCE;
  712. maxfev = 200 * (n + 1);
  713. ml = n - 1;
  714. mu = n - 1;
  715. epsfcn = 0.0;
  716. diag = (double *) malloc(sizeof(double) * n);
  717. mode = 1;
  718. factor = 100.0;
  719. nprint = 0;
  720. ldfjac = n;
  721. fjac = (double *) malloc(sizeof(double) * ldfjac * n);
  722. lr = (n * (n + 1)) / 2;
  723. r = (double *) malloc(sizeof(double) * lr);
  724. qtf = (double *) malloc(sizeof(double) * n);
  725. wa1 = (double *) malloc(sizeof(double) * n);
  726. wa2 = (double *) malloc(sizeof(double) * n);
  727. wa3 = (double *) malloc(sizeof(double) * n);
  728. wa4 = (double *) malloc(sizeof(double) * n);
  729. top->origin = (*fault ? NULL : (double *) avm_vector_of_list(operand->tail->tail,sizeof(double),&result,fault));
  730. if (!*fault)
  731. *fault = !(x? (fvec? (diag? (fjac? (r? (qtf? (wa1? (wa2? (wa3? (wa4? !!(top->origin):0):0):0):0):0):0):0):0):0):0);
  732. top->message = NULL;
  733. tries = info = top->fault = 0;
  734. while (*fault ? 0 : ((info != 1) ? (tries++ < TIME_LIMIT) : 0))
  735. {
  736. hybrd_ (&hybrd_fcn, &n, x, fvec, &xtol, &maxfev, &ml, &mu, &epsfcn, diag, &mode, &factor, &nprint, &info, &nfev, fjac,
  737. &ldfjac, r, &lr, qtf, wa1, wa2, wa3, wa4);
  738. if (!info)
  739. avm_internal_error (100);
  740. if (*fault = (top->fault ? 1 : !!(top->message)))
  741. {
  742. if (result ? top->message : NULL)
  743. avm_dispose (top->message);
  744. else
  745. result = (top->message ? top->message : avm_copied(bad_minpack_spec));
  746. }
  747. xtol = xtol * MAGNIFIER;
  748. }
  749. freeif (fvec);
  750. freeif (diag);
  751. freeif (fjac);
  752. freeif (r);
  753. freeif (qtf);
  754. freeif (wa1);
  755. freeif (wa2);
  756. freeif (wa3);
  757. freeif (wa4);
  758. freeif (top->origin);
  759. pop_spec ();
  760. if (*fault ? 0 : (info == 1))
  761. result = avm_list_of_vector((void *) x,n,sizeof(double),fault);
  762. freeif (x);
  763. return (*fault ? (result ? result : avm_copied(memory_overflow)) : result);
  764. }
  765. static void
  766. hybrj_fcn(n,x,fvec,fjac,ldfjac,iflag)
  767. int *n;
  768. double *x;
  769. double *fvec;
  770. double *fjac;
  771. int *ldfjac;
  772. int *iflag;
  773. /* the c function to be passed to the minpack hybrj function;
  774. evaluates the function described by the global variable
  775. top->fcn, which is expected to take a list of n reals to a
  776. list of at most n reals, or evaluates the function described
  777. by the global variable top->jac, which is expected to take a
  778. list of n reals to list of n lists of at most n reals. If the
  779. actual output length is less than n, it must match the global
  780. variable top->number_of_outputs, and the arrays passed to
  781. minpack are padded with zeros. */
  782. {
  783. list operand,result,row,col;
  784. int i,j;
  785. double *item;
  786. operand = (top->fault ? NULL : avm_list_of_vector((void *) x,*n,sizeof(double),&(top->fault)));
  787. if (top->fault)
  788. {
  789. top->message = (top->message ? top->message : operand);
  790. *iflag = -1;
  791. return;
  792. }
  793. row = result = avm_recoverable_apply(avm_copied((*iflag == 1) ? top->fcn : top->jac), operand, &(top->fault));
  794. if (top->fault)
  795. {
  796. top->message = result;
  797. *iflag = -1;
  798. return;
  799. }
  800. i = 0;
  801. operand = NULL;
  802. while (top->fault ? 0 : (i < top->number_of_outputs))
  803. {
  804. if (*iflag == 1)
  805. {
  806. item = ((top->fault = !row) ? NULL : (double *) avm_value_of_list(row->head, &operand, &(top->fault)));
  807. fvec[i] = (top->fault ? 0.0 : (*item - top->origin[i]));
  808. }
  809. else if (!(top->fault = !row))
  810. {
  811. j = 0;
  812. col = row->head;
  813. while (top->fault ? 0 : (j < *n))
  814. {
  815. item = ((top->fault = !col) ? NULL : (double *) avm_value_of_list(col->head, &operand, &(top->fault)));
  816. fjac[(j++ * *n) + i] = (top->fault ? 0.0 : *item);
  817. col = (top->fault ? col : col->tail);
  818. }
  819. top->fault = (top->fault ? 1 : !!col);
  820. }
  821. row = (top->fault ? row : row->tail);
  822. i++;
  823. }
  824. while (i < *n)
  825. {
  826. if (*iflag == 1)
  827. fvec[i] = 0.0;
  828. else
  829. {
  830. j = 0;
  831. while (j < *n)
  832. fjac[(j++ * *n) + i] = 0.0;
  833. }
  834. i++;
  835. }
  836. avm_dispose (result);
  837. if (!(top->fault = (top->fault ? 1 : !!row)))
  838. return;
  839. top->message = (operand ? operand : avm_copied (bad_minpack_spec));
  840. *iflag = -1;
  841. return;
  842. }
  843. static list
  844. avm_hybrj (operand, fault)
  845. list operand;
  846. int *fault;
  847. /* the operand represents ((f,j),x,y) where f and j are functions
  848. and x and y are lists of reals of length n. y is the preferred
  849. output of f, not necessarily 0, and x is the initial estimate
  850. of the input. j is a function that takes a list of reals to
  851. the jacobian of f represented as a list of rows. The jacobian
  852. is a matrix whose ith row is the list of partial derivatives
  853. of the ith output component of f with respect to each input
  854. component. The result returned is a more accurate estimate of
  855. the input if one is found, but is empty otherwise. If the
  856. output list is longer than the input list, avm_lmder is called
  857. instead, and if it's shorter it's automatically padded. */
  858. {
  859. int n;
  860. double *x;
  861. double *fvec;
  862. double *fjac;
  863. int ldfjac;
  864. double xtol;
  865. int maxfev;
  866. double *diag;
  867. int mode;
  868. double factor;
  869. int nprint;
  870. int info;
  871. int nfev;
  872. int njev;
  873. double *r;
  874. int lr;
  875. double *qtf;
  876. double *wa1;
  877. double *wa2;
  878. double *wa3;
  879. double *wa4;
  880. list result;
  881. int tries;
  882. spec_stack top;
  883. int number_of_outputs;
  884. if (*fault)
  885. return NULL;
  886. result = NULL;
  887. if (*fault = !(operand ? (operand->head ? (operand->head->head ? (operand->head->tail ? !!(operand->tail):0):0):0):0))
  888. return avm_copied (bad_minpack_spec);
  889. n = (int) avm_length(operand->tail->head);
  890. if (n < (number_of_outputs = (int) avm_length (operand->tail->tail)))
  891. return avm_lmder (operand, fault);
  892. if (!(top = new_top()))
  893. return avm_copied (memory_overflow);
  894. top->fcn = operand->head->head;
  895. top->jac = operand->head->tail;
  896. top->number_of_outputs = number_of_outputs;
  897. x = (double *) avm_vector_of_list(operand->tail->head,sizeof(double),&result,fault);
  898. fvec = (double *) malloc(sizeof(double) * n);
  899. fjac = (double *) malloc(sizeof(double) * n * n);
  900. ldfjac = n;
  901. xtol = MINIMUM_TOLERANCE;
  902. maxfev = 200 * (n + 1);
  903. diag = (double *) malloc(sizeof(double) * n);
  904. mode = 1;
  905. factor = 100.0;
  906. nprint = 0;
  907. lr = (n * (n + 1))/2;
  908. r = (double *) malloc(sizeof(double) * lr);
  909. qtf = (double *) malloc(sizeof(double) * n);
  910. wa1 = (double *) malloc(sizeof(double) * n);
  911. wa2 = (double *) malloc(sizeof(double) * n);
  912. wa3 = (double *) malloc(sizeof(double) * n);
  913. wa4 = (double *) malloc(sizeof(double) * n);
  914. top->origin = (*fault ? NULL : (double *) avm_vector_of_list(operand->tail->tail,sizeof(double),&result,fault));
  915. if (!*fault)
  916. *fault = !(x? (fvec? (diag? (fjac? (r? (qtf? (wa1? (wa2? (wa3? (wa4? !!(top->origin):0):0):0):0):0):0):0):0):0):0);
  917. top->message = NULL;
  918. tries = info = top->fault = 0;
  919. while (*fault ? 0 : ((info != 1) ? (tries++ < TIME_LIMIT) : 0))
  920. {
  921. hybrj_ (&hybrj_fcn, &n, x, fvec, fjac, &ldfjac, &xtol, &maxfev, diag, &mode, &factor, &nprint, &info, &nfev, &njev, r,
  922. &lr, qtf, wa1, wa2, wa3, wa4);
  923. if (!info)
  924. avm_internal_error (101);
  925. if (*fault = (top->fault ? 1 : !!(top->message)))
  926. {
  927. if (result ? top->message : NULL)
  928. avm_dispose (top->message);
  929. else
  930. result = (top->message ? top->message : avm_copied(bad_minpack_spec));
  931. }
  932. xtol = xtol * MAGNIFIER;
  933. }
  934. freeif (fvec);
  935. freeif (diag);
  936. freeif (fjac);
  937. freeif (r);
  938. freeif (qtf);
  939. freeif (wa1);
  940. freeif (wa2);
  941. freeif (wa3);
  942. freeif (wa4);
  943. freeif (top->origin);
  944. pop_spec ();
  945. if (*fault ? 0 : (info == 1))
  946. result = avm_list_of_vector((void *) x,n,sizeof(double),fault);
  947. freeif (x);
  948. return (*fault ? (result ? result : avm_copied(memory_overflow)) : result);
  949. }
  950. #endif
  951. list
  952. avm_have_minpack_call (function_name, fault)
  953. list function_name;
  954. int *fault;
  955. /* this reports the availability of a function */
  956. {
  957. #if HAVE_MINPACK
  958. list membership;
  959. list comparison;
  960. list result;
  961. if (!initialized)
  962. avm_initialize_minpack ();
  963. if (*fault)
  964. return NULL;
  965. comparison = avm_binary_comparison (function_name, wild, fault);
  966. if (*fault)
  967. return comparison;
  968. if (comparison)
  969. {
  970. avm_dispose(comparison);
  971. return avm_copied(funs);
  972. }
  973. if (!(membership = avm_binary_membership (function_name, funs, fault)) ? 1 : *fault)
  974. return membership;
  975. avm_dispose(membership);
  976. return ((*fault = !(result = avm_recoverable_join(avm_copied(function_name),NULL))) ? avm_copied(memory_overflow) : result);
  977. #endif
  978. return NULL;
  979. }
  980. list
  981. avm_minpack_call (function_name, argument, fault)
  982. list function_name;
  983. list argument;
  984. int *fault;
  985. {
  986. #if HAVE_MINPACK
  987. list message;
  988. int function_number;
  989. if (*fault)
  990. return NULL;
  991. if (! initialized)
  992. avm_initialize_minpack ();
  993. if (!(function_number = 0xff & (function_name ? function_name->characterization : 0)))
  994. {
  995. message = avm_position (function_name, funs, fault);
  996. if (*fault)
  997. return message;
  998. if (*fault = !message)
  999. return avm_copied (unrecognized_function_name);
  1000. function_number = message->characterization;
  1001. function_name->characterization = function_number;
  1002. avm_dispose (message);
  1003. }
  1004. switch (function_number)
  1005. {
  1006. case 1: return avm_lmder (argument, fault);
  1007. case 2: return avm_lmstr (argument, fault);
  1008. case 3: return avm_lmdif (argument, fault);
  1009. case 4: return avm_hybrd (argument, fault);
  1010. case 5: return avm_hybrj (argument, fault);
  1011. }
  1012. #endif /* HAVE_MINPACK */
  1013. *fault = 1;
  1014. return avm_copied (unrecognized_function_name);
  1015. }
  1016. void
  1017. avm_initialize_minpack ()
  1018. /* This initializes some static data structures. */
  1019. {
  1020. char *funames[] = {
  1021. "lmder",
  1022. "lmstr",
  1023. "lmdif",
  1024. "hybrd",
  1025. "hybrj",
  1026. NULL}; /* add more function names here up to a total of 255 */
  1027. list back;
  1028. int string_number;
  1029. if (initialized)
  1030. return;
  1031. initialized = 1;
  1032. avm_initialize_lists ();
  1033. avm_initialize_matcon ();
  1034. avm_initialize_chrcodes ();
  1035. wild = avm_strung("*");
  1036. minpack_error = avm_join (avm_strung ("minpack error"), NULL);
  1037. memory_overflow = avm_join (avm_strung ("memory overflow"), NULL);
  1038. bad_minpack_spec = avm_join (avm_strung ("bad minpack specification"), NULL);
  1039. unrecognized_function_name = avm_join (avm_strung ("unrecognized minpack function name"), NULL);
  1040. string_number = 0;
  1041. funs = back = NULL;
  1042. while (funames[string_number])
  1043. avm_enqueue (&funs, &back, avm_standard_strung (funames[string_number++]));
  1044. }
  1045. void
  1046. avm_count_minpack ()
  1047. /* This frees some static data structures as an aid to the
  1048. detection of memory leaks. */
  1049. {
  1050. counter unreclaimed;
  1051. if (!initialized)
  1052. return;
  1053. initialized = 0;
  1054. avm_dispose (funs);
  1055. avm_dispose (wild);
  1056. avm_dispose (minpack_error);
  1057. avm_dispose (memory_overflow);
  1058. avm_dispose (bad_minpack_spec);
  1059. avm_dispose (unrecognized_function_name);
  1060. funs = NULL;
  1061. wild = NULL;
  1062. minpack_error = NULL;
  1063. memory_overflow = NULL;
  1064. bad_minpack_spec = NULL;
  1065. unrecognized_function_name = NULL;
  1066. unreclaimed = 0;
  1067. while (top)
  1068. {
  1069. unreclaimed++;
  1070. top = top->other_specs;
  1071. }
  1072. if (unreclaimed)
  1073. avm_reclamation_failure ("spec stacks", unreclaimed);
  1074. }