1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.estimation;
19  
20  import java.util.Arrays;
21  
22  import org.apache.commons.math.estimation.EstimatedParameter;
23  import org.apache.commons.math.estimation.EstimationException;
24  import org.apache.commons.math.estimation.EstimationProblem;
25  import org.apache.commons.math.estimation.LevenbergMarquardtEstimator;
26  import org.apache.commons.math.estimation.WeightedMeasurement;
27  
28  import junit.framework.*;
29  
30  /**
31   * <p>Some of the unit tests are re-implementations of the MINPACK <a
32   * href="http://www.netlib.org/minpack/ex/file17">file17</a> and <a
33   * href="http://www.netlib.org/minpack/ex/file22">file22</a> test files. 
34   * The redistribution policy for MINPACK is available <a
35   * href="http://www.netlib.org/minpack/disclaimer">here</a>, for
36   * convenience, it is reproduced below.</p>
37  
38   * <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0">
39   * <tr><td>
40   *    Minpack Copyright Notice (1999) University of Chicago.
41   *    All rights reserved
42   * </td></tr>
43   * <tr><td>
44   * Redistribution and use in source and binary forms, with or without
45   * modification, are permitted provided that the following conditions
46   * are met:
47   * <ol>
48   *  <li>Redistributions of source code must retain the above copyright
49   *      notice, this list of conditions and the following disclaimer.</li>
50   * <li>Redistributions in binary form must reproduce the above
51   *     copyright notice, this list of conditions and the following
52   *     disclaimer in the documentation and/or other materials provided
53   *     with the distribution.</li>
54   * <li>The end-user documentation included with the redistribution, if any,
55   *     must include the following acknowledgment:
56   *     <code>This product includes software developed by the University of
57   *           Chicago, as Operator of Argonne National Laboratory.</code>
58   *     Alternately, this acknowledgment may appear in the software itself,
59   *     if and wherever such third-party acknowledgments normally appear.</li>
60   * <li><strong>WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
61   *     WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
62   *     UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
63   *     THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
64   *     IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
65   *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
66   *     OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
67   *     OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
68   *     USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
69   *     THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
70   *     DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
71   *     UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
72   *     BE CORRECTED.</strong></li>
73   * <li><strong>LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
74   *     HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
75   *     ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
76   *     INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
77   *     ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
78   *     PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
79   *     SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
80   *     (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
81   *     EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
82   *     POSSIBILITY OF SUCH LOSS OR DAMAGES.</strong></li>
83   * <ol></td></tr>
84   * </table>
85  
86   * @author Argonne National Laboratory. MINPACK project. March 1980 (original fortran minpack tests)
87   * @author Burton S. Garbow (original fortran minpack tests)
88   * @author Kenneth E. Hillstrom (original fortran minpack tests)
89   * @author Jorge J. More (original fortran minpack tests)
90   * @author Luc Maisonobe (non-minpack tests and minpack tests Java translation)
91   */
92  public class MinpackTest
93    extends TestCase {
94  
95    public MinpackTest(String name) {
96      super(name);
97    }
98  
99    public void testMinpackLinearFullRank()
100     throws EstimationException {
101     minpackTest(new LinearFullRankFunction(10, 5, 1.0,
102                                            5.0, 2.23606797749979), false);
103     minpackTest(new LinearFullRankFunction(50, 5, 1.0,
104                                            8.06225774829855, 6.70820393249937), false);
105   }
106 
107   public void testMinpackLinearRank1()
108     throws EstimationException {
109     minpackTest(new LinearRank1Function(10, 5, 1.0,
110                                         291.521868819476, 1.4638501094228), false);
111     minpackTest(new LinearRank1Function(50, 5, 1.0,
112                                         3101.60039334535, 3.48263016573496), false);
113   }
114 
115   public void testMinpackLinearRank1ZeroColsAndRows()
116     throws EstimationException {
117     minpackTest(new LinearRank1ZeroColsAndRowsFunction(10, 5, 1.0), false);
118     minpackTest(new LinearRank1ZeroColsAndRowsFunction(50, 5, 1.0), false);
119   }
120 
121   public void testMinpackRosenbrok()
122     throws EstimationException {
123     minpackTest(new RosenbrockFunction(new double[] { -1.2, 1.0 },
124                                        Math.sqrt(24.2)), false);
125     minpackTest(new RosenbrockFunction(new double[] { -12.0, 10.0 },
126                                        Math.sqrt(1795769.0)), false);
127     minpackTest(new RosenbrockFunction(new double[] { -120.0, 100.0 },
128                                        11.0 * Math.sqrt(169000121.0)), false);
129   }
130 
131   public void testMinpackHelicalValley()
132     throws EstimationException {
133     minpackTest(new HelicalValleyFunction(new double[] { -1.0, 0.0, 0.0 },
134                                           50.0), false);
135     minpackTest(new HelicalValleyFunction(new double[] { -10.0, 0.0, 0.0 },
136                                           102.95630140987), false);
137     minpackTest(new HelicalValleyFunction(new double[] { -100.0, 0.0, 0.0},
138                                           991.261822123701), false);
139   }
140     
141   public void testMinpackPowellSingular()
142     throws EstimationException {
143     minpackTest(new PowellSingularFunction(new double[] { 3.0, -1.0, 0.0, 1.0 },
144                                            14.6628782986152), false);
145     minpackTest(new PowellSingularFunction(new double[] { 30.0, -10.0, 0.0, 10.0 },
146                                            1270.9838708654), false);
147     minpackTest(new PowellSingularFunction(new double[] { 300.0, -100.0, 0.0, 100.0 },
148                                            126887.903284750), false);
149   }
150     
151   public void testMinpackFreudensteinRoth()
152     throws EstimationException {
153     minpackTest(new FreudensteinRothFunction(new double[] { 0.5, -2.0 },
154                                              20.0124960961895, 6.99887517584575,
155                                              new double[] {
156                                                11.4124844654993,
157                                                -0.896827913731509
158                                              }), false);
159     minpackTest(new FreudensteinRothFunction(new double[] { 5.0, -20.0 },
160                                              12432.833948863, 6.9988751744895,
161                                              new double[] {
162                                                11.4130046614746,
163                                                -0.896796038685958
164                                              }), false);
165     minpackTest(new FreudensteinRothFunction(new double[] { 50.0, -200.0 },
166                                              11426454.595762, 6.99887517242903,
167                                              new double[] {
168                                                11.4127817857886,
169                                                -0.89680510749204
170                                              }), false);
171   }
172     
173   public void testMinpackBard()
174     throws EstimationException {
175     minpackTest(new BardFunction(1.0, 6.45613629515967, 0.0906359603390466,
176                                  new double[] {
177                                    0.0824105765758334,
178                                    1.1330366534715,
179                                    2.34369463894115
180                                  }), false);
181     minpackTest(new BardFunction(10.0, 36.1418531596785, 4.17476870138539,
182                                  new double[] {
183                                    0.840666673818329,
184                                    -158848033.259565,
185                                    -164378671.653535
186                                  }), false);
187     minpackTest(new BardFunction(100.0, 384.114678637399, 4.17476870135969,
188                                  new double[] {
189                                    0.840666673867645,
190                                    -158946167.205518,
191                                    -164464906.857771
192                                  }), false);
193   }
194     
195   public void testMinpackKowalikOsborne()
196     throws EstimationException {
197     minpackTest(new KowalikOsborneFunction(new double[] { 0.25, 0.39, 0.415, 0.39 },
198                                            0.0728915102882945,
199                                            0.017535837721129,
200                                            new double[] {
201                                              0.192807810476249,
202                                              0.191262653354071,
203                                              0.123052801046931,
204                                              0.136053221150517
205                                            }), false);
206     minpackTest(new KowalikOsborneFunction(new double[] { 2.5, 3.9, 4.15, 3.9 },
207                                            2.97937007555202,
208                                            0.032052192917937,
209                                            new double[] {
210                                              728675.473768287,
211                                              -14.0758803129393,
212                                              -32977797.7841797,
213                                              -20571594.1977912
214                                            }), false);
215     minpackTest(new KowalikOsborneFunction(new double[] { 25.0, 39.0, 41.5, 39.0 },
216                                            29.9590617016037,
217                                            0.0175364017658228,
218                                            new double[] {
219                                              0.192948328597594,
220                                              0.188053165007911,
221                                              0.122430604321144,
222                                              0.134575665392506
223                                            }), true);
224   }
225     
226   public void testMinpackMeyer()
227     throws EstimationException {
228     minpackTest(new MeyerFunction(new double[] { 0.02, 4000.0, 250.0 },
229                                   41153.4665543031, 9.37794514651874,
230                                   new double[] {
231                                     0.00560963647102661,
232                                     6181.34634628659,
233                                     345.223634624144
234                                   }), false);
235     minpackTest(new MeyerFunction(new double[] { 0.2, 40000.0, 2500.0 },
236                                   4168216.89130846, 792.917871779501,
237                                   new double[] {
238                                     1.42367074157994e-11,
239                                     33695.7133432541,
240                                     901.268527953801
241                                   }), true);
242   }
243     
244   public void testMinpackWatson()
245     throws EstimationException {
246   
247     minpackTest(new WatsonFunction(6, 0.0,
248                                    5.47722557505166, 0.0478295939097601,
249                                    new double[] {
250                                      -0.0157249615083782, 1.01243488232965,
251                                      -0.232991722387673,  1.26043101102818,
252                                      -1.51373031394421,   0.99299727291842
253                                    }), false);
254     minpackTest(new WatsonFunction(6, 10.0,
255                                    6433.12578950026, 0.0478295939096951,
256                                    new double[] {
257                                      -0.0157251901386677, 1.01243485860105,
258                                      -0.232991545843829,  1.26042932089163,
259                                      -1.51372776706575,   0.99299573426328
260                                    }), false);
261     minpackTest(new WatsonFunction(6, 100.0,
262                                    674256.040605213, 0.047829593911544,
263                                    new double[] {
264                                     -0.0157247019712586, 1.01243490925658,
265                                     -0.232991922761641,  1.26043292929555,
266                                     -1.51373320452707,   0.99299901922322
267                                    }), false);
268 
269     minpackTest(new WatsonFunction(9, 0.0,
270                                    5.47722557505166, 0.00118311459212420,
271                                    new double[] {
272                                     -0.153070644166722e-4, 0.999789703934597,
273                                      0.0147639634910978,   0.146342330145992,
274                                      1.00082109454817,    -2.61773112070507,
275                                      4.10440313943354,    -3.14361226236241,
276                                      1.05262640378759
277                                    }), false);
278     minpackTest(new WatsonFunction(9, 10.0,
279                                    12088.127069307, 0.00118311459212513,
280                                    new double[] {
281                                    -0.153071334849279e-4, 0.999789703941234,
282                                     0.0147639629786217,   0.146342334818836,
283                                     1.00082107321386,    -2.61773107084722,
284                                     4.10440307655564,    -3.14361222178686,
285                                     1.05262639322589
286                                    }), false);
287     minpackTest(new WatsonFunction(9, 100.0,
288                                    1269109.29043834, 0.00118311459212384,
289                                    new double[] {
290                                     -0.153069523352176e-4, 0.999789703958371,
291                                      0.0147639625185392,   0.146342341096326,
292                                      1.00082104729164,    -2.61773101573645,
293                                      4.10440301427286,    -3.14361218602503,
294                                      1.05262638516774
295                                    }), false);
296 
297     minpackTest(new WatsonFunction(12, 0.0,
298                                    5.47722557505166, 0.217310402535861e-4,
299                                    new double[] {
300                                     -0.660266001396382e-8, 1.00000164411833,
301                                     -0.000563932146980154, 0.347820540050756,
302                                     -0.156731500244233,    1.05281515825593,
303                                     -3.24727109519451,     7.2884347837505,
304                                    -10.271848098614,       9.07411353715783,
305                                     -4.54137541918194,     1.01201187975044
306                                    }), false);
307     minpackTest(new WatsonFunction(12, 10.0,
308                                    19220.7589790951, 0.217310402518509e-4,
309                                    new double[] {
310                                     -0.663710223017410e-8, 1.00000164411787,
311                                     -0.000563932208347327, 0.347820540486998,
312                                     -0.156731503955652,    1.05281517654573,
313                                     -3.2472711515214,      7.28843489430665,
314                                    -10.2718482369638,      9.07411364383733,
315                                     -4.54137546533666,     1.01201188830857
316                                    }), false);
317     minpackTest(new WatsonFunction(12, 100.0,
318                                    2018918.04462367, 0.217310402539845e-4,
319                                    new double[] {
320                                     -0.663806046485249e-8, 1.00000164411786,
321                                     -0.000563932210324959, 0.347820540503588,
322                                     -0.156731504091375,    1.05281517718031,
323                                     -3.24727115337025,     7.28843489775302,
324                                    -10.2718482410813,      9.07411364688464,
325                                     -4.54137546660822,     1.0120118885369
326                                    }), false);
327 
328   }
329     
330   public void testMinpackBox3Dimensional()
331   throws EstimationException {
332     minpackTest(new Box3DimensionalFunction(10, new double[] { 0.0, 10.0, 20.0 },
333                                             32.1115837449572), false);
334   }
335     
336   public void testMinpackJennrichSampson()
337     throws EstimationException {
338     minpackTest(new JennrichSampsonFunction(10, new double[] { 0.3, 0.4 },
339                                             64.5856498144943, 11.1517793413499,
340                                             new double[] {
341                                              0.257819926636811, 0.257829976764542
342                                             }), false);
343   }
344 
345   public void testMinpackBrownDennis()
346     throws EstimationException {
347     minpackTest(new BrownDennisFunction(20,
348                                         new double[] { 25.0, 5.0, -5.0, -1.0 },
349                                         2815.43839161816, 292.954288244866,
350                                         new double[] {
351                                          -11.59125141003, 13.2024883984741,
352                                          -0.403574643314272, 0.236736269844604
353                                         }), false);
354     minpackTest(new BrownDennisFunction(20,
355                                         new double[] { 250.0, 50.0, -50.0, -10.0 },
356                                         555073.354173069, 292.954270581415,
357                                         new double[] {
358                                          -11.5959274272203, 13.2041866926242,
359                                          -0.403417362841545, 0.236771143410386
360                                        }), false);
361     minpackTest(new BrownDennisFunction(20,
362                                         new double[] { 2500.0, 500.0, -500.0, -100.0 },
363                                         61211252.2338581, 292.954306151134,
364                                         new double[] {
365                                          -11.5902596937374, 13.2020628854665,
366                                          -0.403688070279258, 0.236665033746463
367                                         }), false);
368   }
369     
370   public void testMinpackChebyquad()
371     throws EstimationException {
372     minpackTest(new ChebyquadFunction(1, 8, 1.0,
373                                       1.88623796907732, 1.88623796907732,
374                                       new double[] { 0.5 }), false);
375     minpackTest(new ChebyquadFunction(1, 8, 10.0,
376                                       5383344372.34005, 1.88424820499951,
377                                       new double[] { 0.9817314924684 }), false);
378     minpackTest(new ChebyquadFunction(1, 8, 100.0,
379                                       0.118088726698392e19, 1.88424820499347,
380                                       new double[] { 0.9817314852934 }), false);
381     minpackTest(new ChebyquadFunction(8, 8, 1.0,
382                                       0.196513862833975, 0.0593032355046727,
383                                       new double[] {
384                                         0.0431536648587336, 0.193091637843267,
385                                         0.266328593812698,  0.499999334628884,
386                                         0.500000665371116,  0.733671406187302,
387                                         0.806908362156733,  0.956846335141266
388                                       }), false);
389     minpackTest(new ChebyquadFunction(9, 9, 1.0,
390                                       0.16994993465202, 0.0,
391                                       new double[] {
392                                         0.0442053461357828, 0.199490672309881,
393                                         0.23561910847106,   0.416046907892598,
394                                         0.5,                0.583953092107402,
395                                         0.764380891528940,  0.800509327690119,
396                                         0.955794653864217
397                                       }), false);
398     minpackTest(new ChebyquadFunction(10, 10, 1.0,
399                                       0.183747831178711, 0.0806471004038253,
400                                       new double[] {
401                                         0.0596202671753563, 0.166708783805937,
402                                         0.239171018813509,  0.398885290346268,
403                                         0.398883667870681,  0.601116332129320,
404                                         0.60111470965373,   0.760828981186491,
405                                         0.833291216194063,  0.940379732824644
406                                       }), false);
407   }
408     
409   public void testMinpackBrownAlmostLinear()
410     throws EstimationException {
411     minpackTest(new BrownAlmostLinearFunction(10, 0.5,
412                                               16.5302162063499, 0.0,
413                                               new double[] {
414                                                 0.979430303349862, 0.979430303349862,
415                                                 0.979430303349862, 0.979430303349862,
416                                                 0.979430303349862, 0.979430303349862,
417                                                 0.979430303349862, 0.979430303349862,
418                                                 0.979430303349862, 1.20569696650138
419                                               }), false);
420     minpackTest(new BrownAlmostLinearFunction(10, 5.0,
421                                               9765624.00089211, 0.0,
422                                               new double[] {
423                                                0.979430303349865, 0.979430303349865,
424                                                0.979430303349865, 0.979430303349865,
425                                                0.979430303349865, 0.979430303349865,
426                                                0.979430303349865, 0.979430303349865,
427                                                0.979430303349865, 1.20569696650135
428                                               }), false);  
429     minpackTest(new BrownAlmostLinearFunction(10, 50.0,
430                                               0.9765625e17, 0.0,
431                                               new double[] {
432                                                 1.0, 1.0, 1.0, 1.0, 1.0,
433                                                 1.0, 1.0, 1.0, 1.0, 1.0
434                                               }), false);
435     minpackTest(new BrownAlmostLinearFunction(30, 0.5,
436                                               83.476044467848, 0.0,
437                                               new double[] {
438                                                 0.997754216442807, 0.997754216442807,
439                                                 0.997754216442807, 0.997754216442807,
440                                                 0.997754216442807, 0.997754216442807,
441                                                 0.997754216442807, 0.997754216442807,
442                                                 0.997754216442807, 0.997754216442807,
443                                                 0.997754216442807, 0.997754216442807,
444                                                 0.997754216442807, 0.997754216442807,
445                                                 0.997754216442807, 0.997754216442807,
446                                                 0.997754216442807, 0.997754216442807,
447                                                 0.997754216442807, 0.997754216442807,
448                                                 0.997754216442807, 0.997754216442807,
449                                                 0.997754216442807, 0.997754216442807,
450                                                 0.997754216442807, 0.997754216442807,
451                                                 0.997754216442807, 0.997754216442807,
452                                                 0.997754216442807, 1.06737350671578
453                                               }), false);
454     minpackTest(new BrownAlmostLinearFunction(40, 0.5,
455                                               128.026364472323, 0.0,
456                                               new double[] {
457                                                 1.00000000000002, 1.00000000000002,
458                                                 1.00000000000002, 1.00000000000002,
459                                                 1.00000000000002, 1.00000000000002,
460                                                 1.00000000000002, 1.00000000000002,
461                                                 1.00000000000002, 1.00000000000002,
462                                                 1.00000000000002, 1.00000000000002,
463                                                 1.00000000000002, 1.00000000000002,
464                                                 1.00000000000002, 1.00000000000002,
465                                                 1.00000000000002, 1.00000000000002,
466                                                 1.00000000000002, 1.00000000000002,
467                                                 1.00000000000002, 1.00000000000002,
468                                                 1.00000000000002, 1.00000000000002,
469                                                 1.00000000000002, 1.00000000000002,
470                                                 1.00000000000002, 1.00000000000002,
471                                                 1.00000000000002, 1.00000000000002,
472                                                 1.00000000000002, 1.00000000000002,
473                                                 1.00000000000002, 1.00000000000002,
474                                                 0.999999999999121
475                                               }), false);
476     }
477     
478   public void testMinpackOsborne1()
479     throws EstimationException {
480       minpackTest(new Osborne1Function(new double[] { 0.5, 1.5, -1.0, 0.01, 0.02, },
481                                        0.937564021037838, 0.00739249260904843,
482                                        new double[] {
483                                          0.375410049244025, 1.93584654543108,
484                                         -1.46468676748716, 0.0128675339110439,
485                                          0.0221227011813076
486                                        }), false);
487     }
488     
489   public void testMinpackOsborne2()
490     throws EstimationException {
491       
492     minpackTest(new Osborne2Function(new double[] {
493                                        1.3, 0.65, 0.65, 0.7, 0.6,
494                                        3.0, 5.0, 7.0, 2.0, 4.5, 5.5
495                                      },
496                                      1.44686540984712, 0.20034404483314,
497                                      new double[] {
498                                        1.30997663810096,  0.43155248076,
499                                        0.633661261602859, 0.599428560991695,
500                                        0.754179768272449, 0.904300082378518,
501                                        1.36579949521007, 4.82373199748107,
502                                        2.39868475104871, 4.56887554791452,
503                                        5.67534206273052
504                                      }), false);
505   }
506 
507   private void minpackTest(MinpackFunction function, boolean exceptionExpected) {
508     LevenbergMarquardtEstimator estimator = new LevenbergMarquardtEstimator();
509     estimator.setMaxCostEval(100 * (function.getN() + 1));
510     estimator.setCostRelativeTolerance(Math.sqrt(2.22044604926e-16));
511     estimator.setParRelativeTolerance(Math.sqrt(2.22044604926e-16));
512     estimator.setOrthoTolerance(2.22044604926e-16);
513     assertTrue(function.checkTheoreticalStartCost(estimator.getRMS(function)));
514     try {
515       estimator.estimate(function);
516       assertFalse(exceptionExpected);
517     } catch (EstimationException lsse) {
518       assertTrue(exceptionExpected);
519     }
520     assertTrue(function.checkTheoreticalMinCost(estimator.getRMS(function)));
521     assertTrue(function.checkTheoreticalMinParams());
522   }
523 
524   private static abstract class MinpackFunction implements EstimationProblem {
525  
526     protected MinpackFunction(int m,
527                               double[] startParams,
528                               double   theoreticalStartCost,
529                               double   theoreticalMinCost,
530                               double[] theoreticalMinParams) {
531       this.m = m;
532       this.n = startParams.length;
533       parameters = new EstimatedParameter[n];
534       for (int i = 0; i < n; ++i) {
535         parameters[i] = new EstimatedParameter("p" + i, startParams[i]);
536       }
537       this.theoreticalStartCost = theoreticalStartCost;
538       this.theoreticalMinCost   = theoreticalMinCost;
539       this.theoreticalMinParams = theoreticalMinParams;
540       this.costAccuracy         = 1.0e-8;
541       this.paramsAccuracy       = 1.0e-5;
542     }
543 
544     protected static double[] buildArray(int n, double x) {
545       double[] array = new double[n];
546       Arrays.fill(array, x);
547       return array;
548     }
549 
550     protected void setCostAccuracy(double costAccuracy) {
551       this.costAccuracy = costAccuracy;
552     }
553 
554     protected void setParamsAccuracy(double paramsAccuracy) {
555       this.paramsAccuracy = paramsAccuracy;
556     }
557 
558     public int getN() {
559       return parameters.length;
560     }
561 
562     public boolean checkTheoreticalStartCost(double rms) {
563       double threshold = costAccuracy * (1.0 + theoreticalStartCost);
564       return Math.abs(Math.sqrt(m) * rms - theoreticalStartCost) <= threshold;
565     }
566 
567     public boolean checkTheoreticalMinCost(double rms) {
568       double threshold = costAccuracy * (1.0 + theoreticalMinCost);
569      return Math.abs(Math.sqrt(m) * rms - theoreticalMinCost) <= threshold;
570     }
571 
572     public boolean checkTheoreticalMinParams() {
573       if (theoreticalMinParams != null) {
574         for (int i = 0; i < theoreticalMinParams.length; ++i) {
575           double mi = theoreticalMinParams[i];
576           double vi = parameters[i].getEstimate();
577           if (Math.abs(mi - vi) > (paramsAccuracy * (1.0 + Math.abs(mi)))) {
578             return false;
579           }
580         }
581       }
582       return true;
583     }
584  
585     public WeightedMeasurement[] getMeasurements() {
586       WeightedMeasurement[] measurements = new WeightedMeasurement[m];
587       for (int i = 0; i < m; ++i) {
588         measurements[i] = new MinpackMeasurement(i);
589       }
590       return measurements;
591     }
592 
593     public EstimatedParameter[] getUnboundParameters() {
594       return parameters;
595     }
596 
597     public EstimatedParameter[] getAllParameters() {
598       return parameters;
599     }
600 
601     protected abstract double[][] getJacobian();
602 
603     protected abstract double[] getResiduals();
604 
605     private class MinpackMeasurement extends WeightedMeasurement {
606 
607       public MinpackMeasurement(int index) {
608         super(1.0, 0.0);
609         this.index = index;
610       }
611 
612       public double getTheoreticalValue() {
613         // this is obviously NOT efficient as we recompute the whole vector
614         // each time we need only one element, but it is only for test
615         // purposes and is simpler to check.
616         // This implementation should NOT be taken as an example, it is ugly!
617         return getResiduals()[index];
618       }
619 
620       public double getPartial(EstimatedParameter parameter) {
621         // this is obviously NOT efficient as we recompute the whole jacobian
622         // each time we need only one element, but it is only for test
623         // purposes and is simpler to check.
624         // This implementation should NOT be taken as an example, it is ugly!
625         for (int j = 0; j < n; ++j) {
626           if (parameter == parameters[j]) {
627             return getJacobian()[index][j];
628           }
629         }
630         return 0;
631       }
632 
633       private int index;
634       private static final long serialVersionUID = 1L;
635 
636     }
637 
638     protected int                  n;
639     protected int                  m;
640     protected EstimatedParameter[] parameters;
641     protected double               theoreticalStartCost;
642     protected double               theoreticalMinCost;
643     protected double[]             theoreticalMinParams;
644     protected double               costAccuracy;
645     protected double               paramsAccuracy;
646 
647   }
648 
649   private static class LinearFullRankFunction extends MinpackFunction {
650 
651     public LinearFullRankFunction(int m, int n, double x0,
652                                   double theoreticalStartCost,
653                                   double theoreticalMinCost) {
654       super(m, buildArray(n, x0), theoreticalStartCost,
655             theoreticalMinCost, buildArray(n, -1.0));
656     }
657 
658     protected double[][] getJacobian() {
659       double t = 2.0 / m;
660       double[][] jacobian = new double[m][];
661       for (int i = 0; i < m; ++i) {
662         jacobian[i] = new double[n];
663         for (int j = 0; j < n; ++j) {
664           jacobian[i][j] = (i == j) ? (1 - t) : -t;
665         }
666       }
667       return jacobian;
668     }
669 
670     protected double[] getResiduals() {
671       double sum = 0;
672       for (int i = 0; i < n; ++i) {
673         sum += parameters[i].getEstimate();
674       }
675       double t  = 1 + 2 * sum / m;
676       double[] f = new double[m];
677       for (int i = 0; i < n; ++i) {
678         f[i] = parameters[i].getEstimate() - t;
679       }
680       Arrays.fill(f, n, m, -t);
681       return f;
682     }
683 
684   }
685 
686   private static class LinearRank1Function extends MinpackFunction {
687 
688     public LinearRank1Function(int m, int n, double x0,
689                                   double theoreticalStartCost,
690                                   double theoreticalMinCost) {
691       super(m, buildArray(n, x0), theoreticalStartCost, theoreticalMinCost, null);
692     }
693 
694     protected double[][] getJacobian() {
695       double[][] jacobian = new double[m][];
696       for (int i = 0; i < m; ++i) {
697         jacobian[i] = new double[n];
698         for (int j = 0; j < n; ++j) {
699           jacobian[i][j] = (i + 1) * (j + 1);
700         }
701       }
702       return jacobian;
703     }
704 
705     protected double[] getResiduals() {
706       double[] f = new double[m];
707       double sum = 0;
708       for (int i = 0; i < n; ++i) {
709         sum += (i + 1) * parameters[i].getEstimate();
710       }
711       for (int i = 0; i < m; ++i) {
712         f[i] = (i + 1) * sum - 1;
713       }
714       return f;
715     }
716 
717   }
718 
719   private static class LinearRank1ZeroColsAndRowsFunction extends MinpackFunction {
720 
721     public LinearRank1ZeroColsAndRowsFunction(int m, int n, double x0) {
722       super(m, buildArray(n, x0),
723             Math.sqrt(m + (n+1)*(n-2)*(m-2)*(m-1) * ((n+1)*(n-2)*(2*m-3) - 12) / 24.0),
724             Math.sqrt((m * (m + 3) - 6) / (2.0 * (2 * m - 3))),
725             null);
726     }
727 
728     protected double[][] getJacobian() {
729       double[][] jacobian = new double[m][];
730       for (int i = 0; i < m; ++i) {
731         jacobian[i] = new double[n];
732         jacobian[i][0] = 0;
733         for (int j = 1; j < (n - 1); ++j) {
734           if (i == 0) {
735             jacobian[i][j] = 0;
736           } else if (i != (m - 1)) {
737             jacobian[i][j] = i * (j + 1);
738           } else {
739             jacobian[i][j] = 0;
740           }
741         }
742         jacobian[i][n - 1] = 0;
743       }
744       return jacobian;
745     }
746 
747     protected double[] getResiduals() {
748       double[] f = new double[m];
749       double sum = 0;
750       for (int i = 1; i < (n - 1); ++i) {
751         sum += (i + 1) * parameters[i].getEstimate();
752       }
753       for (int i = 0; i < (m - 1); ++i) {
754         f[i] = i * sum - 1;
755       }
756       f[m - 1] = -1;
757       return f;
758     }
759 
760   }
761 
762   private static class RosenbrockFunction extends MinpackFunction {
763 
764     public RosenbrockFunction(double[] startParams, double theoreticalStartCost) {
765       super(2, startParams, theoreticalStartCost, 0.0, buildArray(2, 1.0));
766     }
767 
768     protected double[][] getJacobian() {
769       double x1 = parameters[0].getEstimate();
770       return new double[][] { { -20 * x1, 10 }, { -1, 0 } };
771     }
772 
773     protected double[] getResiduals() {
774       double x1 = parameters[0].getEstimate();
775       double x2 = parameters[1].getEstimate();
776       return new double[] { 10 * (x2 - x1 * x1), 1 - x1 };
777     }
778 
779   }
780 
781   private static class HelicalValleyFunction extends MinpackFunction {
782 
783     public HelicalValleyFunction(double[] startParams,
784                                  double theoreticalStartCost) {
785       super(3, startParams, theoreticalStartCost, 0.0,
786             new double[] { 1.0, 0.0, 0.0 });
787     }
788 
789     protected double[][] getJacobian() {
790       double x1 = parameters[0].getEstimate();
791       double x2 = parameters[1].getEstimate();
792       double tmpSquare = x1 * x1 + x2 * x2;
793       double tmp1 = twoPi * tmpSquare;
794       double tmp2 = Math.sqrt(tmpSquare);
795       return new double[][] {
796         {  100 * x2 / tmp1, -100 * x1 / tmp1, 10 },
797         { 10 * x1 / tmp2, 10 * x2 / tmp2, 0 },
798         { 0, 0, 1 }
799       };
800     }
801 
802     protected double[] getResiduals() {
803       double x1 = parameters[0].getEstimate();
804       double x2 = parameters[1].getEstimate();
805       double x3 = parameters[2].getEstimate();
806       double tmp1;
807       if (x1 == 0) {
808         tmp1 = (x2 >= 0) ? 0.25 : -0.25;
809       } else {
810         tmp1 = Math.atan(x2 / x1) / twoPi;
811         if (x1 < 0) {
812           tmp1 += 0.5;
813         }
814       }
815       double tmp2 = Math.sqrt(x1 * x1 + x2 * x2);
816       return new double[] {
817         10.0 * (x3 - 10 * tmp1),
818         10.0 * (tmp2 - 1),
819         x3
820       };
821     }
822 
823     private static final double twoPi = 2.0 * Math.PI;
824 
825   }
826 
827   private static class PowellSingularFunction extends MinpackFunction {
828 
829     public PowellSingularFunction(double[] startParams,
830                                   double theoreticalStartCost) {
831       super(4, startParams, theoreticalStartCost, 0.0, buildArray(4, 0.0));
832     }
833 
834     protected double[][] getJacobian() {
835       double x1 = parameters[0].getEstimate();
836       double x2 = parameters[1].getEstimate();
837       double x3 = parameters[2].getEstimate();
838       double x4 = parameters[3].getEstimate();
839       return new double[][] {
840         { 1, 10, 0, 0 },
841         { 0, 0, sqrt5, -sqrt5 },
842         { 0, 2 * (x2 - 2 * x3), -4 * (x2 - 2 * x3), 0 },
843         { 2 * sqrt10 * (x1 - x4), 0, 0, -2 * sqrt10 * (x1 - x4) }
844       };
845     }
846 
847     protected double[] getResiduals() {
848       double x1 = parameters[0].getEstimate();
849       double x2 = parameters[1].getEstimate();
850       double x3 = parameters[2].getEstimate();
851       double x4 = parameters[3].getEstimate();
852       return new double[] {
853         x1 + 10 * x2,
854         sqrt5 * (x3 - x4),
855         (x2 - 2 * x3) * (x2 - 2 * x3),
856         sqrt10 * (x1 - x4) * (x1 - x4)
857       };
858     }
859 
860     private static final double sqrt5  = Math.sqrt( 5.0);
861     private static final double sqrt10 = Math.sqrt(10.0);
862 
863   }
864 
865   private static class FreudensteinRothFunction extends MinpackFunction {
866 
867     public FreudensteinRothFunction(double[] startParams,
868                                     double theoreticalStartCost,
869                                     double theoreticalMinCost,
870                                     double[] theoreticalMinParams) {
871       super(2, startParams, theoreticalStartCost,
872             theoreticalMinCost, theoreticalMinParams);
873     }
874 
875     protected double[][] getJacobian() {
876       double x2 = parameters[1].getEstimate();
877       return new double[][] {
878         { 1, x2 * (10 - 3 * x2) -  2 },
879         { 1, x2 * ( 2 + 3 * x2) - 14, }
880       };
881     }
882 
883     protected double[] getResiduals() {
884       double x1 = parameters[0].getEstimate();
885       double x2 = parameters[1].getEstimate();
886       return new double[] {
887        -13.0 + x1 + ((5.0 - x2) * x2 -  2.0) * x2,
888        -29.0 + x1 + ((1.0 + x2) * x2 - 14.0) * x2
889       };
890     }
891 
892   }
893 
894   private static class BardFunction extends MinpackFunction {
895 
896     public BardFunction(double x0,
897                         double theoreticalStartCost,
898                         double theoreticalMinCost,
899                         double[] theoreticalMinParams) {
900       super(15, buildArray(3, x0), theoreticalStartCost,
901             theoreticalMinCost, theoreticalMinParams);
902     }
903 
904     protected double[][] getJacobian() {
905       double   x2 = parameters[1].getEstimate();
906       double   x3 = parameters[2].getEstimate();
907       double[][] jacobian = new double[m][];
908       for (int i = 0; i < m; ++i) {
909         double tmp1 = i  + 1;
910         double tmp2 = 15 - i;
911         double tmp3 = (i <= 7) ? tmp1 : tmp2;
912         double tmp4 = x2 * tmp2 + x3 * tmp3;
913         tmp4 *= tmp4;
914         jacobian[i] = new double[] { -1, tmp1 * tmp2 / tmp4, tmp1 * tmp3 / tmp4 };
915       }
916       return jacobian;
917     }
918 
919     protected double[] getResiduals() {
920       double   x1 = parameters[0].getEstimate();
921       double   x2 = parameters[1].getEstimate();
922       double   x3 = parameters[2].getEstimate();
923       double[] f = new double[m];
924       for (int i = 0; i < m; ++i) {
925         double tmp1 = i + 1;
926         double tmp2 = 15 - i;
927         double tmp3 = (i <= 7) ? tmp1 : tmp2;
928         f[i] = y[i] - (x1 + tmp1 / (x2 * tmp2 + x3 * tmp3));
929       }
930       return f;
931     }
932 
933     private static final double[] y = {
934       0.14, 0.18, 0.22, 0.25, 0.29,
935       0.32, 0.35, 0.39, 0.37, 0.58,
936       0.73, 0.96, 1.34, 2.10, 4.39
937     };
938 
939   }
940 
941   private static class KowalikOsborneFunction extends MinpackFunction {
942 
943     public KowalikOsborneFunction(double[] startParams,
944                                   double theoreticalStartCost,
945                                   double theoreticalMinCost,
946                                   double[] theoreticalMinParams) {
947       super(11, startParams, theoreticalStartCost,
948             theoreticalMinCost, theoreticalMinParams);
949       if (theoreticalStartCost > 20.0) {
950         setCostAccuracy(2.0e-4);
951         setParamsAccuracy(5.0e-3);
952       }
953     }
954 
955     protected double[][] getJacobian() {
956       double   x1 = parameters[0].getEstimate();
957       double   x2 = parameters[1].getEstimate();
958       double   x3 = parameters[2].getEstimate();
959       double   x4 = parameters[3].getEstimate();
960       double[][] jacobian = new double[m][];
961       for (int i = 0; i < m; ++i) {
962         double tmp = v[i] * (v[i] + x3) + x4;
963         double j1  = -v[i] * (v[i] + x2) / tmp;
964         double j2  = -v[i] * x1 / tmp;
965         double j3  = j1 * j2;
966         double j4  = j3 / v[i];
967         jacobian[i] = new double[] { j1, j2, j3, j4 };
968       }
969       return jacobian;
970     }
971 
972     protected double[] getResiduals() {
973       double x1 = parameters[0].getEstimate();
974       double x2 = parameters[1].getEstimate();
975       double x3 = parameters[2].getEstimate();
976       double x4 = parameters[3].getEstimate();
977       double[] f = new double[m];
978       for (int i = 0; i < m; ++i) {
979         f[i] = y[i] - x1 * (v[i] * (v[i] + x2)) / (v[i] * (v[i] + x3) + x4);
980       }
981       return f;
982     }
983 
984     private static final double[] v = {
985       4.0, 2.0, 1.0, 0.5, 0.25, 0.167, 0.125, 0.1, 0.0833, 0.0714, 0.0625
986     };
987 
988     private static final double[] y = {
989       0.1957, 0.1947, 0.1735, 0.1600, 0.0844, 0.0627,
990       0.0456, 0.0342, 0.0323, 0.0235, 0.0246
991     };
992 
993   }
994 
995   private static class MeyerFunction extends MinpackFunction {
996 
997     public MeyerFunction(double[] startParams,
998                          double theoreticalStartCost,
999                          double theoreticalMinCost,
1000                          double[] theoreticalMinParams) {
1001       super(16, startParams, theoreticalStartCost,
1002             theoreticalMinCost, theoreticalMinParams);
1003       if (theoreticalStartCost > 1.0e6) {
1004         setCostAccuracy(7.0e-3);
1005         setParamsAccuracy(2.0e-2);
1006       }
1007     }
1008 
1009     protected double[][] getJacobian() {
1010       double   x1 = parameters[0].getEstimate();
1011       double   x2 = parameters[1].getEstimate();
1012       double   x3 = parameters[2].getEstimate();
1013       double[][] jacobian = new double[m][];
1014       for (int i = 0; i < m; ++i) {
1015         double temp = 5.0 * (i + 1) + 45.0 + x3;
1016         double tmp1 = x2 / temp;
1017         double tmp2 = Math.exp(tmp1);
1018         double tmp3 = x1 * tmp2 / temp;
1019         jacobian[i] = new double[] { tmp2, tmp3, -tmp1 * tmp3 };
1020       }
1021       return jacobian;
1022     }
1023 
1024     protected double[] getResiduals() {
1025       double x1 = parameters[0].getEstimate();
1026       double x2 = parameters[1].getEstimate();
1027       double x3 = parameters[2].getEstimate();
1028       double[] f = new double[m];
1029       for (int i = 0; i < m; ++i) {
1030         f[i] = x1 * Math.exp(x2 / (5.0 * (i + 1) + 45.0 + x3)) - y[i];
1031       }
1032      return f;
1033     }
1034 
1035     private static final double[] y = {
1036       34780.0, 28610.0, 23650.0, 19630.0,
1037       16370.0, 13720.0, 11540.0,  9744.0,
1038        8261.0,  7030.0,  6005.0,  5147.0,
1039        4427.0,  3820.0,  3307.0,  2872.0                  
1040     };
1041 
1042   }
1043 
1044   private static class WatsonFunction extends MinpackFunction {
1045 
1046     public WatsonFunction(int n, double x0,
1047                           double theoreticalStartCost,
1048                           double theoreticalMinCost,
1049                           double[] theoreticalMinParams) {
1050       super(31, buildArray(n, x0), theoreticalStartCost,
1051             theoreticalMinCost, theoreticalMinParams);
1052     }
1053 
1054     protected double[][] getJacobian() {
1055 
1056       double[][] jacobian = new double[m][];
1057 
1058       for (int i = 0; i < (m - 2); ++i) {
1059         double div = (i + 1) / 29.0;
1060         double s2  = 0.0;
1061         double dx  = 1.0;
1062         for (int j = 0; j < n; ++j) {
1063           s2 += dx * parameters[j].getEstimate();
1064           dx *= div;
1065         }
1066         double temp= 2 * div * s2;
1067         dx = 1.0 / div;
1068         jacobian[i] = new double[n];
1069         for (int j = 0; j < n; ++j) {
1070           jacobian[i][j] = dx * (j - temp);
1071           dx *= div;
1072         }
1073       }
1074 
1075       jacobian[m - 2]    = new double[n];
1076       jacobian[m - 2][0] = 1;
1077 
1078       jacobian[m - 1]   = new double[n];
1079       jacobian[m - 1][0]= -2 * parameters[0].getEstimate();
1080       jacobian[m - 1][1]= 1;
1081 
1082       return jacobian;
1083 
1084     }
1085 
1086     protected double[] getResiduals() {
1087      double[] f = new double[m];
1088      for (int i = 0; i < (m - 2); ++i) {
1089        double div = (i + 1) / 29.0;
1090        double s1 = 0;
1091        double dx = 1;
1092        for (int j = 1; j < n; ++j) {
1093          s1 += j * dx * parameters[j].getEstimate();
1094          dx *= div;
1095        }
1096        double s2 =0;
1097        dx =1;
1098        for (int j = 0; j < n; ++j) {
1099          s2 += dx * parameters[j].getEstimate();
1100          dx *= div;
1101        }
1102        f[i] = s1 - s2 * s2 - 1;
1103      }
1104 
1105      double x1 = parameters[0].getEstimate();
1106      double x2 = parameters[1].getEstimate();
1107      f[m - 2] = x1;
1108      f[m - 1] = x2 - x1 * x1 - 1;
1109 
1110      return f;
1111 
1112     }
1113 
1114   }
1115 
1116   private static class Box3DimensionalFunction extends MinpackFunction {
1117 
1118     public Box3DimensionalFunction(int m, double[] startParams,
1119                                    double theoreticalStartCost) {
1120       super(m, startParams, theoreticalStartCost,
1121             0.0, new double[] { 1.0, 10.0, 1.0 });
1122    }
1123 
1124     protected double[][] getJacobian() {
1125       double   x1 = parameters[0].getEstimate();
1126       double   x2 = parameters[1].getEstimate();
1127       double[][] jacobian = new double[m][];
1128       for (int i = 0; i < m; ++i) {
1129         double tmp = (i + 1) / 10.0;
1130         jacobian[i] = new double[] {
1131           -tmp * Math.exp(-tmp * x1),
1132            tmp * Math.exp(-tmp * x2),
1133           Math.exp(-i - 1) - Math.exp(-tmp)
1134         };
1135       }
1136       return jacobian;
1137     }
1138 
1139     protected double[] getResiduals() {
1140       double x1 = parameters[0].getEstimate();
1141       double x2 = parameters[1].getEstimate();
1142       double x3 = parameters[2].getEstimate();
1143       double[] f = new double[m];
1144       for (int i = 0; i < m; ++i) {
1145         double tmp = (i + 1) / 10.0;
1146         f[i] = Math.exp(-tmp * x1) - Math.exp(-tmp * x2)
1147              + (Math.exp(-i - 1) - Math.exp(-tmp)) * x3;
1148       }
1149       return f;
1150     }
1151 
1152   }
1153 
1154   private static class JennrichSampsonFunction extends MinpackFunction {
1155 
1156     public JennrichSampsonFunction(int m, double[] startParams,
1157                                    double theoreticalStartCost,
1158                                    double theoreticalMinCost,
1159                                    double[] theoreticalMinParams) {
1160       super(m, startParams, theoreticalStartCost,
1161             theoreticalMinCost, theoreticalMinParams);
1162     }
1163 
1164     protected double[][] getJacobian() {
1165       double   x1 = parameters[0].getEstimate();
1166       double   x2 = parameters[1].getEstimate();
1167       double[][] jacobian = new double[m][];
1168       for (int i = 0; i < m; ++i) {
1169         double t = i + 1;
1170         jacobian[i] = new double[] { -t * Math.exp(t * x1), -t * Math.exp(t * x2) };
1171       }
1172       return jacobian;
1173     }
1174 
1175     protected double[] getResiduals() {
1176       double x1 = parameters[0].getEstimate();
1177       double x2 = parameters[1].getEstimate();
1178       double[] f = new double[m];
1179       for (int i = 0; i < m; ++i) {
1180         double temp = i + 1;
1181         f[i] = 2 + 2 * temp - Math.exp(temp * x1) - Math.exp(temp * x2);
1182       }
1183       return f;
1184     }
1185 
1186   }
1187 
1188   private static class BrownDennisFunction extends MinpackFunction {
1189 
1190     public BrownDennisFunction(int m, double[] startParams,
1191                                double theoreticalStartCost,
1192                                double theoreticalMinCost,
1193                                double[] theoreticalMinParams) {
1194       super(m, startParams, theoreticalStartCost,
1195             theoreticalMinCost, theoreticalMinParams);
1196     }
1197 
1198     protected double[][] getJacobian() {
1199       double   x1 = parameters[0].getEstimate();
1200       double   x2 = parameters[1].getEstimate();
1201       double   x3 = parameters[2].getEstimate();
1202       double   x4 = parameters[3].getEstimate();
1203       double[][] jacobian = new double[m][];
1204       for (int i = 0; i < m; ++i) {
1205         double temp = (i + 1) / 5.0;
1206         double ti   = Math.sin(temp);
1207         double tmp1 = x1 + temp * x2 - Math.exp(temp);
1208         double tmp2 = x3 + ti   * x4 - Math.cos(temp);
1209         jacobian[i] = new double[] {
1210           2 * tmp1, 2 * temp * tmp1, 2 * tmp2, 2 * ti * tmp2
1211         };
1212       }
1213       return jacobian;
1214     }
1215 
1216     protected double[] getResiduals() {
1217       double x1 = parameters[0].getEstimate();
1218       double x2 = parameters[1].getEstimate();
1219       double x3 = parameters[2].getEstimate();
1220       double x4 = parameters[3].getEstimate();
1221       double[] f = new double[m];
1222       for (int i = 0; i < m; ++i) {
1223         double temp = (i + 1) / 5.0;
1224         double tmp1 = x1 + temp * x2 - Math.exp(temp);
1225         double tmp2 = x3 + Math.sin(temp) * x4 - Math.cos(temp);
1226         f[i] = tmp1 * tmp1 + tmp2 * tmp2;
1227       }
1228       return f;
1229     }
1230 
1231   }
1232 
1233   private static class ChebyquadFunction extends MinpackFunction {
1234 
1235     private static double[] buildChebyquadArray(int n, double factor) {
1236       double[] array = new double[n];
1237       double inv = factor / (n + 1);
1238       for (int i = 0; i < n; ++i) {
1239         array[i] = (i + 1) * inv;
1240       }
1241       return array;
1242     }
1243 
1244     public ChebyquadFunction(int n, int m, double factor,
1245                              double theoreticalStartCost,
1246                              double theoreticalMinCost,
1247                              double[] theoreticalMinParams) {
1248       super(m, buildChebyquadArray(n, factor), theoreticalStartCost,
1249             theoreticalMinCost, theoreticalMinParams);
1250     }
1251 
1252     protected double[][] getJacobian() {
1253 
1254       double[][] jacobian = new double[m][];
1255       for (int i = 0; i < m; ++i) {
1256         jacobian[i] = new double[n];
1257       }
1258 
1259       double dx = 1.0 / n;
1260       for (int j = 0; j < n; ++j) {
1261         double tmp1 = 1;
1262         double tmp2 = 2 * parameters[j].getEstimate() - 1;
1263         double temp = 2 * tmp2;
1264         double tmp3 = 0;
1265         double tmp4 = 2;
1266         for (int i = 0; i < m; ++i) {
1267           jacobian[i][j] = dx * tmp4;
1268           double ti = 4 * tmp2 + temp * tmp4 - tmp3;
1269           tmp3 = tmp4;
1270           tmp4 = ti;
1271           ti   = temp * tmp2 - tmp1;
1272           tmp1 = tmp2;
1273           tmp2 = ti;
1274         }
1275       }
1276 
1277       return jacobian;
1278 
1279     }
1280 
1281     protected double[] getResiduals() {
1282 
1283       double[] f = new double[m];
1284 
1285       for (int j = 0; j < n; ++j) {
1286         double tmp1 = 1;
1287         double tmp2 = 2 * parameters[j].getEstimate() - 1;
1288         double temp = 2 * tmp2;
1289         for (int i = 0; i < m; ++i) {
1290           f[i] += tmp2;
1291           double ti = temp * tmp2 - tmp1;
1292           tmp1 = tmp2;
1293           tmp2 = ti;
1294         }
1295       }
1296 
1297       double dx = 1.0 / n;
1298       boolean iev = false;
1299       for (int i = 0; i < m; ++i) {
1300         f[i] *= dx;
1301         if (iev) {
1302           f[i] += 1.0 / (i * (i + 2));
1303         }
1304         iev = ! iev;
1305       }
1306 
1307       return f;
1308 
1309     }
1310 
1311   }
1312 
1313   private static class BrownAlmostLinearFunction extends MinpackFunction {
1314 
1315     public BrownAlmostLinearFunction(int m, double factor,
1316                                      double theoreticalStartCost,
1317                                      double theoreticalMinCost,
1318                                      double[] theoreticalMinParams) {
1319       super(m, buildArray(m, factor), theoreticalStartCost,
1320             theoreticalMinCost, theoreticalMinParams);
1321     }
1322 
1323     protected double[][] getJacobian() {
1324       double[][] jacobian = new double[m][];
1325       for (int i = 0; i < m; ++i) {
1326         jacobian[i] = new double[n];
1327       }
1328 
1329       double prod = 1;
1330       for (int j = 0; j < n; ++j) {
1331         prod *= parameters[j].getEstimate();
1332         for (int i = 0; i < n; ++i) {
1333           jacobian[i][j] = 1;
1334         }
1335         jacobian[j][j] = 2;
1336       }
1337 
1338       for (int j = 0; j < n; ++j) {
1339         EstimatedParameter vj = parameters[j];
1340         double temp = vj.getEstimate();
1341         if (temp == 0) {
1342           temp = 1;
1343           prod = 1;
1344           for (int k = 0; k < n; ++k) {
1345             if (k != j) {
1346               prod *= parameters[k].getEstimate();
1347             }
1348           }
1349         }
1350         jacobian[n - 1][j] = prod / temp;
1351       }
1352 
1353       return jacobian;
1354 
1355     }
1356 
1357     protected double[] getResiduals() {
1358       double[] f = new double[m];
1359       double sum  = -(n + 1);
1360       double prod = 1;
1361       for (int j = 0; j < n; ++j) {
1362         sum  += parameters[j].getEstimate();
1363         prod *= parameters[j].getEstimate();
1364       }
1365       for (int i = 0; i < n; ++i) {
1366         f[i] = parameters[i].getEstimate() + sum;
1367       }
1368       f[n - 1] = prod - 1;
1369       return f;
1370     }
1371 
1372   }
1373 
1374   private static class Osborne1Function extends MinpackFunction {
1375 
1376     public Osborne1Function(double[] startParams,
1377                             double theoreticalStartCost,
1378                             double theoreticalMinCost,
1379                             double[] theoreticalMinParams) {
1380       super(33, startParams, theoreticalStartCost,
1381             theoreticalMinCost, theoreticalMinParams);
1382     }
1383 
1384     protected double[][] getJacobian() {
1385       double   x2 = parameters[1].getEstimate();
1386       double   x3 = parameters[2].getEstimate();
1387       double   x4 = parameters[3].getEstimate();
1388       double   x5 = parameters[4].getEstimate();
1389       double[][] jacobian = new double[m][];
1390       for (int i = 0; i < m; ++i) {
1391         double temp = 10.0 * i;
1392         double tmp1 = Math.exp(-temp * x4);
1393         double tmp2 = Math.exp(-temp * x5);
1394         jacobian[i] = new double[] {
1395           -1, -tmp1, -tmp2, temp * x2 * tmp1, temp * x3 * tmp2
1396         };
1397       }
1398       return jacobian;
1399     }
1400 
1401     protected double[] getResiduals() {
1402       double x1 = parameters[0].getEstimate();
1403       double x2 = parameters[1].getEstimate();
1404       double x3 = parameters[2].getEstimate();
1405       double x4 = parameters[3].getEstimate();
1406       double x5 = parameters[4].getEstimate();
1407       double[] f = new double[m];
1408       for (int i = 0; i < m; ++i) {
1409         double temp = 10.0 * i;
1410         double tmp1 = Math.exp(-temp * x4);
1411         double tmp2 = Math.exp(-temp * x5);
1412         f[i] = y[i] - (x1 + x2 * tmp1 + x3 * tmp2);
1413       }
1414       return f;
1415     }
1416 
1417     private static final double[] y = {
1418       0.844, 0.908, 0.932, 0.936, 0.925, 0.908, 0.881, 0.850, 0.818, 0.784, 0.751,
1419       0.718, 0.685, 0.658, 0.628, 0.603, 0.580, 0.558, 0.538, 0.522, 0.506, 0.490,
1420       0.478, 0.467, 0.457, 0.448, 0.438, 0.431, 0.424, 0.420, 0.414, 0.411, 0.406
1421     };
1422 
1423   }
1424 
1425   private static class Osborne2Function extends MinpackFunction {
1426 
1427     public Osborne2Function(double[] startParams,
1428                             double theoreticalStartCost,
1429                             double theoreticalMinCost,
1430                             double[] theoreticalMinParams) {
1431       super(65, startParams, theoreticalStartCost,
1432             theoreticalMinCost, theoreticalMinParams);
1433     }
1434 
1435     protected double[][] getJacobian() {
1436       double   x01 = parameters[0].getEstimate();
1437       double   x02 = parameters[1].getEstimate();
1438       double   x03 = parameters[2].getEstimate();
1439       double   x04 = parameters[3].getEstimate();
1440       double   x05 = parameters[4].getEstimate();
1441       double   x06 = parameters[5].getEstimate();
1442       double   x07 = parameters[6].getEstimate();
1443       double   x08 = parameters[7].getEstimate();
1444       double   x09 = parameters[8].getEstimate();
1445       double   x10 = parameters[9].getEstimate();
1446       double   x11 = parameters[10].getEstimate();
1447       double[][] jacobian = new double[m][];
1448       for (int i = 0; i < m; ++i) {
1449         double temp = i / 10.0;
1450         double tmp1 = Math.exp(-x05 * temp);
1451         double tmp2 = Math.exp(-x06 * (temp - x09) * (temp - x09));
1452         double tmp3 = Math.exp(-x07 * (temp - x10) * (temp - x10));
1453         double tmp4 = Math.exp(-x08 * (temp - x11) * (temp - x11));
1454         jacobian[i] = new double[] {
1455           -tmp1,
1456           -tmp2,
1457           -tmp3,
1458           -tmp4,
1459           temp * x01 * tmp1,
1460           x02 * (temp - x09) * (temp - x09) * tmp2,
1461           x03 * (temp - x10) * (temp - x10) * tmp3,
1462           x04 * (temp - x11) * (temp - x11) * tmp4,
1463           -2 * x02 * x06 * (temp - x09) * tmp2,
1464           -2 * x03 * x07 * (temp - x10) * tmp3,
1465           -2 * x04 * x08 * (temp - x11) * tmp4
1466         };
1467       }
1468       return jacobian;
1469     }
1470 
1471     protected double[] getResiduals() {
1472       double x01 = parameters[0].getEstimate();
1473       double x02 = parameters[1].getEstimate();
1474       double x03 = parameters[2].getEstimate();
1475       double x04 = parameters[3].getEstimate();
1476       double x05 = parameters[4].getEstimate();
1477       double x06 = parameters[5].getEstimate();
1478       double x07 = parameters[6].getEstimate();
1479       double x08 = parameters[7].getEstimate();
1480       double x09 = parameters[8].getEstimate();
1481       double x10 = parameters[9].getEstimate();
1482       double x11 = parameters[10].getEstimate();
1483       double[] f = new double[m];
1484       for (int i = 0; i < m; ++i) {
1485         double temp = i / 10.0;
1486         double tmp1 = Math.exp(-x05 * temp);
1487         double tmp2 = Math.exp(-x06 * (temp - x09) * (temp - x09));
1488         double tmp3 = Math.exp(-x07 * (temp - x10) * (temp - x10));
1489         double tmp4 = Math.exp(-x08 * (temp - x11) * (temp - x11));
1490         f[i] = y[i] - (x01 * tmp1 + x02 * tmp2 + x03 * tmp3 + x04 * tmp4);
1491       }
1492       return f;
1493     }
1494 
1495     private static final double[] y = {
1496       1.366, 1.191, 1.112, 1.013, 0.991,
1497       0.885, 0.831, 0.847, 0.786, 0.725,
1498       0.746, 0.679, 0.608, 0.655, 0.616,
1499       0.606, 0.602, 0.626, 0.651, 0.724,
1500       0.649, 0.649, 0.694, 0.644, 0.624,
1501       0.661, 0.612, 0.558, 0.533, 0.495,
1502       0.500, 0.423, 0.395, 0.375, 0.372,
1503       0.391, 0.396, 0.405, 0.428, 0.429,
1504       0.523, 0.562, 0.607, 0.653, 0.672,
1505       0.708, 0.633, 0.668, 0.645, 0.632,
1506       0.591, 0.559, 0.597, 0.625, 0.739,
1507       0.710, 0.729, 0.720, 0.636, 0.581,
1508       0.428, 0.292, 0.162, 0.098, 0.054
1509     };
1510 
1511   }
1512 
1513   public static Test suite() {
1514     return new TestSuite(MinpackTest.class);
1515   }
1516 
1517 }