NonLinearOptimization.cpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
  5. #include <stdio.h>
  6. #include "main.h"
  7. #include <unsupported/Eigen/NonLinearOptimization>
  8. // This disables some useless Warnings on MSVC.
  9. // It is intended to be done for this test only.
  10. #include <Eigen/src/Core/util/DisableStupidWarnings.h>
  11. // tolerance for chekcing number of iterations
  12. #define LM_EVAL_COUNT_TOL 4/3
  13. #define LM_CHECK_N_ITERS(SOLVER,NFEV,NJEV) { \
  14. ++g_test_level; \
  15. VERIFY_IS_EQUAL(SOLVER.nfev, NFEV); \
  16. VERIFY_IS_EQUAL(SOLVER.njev, NJEV); \
  17. --g_test_level; \
  18. VERIFY(SOLVER.nfev <= NFEV * LM_EVAL_COUNT_TOL); \
  19. VERIFY(SOLVER.njev <= NJEV * LM_EVAL_COUNT_TOL); \
  20. }
  21. int fcn_chkder(const VectorXd &x, VectorXd &fvec, MatrixXd &fjac, int iflag)
  22. {
  23. /* subroutine fcn for chkder example. */
  24. int i;
  25. assert(15 == fvec.size());
  26. assert(3 == x.size());
  27. double tmp1, tmp2, tmp3, tmp4;
  28. static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
  29. 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
  30. if (iflag == 0)
  31. return 0;
  32. if (iflag != 2)
  33. for (i=0; i<15; i++) {
  34. tmp1 = i+1;
  35. tmp2 = 16-i-1;
  36. tmp3 = tmp1;
  37. if (i >= 8) tmp3 = tmp2;
  38. fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
  39. }
  40. else {
  41. for (i = 0; i < 15; i++) {
  42. tmp1 = i+1;
  43. tmp2 = 16-i-1;
  44. /* error introduced into next statement for illustration. */
  45. /* corrected statement should read tmp3 = tmp1 . */
  46. tmp3 = tmp2;
  47. if (i >= 8) tmp3 = tmp2;
  48. tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4=tmp4*tmp4;
  49. fjac(i,0) = -1.;
  50. fjac(i,1) = tmp1*tmp2/tmp4;
  51. fjac(i,2) = tmp1*tmp3/tmp4;
  52. }
  53. }
  54. return 0;
  55. }
  56. void testChkder()
  57. {
  58. const int m=15, n=3;
  59. VectorXd x(n), fvec(m), xp, fvecp(m), err;
  60. MatrixXd fjac(m,n);
  61. VectorXi ipvt;
  62. /* the following values should be suitable for */
  63. /* checking the jacobian matrix. */
  64. x << 9.2e-1, 1.3e-1, 5.4e-1;
  65. internal::chkder(x, fvec, fjac, xp, fvecp, 1, err);
  66. fcn_chkder(x, fvec, fjac, 1);
  67. fcn_chkder(x, fvec, fjac, 2);
  68. fcn_chkder(xp, fvecp, fjac, 1);
  69. internal::chkder(x, fvec, fjac, xp, fvecp, 2, err);
  70. fvecp -= fvec;
  71. // check those
  72. VectorXd fvec_ref(m), fvecp_ref(m), err_ref(m);
  73. fvec_ref <<
  74. -1.181606, -1.429655, -1.606344,
  75. -1.745269, -1.840654, -1.921586,
  76. -1.984141, -2.022537, -2.468977,
  77. -2.827562, -3.473582, -4.437612,
  78. -6.047662, -9.267761, -18.91806;
  79. fvecp_ref <<
  80. -7.724666e-09, -3.432406e-09, -2.034843e-10,
  81. 2.313685e-09, 4.331078e-09, 5.984096e-09,
  82. 7.363281e-09, 8.53147e-09, 1.488591e-08,
  83. 2.33585e-08, 3.522012e-08, 5.301255e-08,
  84. 8.26666e-08, 1.419747e-07, 3.19899e-07;
  85. err_ref <<
  86. 0.1141397, 0.09943516, 0.09674474,
  87. 0.09980447, 0.1073116, 0.1220445,
  88. 0.1526814, 1, 1,
  89. 1, 1, 1,
  90. 1, 1, 1;
  91. VERIFY_IS_APPROX(fvec, fvec_ref);
  92. VERIFY_IS_APPROX(fvecp, fvecp_ref);
  93. VERIFY_IS_APPROX(err, err_ref);
  94. }
  95. // Generic functor
  96. template<typename _Scalar, int NX=Dynamic, int NY=Dynamic>
  97. struct Functor
  98. {
  99. typedef _Scalar Scalar;
  100. enum {
  101. InputsAtCompileTime = NX,
  102. ValuesAtCompileTime = NY
  103. };
  104. typedef Matrix<Scalar,InputsAtCompileTime,1> InputType;
  105. typedef Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
  106. typedef Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
  107. const int m_inputs, m_values;
  108. Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
  109. Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
  110. int inputs() const { return m_inputs; }
  111. int values() const { return m_values; }
  112. // you should define that in the subclass :
  113. // void operator() (const InputType& x, ValueType* v, JacobianType* _j=0) const;
  114. };
  115. struct lmder_functor : Functor<double>
  116. {
  117. lmder_functor(void): Functor<double>(3,15) {}
  118. int operator()(const VectorXd &x, VectorXd &fvec) const
  119. {
  120. double tmp1, tmp2, tmp3;
  121. static const double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
  122. 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
  123. for (int i = 0; i < values(); i++)
  124. {
  125. tmp1 = i+1;
  126. tmp2 = 16 - i - 1;
  127. tmp3 = (i>=8)? tmp2 : tmp1;
  128. fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
  129. }
  130. return 0;
  131. }
  132. int df(const VectorXd &x, MatrixXd &fjac) const
  133. {
  134. double tmp1, tmp2, tmp3, tmp4;
  135. for (int i = 0; i < values(); i++)
  136. {
  137. tmp1 = i+1;
  138. tmp2 = 16 - i - 1;
  139. tmp3 = (i>=8)? tmp2 : tmp1;
  140. tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4;
  141. fjac(i,0) = -1;
  142. fjac(i,1) = tmp1*tmp2/tmp4;
  143. fjac(i,2) = tmp1*tmp3/tmp4;
  144. }
  145. return 0;
  146. }
  147. };
  148. void testLmder1()
  149. {
  150. int n=3, info;
  151. VectorXd x;
  152. /* the following starting values provide a rough fit. */
  153. x.setConstant(n, 1.);
  154. // do the computation
  155. lmder_functor functor;
  156. LevenbergMarquardt<lmder_functor> lm(functor);
  157. info = lm.lmder1(x);
  158. // check return value
  159. VERIFY_IS_EQUAL(info, 1);
  160. LM_CHECK_N_ITERS(lm, 6, 5);
  161. // check norm
  162. VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596);
  163. // check x
  164. VectorXd x_ref(n);
  165. x_ref << 0.08241058, 1.133037, 2.343695;
  166. VERIFY_IS_APPROX(x, x_ref);
  167. }
  168. void testLmder()
  169. {
  170. const int m=15, n=3;
  171. int info;
  172. double fnorm, covfac;
  173. VectorXd x;
  174. /* the following starting values provide a rough fit. */
  175. x.setConstant(n, 1.);
  176. // do the computation
  177. lmder_functor functor;
  178. LevenbergMarquardt<lmder_functor> lm(functor);
  179. info = lm.minimize(x);
  180. // check return values
  181. VERIFY_IS_EQUAL(info, 1);
  182. LM_CHECK_N_ITERS(lm, 6, 5);
  183. // check norm
  184. fnorm = lm.fvec.blueNorm();
  185. VERIFY_IS_APPROX(fnorm, 0.09063596);
  186. // check x
  187. VectorXd x_ref(n);
  188. x_ref << 0.08241058, 1.133037, 2.343695;
  189. VERIFY_IS_APPROX(x, x_ref);
  190. // check covariance
  191. covfac = fnorm*fnorm/(m-n);
  192. internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm
  193. MatrixXd cov_ref(n,n);
  194. cov_ref <<
  195. 0.0001531202, 0.002869941, -0.002656662,
  196. 0.002869941, 0.09480935, -0.09098995,
  197. -0.002656662, -0.09098995, 0.08778727;
  198. // std::cout << fjac*covfac << std::endl;
  199. MatrixXd cov;
  200. cov = covfac*lm.fjac.topLeftCorner<n,n>();
  201. VERIFY_IS_APPROX( cov, cov_ref);
  202. // TODO: why isn't this allowed ? :
  203. // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref);
  204. }
  205. struct hybrj_functor : Functor<double>
  206. {
  207. hybrj_functor(void) : Functor<double>(9,9) {}
  208. int operator()(const VectorXd &x, VectorXd &fvec)
  209. {
  210. double temp, temp1, temp2;
  211. const VectorXd::Index n = x.size();
  212. assert(fvec.size()==n);
  213. for (VectorXd::Index k = 0; k < n; k++)
  214. {
  215. temp = (3. - 2.*x[k])*x[k];
  216. temp1 = 0.;
  217. if (k) temp1 = x[k-1];
  218. temp2 = 0.;
  219. if (k != n-1) temp2 = x[k+1];
  220. fvec[k] = temp - temp1 - 2.*temp2 + 1.;
  221. }
  222. return 0;
  223. }
  224. int df(const VectorXd &x, MatrixXd &fjac)
  225. {
  226. const VectorXd::Index n = x.size();
  227. assert(fjac.rows()==n);
  228. assert(fjac.cols()==n);
  229. for (VectorXd::Index k = 0; k < n; k++)
  230. {
  231. for (VectorXd::Index j = 0; j < n; j++)
  232. fjac(k,j) = 0.;
  233. fjac(k,k) = 3.- 4.*x[k];
  234. if (k) fjac(k,k-1) = -1.;
  235. if (k != n-1) fjac(k,k+1) = -2.;
  236. }
  237. return 0;
  238. }
  239. };
  240. void testHybrj1()
  241. {
  242. const int n=9;
  243. int info;
  244. VectorXd x(n);
  245. /* the following starting values provide a rough fit. */
  246. x.setConstant(n, -1.);
  247. // do the computation
  248. hybrj_functor functor;
  249. HybridNonLinearSolver<hybrj_functor> solver(functor);
  250. info = solver.hybrj1(x);
  251. // check return value
  252. VERIFY_IS_EQUAL(info, 1);
  253. LM_CHECK_N_ITERS(solver, 11, 1);
  254. // check norm
  255. VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
  256. // check x
  257. VectorXd x_ref(n);
  258. x_ref <<
  259. -0.5706545, -0.6816283, -0.7017325,
  260. -0.7042129, -0.701369, -0.6918656,
  261. -0.665792, -0.5960342, -0.4164121;
  262. VERIFY_IS_APPROX(x, x_ref);
  263. }
  264. void testHybrj()
  265. {
  266. const int n=9;
  267. int info;
  268. VectorXd x(n);
  269. /* the following starting values provide a rough fit. */
  270. x.setConstant(n, -1.);
  271. // do the computation
  272. hybrj_functor functor;
  273. HybridNonLinearSolver<hybrj_functor> solver(functor);
  274. solver.diag.setConstant(n, 1.);
  275. solver.useExternalScaling = true;
  276. info = solver.solve(x);
  277. // check return value
  278. VERIFY_IS_EQUAL(info, 1);
  279. LM_CHECK_N_ITERS(solver, 11, 1);
  280. // check norm
  281. VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
  282. // check x
  283. VectorXd x_ref(n);
  284. x_ref <<
  285. -0.5706545, -0.6816283, -0.7017325,
  286. -0.7042129, -0.701369, -0.6918656,
  287. -0.665792, -0.5960342, -0.4164121;
  288. VERIFY_IS_APPROX(x, x_ref);
  289. }
  290. struct hybrd_functor : Functor<double>
  291. {
  292. hybrd_functor(void) : Functor<double>(9,9) {}
  293. int operator()(const VectorXd &x, VectorXd &fvec) const
  294. {
  295. double temp, temp1, temp2;
  296. const VectorXd::Index n = x.size();
  297. assert(fvec.size()==n);
  298. for (VectorXd::Index k=0; k < n; k++)
  299. {
  300. temp = (3. - 2.*x[k])*x[k];
  301. temp1 = 0.;
  302. if (k) temp1 = x[k-1];
  303. temp2 = 0.;
  304. if (k != n-1) temp2 = x[k+1];
  305. fvec[k] = temp - temp1 - 2.*temp2 + 1.;
  306. }
  307. return 0;
  308. }
  309. };
  310. void testHybrd1()
  311. {
  312. int n=9, info;
  313. VectorXd x(n);
  314. /* the following starting values provide a rough solution. */
  315. x.setConstant(n, -1.);
  316. // do the computation
  317. hybrd_functor functor;
  318. HybridNonLinearSolver<hybrd_functor> solver(functor);
  319. info = solver.hybrd1(x);
  320. // check return value
  321. VERIFY_IS_EQUAL(info, 1);
  322. VERIFY_IS_EQUAL(solver.nfev, 20);
  323. // check norm
  324. VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
  325. // check x
  326. VectorXd x_ref(n);
  327. x_ref << -0.5706545, -0.6816283, -0.7017325, -0.7042129, -0.701369, -0.6918656, -0.665792, -0.5960342, -0.4164121;
  328. VERIFY_IS_APPROX(x, x_ref);
  329. }
  330. void testHybrd()
  331. {
  332. const int n=9;
  333. int info;
  334. VectorXd x;
  335. /* the following starting values provide a rough fit. */
  336. x.setConstant(n, -1.);
  337. // do the computation
  338. hybrd_functor functor;
  339. HybridNonLinearSolver<hybrd_functor> solver(functor);
  340. solver.parameters.nb_of_subdiagonals = 1;
  341. solver.parameters.nb_of_superdiagonals = 1;
  342. solver.diag.setConstant(n, 1.);
  343. solver.useExternalScaling = true;
  344. info = solver.solveNumericalDiff(x);
  345. // check return value
  346. VERIFY_IS_EQUAL(info, 1);
  347. VERIFY_IS_EQUAL(solver.nfev, 14);
  348. // check norm
  349. VERIFY_IS_APPROX(solver.fvec.blueNorm(), 1.192636e-08);
  350. // check x
  351. VectorXd x_ref(n);
  352. x_ref <<
  353. -0.5706545, -0.6816283, -0.7017325,
  354. -0.7042129, -0.701369, -0.6918656,
  355. -0.665792, -0.5960342, -0.4164121;
  356. VERIFY_IS_APPROX(x, x_ref);
  357. }
  358. struct lmstr_functor : Functor<double>
  359. {
  360. lmstr_functor(void) : Functor<double>(3,15) {}
  361. int operator()(const VectorXd &x, VectorXd &fvec)
  362. {
  363. /* subroutine fcn for lmstr1 example. */
  364. double tmp1, tmp2, tmp3;
  365. static const double y[15]={1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1,
  366. 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39};
  367. assert(15==fvec.size());
  368. assert(3==x.size());
  369. for (int i=0; i<15; i++)
  370. {
  371. tmp1 = i+1;
  372. tmp2 = 16 - i - 1;
  373. tmp3 = (i>=8)? tmp2 : tmp1;
  374. fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
  375. }
  376. return 0;
  377. }
  378. int df(const VectorXd &x, VectorXd &jac_row, VectorXd::Index rownb)
  379. {
  380. assert(x.size()==3);
  381. assert(jac_row.size()==x.size());
  382. double tmp1, tmp2, tmp3, tmp4;
  383. VectorXd::Index i = rownb-2;
  384. tmp1 = i+1;
  385. tmp2 = 16 - i - 1;
  386. tmp3 = (i>=8)? tmp2 : tmp1;
  387. tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4;
  388. jac_row[0] = -1;
  389. jac_row[1] = tmp1*tmp2/tmp4;
  390. jac_row[2] = tmp1*tmp3/tmp4;
  391. return 0;
  392. }
  393. };
  394. void testLmstr1()
  395. {
  396. const int n=3;
  397. int info;
  398. VectorXd x(n);
  399. /* the following starting values provide a rough fit. */
  400. x.setConstant(n, 1.);
  401. // do the computation
  402. lmstr_functor functor;
  403. LevenbergMarquardt<lmstr_functor> lm(functor);
  404. info = lm.lmstr1(x);
  405. // check return value
  406. VERIFY_IS_EQUAL(info, 1);
  407. LM_CHECK_N_ITERS(lm, 6, 5);
  408. // check norm
  409. VERIFY_IS_APPROX(lm.fvec.blueNorm(), 0.09063596);
  410. // check x
  411. VectorXd x_ref(n);
  412. x_ref << 0.08241058, 1.133037, 2.343695 ;
  413. VERIFY_IS_APPROX(x, x_ref);
  414. }
  415. void testLmstr()
  416. {
  417. const int n=3;
  418. int info;
  419. double fnorm;
  420. VectorXd x(n);
  421. /* the following starting values provide a rough fit. */
  422. x.setConstant(n, 1.);
  423. // do the computation
  424. lmstr_functor functor;
  425. LevenbergMarquardt<lmstr_functor> lm(functor);
  426. info = lm.minimizeOptimumStorage(x);
  427. // check return values
  428. VERIFY_IS_EQUAL(info, 1);
  429. LM_CHECK_N_ITERS(lm, 6, 5);
  430. // check norm
  431. fnorm = lm.fvec.blueNorm();
  432. VERIFY_IS_APPROX(fnorm, 0.09063596);
  433. // check x
  434. VectorXd x_ref(n);
  435. x_ref << 0.08241058, 1.133037, 2.343695;
  436. VERIFY_IS_APPROX(x, x_ref);
  437. }
  438. struct lmdif_functor : Functor<double>
  439. {
  440. lmdif_functor(void) : Functor<double>(3,15) {}
  441. int operator()(const VectorXd &x, VectorXd &fvec) const
  442. {
  443. int i;
  444. double tmp1,tmp2,tmp3;
  445. static const double y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1,
  446. 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0};
  447. assert(x.size()==3);
  448. assert(fvec.size()==15);
  449. for (i=0; i<15; i++)
  450. {
  451. tmp1 = i+1;
  452. tmp2 = 15 - i;
  453. tmp3 = tmp1;
  454. if (i >= 8) tmp3 = tmp2;
  455. fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3));
  456. }
  457. return 0;
  458. }
  459. };
  460. void testLmdif1()
  461. {
  462. const int n=3;
  463. int info;
  464. VectorXd x(n), fvec(15);
  465. /* the following starting values provide a rough fit. */
  466. x.setConstant(n, 1.);
  467. // do the computation
  468. lmdif_functor functor;
  469. DenseIndex nfev = -1; // initialize to avoid maybe-uninitialized warning
  470. info = LevenbergMarquardt<lmdif_functor>::lmdif1(functor, x, &nfev);
  471. // check return value
  472. VERIFY_IS_EQUAL(info, 1);
  473. VERIFY_IS_EQUAL(nfev, 26);
  474. // check norm
  475. functor(x, fvec);
  476. VERIFY_IS_APPROX(fvec.blueNorm(), 0.09063596);
  477. // check x
  478. VectorXd x_ref(n);
  479. x_ref << 0.0824106, 1.1330366, 2.3436947;
  480. VERIFY_IS_APPROX(x, x_ref);
  481. }
  482. void testLmdif()
  483. {
  484. const int m=15, n=3;
  485. int info;
  486. double fnorm, covfac;
  487. VectorXd x(n);
  488. /* the following starting values provide a rough fit. */
  489. x.setConstant(n, 1.);
  490. // do the computation
  491. lmdif_functor functor;
  492. NumericalDiff<lmdif_functor> numDiff(functor);
  493. LevenbergMarquardt<NumericalDiff<lmdif_functor> > lm(numDiff);
  494. info = lm.minimize(x);
  495. // check return values
  496. VERIFY_IS_EQUAL(info, 1);
  497. VERIFY_IS_EQUAL(lm.nfev, 26);
  498. // check norm
  499. fnorm = lm.fvec.blueNorm();
  500. VERIFY_IS_APPROX(fnorm, 0.09063596);
  501. // check x
  502. VectorXd x_ref(n);
  503. x_ref << 0.08241058, 1.133037, 2.343695;
  504. VERIFY_IS_APPROX(x, x_ref);
  505. // check covariance
  506. covfac = fnorm*fnorm/(m-n);
  507. internal::covar(lm.fjac, lm.permutation.indices()); // TODO : move this as a function of lm
  508. MatrixXd cov_ref(n,n);
  509. cov_ref <<
  510. 0.0001531202, 0.002869942, -0.002656662,
  511. 0.002869942, 0.09480937, -0.09098997,
  512. -0.002656662, -0.09098997, 0.08778729;
  513. // std::cout << fjac*covfac << std::endl;
  514. MatrixXd cov;
  515. cov = covfac*lm.fjac.topLeftCorner<n,n>();
  516. VERIFY_IS_APPROX( cov, cov_ref);
  517. // TODO: why isn't this allowed ? :
  518. // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref);
  519. }
  520. struct chwirut2_functor : Functor<double>
  521. {
  522. chwirut2_functor(void) : Functor<double>(3,54) {}
  523. static const double m_x[54];
  524. static const double m_y[54];
  525. int operator()(const VectorXd &b, VectorXd &fvec)
  526. {
  527. int i;
  528. assert(b.size()==3);
  529. assert(fvec.size()==54);
  530. for(i=0; i<54; i++) {
  531. double x = m_x[i];
  532. fvec[i] = exp(-b[0]*x)/(b[1]+b[2]*x) - m_y[i];
  533. }
  534. return 0;
  535. }
  536. int df(const VectorXd &b, MatrixXd &fjac)
  537. {
  538. assert(b.size()==3);
  539. assert(fjac.rows()==54);
  540. assert(fjac.cols()==3);
  541. for(int i=0; i<54; i++) {
  542. double x = m_x[i];
  543. double factor = 1./(b[1]+b[2]*x);
  544. double e = exp(-b[0]*x);
  545. fjac(i,0) = -x*e*factor;
  546. fjac(i,1) = -e*factor*factor;
  547. fjac(i,2) = -x*e*factor*factor;
  548. }
  549. return 0;
  550. }
  551. };
  552. const double chwirut2_functor::m_x[54] = { 0.500E0, 1.000E0, 1.750E0, 3.750E0, 5.750E0, 0.875E0, 2.250E0, 3.250E0, 5.250E0, 0.750E0, 1.750E0, 2.750E0, 4.750E0, 0.625E0, 1.250E0, 2.250E0, 4.250E0, .500E0, 3.000E0, .750E0, 3.000E0, 1.500E0, 6.000E0, 3.000E0, 6.000E0, 1.500E0, 3.000E0, .500E0, 2.000E0, 4.000E0, .750E0, 2.000E0, 5.000E0, .750E0, 2.250E0, 3.750E0, 5.750E0, 3.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .500E0, 6.000E0, 3.000E0, .500E0, 2.750E0, .500E0, 1.750E0};
  553. const double chwirut2_functor::m_y[54] = { 92.9000E0 ,57.1000E0 ,31.0500E0 ,11.5875E0 ,8.0250E0 ,63.6000E0 ,21.4000E0 ,14.2500E0 ,8.4750E0 ,63.8000E0 ,26.8000E0 ,16.4625E0 ,7.1250E0 ,67.3000E0 ,41.0000E0 ,21.1500E0 ,8.1750E0 ,81.5000E0 ,13.1200E0 ,59.9000E0 ,14.6200E0 ,32.9000E0 ,5.4400E0 ,12.5600E0 ,5.4400E0 ,32.0000E0 ,13.9500E0 ,75.8000E0 ,20.0000E0 ,10.4200E0 ,59.5000E0 ,21.6700E0 ,8.5500E0 ,62.0000E0 ,20.2000E0 ,7.7600E0 ,3.7500E0 ,11.8100E0 ,54.7000E0 ,23.7000E0 ,11.5500E0 ,61.3000E0 ,17.7000E0 ,8.7400E0 ,59.2000E0 ,16.3000E0 ,8.6200E0 ,81.0000E0 ,4.8700E0 ,14.6200E0 ,81.7000E0 ,17.1700E0 ,81.3000E0 ,28.9000E0 };
  554. // http://www.itl.nist.gov/div898/strd/nls/data/chwirut2.shtml
  555. void testNistChwirut2(void)
  556. {
  557. const int n=3;
  558. int info;
  559. VectorXd x(n);
  560. /*
  561. * First try
  562. */
  563. x<< 0.1, 0.01, 0.02;
  564. // do the computation
  565. chwirut2_functor functor;
  566. LevenbergMarquardt<chwirut2_functor> lm(functor);
  567. info = lm.minimize(x);
  568. // check return value
  569. VERIFY_IS_EQUAL(info, 1);
  570. LM_CHECK_N_ITERS(lm, 10, 8);
  571. // check norm^2
  572. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02);
  573. // check x
  574. VERIFY_IS_APPROX(x[0], 1.6657666537E-01);
  575. VERIFY_IS_APPROX(x[1], 5.1653291286E-03);
  576. VERIFY_IS_APPROX(x[2], 1.2150007096E-02);
  577. /*
  578. * Second try
  579. */
  580. x<< 0.15, 0.008, 0.010;
  581. // do the computation
  582. lm.resetParameters();
  583. lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
  584. lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
  585. info = lm.minimize(x);
  586. // check return value
  587. VERIFY_IS_EQUAL(info, 1);
  588. LM_CHECK_N_ITERS(lm, 7, 6);
  589. // check norm^2
  590. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.1304802941E+02);
  591. // check x
  592. VERIFY_IS_APPROX(x[0], 1.6657666537E-01);
  593. VERIFY_IS_APPROX(x[1], 5.1653291286E-03);
  594. VERIFY_IS_APPROX(x[2], 1.2150007096E-02);
  595. }
  596. struct misra1a_functor : Functor<double>
  597. {
  598. misra1a_functor(void) : Functor<double>(2,14) {}
  599. static const double m_x[14];
  600. static const double m_y[14];
  601. int operator()(const VectorXd &b, VectorXd &fvec)
  602. {
  603. assert(b.size()==2);
  604. assert(fvec.size()==14);
  605. for(int i=0; i<14; i++) {
  606. fvec[i] = b[0]*(1.-exp(-b[1]*m_x[i])) - m_y[i] ;
  607. }
  608. return 0;
  609. }
  610. int df(const VectorXd &b, MatrixXd &fjac)
  611. {
  612. assert(b.size()==2);
  613. assert(fjac.rows()==14);
  614. assert(fjac.cols()==2);
  615. for(int i=0; i<14; i++) {
  616. fjac(i,0) = (1.-exp(-b[1]*m_x[i]));
  617. fjac(i,1) = (b[0]*m_x[i]*exp(-b[1]*m_x[i]));
  618. }
  619. return 0;
  620. }
  621. };
  622. const double misra1a_functor::m_x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
  623. const double misra1a_functor::m_y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
  624. // http://www.itl.nist.gov/div898/strd/nls/data/misra1a.shtml
  625. void testNistMisra1a(void)
  626. {
  627. const int n=2;
  628. int info;
  629. VectorXd x(n);
  630. /*
  631. * First try
  632. */
  633. x<< 500., 0.0001;
  634. // do the computation
  635. misra1a_functor functor;
  636. LevenbergMarquardt<misra1a_functor> lm(functor);
  637. info = lm.minimize(x);
  638. // check return value
  639. VERIFY_IS_EQUAL(info, 1);
  640. LM_CHECK_N_ITERS(lm, 19, 15);
  641. // check norm^2
  642. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01);
  643. // check x
  644. VERIFY_IS_APPROX(x[0], 2.3894212918E+02);
  645. VERIFY_IS_APPROX(x[1], 5.5015643181E-04);
  646. /*
  647. * Second try
  648. */
  649. x<< 250., 0.0005;
  650. // do the computation
  651. info = lm.minimize(x);
  652. // check return value
  653. VERIFY_IS_EQUAL(info, 1);
  654. LM_CHECK_N_ITERS(lm, 5, 4);
  655. // check norm^2
  656. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.2455138894E-01);
  657. // check x
  658. VERIFY_IS_APPROX(x[0], 2.3894212918E+02);
  659. VERIFY_IS_APPROX(x[1], 5.5015643181E-04);
  660. }
  661. struct hahn1_functor : Functor<double>
  662. {
  663. hahn1_functor(void) : Functor<double>(7,236) {}
  664. static const double m_x[236];
  665. int operator()(const VectorXd &b, VectorXd &fvec)
  666. {
  667. static const double m_y[236] = { .591E0 , 1.547E0 , 2.902E0 , 2.894E0 , 4.703E0 , 6.307E0 , 7.03E0 , 7.898E0 , 9.470E0 , 9.484E0 , 10.072E0 , 10.163E0 , 11.615E0 , 12.005E0 , 12.478E0 , 12.982E0 , 12.970E0 , 13.926E0 , 14.452E0 , 14.404E0 , 15.190E0 , 15.550E0 , 15.528E0 , 15.499E0 , 16.131E0 , 16.438E0 , 16.387E0 , 16.549E0 , 16.872E0 , 16.830E0 , 16.926E0 , 16.907E0 , 16.966E0 , 17.060E0 , 17.122E0 , 17.311E0 , 17.355E0 , 17.668E0 , 17.767E0 , 17.803E0 , 17.765E0 , 17.768E0 , 17.736E0 , 17.858E0 , 17.877E0 , 17.912E0 , 18.046E0 , 18.085E0 , 18.291E0 , 18.357E0 , 18.426E0 , 18.584E0 , 18.610E0 , 18.870E0 , 18.795E0 , 19.111E0 , .367E0 , .796E0 , 0.892E0 , 1.903E0 , 2.150E0 , 3.697E0 , 5.870E0 , 6.421E0 , 7.422E0 , 9.944E0 , 11.023E0 , 11.87E0 , 12.786E0 , 14.067E0 , 13.974E0 , 14.462E0 , 14.464E0 , 15.381E0 , 15.483E0 , 15.59E0 , 16.075E0 , 16.347E0 , 16.181E0 , 16.915E0 , 17.003E0 , 16.978E0 , 17.756E0 , 17.808E0 , 17.868E0 , 18.481E0 , 18.486E0 , 19.090E0 , 16.062E0 , 16.337E0 , 16.345E0 ,
  668. 16.388E0 , 17.159E0 , 17.116E0 , 17.164E0 , 17.123E0 , 17.979E0 , 17.974E0 , 18.007E0 , 17.993E0 , 18.523E0 , 18.669E0 , 18.617E0 , 19.371E0 , 19.330E0 , 0.080E0 , 0.248E0 , 1.089E0 , 1.418E0 , 2.278E0 , 3.624E0 , 4.574E0 , 5.556E0 , 7.267E0 , 7.695E0 , 9.136E0 , 9.959E0 , 9.957E0 , 11.600E0 , 13.138E0 , 13.564E0 , 13.871E0 , 13.994E0 , 14.947E0 , 15.473E0 , 15.379E0 , 15.455E0 , 15.908E0 , 16.114E0 , 17.071E0 , 17.135E0 , 17.282E0 , 17.368E0 , 17.483E0 , 17.764E0 , 18.185E0 , 18.271E0 , 18.236E0 , 18.237E0 , 18.523E0 , 18.627E0 , 18.665E0 , 19.086E0 , 0.214E0 , 0.943E0 , 1.429E0 , 2.241E0 , 2.951E0 , 3.782E0 , 4.757E0 , 5.602E0 , 7.169E0 , 8.920E0 , 10.055E0 , 12.035E0 , 12.861E0 , 13.436E0 , 14.167E0 , 14.755E0 , 15.168E0 , 15.651E0 , 15.746E0 , 16.216E0 , 16.445E0 , 16.965E0 , 17.121E0 , 17.206E0 , 17.250E0 , 17.339E0 , 17.793E0 , 18.123E0 , 18.49E0 , 18.566E0 , 18.645E0 , 18.706E0 , 18.924E0 , 19.1E0 , 0.375E0 , 0.471E0 , 1.504E0 , 2.204E0 , 2.813E0 , 4.765E0 , 9.835E0 , 10.040E0 , 11.946E0 , 12.596E0 ,
  669. 13.303E0 , 13.922E0 , 14.440E0 , 14.951E0 , 15.627E0 , 15.639E0 , 15.814E0 , 16.315E0 , 16.334E0 , 16.430E0 , 16.423E0 , 17.024E0 , 17.009E0 , 17.165E0 , 17.134E0 , 17.349E0 , 17.576E0 , 17.848E0 , 18.090E0 , 18.276E0 , 18.404E0 , 18.519E0 , 19.133E0 , 19.074E0 , 19.239E0 , 19.280E0 , 19.101E0 , 19.398E0 , 19.252E0 , 19.89E0 , 20.007E0 , 19.929E0 , 19.268E0 , 19.324E0 , 20.049E0 , 20.107E0 , 20.062E0 , 20.065E0 , 19.286E0 , 19.972E0 , 20.088E0 , 20.743E0 , 20.83E0 , 20.935E0 , 21.035E0 , 20.93E0 , 21.074E0 , 21.085E0 , 20.935E0 };
  670. // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++;
  671. assert(b.size()==7);
  672. assert(fvec.size()==236);
  673. for(int i=0; i<236; i++) {
  674. double x=m_x[i], xx=x*x, xxx=xx*x;
  675. fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - m_y[i];
  676. }
  677. return 0;
  678. }
  679. int df(const VectorXd &b, MatrixXd &fjac)
  680. {
  681. assert(b.size()==7);
  682. assert(fjac.rows()==236);
  683. assert(fjac.cols()==7);
  684. for(int i=0; i<236; i++) {
  685. double x=m_x[i], xx=x*x, xxx=xx*x;
  686. double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx);
  687. fjac(i,0) = 1.*fact;
  688. fjac(i,1) = x*fact;
  689. fjac(i,2) = xx*fact;
  690. fjac(i,3) = xxx*fact;
  691. fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact;
  692. fjac(i,4) = x*fact;
  693. fjac(i,5) = xx*fact;
  694. fjac(i,6) = xxx*fact;
  695. }
  696. return 0;
  697. }
  698. };
  699. const double hahn1_functor::m_x[236] = { 24.41E0 , 34.82E0 , 44.09E0 , 45.07E0 , 54.98E0 , 65.51E0 , 70.53E0 , 75.70E0 , 89.57E0 , 91.14E0 , 96.40E0 , 97.19E0 , 114.26E0 , 120.25E0 , 127.08E0 , 133.55E0 , 133.61E0 , 158.67E0 , 172.74E0 , 171.31E0 , 202.14E0 , 220.55E0 , 221.05E0 , 221.39E0 , 250.99E0 , 268.99E0 , 271.80E0 , 271.97E0 , 321.31E0 , 321.69E0 , 330.14E0 , 333.03E0 , 333.47E0 , 340.77E0 , 345.65E0 , 373.11E0 , 373.79E0 , 411.82E0 , 419.51E0 , 421.59E0 , 422.02E0 , 422.47E0 , 422.61E0 , 441.75E0 , 447.41E0 , 448.7E0 , 472.89E0 , 476.69E0 , 522.47E0 , 522.62E0 , 524.43E0 , 546.75E0 , 549.53E0 , 575.29E0 , 576.00E0 , 625.55E0 , 20.15E0 , 28.78E0 , 29.57E0 , 37.41E0 , 39.12E0 , 50.24E0 , 61.38E0 , 66.25E0 , 73.42E0 , 95.52E0 , 107.32E0 , 122.04E0 , 134.03E0 , 163.19E0 , 163.48E0 , 175.70E0 , 179.86E0 , 211.27E0 , 217.78E0 , 219.14E0 , 262.52E0 , 268.01E0 , 268.62E0 , 336.25E0 , 337.23E0 , 339.33E0 , 427.38E0 , 428.58E0 , 432.68E0 , 528.99E0 , 531.08E0 , 628.34E0 , 253.24E0 , 273.13E0 , 273.66E0 ,
  700. 282.10E0 , 346.62E0 , 347.19E0 , 348.78E0 , 351.18E0 , 450.10E0 , 450.35E0 , 451.92E0 , 455.56E0 , 552.22E0 , 553.56E0 , 555.74E0 , 652.59E0 , 656.20E0 , 14.13E0 , 20.41E0 , 31.30E0 , 33.84E0 , 39.70E0 , 48.83E0 , 54.50E0 , 60.41E0 , 72.77E0 , 75.25E0 , 86.84E0 , 94.88E0 , 96.40E0 , 117.37E0 , 139.08E0 , 147.73E0 , 158.63E0 , 161.84E0 , 192.11E0 , 206.76E0 , 209.07E0 , 213.32E0 , 226.44E0 , 237.12E0 , 330.90E0 , 358.72E0 , 370.77E0 , 372.72E0 , 396.24E0 , 416.59E0 , 484.02E0 , 495.47E0 , 514.78E0 , 515.65E0 , 519.47E0 , 544.47E0 , 560.11E0 , 620.77E0 , 18.97E0 , 28.93E0 , 33.91E0 , 40.03E0 , 44.66E0 , 49.87E0 , 55.16E0 , 60.90E0 , 72.08E0 , 85.15E0 , 97.06E0 , 119.63E0 , 133.27E0 , 143.84E0 , 161.91E0 , 180.67E0 , 198.44E0 , 226.86E0 , 229.65E0 , 258.27E0 , 273.77E0 , 339.15E0 , 350.13E0 , 362.75E0 , 371.03E0 , 393.32E0 , 448.53E0 , 473.78E0 , 511.12E0 , 524.70E0 , 548.75E0 , 551.64E0 , 574.02E0 , 623.86E0 , 21.46E0 , 24.33E0 , 33.43E0 , 39.22E0 , 44.18E0 , 55.02E0 , 94.33E0 , 96.44E0 , 118.82E0 , 128.48E0 ,
  701. 141.94E0 , 156.92E0 , 171.65E0 , 190.00E0 , 223.26E0 , 223.88E0 , 231.50E0 , 265.05E0 , 269.44E0 , 271.78E0 , 273.46E0 , 334.61E0 , 339.79E0 , 349.52E0 , 358.18E0 , 377.98E0 , 394.77E0 , 429.66E0 , 468.22E0 , 487.27E0 , 519.54E0 , 523.03E0 , 612.99E0 , 638.59E0 , 641.36E0 , 622.05E0 , 631.50E0 , 663.97E0 , 646.9E0 , 748.29E0 , 749.21E0 , 750.14E0 , 647.04E0 , 646.89E0 , 746.9E0 , 748.43E0 , 747.35E0 , 749.27E0 , 647.61E0 , 747.78E0 , 750.51E0 , 851.37E0 , 845.97E0 , 847.54E0 , 849.93E0 , 851.61E0 , 849.75E0 , 850.98E0 , 848.23E0};
  702. // http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml
  703. void testNistHahn1(void)
  704. {
  705. const int n=7;
  706. int info;
  707. VectorXd x(n);
  708. /*
  709. * First try
  710. */
  711. x<< 10., -1., .05, -.00001, -.05, .001, -.000001;
  712. // do the computation
  713. hahn1_functor functor;
  714. LevenbergMarquardt<hahn1_functor> lm(functor);
  715. info = lm.minimize(x);
  716. // check return value
  717. VERIFY_IS_EQUAL(info, 1);
  718. LM_CHECK_N_ITERS(lm, 11, 10);
  719. // check norm^2
  720. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00);
  721. // check x
  722. VERIFY_IS_APPROX(x[0], 1.0776351733E+00);
  723. VERIFY_IS_APPROX(x[1],-1.2269296921E-01);
  724. VERIFY_IS_APPROX(x[2], 4.0863750610E-03);
  725. VERIFY_IS_APPROX(x[3],-1.426264e-06); // shoulde be : -1.4262662514E-06
  726. VERIFY_IS_APPROX(x[4],-5.7609940901E-03);
  727. VERIFY_IS_APPROX(x[5], 2.4053735503E-04);
  728. VERIFY_IS_APPROX(x[6],-1.2314450199E-07);
  729. /*
  730. * Second try
  731. */
  732. x<< .1, -.1, .005, -.000001, -.005, .0001, -.0000001;
  733. // do the computation
  734. info = lm.minimize(x);
  735. // check return value
  736. VERIFY_IS_EQUAL(info, 1);
  737. LM_CHECK_N_ITERS(lm, 11, 10);
  738. // check norm^2
  739. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.5324382854E+00);
  740. // check x
  741. VERIFY_IS_APPROX(x[0], 1.077640); // should be : 1.0776351733E+00
  742. VERIFY_IS_APPROX(x[1], -0.1226933); // should be : -1.2269296921E-01
  743. VERIFY_IS_APPROX(x[2], 0.004086383); // should be : 4.0863750610E-03
  744. VERIFY_IS_APPROX(x[3], -1.426277e-06); // shoulde be : -1.4262662514E-06
  745. VERIFY_IS_APPROX(x[4],-5.7609940901E-03);
  746. VERIFY_IS_APPROX(x[5], 0.00024053772); // should be : 2.4053735503E-04
  747. VERIFY_IS_APPROX(x[6], -1.231450e-07); // should be : -1.2314450199E-07
  748. }
  749. struct misra1d_functor : Functor<double>
  750. {
  751. misra1d_functor(void) : Functor<double>(2,14) {}
  752. static const double x[14];
  753. static const double y[14];
  754. int operator()(const VectorXd &b, VectorXd &fvec)
  755. {
  756. assert(b.size()==2);
  757. assert(fvec.size()==14);
  758. for(int i=0; i<14; i++) {
  759. fvec[i] = b[0]*b[1]*x[i]/(1.+b[1]*x[i]) - y[i];
  760. }
  761. return 0;
  762. }
  763. int df(const VectorXd &b, MatrixXd &fjac)
  764. {
  765. assert(b.size()==2);
  766. assert(fjac.rows()==14);
  767. assert(fjac.cols()==2);
  768. for(int i=0; i<14; i++) {
  769. double den = 1.+b[1]*x[i];
  770. fjac(i,0) = b[1]*x[i] / den;
  771. fjac(i,1) = b[0]*x[i]*(den-b[1]*x[i])/den/den;
  772. }
  773. return 0;
  774. }
  775. };
  776. const double misra1d_functor::x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
  777. const double misra1d_functor::y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
  778. // http://www.itl.nist.gov/div898/strd/nls/data/misra1d.shtml
  779. void testNistMisra1d(void)
  780. {
  781. const int n=2;
  782. int info;
  783. VectorXd x(n);
  784. /*
  785. * First try
  786. */
  787. x<< 500., 0.0001;
  788. // do the computation
  789. misra1d_functor functor;
  790. LevenbergMarquardt<misra1d_functor> lm(functor);
  791. info = lm.minimize(x);
  792. // check return value
  793. VERIFY_IS_EQUAL(info, 3);
  794. LM_CHECK_N_ITERS(lm, 9, 7);
  795. // check norm^2
  796. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02);
  797. // check x
  798. VERIFY_IS_APPROX(x[0], 4.3736970754E+02);
  799. VERIFY_IS_APPROX(x[1], 3.0227324449E-04);
  800. /*
  801. * Second try
  802. */
  803. x<< 450., 0.0003;
  804. // do the computation
  805. info = lm.minimize(x);
  806. // check return value
  807. VERIFY_IS_EQUAL(info, 1);
  808. LM_CHECK_N_ITERS(lm, 4, 3);
  809. // check norm^2
  810. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6419295283E-02);
  811. // check x
  812. VERIFY_IS_APPROX(x[0], 4.3736970754E+02);
  813. VERIFY_IS_APPROX(x[1], 3.0227324449E-04);
  814. }
  815. struct lanczos1_functor : Functor<double>
  816. {
  817. lanczos1_functor(void) : Functor<double>(6,24) {}
  818. static const double x[24];
  819. static const double y[24];
  820. int operator()(const VectorXd &b, VectorXd &fvec)
  821. {
  822. assert(b.size()==6);
  823. assert(fvec.size()==24);
  824. for(int i=0; i<24; i++)
  825. fvec[i] = b[0]*exp(-b[1]*x[i]) + b[2]*exp(-b[3]*x[i]) + b[4]*exp(-b[5]*x[i]) - y[i];
  826. return 0;
  827. }
  828. int df(const VectorXd &b, MatrixXd &fjac)
  829. {
  830. assert(b.size()==6);
  831. assert(fjac.rows()==24);
  832. assert(fjac.cols()==6);
  833. for(int i=0; i<24; i++) {
  834. fjac(i,0) = exp(-b[1]*x[i]);
  835. fjac(i,1) = -b[0]*x[i]*exp(-b[1]*x[i]);
  836. fjac(i,2) = exp(-b[3]*x[i]);
  837. fjac(i,3) = -b[2]*x[i]*exp(-b[3]*x[i]);
  838. fjac(i,4) = exp(-b[5]*x[i]);
  839. fjac(i,5) = -b[4]*x[i]*exp(-b[5]*x[i]);
  840. }
  841. return 0;
  842. }
  843. };
  844. const double lanczos1_functor::x[24] = { 0.000000000000E+00, 5.000000000000E-02, 1.000000000000E-01, 1.500000000000E-01, 2.000000000000E-01, 2.500000000000E-01, 3.000000000000E-01, 3.500000000000E-01, 4.000000000000E-01, 4.500000000000E-01, 5.000000000000E-01, 5.500000000000E-01, 6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01, 8.000000000000E-01, 8.500000000000E-01, 9.000000000000E-01, 9.500000000000E-01, 1.000000000000E+00, 1.050000000000E+00, 1.100000000000E+00, 1.150000000000E+00 };
  845. const double lanczos1_functor::y[24] = { 2.513400000000E+00 ,2.044333373291E+00 ,1.668404436564E+00 ,1.366418021208E+00 ,1.123232487372E+00 ,9.268897180037E-01 ,7.679338563728E-01 ,6.388775523106E-01 ,5.337835317402E-01 ,4.479363617347E-01 ,3.775847884350E-01 ,3.197393199326E-01 ,2.720130773746E-01 ,2.324965529032E-01 ,1.996589546065E-01 ,1.722704126914E-01 ,1.493405660168E-01 ,1.300700206922E-01 ,1.138119324644E-01 ,1.000415587559E-01 ,8.833209084540E-02 ,7.833544019350E-02 ,6.976693743449E-02 ,6.239312536719E-02 };
  846. // http://www.itl.nist.gov/div898/strd/nls/data/lanczos1.shtml
  847. void testNistLanczos1(void)
  848. {
  849. const int n=6;
  850. int info;
  851. VectorXd x(n);
  852. /*
  853. * First try
  854. */
  855. x<< 1.2, 0.3, 5.6, 5.5, 6.5, 7.6;
  856. // do the computation
  857. lanczos1_functor functor;
  858. LevenbergMarquardt<lanczos1_functor> lm(functor);
  859. info = lm.minimize(x);
  860. // check return value
  861. VERIFY_IS_EQUAL(info, 2);
  862. LM_CHECK_N_ITERS(lm, 79, 72);
  863. // check norm^2
  864. std::cout.precision(30);
  865. std::cout << lm.fvec.squaredNorm() << "\n";
  866. VERIFY(lm.fvec.squaredNorm() <= 1.4307867721E-25);
  867. // check x
  868. VERIFY_IS_APPROX(x[0], 9.5100000027E-02);
  869. VERIFY_IS_APPROX(x[1], 1.0000000001E+00);
  870. VERIFY_IS_APPROX(x[2], 8.6070000013E-01);
  871. VERIFY_IS_APPROX(x[3], 3.0000000002E+00);
  872. VERIFY_IS_APPROX(x[4], 1.5575999998E+00);
  873. VERIFY_IS_APPROX(x[5], 5.0000000001E+00);
  874. /*
  875. * Second try
  876. */
  877. x<< 0.5, 0.7, 3.6, 4.2, 4., 6.3;
  878. // do the computation
  879. info = lm.minimize(x);
  880. // check return value
  881. VERIFY_IS_EQUAL(info, 2);
  882. LM_CHECK_N_ITERS(lm, 9, 8);
  883. // check norm^2
  884. VERIFY(lm.fvec.squaredNorm() <= 1.4307867721E-25);
  885. // check x
  886. VERIFY_IS_APPROX(x[0], 9.5100000027E-02);
  887. VERIFY_IS_APPROX(x[1], 1.0000000001E+00);
  888. VERIFY_IS_APPROX(x[2], 8.6070000013E-01);
  889. VERIFY_IS_APPROX(x[3], 3.0000000002E+00);
  890. VERIFY_IS_APPROX(x[4], 1.5575999998E+00);
  891. VERIFY_IS_APPROX(x[5], 5.0000000001E+00);
  892. }
  893. struct rat42_functor : Functor<double>
  894. {
  895. rat42_functor(void) : Functor<double>(3,9) {}
  896. static const double x[9];
  897. static const double y[9];
  898. int operator()(const VectorXd &b, VectorXd &fvec)
  899. {
  900. assert(b.size()==3);
  901. assert(fvec.size()==9);
  902. for(int i=0; i<9; i++) {
  903. fvec[i] = b[0] / (1.+exp(b[1]-b[2]*x[i])) - y[i];
  904. }
  905. return 0;
  906. }
  907. int df(const VectorXd &b, MatrixXd &fjac)
  908. {
  909. assert(b.size()==3);
  910. assert(fjac.rows()==9);
  911. assert(fjac.cols()==3);
  912. for(int i=0; i<9; i++) {
  913. double e = exp(b[1]-b[2]*x[i]);
  914. fjac(i,0) = 1./(1.+e);
  915. fjac(i,1) = -b[0]*e/(1.+e)/(1.+e);
  916. fjac(i,2) = +b[0]*e*x[i]/(1.+e)/(1.+e);
  917. }
  918. return 0;
  919. }
  920. };
  921. const double rat42_functor::x[9] = { 9.000E0, 14.000E0, 21.000E0, 28.000E0, 42.000E0, 57.000E0, 63.000E0, 70.000E0, 79.000E0 };
  922. const double rat42_functor::y[9] = { 8.930E0 ,10.800E0 ,18.590E0 ,22.330E0 ,39.350E0 ,56.110E0 ,61.730E0 ,64.620E0 ,67.080E0 };
  923. // http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky2.shtml
  924. void testNistRat42(void)
  925. {
  926. const int n=3;
  927. int info;
  928. VectorXd x(n);
  929. /*
  930. * First try
  931. */
  932. x<< 100., 1., 0.1;
  933. // do the computation
  934. rat42_functor functor;
  935. LevenbergMarquardt<rat42_functor> lm(functor);
  936. info = lm.minimize(x);
  937. // check return value
  938. VERIFY_IS_EQUAL(info, 1);
  939. LM_CHECK_N_ITERS(lm, 10, 8);
  940. // check norm^2
  941. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00);
  942. // check x
  943. VERIFY_IS_APPROX(x[0], 7.2462237576E+01);
  944. VERIFY_IS_APPROX(x[1], 2.6180768402E+00);
  945. VERIFY_IS_APPROX(x[2], 6.7359200066E-02);
  946. /*
  947. * Second try
  948. */
  949. x<< 75., 2.5, 0.07;
  950. // do the computation
  951. info = lm.minimize(x);
  952. // check return value
  953. VERIFY_IS_EQUAL(info, 1);
  954. LM_CHECK_N_ITERS(lm, 6, 5);
  955. // check norm^2
  956. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.0565229338E+00);
  957. // check x
  958. VERIFY_IS_APPROX(x[0], 7.2462237576E+01);
  959. VERIFY_IS_APPROX(x[1], 2.6180768402E+00);
  960. VERIFY_IS_APPROX(x[2], 6.7359200066E-02);
  961. }
  962. struct MGH10_functor : Functor<double>
  963. {
  964. MGH10_functor(void) : Functor<double>(3,16) {}
  965. static const double x[16];
  966. static const double y[16];
  967. int operator()(const VectorXd &b, VectorXd &fvec)
  968. {
  969. assert(b.size()==3);
  970. assert(fvec.size()==16);
  971. for(int i=0; i<16; i++)
  972. fvec[i] = b[0] * exp(b[1]/(x[i]+b[2])) - y[i];
  973. return 0;
  974. }
  975. int df(const VectorXd &b, MatrixXd &fjac)
  976. {
  977. assert(b.size()==3);
  978. assert(fjac.rows()==16);
  979. assert(fjac.cols()==3);
  980. for(int i=0; i<16; i++) {
  981. double factor = 1./(x[i]+b[2]);
  982. double e = exp(b[1]*factor);
  983. fjac(i,0) = e;
  984. fjac(i,1) = b[0]*factor*e;
  985. fjac(i,2) = -b[1]*b[0]*factor*factor*e;
  986. }
  987. return 0;
  988. }
  989. };
  990. const double MGH10_functor::x[16] = { 5.000000E+01, 5.500000E+01, 6.000000E+01, 6.500000E+01, 7.000000E+01, 7.500000E+01, 8.000000E+01, 8.500000E+01, 9.000000E+01, 9.500000E+01, 1.000000E+02, 1.050000E+02, 1.100000E+02, 1.150000E+02, 1.200000E+02, 1.250000E+02 };
  991. const double MGH10_functor::y[16] = { 3.478000E+04, 2.861000E+04, 2.365000E+04, 1.963000E+04, 1.637000E+04, 1.372000E+04, 1.154000E+04, 9.744000E+03, 8.261000E+03, 7.030000E+03, 6.005000E+03, 5.147000E+03, 4.427000E+03, 3.820000E+03, 3.307000E+03, 2.872000E+03 };
  992. // http://www.itl.nist.gov/div898/strd/nls/data/mgh10.shtml
  993. void testNistMGH10(void)
  994. {
  995. const int n=3;
  996. int info;
  997. VectorXd x(n);
  998. /*
  999. * First try
  1000. */
  1001. x<< 2., 400000., 25000.;
  1002. // do the computation
  1003. MGH10_functor functor;
  1004. LevenbergMarquardt<MGH10_functor> lm(functor);
  1005. info = lm.minimize(x);
  1006. // check return value
  1007. VERIFY_IS_EQUAL(info, 2);
  1008. LM_CHECK_N_ITERS(lm, 284, 249);
  1009. // check norm^2
  1010. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01);
  1011. // check x
  1012. VERIFY_IS_APPROX(x[0], 5.6096364710E-03);
  1013. VERIFY_IS_APPROX(x[1], 6.1813463463E+03);
  1014. VERIFY_IS_APPROX(x[2], 3.4522363462E+02);
  1015. /*
  1016. * Second try
  1017. */
  1018. x<< 0.02, 4000., 250.;
  1019. // do the computation
  1020. info = lm.minimize(x);
  1021. // check return value
  1022. VERIFY_IS_EQUAL(info, 3);
  1023. LM_CHECK_N_ITERS(lm, 126, 116);
  1024. // check norm^2
  1025. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7945855171E+01);
  1026. // check x
  1027. VERIFY_IS_APPROX(x[0], 5.6096364710E-03);
  1028. VERIFY_IS_APPROX(x[1], 6.1813463463E+03);
  1029. VERIFY_IS_APPROX(x[2], 3.4522363462E+02);
  1030. }
  1031. struct BoxBOD_functor : Functor<double>
  1032. {
  1033. BoxBOD_functor(void) : Functor<double>(2,6) {}
  1034. static const double x[6];
  1035. int operator()(const VectorXd &b, VectorXd &fvec)
  1036. {
  1037. static const double y[6] = { 109., 149., 149., 191., 213., 224. };
  1038. assert(b.size()==2);
  1039. assert(fvec.size()==6);
  1040. for(int i=0; i<6; i++)
  1041. fvec[i] = b[0]*(1.-exp(-b[1]*x[i])) - y[i];
  1042. return 0;
  1043. }
  1044. int df(const VectorXd &b, MatrixXd &fjac)
  1045. {
  1046. assert(b.size()==2);
  1047. assert(fjac.rows()==6);
  1048. assert(fjac.cols()==2);
  1049. for(int i=0; i<6; i++) {
  1050. double e = exp(-b[1]*x[i]);
  1051. fjac(i,0) = 1.-e;
  1052. fjac(i,1) = b[0]*x[i]*e;
  1053. }
  1054. return 0;
  1055. }
  1056. };
  1057. const double BoxBOD_functor::x[6] = { 1., 2., 3., 5., 7., 10. };
  1058. // http://www.itl.nist.gov/div898/strd/nls/data/boxbod.shtml
  1059. void testNistBoxBOD(void)
  1060. {
  1061. const int n=2;
  1062. int info;
  1063. VectorXd x(n);
  1064. /*
  1065. * First try
  1066. */
  1067. x<< 1., 1.;
  1068. // do the computation
  1069. BoxBOD_functor functor;
  1070. LevenbergMarquardt<BoxBOD_functor> lm(functor);
  1071. lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
  1072. lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
  1073. lm.parameters.factor = 10.;
  1074. info = lm.minimize(x);
  1075. // check return value
  1076. VERIFY_IS_EQUAL(info, 1);
  1077. LM_CHECK_N_ITERS(lm, 31, 25);
  1078. // check norm^2
  1079. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03);
  1080. // check x
  1081. VERIFY_IS_APPROX(x[0], 2.1380940889E+02);
  1082. VERIFY_IS_APPROX(x[1], 5.4723748542E-01);
  1083. /*
  1084. * Second try
  1085. */
  1086. x<< 100., 0.75;
  1087. // do the computation
  1088. lm.resetParameters();
  1089. lm.parameters.ftol = NumTraits<double>::epsilon();
  1090. lm.parameters.xtol = NumTraits<double>::epsilon();
  1091. info = lm.minimize(x);
  1092. // check return value
  1093. VERIFY_IS_EQUAL(info, 1);
  1094. LM_CHECK_N_ITERS(lm, 15, 14);
  1095. // check norm^2
  1096. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.1680088766E+03);
  1097. // check x
  1098. VERIFY_IS_APPROX(x[0], 2.1380940889E+02);
  1099. VERIFY_IS_APPROX(x[1], 5.4723748542E-01);
  1100. }
  1101. struct MGH17_functor : Functor<double>
  1102. {
  1103. MGH17_functor(void) : Functor<double>(5,33) {}
  1104. static const double x[33];
  1105. static const double y[33];
  1106. int operator()(const VectorXd &b, VectorXd &fvec)
  1107. {
  1108. assert(b.size()==5);
  1109. assert(fvec.size()==33);
  1110. for(int i=0; i<33; i++)
  1111. fvec[i] = b[0] + b[1]*exp(-b[3]*x[i]) + b[2]*exp(-b[4]*x[i]) - y[i];
  1112. return 0;
  1113. }
  1114. int df(const VectorXd &b, MatrixXd &fjac)
  1115. {
  1116. assert(b.size()==5);
  1117. assert(fjac.rows()==33);
  1118. assert(fjac.cols()==5);
  1119. for(int i=0; i<33; i++) {
  1120. fjac(i,0) = 1.;
  1121. fjac(i,1) = exp(-b[3]*x[i]);
  1122. fjac(i,2) = exp(-b[4]*x[i]);
  1123. fjac(i,3) = -x[i]*b[1]*exp(-b[3]*x[i]);
  1124. fjac(i,4) = -x[i]*b[2]*exp(-b[4]*x[i]);
  1125. }
  1126. return 0;
  1127. }
  1128. };
  1129. const double MGH17_functor::x[33] = { 0.000000E+00, 1.000000E+01, 2.000000E+01, 3.000000E+01, 4.000000E+01, 5.000000E+01, 6.000000E+01, 7.000000E+01, 8.000000E+01, 9.000000E+01, 1.000000E+02, 1.100000E+02, 1.200000E+02, 1.300000E+02, 1.400000E+02, 1.500000E+02, 1.600000E+02, 1.700000E+02, 1.800000E+02, 1.900000E+02, 2.000000E+02, 2.100000E+02, 2.200000E+02, 2.300000E+02, 2.400000E+02, 2.500000E+02, 2.600000E+02, 2.700000E+02, 2.800000E+02, 2.900000E+02, 3.000000E+02, 3.100000E+02, 3.200000E+02 };
  1130. const double MGH17_functor::y[33] = { 8.440000E-01, 9.080000E-01, 9.320000E-01, 9.360000E-01, 9.250000E-01, 9.080000E-01, 8.810000E-01, 8.500000E-01, 8.180000E-01, 7.840000E-01, 7.510000E-01, 7.180000E-01, 6.850000E-01, 6.580000E-01, 6.280000E-01, 6.030000E-01, 5.800000E-01, 5.580000E-01, 5.380000E-01, 5.220000E-01, 5.060000E-01, 4.900000E-01, 4.780000E-01, 4.670000E-01, 4.570000E-01, 4.480000E-01, 4.380000E-01, 4.310000E-01, 4.240000E-01, 4.200000E-01, 4.140000E-01, 4.110000E-01, 4.060000E-01 };
  1131. // http://www.itl.nist.gov/div898/strd/nls/data/mgh17.shtml
  1132. void testNistMGH17(void)
  1133. {
  1134. const int n=5;
  1135. int info;
  1136. VectorXd x(n);
  1137. /*
  1138. * First try
  1139. */
  1140. x<< 50., 150., -100., 1., 2.;
  1141. // do the computation
  1142. MGH17_functor functor;
  1143. LevenbergMarquardt<MGH17_functor> lm(functor);
  1144. lm.parameters.ftol = NumTraits<double>::epsilon();
  1145. lm.parameters.xtol = NumTraits<double>::epsilon();
  1146. lm.parameters.maxfev = 1000;
  1147. info = lm.minimize(x);
  1148. // check norm^2
  1149. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05);
  1150. // check x
  1151. VERIFY_IS_APPROX(x[0], 3.7541005211E-01);
  1152. VERIFY_IS_APPROX(x[1], 1.9358469127E+00);
  1153. VERIFY_IS_APPROX(x[2], -1.4646871366E+00);
  1154. VERIFY_IS_APPROX(x[3], 1.2867534640E-02);
  1155. VERIFY_IS_APPROX(x[4], 2.2122699662E-02);
  1156. // check return value
  1157. VERIFY_IS_EQUAL(info, 2);
  1158. LM_CHECK_N_ITERS(lm, 602, 545);
  1159. /*
  1160. * Second try
  1161. */
  1162. x<< 0.5 ,1.5 ,-1 ,0.01 ,0.02;
  1163. // do the computation
  1164. lm.resetParameters();
  1165. info = lm.minimize(x);
  1166. // check return value
  1167. VERIFY_IS_EQUAL(info, 1);
  1168. LM_CHECK_N_ITERS(lm, 18, 15);
  1169. // check norm^2
  1170. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.4648946975E-05);
  1171. // check x
  1172. VERIFY_IS_APPROX(x[0], 3.7541005211E-01);
  1173. VERIFY_IS_APPROX(x[1], 1.9358469127E+00);
  1174. VERIFY_IS_APPROX(x[2], -1.4646871366E+00);
  1175. VERIFY_IS_APPROX(x[3], 1.2867534640E-02);
  1176. VERIFY_IS_APPROX(x[4], 2.2122699662E-02);
  1177. }
  1178. struct MGH09_functor : Functor<double>
  1179. {
  1180. MGH09_functor(void) : Functor<double>(4,11) {}
  1181. static const double _x[11];
  1182. static const double y[11];
  1183. int operator()(const VectorXd &b, VectorXd &fvec)
  1184. {
  1185. assert(b.size()==4);
  1186. assert(fvec.size()==11);
  1187. for(int i=0; i<11; i++) {
  1188. double x = _x[i], xx=x*x;
  1189. fvec[i] = b[0]*(xx+x*b[1])/(xx+x*b[2]+b[3]) - y[i];
  1190. }
  1191. return 0;
  1192. }
  1193. int df(const VectorXd &b, MatrixXd &fjac)
  1194. {
  1195. assert(b.size()==4);
  1196. assert(fjac.rows()==11);
  1197. assert(fjac.cols()==4);
  1198. for(int i=0; i<11; i++) {
  1199. double x = _x[i], xx=x*x;
  1200. double factor = 1./(xx+x*b[2]+b[3]);
  1201. fjac(i,0) = (xx+x*b[1]) * factor;
  1202. fjac(i,1) = b[0]*x* factor;
  1203. fjac(i,2) = - b[0]*(xx+x*b[1]) * x * factor * factor;
  1204. fjac(i,3) = - b[0]*(xx+x*b[1]) * factor * factor;
  1205. }
  1206. return 0;
  1207. }
  1208. };
  1209. const double MGH09_functor::_x[11] = { 4., 2., 1., 5.E-1 , 2.5E-01, 1.670000E-01, 1.250000E-01, 1.E-01, 8.330000E-02, 7.140000E-02, 6.250000E-02 };
  1210. const double MGH09_functor::y[11] = { 1.957000E-01, 1.947000E-01, 1.735000E-01, 1.600000E-01, 8.440000E-02, 6.270000E-02, 4.560000E-02, 3.420000E-02, 3.230000E-02, 2.350000E-02, 2.460000E-02 };
  1211. // http://www.itl.nist.gov/div898/strd/nls/data/mgh09.shtml
  1212. void testNistMGH09(void)
  1213. {
  1214. const int n=4;
  1215. int info;
  1216. VectorXd x(n);
  1217. /*
  1218. * First try
  1219. */
  1220. x<< 25., 39, 41.5, 39.;
  1221. // do the computation
  1222. MGH09_functor functor;
  1223. LevenbergMarquardt<MGH09_functor> lm(functor);
  1224. lm.parameters.maxfev = 1000;
  1225. info = lm.minimize(x);
  1226. // check return value
  1227. VERIFY_IS_EQUAL(info, 1);
  1228. LM_CHECK_N_ITERS(lm, 490, 376);
  1229. // check norm^2
  1230. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04);
  1231. // check x
  1232. VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01
  1233. VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01
  1234. VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01
  1235. VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01
  1236. /*
  1237. * Second try
  1238. */
  1239. x<< 0.25, 0.39, 0.415, 0.39;
  1240. // do the computation
  1241. lm.resetParameters();
  1242. info = lm.minimize(x);
  1243. // check return value
  1244. VERIFY_IS_EQUAL(info, 1);
  1245. LM_CHECK_N_ITERS(lm, 18, 16);
  1246. // check norm^2
  1247. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 3.0750560385E-04);
  1248. // check x
  1249. VERIFY_IS_APPROX(x[0], 0.19280781); // should be 1.9280693458E-01
  1250. VERIFY_IS_APPROX(x[1], 0.19126265); // should be 1.9128232873E-01
  1251. VERIFY_IS_APPROX(x[2], 0.12305280); // should be 1.2305650693E-01
  1252. VERIFY_IS_APPROX(x[3], 0.13605322); // should be 1.3606233068E-01
  1253. }
  1254. struct Bennett5_functor : Functor<double>
  1255. {
  1256. Bennett5_functor(void) : Functor<double>(3,154) {}
  1257. static const double x[154];
  1258. static const double y[154];
  1259. int operator()(const VectorXd &b, VectorXd &fvec)
  1260. {
  1261. assert(b.size()==3);
  1262. assert(fvec.size()==154);
  1263. for(int i=0; i<154; i++)
  1264. fvec[i] = b[0]* pow(b[1]+x[i],-1./b[2]) - y[i];
  1265. return 0;
  1266. }
  1267. int df(const VectorXd &b, MatrixXd &fjac)
  1268. {
  1269. assert(b.size()==3);
  1270. assert(fjac.rows()==154);
  1271. assert(fjac.cols()==3);
  1272. for(int i=0; i<154; i++) {
  1273. double e = pow(b[1]+x[i],-1./b[2]);
  1274. fjac(i,0) = e;
  1275. fjac(i,1) = - b[0]*e/b[2]/(b[1]+x[i]);
  1276. fjac(i,2) = b[0]*e*log(b[1]+x[i])/b[2]/b[2];
  1277. }
  1278. return 0;
  1279. }
  1280. };
  1281. const double Bennett5_functor::x[154] = { 7.447168E0, 8.102586E0, 8.452547E0, 8.711278E0, 8.916774E0, 9.087155E0, 9.232590E0, 9.359535E0, 9.472166E0, 9.573384E0, 9.665293E0, 9.749461E0, 9.827092E0, 9.899128E0, 9.966321E0, 10.029280E0, 10.088510E0, 10.144430E0, 10.197380E0, 10.247670E0, 10.295560E0, 10.341250E0, 10.384950E0, 10.426820E0, 10.467000E0, 10.505640E0, 10.542830E0, 10.578690E0, 10.613310E0, 10.646780E0, 10.679150E0, 10.710520E0, 10.740920E0, 10.770440E0, 10.799100E0, 10.826970E0, 10.854080E0, 10.880470E0, 10.906190E0, 10.931260E0, 10.955720E0, 10.979590E0, 11.002910E0, 11.025700E0, 11.047980E0, 11.069770E0, 11.091100E0, 11.111980E0, 11.132440E0, 11.152480E0, 11.172130E0, 11.191410E0, 11.210310E0, 11.228870E0, 11.247090E0, 11.264980E0, 11.282560E0, 11.299840E0, 11.316820E0, 11.333520E0, 11.349940E0, 11.366100E0, 11.382000E0, 11.397660E0, 11.413070E0, 11.428240E0, 11.443200E0, 11.457930E0, 11.472440E0, 11.486750E0, 11.500860E0, 11.514770E0, 11.528490E0, 11.542020E0, 11.555380E0, 11.568550E0,
  1282. 11.581560E0, 11.594420E0, 11.607121E0, 11.619640E0, 11.632000E0, 11.644210E0, 11.656280E0, 11.668200E0, 11.679980E0, 11.691620E0, 11.703130E0, 11.714510E0, 11.725760E0, 11.736880E0, 11.747890E0, 11.758780E0, 11.769550E0, 11.780200E0, 11.790730E0, 11.801160E0, 11.811480E0, 11.821700E0, 11.831810E0, 11.841820E0, 11.851730E0, 11.861550E0, 11.871270E0, 11.880890E0, 11.890420E0, 11.899870E0, 11.909220E0, 11.918490E0, 11.927680E0, 11.936780E0, 11.945790E0, 11.954730E0, 11.963590E0, 11.972370E0, 11.981070E0, 11.989700E0, 11.998260E0, 12.006740E0, 12.015150E0, 12.023490E0, 12.031760E0, 12.039970E0, 12.048100E0, 12.056170E0, 12.064180E0, 12.072120E0, 12.080010E0, 12.087820E0, 12.095580E0, 12.103280E0, 12.110920E0, 12.118500E0, 12.126030E0, 12.133500E0, 12.140910E0, 12.148270E0, 12.155570E0, 12.162830E0, 12.170030E0, 12.177170E0, 12.184270E0, 12.191320E0, 12.198320E0, 12.205270E0, 12.212170E0, 12.219030E0, 12.225840E0, 12.232600E0, 12.239320E0, 12.245990E0, 12.252620E0, 12.259200E0, 12.265750E0, 12.272240E0 };
  1283. const double Bennett5_functor::y[154] = { -34.834702E0 ,-34.393200E0 ,-34.152901E0 ,-33.979099E0 ,-33.845901E0 ,-33.732899E0 ,-33.640301E0 ,-33.559200E0 ,-33.486801E0 ,-33.423100E0 ,-33.365101E0 ,-33.313000E0 ,-33.260899E0 ,-33.217400E0 ,-33.176899E0 ,-33.139198E0 ,-33.101601E0 ,-33.066799E0 ,-33.035000E0 ,-33.003101E0 ,-32.971298E0 ,-32.942299E0 ,-32.916302E0 ,-32.890202E0 ,-32.864101E0 ,-32.841000E0 ,-32.817799E0 ,-32.797501E0 ,-32.774300E0 ,-32.757000E0 ,-32.733799E0 ,-32.716400E0 ,-32.699100E0 ,-32.678799E0 ,-32.661400E0 ,-32.644001E0 ,-32.626701E0 ,-32.612202E0 ,-32.597698E0 ,-32.583199E0 ,-32.568699E0 ,-32.554298E0 ,-32.539799E0 ,-32.525299E0 ,-32.510799E0 ,-32.499199E0 ,-32.487598E0 ,-32.473202E0 ,-32.461601E0 ,-32.435501E0 ,-32.435501E0 ,-32.426800E0 ,-32.412300E0 ,-32.400799E0 ,-32.392101E0 ,-32.380501E0 ,-32.366001E0 ,-32.357300E0 ,-32.348598E0 ,-32.339901E0 ,-32.328400E0 ,-32.319698E0 ,-32.311001E0 ,-32.299400E0 ,-32.290699E0 ,-32.282001E0 ,-32.273300E0 ,-32.264599E0 ,-32.256001E0 ,-32.247299E0
  1284. ,-32.238602E0 ,-32.229900E0 ,-32.224098E0 ,-32.215401E0 ,-32.203800E0 ,-32.198002E0 ,-32.189400E0 ,-32.183601E0 ,-32.174900E0 ,-32.169102E0 ,-32.163300E0 ,-32.154598E0 ,-32.145901E0 ,-32.140099E0 ,-32.131401E0 ,-32.125599E0 ,-32.119801E0 ,-32.111198E0 ,-32.105400E0 ,-32.096699E0 ,-32.090900E0 ,-32.088001E0 ,-32.079300E0 ,-32.073502E0 ,-32.067699E0 ,-32.061901E0 ,-32.056099E0 ,-32.050301E0 ,-32.044498E0 ,-32.038799E0 ,-32.033001E0 ,-32.027199E0 ,-32.024300E0 ,-32.018501E0 ,-32.012699E0 ,-32.004002E0 ,-32.001099E0 ,-31.995300E0 ,-31.989500E0 ,-31.983700E0 ,-31.977900E0 ,-31.972099E0 ,-31.969299E0 ,-31.963501E0 ,-31.957701E0 ,-31.951900E0 ,-31.946100E0 ,-31.940300E0 ,-31.937401E0 ,-31.931601E0 ,-31.925800E0 ,-31.922899E0 ,-31.917101E0 ,-31.911301E0 ,-31.908400E0 ,-31.902599E0 ,-31.896900E0 ,-31.893999E0 ,-31.888201E0 ,-31.885300E0 ,-31.882401E0 ,-31.876600E0 ,-31.873699E0 ,-31.867901E0 ,-31.862101E0 ,-31.859200E0 ,-31.856300E0 ,-31.850500E0 ,-31.844700E0 ,-31.841801E0 ,-31.838900E0 ,-31.833099E0 ,-31.830200E0 ,
  1285. -31.827299E0 ,-31.821600E0 ,-31.818701E0 ,-31.812901E0 ,-31.809999E0 ,-31.807100E0 ,-31.801300E0 ,-31.798401E0 ,-31.795500E0 ,-31.789700E0 ,-31.786800E0 };
  1286. // http://www.itl.nist.gov/div898/strd/nls/data/bennett5.shtml
  1287. void testNistBennett5(void)
  1288. {
  1289. const int n=3;
  1290. int info;
  1291. VectorXd x(n);
  1292. /*
  1293. * First try
  1294. */
  1295. x<< -2000., 50., 0.8;
  1296. // do the computation
  1297. Bennett5_functor functor;
  1298. LevenbergMarquardt<Bennett5_functor> lm(functor);
  1299. lm.parameters.maxfev = 1000;
  1300. info = lm.minimize(x);
  1301. // check return value
  1302. VERIFY_IS_EQUAL(info, 1);
  1303. LM_CHECK_N_ITERS(lm, 758, 744);
  1304. // check norm^2
  1305. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04);
  1306. // check x
  1307. VERIFY_IS_APPROX(x[0], -2.5235058043E+03);
  1308. VERIFY_IS_APPROX(x[1], 4.6736564644E+01);
  1309. VERIFY_IS_APPROX(x[2], 9.3218483193E-01);
  1310. /*
  1311. * Second try
  1312. */
  1313. x<< -1500., 45., 0.85;
  1314. // do the computation
  1315. lm.resetParameters();
  1316. info = lm.minimize(x);
  1317. // check return value
  1318. VERIFY_IS_EQUAL(info, 1);
  1319. LM_CHECK_N_ITERS(lm, 203, 192);
  1320. // check norm^2
  1321. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.2404744073E-04);
  1322. // check x
  1323. VERIFY_IS_APPROX(x[0], -2523.3007865); // should be -2.5235058043E+03
  1324. VERIFY_IS_APPROX(x[1], 46.735705771); // should be 4.6736564644E+01);
  1325. VERIFY_IS_APPROX(x[2], 0.93219881891); // should be 9.3218483193E-01);
  1326. }
  1327. struct thurber_functor : Functor<double>
  1328. {
  1329. thurber_functor(void) : Functor<double>(7,37) {}
  1330. static const double _x[37];
  1331. static const double _y[37];
  1332. int operator()(const VectorXd &b, VectorXd &fvec)
  1333. {
  1334. // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++;
  1335. assert(b.size()==7);
  1336. assert(fvec.size()==37);
  1337. for(int i=0; i<37; i++) {
  1338. double x=_x[i], xx=x*x, xxx=xx*x;
  1339. fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - _y[i];
  1340. }
  1341. return 0;
  1342. }
  1343. int df(const VectorXd &b, MatrixXd &fjac)
  1344. {
  1345. assert(b.size()==7);
  1346. assert(fjac.rows()==37);
  1347. assert(fjac.cols()==7);
  1348. for(int i=0; i<37; i++) {
  1349. double x=_x[i], xx=x*x, xxx=xx*x;
  1350. double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx);
  1351. fjac(i,0) = 1.*fact;
  1352. fjac(i,1) = x*fact;
  1353. fjac(i,2) = xx*fact;
  1354. fjac(i,3) = xxx*fact;
  1355. fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact;
  1356. fjac(i,4) = x*fact;
  1357. fjac(i,5) = xx*fact;
  1358. fjac(i,6) = xxx*fact;
  1359. }
  1360. return 0;
  1361. }
  1362. };
  1363. const double thurber_functor::_x[37] = { -3.067E0, -2.981E0, -2.921E0, -2.912E0, -2.840E0, -2.797E0, -2.702E0, -2.699E0, -2.633E0, -2.481E0, -2.363E0, -2.322E0, -1.501E0, -1.460E0, -1.274E0, -1.212E0, -1.100E0, -1.046E0, -0.915E0, -0.714E0, -0.566E0, -0.545E0, -0.400E0, -0.309E0, -0.109E0, -0.103E0, 0.010E0, 0.119E0, 0.377E0, 0.790E0, 0.963E0, 1.006E0, 1.115E0, 1.572E0, 1.841E0, 2.047E0, 2.200E0 };
  1364. const double thurber_functor::_y[37] = { 80.574E0, 84.248E0, 87.264E0, 87.195E0, 89.076E0, 89.608E0, 89.868E0, 90.101E0, 92.405E0, 95.854E0, 100.696E0, 101.060E0, 401.672E0, 390.724E0, 567.534E0, 635.316E0, 733.054E0, 759.087E0, 894.206E0, 990.785E0, 1090.109E0, 1080.914E0, 1122.643E0, 1178.351E0, 1260.531E0, 1273.514E0, 1288.339E0, 1327.543E0, 1353.863E0, 1414.509E0, 1425.208E0, 1421.384E0, 1442.962E0, 1464.350E0, 1468.705E0, 1447.894E0, 1457.628E0};
  1365. // http://www.itl.nist.gov/div898/strd/nls/data/thurber.shtml
  1366. void testNistThurber(void)
  1367. {
  1368. const int n=7;
  1369. int info;
  1370. VectorXd x(n);
  1371. /*
  1372. * First try
  1373. */
  1374. x<< 1000 ,1000 ,400 ,40 ,0.7,0.3,0.0 ;
  1375. // do the computation
  1376. thurber_functor functor;
  1377. LevenbergMarquardt<thurber_functor> lm(functor);
  1378. lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon();
  1379. lm.parameters.xtol = 1.E4*NumTraits<double>::epsilon();
  1380. info = lm.minimize(x);
  1381. // check return value
  1382. VERIFY_IS_EQUAL(info, 1);
  1383. LM_CHECK_N_ITERS(lm, 39,36);
  1384. // check norm^2
  1385. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03);
  1386. // check x
  1387. VERIFY_IS_APPROX(x[0], 1.2881396800E+03);
  1388. VERIFY_IS_APPROX(x[1], 1.4910792535E+03);
  1389. VERIFY_IS_APPROX(x[2], 5.8323836877E+02);
  1390. VERIFY_IS_APPROX(x[3], 7.5416644291E+01);
  1391. VERIFY_IS_APPROX(x[4], 9.6629502864E-01);
  1392. VERIFY_IS_APPROX(x[5], 3.9797285797E-01);
  1393. VERIFY_IS_APPROX(x[6], 4.9727297349E-02);
  1394. /*
  1395. * Second try
  1396. */
  1397. x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ;
  1398. // do the computation
  1399. lm.resetParameters();
  1400. lm.parameters.ftol = 1.E4*NumTraits<double>::epsilon();
  1401. lm.parameters.xtol = 1.E4*NumTraits<double>::epsilon();
  1402. info = lm.minimize(x);
  1403. // check return value
  1404. VERIFY_IS_EQUAL(info, 1);
  1405. LM_CHECK_N_ITERS(lm, 29, 28);
  1406. // check norm^2
  1407. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 5.6427082397E+03);
  1408. // check x
  1409. VERIFY_IS_APPROX(x[0], 1.2881396800E+03);
  1410. VERIFY_IS_APPROX(x[1], 1.4910792535E+03);
  1411. VERIFY_IS_APPROX(x[2], 5.8323836877E+02);
  1412. VERIFY_IS_APPROX(x[3], 7.5416644291E+01);
  1413. VERIFY_IS_APPROX(x[4], 9.6629502864E-01);
  1414. VERIFY_IS_APPROX(x[5], 3.9797285797E-01);
  1415. VERIFY_IS_APPROX(x[6], 4.9727297349E-02);
  1416. }
  1417. struct rat43_functor : Functor<double>
  1418. {
  1419. rat43_functor(void) : Functor<double>(4,15) {}
  1420. static const double x[15];
  1421. static const double y[15];
  1422. int operator()(const VectorXd &b, VectorXd &fvec)
  1423. {
  1424. assert(b.size()==4);
  1425. assert(fvec.size()==15);
  1426. for(int i=0; i<15; i++)
  1427. fvec[i] = b[0] * pow(1.+exp(b[1]-b[2]*x[i]),-1./b[3]) - y[i];
  1428. return 0;
  1429. }
  1430. int df(const VectorXd &b, MatrixXd &fjac)
  1431. {
  1432. assert(b.size()==4);
  1433. assert(fjac.rows()==15);
  1434. assert(fjac.cols()==4);
  1435. for(int i=0; i<15; i++) {
  1436. double e = exp(b[1]-b[2]*x[i]);
  1437. double power = -1./b[3];
  1438. fjac(i,0) = pow(1.+e, power);
  1439. fjac(i,1) = power*b[0]*e*pow(1.+e, power-1.);
  1440. fjac(i,2) = -power*b[0]*e*x[i]*pow(1.+e, power-1.);
  1441. fjac(i,3) = b[0]*power*power*log(1.+e)*pow(1.+e, power);
  1442. }
  1443. return 0;
  1444. }
  1445. };
  1446. const double rat43_functor::x[15] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15. };
  1447. const double rat43_functor::y[15] = { 16.08, 33.83, 65.80, 97.20, 191.55, 326.20, 386.87, 520.53, 590.03, 651.92, 724.93, 699.56, 689.96, 637.56, 717.41 };
  1448. // http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky3.shtml
  1449. void testNistRat43(void)
  1450. {
  1451. const int n=4;
  1452. int info;
  1453. VectorXd x(n);
  1454. /*
  1455. * First try
  1456. */
  1457. x<< 100., 10., 1., 1.;
  1458. // do the computation
  1459. rat43_functor functor;
  1460. LevenbergMarquardt<rat43_functor> lm(functor);
  1461. lm.parameters.ftol = 1.E6*NumTraits<double>::epsilon();
  1462. lm.parameters.xtol = 1.E6*NumTraits<double>::epsilon();
  1463. info = lm.minimize(x);
  1464. // check return value
  1465. VERIFY_IS_EQUAL(info, 1);
  1466. LM_CHECK_N_ITERS(lm, 27, 20);
  1467. // check norm^2
  1468. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03);
  1469. // check x
  1470. VERIFY_IS_APPROX(x[0], 6.9964151270E+02);
  1471. VERIFY_IS_APPROX(x[1], 5.2771253025E+00);
  1472. VERIFY_IS_APPROX(x[2], 7.5962938329E-01);
  1473. VERIFY_IS_APPROX(x[3], 1.2792483859E+00);
  1474. /*
  1475. * Second try
  1476. */
  1477. x<< 700., 5., 0.75, 1.3;
  1478. // do the computation
  1479. lm.resetParameters();
  1480. lm.parameters.ftol = 1.E5*NumTraits<double>::epsilon();
  1481. lm.parameters.xtol = 1.E5*NumTraits<double>::epsilon();
  1482. info = lm.minimize(x);
  1483. // check return value
  1484. VERIFY_IS_EQUAL(info, 1);
  1485. LM_CHECK_N_ITERS(lm, 9, 8);
  1486. // check norm^2
  1487. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 8.7864049080E+03);
  1488. // check x
  1489. VERIFY_IS_APPROX(x[0], 6.9964151270E+02);
  1490. VERIFY_IS_APPROX(x[1], 5.2771253025E+00);
  1491. VERIFY_IS_APPROX(x[2], 7.5962938329E-01);
  1492. VERIFY_IS_APPROX(x[3], 1.2792483859E+00);
  1493. }
  1494. struct eckerle4_functor : Functor<double>
  1495. {
  1496. eckerle4_functor(void) : Functor<double>(3,35) {}
  1497. static const double x[35];
  1498. static const double y[35];
  1499. int operator()(const VectorXd &b, VectorXd &fvec)
  1500. {
  1501. assert(b.size()==3);
  1502. assert(fvec.size()==35);
  1503. for(int i=0; i<35; i++)
  1504. fvec[i] = b[0]/b[1] * exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/(b[1]*b[1])) - y[i];
  1505. return 0;
  1506. }
  1507. int df(const VectorXd &b, MatrixXd &fjac)
  1508. {
  1509. assert(b.size()==3);
  1510. assert(fjac.rows()==35);
  1511. assert(fjac.cols()==3);
  1512. for(int i=0; i<35; i++) {
  1513. double b12 = b[1]*b[1];
  1514. double e = exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/b12);
  1515. fjac(i,0) = e / b[1];
  1516. fjac(i,1) = ((x[i]-b[2])*(x[i]-b[2])/b12-1.) * b[0]*e/b12;
  1517. fjac(i,2) = (x[i]-b[2])*e*b[0]/b[1]/b12;
  1518. }
  1519. return 0;
  1520. }
  1521. };
  1522. const double eckerle4_functor::x[35] = { 400.0, 405.0, 410.0, 415.0, 420.0, 425.0, 430.0, 435.0, 436.5, 438.0, 439.5, 441.0, 442.5, 444.0, 445.5, 447.0, 448.5, 450.0, 451.5, 453.0, 454.5, 456.0, 457.5, 459.0, 460.5, 462.0, 463.5, 465.0, 470.0, 475.0, 480.0, 485.0, 490.0, 495.0, 500.0};
  1523. const double eckerle4_functor::y[35] = { 0.0001575, 0.0001699, 0.0002350, 0.0003102, 0.0004917, 0.0008710, 0.0017418, 0.0046400, 0.0065895, 0.0097302, 0.0149002, 0.0237310, 0.0401683, 0.0712559, 0.1264458, 0.2073413, 0.2902366, 0.3445623, 0.3698049, 0.3668534, 0.3106727, 0.2078154, 0.1164354, 0.0616764, 0.0337200, 0.0194023, 0.0117831, 0.0074357, 0.0022732, 0.0008800, 0.0004579, 0.0002345, 0.0001586, 0.0001143, 0.0000710 };
  1524. // http://www.itl.nist.gov/div898/strd/nls/data/eckerle4.shtml
  1525. void testNistEckerle4(void)
  1526. {
  1527. const int n=3;
  1528. int info;
  1529. VectorXd x(n);
  1530. /*
  1531. * First try
  1532. */
  1533. x<< 1., 10., 500.;
  1534. // do the computation
  1535. eckerle4_functor functor;
  1536. LevenbergMarquardt<eckerle4_functor> lm(functor);
  1537. info = lm.minimize(x);
  1538. // check return value
  1539. VERIFY_IS_EQUAL(info, 1);
  1540. LM_CHECK_N_ITERS(lm, 18, 15);
  1541. // check norm^2
  1542. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03);
  1543. // check x
  1544. VERIFY_IS_APPROX(x[0], 1.5543827178);
  1545. VERIFY_IS_APPROX(x[1], 4.0888321754);
  1546. VERIFY_IS_APPROX(x[2], 4.5154121844E+02);
  1547. /*
  1548. * Second try
  1549. */
  1550. x<< 1.5, 5., 450.;
  1551. // do the computation
  1552. info = lm.minimize(x);
  1553. // check return value
  1554. VERIFY_IS_EQUAL(info, 1);
  1555. LM_CHECK_N_ITERS(lm, 7, 6);
  1556. // check norm^2
  1557. VERIFY_IS_APPROX(lm.fvec.squaredNorm(), 1.4635887487E-03);
  1558. // check x
  1559. VERIFY_IS_APPROX(x[0], 1.5543827178);
  1560. VERIFY_IS_APPROX(x[1], 4.0888321754);
  1561. VERIFY_IS_APPROX(x[2], 4.5154121844E+02);
  1562. }
  1563. EIGEN_DECLARE_TEST(NonLinearOptimization)
  1564. {
  1565. // Tests using the examples provided by (c)minpack
  1566. CALL_SUBTEST/*_1*/(testChkder());
  1567. CALL_SUBTEST/*_1*/(testLmder1());
  1568. CALL_SUBTEST/*_1*/(testLmder());
  1569. CALL_SUBTEST/*_2*/(testHybrj1());
  1570. CALL_SUBTEST/*_2*/(testHybrj());
  1571. CALL_SUBTEST/*_2*/(testHybrd1());
  1572. CALL_SUBTEST/*_2*/(testHybrd());
  1573. CALL_SUBTEST/*_3*/(testLmstr1());
  1574. CALL_SUBTEST/*_3*/(testLmstr());
  1575. CALL_SUBTEST/*_3*/(testLmdif1());
  1576. CALL_SUBTEST/*_3*/(testLmdif());
  1577. // NIST tests, level of difficulty = "Lower"
  1578. CALL_SUBTEST/*_4*/(testNistMisra1a());
  1579. CALL_SUBTEST/*_4*/(testNistChwirut2());
  1580. // NIST tests, level of difficulty = "Average"
  1581. CALL_SUBTEST/*_5*/(testNistHahn1());
  1582. CALL_SUBTEST/*_6*/(testNistMisra1d());
  1583. CALL_SUBTEST/*_7*/(testNistMGH17());
  1584. CALL_SUBTEST/*_8*/(testNistLanczos1());
  1585. // // NIST tests, level of difficulty = "Higher"
  1586. CALL_SUBTEST/*_9*/(testNistRat42());
  1587. // CALL_SUBTEST/*_10*/(testNistMGH10());
  1588. CALL_SUBTEST/*_11*/(testNistBoxBOD());
  1589. // CALL_SUBTEST/*_12*/(testNistMGH09());
  1590. CALL_SUBTEST/*_13*/(testNistBennett5());
  1591. CALL_SUBTEST/*_14*/(testNistThurber());
  1592. CALL_SUBTEST/*_15*/(testNistRat43());
  1593. CALL_SUBTEST/*_16*/(testNistEckerle4());
  1594. }
  1595. /*
  1596. * Can be useful for debugging...
  1597. printf("info, nfev : %d, %d\n", info, lm.nfev);
  1598. printf("info, nfev, njev : %d, %d, %d\n", info, solver.nfev, solver.njev);
  1599. printf("info, nfev : %d, %d\n", info, solver.nfev);
  1600. printf("x[0] : %.32g\n", x[0]);
  1601. printf("x[1] : %.32g\n", x[1]);
  1602. printf("x[2] : %.32g\n", x[2]);
  1603. printf("x[3] : %.32g\n", x[3]);
  1604. printf("fvec.blueNorm() : %.32g\n", solver.fvec.blueNorm());
  1605. printf("fvec.blueNorm() : %.32g\n", lm.fvec.blueNorm());
  1606. printf("info, nfev, njev : %d, %d, %d\n", info, lm.nfev, lm.njev);
  1607. printf("fvec.squaredNorm() : %.13g\n", lm.fvec.squaredNorm());
  1608. std::cout << x << std::endl;
  1609. std::cout.precision(9);
  1610. std::cout << x[0] << std::endl;
  1611. std::cout << x[1] << std::endl;
  1612. std::cout << x[2] << std::endl;
  1613. std::cout << x[3] << std::endl;
  1614. */