| levmar.pd | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 211 | 260 | 81.1 |
| branch | 106 | 152 | 69.7 |
| condition | 50 | 75 | 66.6 |
| subroutine | 15 | 17 | 88.2 |
| pod | 3 | 11 | 27.2 |
| total | 385 | 515 | 74.7 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | # -*-Perl-*- # for emacs | ||||||
| 2 | use strict; | ||||||
| 3 | use warnings; | ||||||
| 4 | use Carp; | ||||||
| 5 | |||||||
| 6 | our $VERSION = '0.0108'; | ||||||
| 7 | pp_setversion( $VERSION ); | ||||||
| 8 | |||||||
| 9 | |||||||
| 10 | our $HAVE_LAPACK; | ||||||
| 11 | require './have_lapack'; | ||||||
| 12 | #print "HAVE_LAPACK = $HAVE_LAPACK\n"; | ||||||
| 13 | |||||||
| 14 | pp_addpm({At=>'Top'},<<'===EOD===top_pm==='); | ||||||
| 15 | #use Data::Dumper; | ||||||
| 16 | |||||||
| 17 | =head1 NAME | ||||||
| 18 | |||||||
| 19 | PDL::Fit::Levmar - Levenberg-Marquardt fit/optimization routines | ||||||
| 20 | |||||||
| 21 | =head1 DESCRIPTION | ||||||
| 22 | |||||||
| 23 | Levenberg-Marquardt routines for least-squares fit to | ||||||
| 24 | functions non-linear in fit parameters. | ||||||
| 25 | |||||||
| 26 | This module provides a L |
||||||
| 27 | library levmar 2.5 (written in C). Levmar is | ||||||
| 28 | L |
||||||
| 29 | or finite difference derivatives (in case no analytic | ||||||
| 30 | derivatives are supplied), L |
||||||
| 31 | and/or L |
||||||
| 32 | constraints (with L |
||||||
| 33 | case) and pure single or double precision computation. The | ||||||
| 34 | routines are re-entrant, so they can be used in | ||||||
| 35 | multi-threaded applications (not tested!). Levmar is suited | ||||||
| 36 | both for data fitting and for optimization problems. | ||||||
| 37 | |||||||
| 38 | The source code for the C levmar library is included in this | ||||||
| 39 | distribution. However, linearly-constrained fitting requires | ||||||
| 40 | that C |
||||||
| 41 | and B |
||||||
| 42 | F |
||||||
| 43 | C |
||||||
| 44 | the fitting options C, C, C |
||||||
| 45 | not be used. All other options, including C |
||||||
| 46 | require C |
||||||
| 47 | |||||||
| 48 | User supplied fit functions can be written in perl code that | ||||||
| 49 | takes pdls as arguments, or, for efficiency, in in a simple | ||||||
| 50 | function description language (C |
||||||
| 51 | transparently translated to C, compiled, and dynamically | ||||||
| 52 | linked. Fit functions may also be written in pure C. If C | ||||||
| 53 | or C |
||||||
| 54 | procedure is done in pure compiled C. The compilation and | ||||||
| 55 | linking is done only the first time the function is defined. | ||||||
| 56 | |||||||
| 57 | There is a document distributed with this module | ||||||
| 58 | F<./doc/levmar.pdf> by the author of liblevmar describing | ||||||
| 59 | the fit algorithms. Additional information on liblevmar is available at | ||||||
| 60 | L |
||||||
| 61 | |||||||
| 62 | Don't confuse this module with, but see also, L |
||||||
| 63 | |||||||
| 64 | =head1 SYNOPSIS | ||||||
| 65 | |||||||
| 66 | use PDL::Fit::Levmar; | ||||||
| 67 | $result_hash = levmar($params,$x,$t, FUNC => ' | ||||||
| 68 | function somename | ||||||
| 69 | x = p0 * exp(-t*t * p1);'); | ||||||
| 70 | print levmar_report($result_hash); | ||||||
| 71 | |||||||
| 72 | |||||||
| 73 | =head1 EXAMPLES | ||||||
| 74 | |||||||
| 75 | |||||||
| 76 | A number of examples of invocations of C |
||||||
| 77 | directory C<./t> in the module distribution contains many more examples. | ||||||
| 78 | The following seven examples are included as stand-alone scripts in the | ||||||
| 79 | ./examples/ directory. Some of the necessary lines are not repeated in | ||||||
| 80 | each example below. | ||||||
| 81 | |||||||
| 82 | =over 3 | ||||||
| 83 | |||||||
| 84 | =item example--1 | ||||||
| 85 | |||||||
| 86 | In this example we fill co-ordinate $t and ordinate $x arrays | ||||||
| 87 | with 100 pairs of sample data. Then we call the fit routine | ||||||
| 88 | with initial guesses of the parameters. | ||||||
| 89 | |||||||
| 90 | use PDL::LiteF; | ||||||
| 91 | use PDL::Fit::Levmar; | ||||||
| 92 | use PDL::NiceSlice; | ||||||
| 93 | |||||||
| 94 | $n = 100; | ||||||
| 95 | $t = 10 * (sequence($n)/$n -1/2); | ||||||
| 96 | $x = 3 * exp(-$t*$t * .3 ); | ||||||
| 97 | $p = pdl [ 1, 1 ]; # initial parameter guesses | ||||||
| 98 | |||||||
| 99 | $h = levmar($p,$x,$t, FUNC => | ||||||
| 100 | ' function | ||||||
| 101 | x = p0 * exp( -t*t * p1); | ||||||
| 102 | '); | ||||||
| 103 | print levmar_report($h); | ||||||
| 104 | |||||||
| 105 | This example gives the output: | ||||||
| 106 | |||||||
| 107 | Estimated parameters: [ 3 0.3] | ||||||
| 108 | Covariance: | ||||||
| 109 | [ | ||||||
| 110 | [5.3772081e-25 7.1703376e-26] | ||||||
| 111 | [7.1703376e-26 2.8682471e-26] | ||||||
| 112 | ] | ||||||
| 113 | |||||||
| 114 | ||e||_2 at initial parameters = 125.201 | ||||||
| 115 | Errors at estimated parameters: | ||||||
| 116 | ||e||_2 = 8.03854e-22 | ||||||
| 117 | ||J^T e||_inf = 2.69892e-05 | ||||||
| 118 | ||Dp||_2 = 3.9274e-15 | ||||||
| 119 | \mu/max[J^T J]_ii ] = 1.37223e-05 | ||||||
| 120 | number of iterations = 15 | ||||||
| 121 | reason for termination: = stopped by small ||e||_2 | ||||||
| 122 | number of function evaluations = 20 | ||||||
| 123 | number of jacobian evaluations = 2 | ||||||
| 124 | |||||||
| 125 | In the example above and all following examples, it is necessary | ||||||
| 126 | to include the three C | ||||||
| 127 | The fit function in this example is in C |
||||||
| 128 | The parameter pdl $p is the input parameters (guesses) | ||||||
| 129 | levmar returns a hash with several elements including a | ||||||
| 130 | plain text report of the fit, which we chose to print. | ||||||
| 131 | |||||||
| 132 | The interface is flexible-- we could have also called levmar like this | ||||||
| 133 | |||||||
| 134 | $h = levmar($p,$x,$t, ' function | ||||||
| 135 | x = p0 * exp( -t*t * p1); | ||||||
| 136 | '); | ||||||
| 137 | |||||||
| 138 | or like this | ||||||
| 139 | |||||||
| 140 | $h = levmar(P =>$p, X => $x, T=> $t, FUNC => ' function | ||||||
| 141 | x = p0 * exp( -t*t * p1); | ||||||
| 142 | '); | ||||||
| 143 | |||||||
| 144 | After the fit, the input parameters $p are left | ||||||
| 145 | unchanged. The output hash $h contains, among other things, | ||||||
| 146 | the optimized parameters in $h->{P}. | ||||||
| 147 | |||||||
| 148 | =item example--2 | ||||||
| 149 | |||||||
| 150 | Next, we do the same fit, but with a perl/PDL fit function. | ||||||
| 151 | |||||||
| 152 | $h = levmar($p,$x,$t, FUNC => sub { | ||||||
| 153 | my ($p,$x,$t) = @_; | ||||||
| 154 | my ($p0,$p1) = list $p; | ||||||
| 155 | $x .= $p0 * exp(-$t*$t * $p1); | ||||||
| 156 | }); | ||||||
| 157 | |||||||
| 158 | Using perl code (second example) results in slower execution | ||||||
| 159 | than using pure C (first example). How much slower depends | ||||||
| 160 | on the problem (see L below). See also the | ||||||
| 161 | section on L |
||||||
| 162 | |||||||
| 163 | =item example--3 | ||||||
| 164 | |||||||
| 165 | Next, we solve the same problem using a C fit routine. | ||||||
| 166 | |||||||
| 167 | levmar($p,$x,$t, FUNC => ' | ||||||
| 168 | #include |
||||||
| 169 | void gaussian(FLOAT *p, FLOAT *x, int m, int n, FLOAT *t) | ||||||
| 170 | { | ||||||
| 171 | int i; | ||||||
| 172 | for(i=0; i | ||||||
| 173 | x[i] = p[0] * exp( -t[i]*t[i] * p[1]); | ||||||
| 174 | } | ||||||
| 175 | '); | ||||||
| 176 | |||||||
| 177 | The macro C |
||||||
| 178 | the C code will be used for both single and double precision | ||||||
| 179 | routines. ( The code is automatically compiled twice; once | ||||||
| 180 | with C |
||||||
| 181 | The correct version is used automatically depending on the | ||||||
| 182 | type of pdls you give levmar. | ||||||
| 183 | |||||||
| 184 | |||||||
| 185 | =item example--4 | ||||||
| 186 | |||||||
| 187 | We supply an analytic derivative ( analytic jacobian). | ||||||
| 188 | |||||||
| 189 | $st = ' | ||||||
| 190 | function | ||||||
| 191 | x = p0 * exp( -t*t * p1); | ||||||
| 192 | |||||||
| 193 | jacobian | ||||||
| 194 | FLOAT ex, arg; | ||||||
| 195 | loop | ||||||
| 196 | arg = -t*t * p1; | ||||||
| 197 | ex = exp(arg); | ||||||
| 198 | d0 = ex; | ||||||
| 199 | d1 = -p0 * t*t * ex ; | ||||||
| 200 | |||||||
| 201 | '; | ||||||
| 202 | |||||||
| 203 | $h = levmar($p,$x,$t, FUNC => $st); | ||||||
| 204 | |||||||
| 205 | If no jacobian function is supplied, levmar automatically | ||||||
| 206 | uses numeric difference derivatives. You can also explicitly | ||||||
| 207 | use numeric derivatives with the option C |
||||||
| 208 | C<< => 'numeric' >>. | ||||||
| 209 | |||||||
| 210 | Note that the directives C |
||||||
| 211 | the function definitions. You can also supply a name if | ||||||
| 212 | you like, eg. C |
||||||
| 213 | |||||||
| 214 | In C |
||||||
| 215 | ordinate data by 'x' in the fit function and by 'dn', with n a | ||||||
| 216 | number, in the jacobian. The parameters are identified by | ||||||
| 217 | 'p'. All other identifiers are pure C identifiers and | ||||||
| 218 | must be defined, as are C |
||||||
| 219 | |||||||
| 220 | Referring to the example above, if the directive C |
||||||
| 221 | on a line by itself, code after it is wrapped in a loop over | ||||||
| 222 | the data; code before it is not. If C |
||||||
| 223 | then all the code is wrapped in a loop. 'loop' must occur zero | ||||||
| 224 | or one times in each of the fit and jacobian definitions. | ||||||
| 225 | For some problems, you will not want a loop at all. In this | ||||||
| 226 | case the directive C |
||||||
| 227 | |||||||
| 228 | To see what C |
||||||
| 229 | and look at the C source file that is written. | ||||||
| 230 | |||||||
| 231 | When defining the derivatives above (d0, d1) etc., you must | ||||||
| 232 | put the lines in the proper order ( eg, not d1,d0 ). (This | ||||||
| 233 | is for efficiency, see the generated C code.) | ||||||
| 234 | |||||||
| 235 | One final note on this example-- we declared C |
||||||
| 236 | be type C |
||||||
| 237 | have hard coded them to double, in which case both the float | ||||||
| 238 | and double code versions would have used type double for them. | ||||||
| 239 | This is ok, because it doesn't cost any storage or cause | ||||||
| 240 | a memory fault because of incorrect pointer arithmetic. | ||||||
| 241 | |||||||
| 242 | |||||||
| 243 | =item example--5 | ||||||
| 244 | |||||||
| 245 | Here is an example from the liblevmar demo program that shows | ||||||
| 246 | one more bit of C |
||||||
| 247 | |||||||
| 248 | $defst = " | ||||||
| 249 | function modros | ||||||
| 250 | noloop | ||||||
| 251 | x0 = 10 * (p1 -p0*p0); | ||||||
| 252 | x1 = 1.0 - p0; | ||||||
| 253 | x2 = 100; | ||||||
| 254 | jacobian jacmodros | ||||||
| 255 | noloop | ||||||
| 256 | d0[0] = -20 * p0; | ||||||
| 257 | d1[0] = 10; | ||||||
| 258 | d0[1] = -1; | ||||||
| 259 | d1[1] = 0; | ||||||
| 260 | d0[2] = 0; | ||||||
| 261 | d1[2] = 0; | ||||||
| 262 | "; | ||||||
| 263 | $p = pdl [-1.2, 1]; | ||||||
| 264 | $x = pdl [0,0,0]; | ||||||
| 265 | $h = levmar( $p,$x, FUNC => $defst ); | ||||||
| 266 | |||||||
| 267 | The directive C |
||||||
| 268 | indicating that there are no implied loops in the | ||||||
| 269 | function. Note that this model function is designed only for | ||||||
| 270 | $x->nelem == 3. The additional syntax is in the | ||||||
| 271 | derivatives. Keeping in mind that there is no loop variable, | ||||||
| 272 | dq[r] means derivative w.r.t q evaluated at x[r]. (This is | ||||||
| 273 | translated by C |
||||||
| 274 | 1-d array.) | ||||||
| 275 | |||||||
| 276 | =item example--6 | ||||||
| 277 | |||||||
| 278 | Here is an example that uses implicit threading. We create data | ||||||
| 279 | from a gaussian function with four different sets of parameters | ||||||
| 280 | and fit it all in one function call. | ||||||
| 281 | |||||||
| 282 | $st = ' | ||||||
| 283 | function | ||||||
| 284 | x = p0 * exp( -t*t * p1); | ||||||
| 285 | '; | ||||||
| 286 | |||||||
| 287 | $n = 10; | ||||||
| 288 | $t = 10 * (sequence($n)/$n -1/2); | ||||||
| 289 | $x = zeroes($n,4); | ||||||
| 290 | map { $x(:,$_->[0]) .= $_->[1] * exp(-$t*$t * $_->[2] ) } | ||||||
| 291 | ( [0,3,.2], [1, 28, .1] , [2,2,.01], [3,3,.3] ); | ||||||
| 292 | $p = [ 5, 1]; # initial guess | ||||||
| 293 | $h = levmar($p,$x,$t, FUNC => $st ); | ||||||
| 294 | print $h->{P} . "\n"; | ||||||
| 295 | |||||||
| 296 | [ | ||||||
| 297 | [ 3 0.2] | ||||||
| 298 | [ 28 0.1] | ||||||
| 299 | [ 2 0.01] | ||||||
| 300 | [ 3 0.3] | ||||||
| 301 | ] | ||||||
| 302 | |||||||
| 303 | |||||||
| 304 | =item example--7 | ||||||
| 305 | |||||||
| 306 | This example shows how to fit a bivariate Gaussian. Here | ||||||
| 307 | is the fit function. | ||||||
| 308 | |||||||
| 309 | sub gauss2d { | ||||||
| 310 | my ($p,$xin,$t) = @_; | ||||||
| 311 | my ($p0,$p1,$p2) = list $p; | ||||||
| 312 | my $n = $t->nelem; | ||||||
| 313 | my $t1 = $t(:,*$n); # first coordinate | ||||||
| 314 | my $t2 = $t(*$n,:); # second coordinate | ||||||
| 315 | my $x = $xin->splitdim(0,$n); | ||||||
| 316 | $x .= $p0 * exp( -$p1*$t1*$t1 - $p2*$t2*$t2); | ||||||
| 317 | } | ||||||
| 318 | |||||||
| 319 | |||||||
| 320 | We would prefer a function that maps t(n,n) --> x(n,n) (with | ||||||
| 321 | p viewed as parameters.) But the levmar library expects one | ||||||
| 322 | dimensional x and t. So we design C |
||||||
| 323 | piddles with these dimensions: C , C |
||||||
| 324 | C |
||||||
| 325 | axes run over the same range, so we only need to pass n | ||||||
| 326 | values for t. The piddles t1 and t2 are (virtual) copies of | ||||||
| 327 | t with dummy dimensions inserted. Each represents | ||||||
| 328 | co-ordinate values along each of the two axes at each point | ||||||
| 329 | in the 2-d space, but independent of the position along the | ||||||
| 330 | other axis. For instance C | ||||||
| 331 | == t(j)>. We assume that the piddle xin is a flattened | ||||||
| 332 | version of the ordinate data, so we split the dimensions in | ||||||
| 333 | x. Then the entire bi-variate gaussian is calculated with | ||||||
| 334 | one line that operates on 2-d matrices. Now we create some | ||||||
| 335 | data, | ||||||
| 336 | |||||||
| 337 | my $n = 101; # number of data points along each axis | ||||||
| 338 | my $scale = 3; # range of co-ordiate data | ||||||
| 339 | my $t = sequence($n); # co-ordinate data (used for both axes) | ||||||
| 340 | $t *= $scale/($n-1); | ||||||
| 341 | $t -= $scale/2; # rescale and shift. | ||||||
| 342 | my $x = zeroes($n,$n); | ||||||
| 343 | my $p = pdl [ .5,2,3]; # actual parameters | ||||||
| 344 | my $xlin = $x->clump(-1); # flatten the x data | ||||||
| 345 | gauss2d( $p, $xlin, $t->copy); # compute the bivariate gaussian data. | ||||||
| 346 | |||||||
| 347 | Now x contains the ordinate data (so does xlin, but in a flattened shape.) | ||||||
| 348 | Finally, we fit the data with an incorrect set of initial parameters, | ||||||
| 349 | |||||||
| 350 | my $p1 = pdl [ 1,1,1]; # not the parameters we used to make the data | ||||||
| 351 | my $h = levmar($p1,$xlin,$t,\&gauss2d); | ||||||
| 352 | |||||||
| 353 | At this point C<$h->{P}> refers to the output parameter piddle C<[0.5, 2, 3]>. | ||||||
| 354 | |||||||
| 355 | =back | ||||||
| 356 | |||||||
| 357 | =head1 CONSTRAINTS | ||||||
| 358 | |||||||
| 359 | Several of the options below are related to constraints. There are | ||||||
| 360 | three types: box, linear equation, and linear inequality. They may | ||||||
| 361 | be used in any combination. (But there is no testing if | ||||||
| 362 | there is a possible solution.) None or one or two of C |
||||||
| 363 | specified. None or both of C and C may be specified. | ||||||
| 364 | None or both of C |
||||||
| 365 | |||||||
| 366 | =head1 OPTIONS | ||||||
| 367 | |||||||
| 368 | It is best to learn how to call levmar by looking at the | ||||||
| 369 | examples first, and looking at this section later. | ||||||
| 370 | |||||||
| 371 | levmar() is called like this | ||||||
| 372 | |||||||
| 373 | levmar($arg1, $arg2, ..., OPT1=>$val1, OPT2=>$val2, ...); | ||||||
| 374 | or this: | ||||||
| 375 | levmar($arg1, $arg2, ..., {OPT1=>$val1, OPT2=>$val2, ...}); | ||||||
| 376 | |||||||
| 377 | When calling levmar, the first 3 piddle arguments (or refs | ||||||
| 378 | to arrays), if present, are taken to be C<$p>,C<$x>, and C<$t> | ||||||
| 379 | (parameters, ordinate data, and co-ordinate data) in that | ||||||
| 380 | order. The first scalar value that can be interpreted as a | ||||||
| 381 | function will be. Everything else must be passed as an | ||||||
| 382 | option in a key-value pair. If you prefer, you can pass some | ||||||
| 383 | or all of C<$p,$x,$t> and the function as key-values in the | ||||||
| 384 | hash. Note that after the first key-value pair, you cannot | ||||||
| 385 | pass any more non-hash arguments. The following calls are equivalent | ||||||
| 386 | (where $func specifies the function as described in L ). | ||||||
| 387 | |||||||
| 388 | levmar($p, $x, $t, $func); | ||||||
| 389 | levmar($func,$p, $x, $t); | ||||||
| 390 | levmar($p, $x, $t, FUNC=> $func); | ||||||
| 391 | levmar($p, $x, T=>$t, FUNC => $func); | ||||||
| 392 | levmar($p, X=>$x, T=>$t, FUNC => $func); | ||||||
| 393 | levmar(P=>$p, X=>$x, T=>$t, FUNC => $func); | ||||||
| 394 | |||||||
| 395 | In the following, if the default value is not mentioned, it is undef. | ||||||
| 396 | C<$outh> refers to the output hash. | ||||||
| 397 | |||||||
| 398 | Some of these options are actually options to Levmar::Func. | ||||||
| 399 | All options to Levmar::Func may by given in calls to levmar(). | ||||||
| 400 | |||||||
| 401 | =over 4 | ||||||
| 402 | |||||||
| 403 | =item FUNC | ||||||
| 404 | |||||||
| 405 | This option is required (but it can be passed before the | ||||||
| 406 | options hash without the key C |
||||||
| 407 | any of the following, which are auto-detected. | ||||||
| 408 | |||||||
| 409 | a string containing lpp code | ||||||
| 410 | a string containing pure C code | ||||||
| 411 | the filename of a file containing lpp code (which must end in '.lpp' ) | ||||||
| 412 | the filename of a file containing pure C code ( which must end in '.c' ) | ||||||
| 413 | a reference to perl code | ||||||
| 414 | a reference to a previously created Levmar::Func object (which was | ||||||
| 415 | previously created via one of the preceeding methods.) | ||||||
| 416 | |||||||
| 417 | If you are fitting a lot of data by doing many iterations over | ||||||
| 418 | a loop of perl code, it is by far most efficient to create a Func | ||||||
| 419 | object from C or lpp code and pass it to levmar. (Implicit threading | ||||||
| 420 | does not recompile code in any case.) | ||||||
| 421 | |||||||
| 422 | You can also pass pure C code via the option CSRC. | ||||||
| 423 | |||||||
| 424 | =item JFUNC | ||||||
| 425 | |||||||
| 426 | This parameter is the jacobian as a ref to perl CODE. For | ||||||
| 427 | C and C |
||||||
| 428 | same source file as the fit function; in this case, you | ||||||
| 429 | should leave C |
||||||
| 430 | |||||||
| 431 | =item DERIVATIVE | ||||||
| 432 | |||||||
| 433 | This takes the value 'numeric' or 'analytic'. If it is | ||||||
| 434 | set to 'analytic', but no analytic jacobian of the model | ||||||
| 435 | function is supplied, then the numeric algorithms will be used | ||||||
| 436 | anyway. | ||||||
| 437 | |||||||
| 438 | =item NOCLEAN | ||||||
| 439 | |||||||
| 440 | If defined (NOCLEAN => 1), files containing generated C | ||||||
| 441 | object and dynamic library code are not deleted. If not | ||||||
| 442 | defined, these files are deleted after they are no longer | ||||||
| 443 | needed. For the source and object (.c and .o) files, this | ||||||
| 444 | means immediately after the dynamic library (.so) is built. | ||||||
| 445 | The dynamic library file is deleted when the corresponding | ||||||
| 446 | Levmar::Func object is destroyed. (It could be deleted after | ||||||
| 447 | it is loaded, I suppose, and then be rebuilt if needed | ||||||
| 448 | again) | ||||||
| 449 | |||||||
| 450 | =item FIX | ||||||
| 451 | |||||||
| 452 | Example: Fix => [1,0,0,1,0]. | ||||||
| 453 | This option takes a pdl (or array ref) of the same shape as | ||||||
| 454 | the parameters $p. Each element must have the value zero or | ||||||
| 455 | one. A zero corresponds to a free parameter and a one to a | ||||||
| 456 | fixed parameter. The best fit is found keeping the fixed | ||||||
| 457 | parameters at their input values and letting the free | ||||||
| 458 | parameters vary. This is implemented by using the linear | ||||||
| 459 | constraint option described below. Each element must be | ||||||
| 460 | either one or zero. This option currently cannot be | ||||||
| 461 | threaded. That is, if the array FIX has more than one | ||||||
| 462 | dimension you will not get correct results. Also, PDL will | ||||||
| 463 | not add dimension correctly if you pass additional | ||||||
| 464 | dimensions in other quantities. Threading will work if you | ||||||
| 465 | use linear constraints directly via C and C. | ||||||
| 466 | |||||||
| 467 | =item FIXB | ||||||
| 468 | |||||||
| 469 | This option is almost the same as FIX. It takes the same | ||||||
| 470 | values with the same meanings. It fixes parameters at the value | ||||||
| 471 | of the input parameters, but uses | ||||||
| 472 | box constraints, i.e., UB and LB rather than linear | ||||||
| 473 | constraints A and B. You can specify all three of UB,LB, and FIXB. | ||||||
| 474 | In this case, first box constraints determined by UB and LB are applied | ||||||
| 475 | Then, for those elements of FIXB with value one, the corresponding | ||||||
| 476 | values of UB and LB are overridden. | ||||||
| 477 | |||||||
| 478 | =item A | ||||||
| 479 | |||||||
| 480 | Example: A =>pdl [ [1,0], [0,1] ] , B => pdl [ 1,2 ] | ||||||
| 481 | |||||||
| 482 | Minimize with linear constraints $A x $p = $b. That is, | ||||||
| 483 | parameters $p are optimized over the subset of parameters | ||||||
| 484 | that solve the equation. The dimensions of the quantities | ||||||
| 485 | are A(k,m), b(m), p(m), where k is the number of | ||||||
| 486 | constraints. ( k <= m ). Note that $b is a vector (it has one | ||||||
| 487 | fewer dimensions than A), but the option key is a capital 'B'. | ||||||
| 488 | |||||||
| 489 | =item B | ||||||
| 490 | |||||||
| 491 | See C. | ||||||
| 492 | |||||||
| 493 | =item UB | ||||||
| 494 | |||||||
| 495 | Example: UB => [10,10,10], LB => [-10,0,-5]. | ||||||
| 496 | Box constraints. These have the same shape as the parameter | ||||||
| 497 | pdl $p. The fit is done with ub forming upper bounds and lb | ||||||
| 498 | lower bounds on the parameter values. Use, for instance | ||||||
| 499 | PDL::Fit::Levmar::get_dbl_max() for parameters that you | ||||||
| 500 | don't want bounded. You can use either linear constraints or | ||||||
| 501 | box constraints, or both. That is, you may specify A, B, UB, and LB. | ||||||
| 502 | |||||||
| 503 | =item LB | ||||||
| 504 | |||||||
| 505 | See C |
||||||
| 506 | |||||||
| 507 | |||||||
| 508 | =item WGHTS | ||||||
| 509 | |||||||
| 510 | Penalty weights can be given optionally when box and linear equality | ||||||
| 511 | constraints are both passed to levmar. See the levmar documenation for | ||||||
| 512 | how to use this. Note that if C and D are used then the WGHTS must | ||||||
| 513 | not passed. | ||||||
| 514 | |||||||
| 515 | =item C | ||||||
| 516 | |||||||
| 517 | Example: C => [ [ -1, -2, -1, -1], [ -3, -1, -2, 1] ], D => [ -5, -0.4] | ||||||
| 518 | Linear inequality constraints. Minimize with constraints $C x $p >= $d. | ||||||
| 519 | The dimensions are C(k2,m), D(m), p(m). | ||||||
| 520 | |||||||
| 521 | =item D | ||||||
| 522 | |||||||
| 523 | See C |
||||||
| 524 | |||||||
| 525 | =item P | ||||||
| 526 | |||||||
| 527 | Keys P, X, and T can be used to send to the parameters, ordinates and coordinates. | ||||||
| 528 | Alternatively, you can send them as non-option arguments to levmar before | ||||||
| 529 | the option arguments. | ||||||
| 530 | |||||||
| 531 | =item X | ||||||
| 532 | |||||||
| 533 | See C
|
||||||
| 534 | |||||||
| 535 | =item T | ||||||
| 536 | |||||||
| 537 | See C
|
||||||
| 538 | |||||||
| 539 | =item DIR | ||||||
| 540 | |||||||
| 541 | The directory containing files created when compiling C |
||||||
| 542 | and C fit functions. This defaults to being created by | ||||||
| 543 | L |
||||||
| 544 | .o, and .so files will be written to this directory. This | ||||||
| 545 | option actually falls through to levmar_func. Such options | ||||||
| 546 | should be in separate section, or otherwise noted. | ||||||
| 547 | |||||||
| 548 | =item GETOPTS | ||||||
| 549 | |||||||
| 550 | If defined, return a ref to a hash containing the default | ||||||
| 551 | values of the parameters. | ||||||
| 552 | |||||||
| 553 | =item COVAR | ||||||
| 554 | |||||||
| 555 | Send a pdl reference for the output hash element COVAR. You may | ||||||
| 556 | want to test if this option is more efficient for | ||||||
| 557 | some problem. But unless the covariance matrix is very large, | ||||||
| 558 | it probably won't help much. On the other hand it almost certainly | ||||||
| 559 | won't make levmar() less efficient. | ||||||
| 560 | |||||||
| 561 | Note that levmar returns a piddle representing the covariance in | ||||||
| 562 | the output hash. This will be the the same piddle that you give | ||||||
| 563 | as input via this option. So, if you do the following, | ||||||
| 564 | |||||||
| 565 | my $covar = PDL->null | ||||||
| 566 | my $h =levmar(...., COVAR => $covar); | ||||||
| 567 | |||||||
| 568 | then $covar and $h->{COVAR} are references to the same | ||||||
| 569 | pdl. The storage for the pdl will not be destroyed until | ||||||
| 570 | both $covar and $h->{COVAR} become undefined. | ||||||
| 571 | |||||||
| 572 | =item NOCOVAR | ||||||
| 573 | |||||||
| 574 | If defined, no covariance matrix is computed. | ||||||
| 575 | |||||||
| 576 | =item POUT | ||||||
| 577 | |||||||
| 578 | Send a pdl reference for the output hash element P. Don't | ||||||
| 579 | confuse this with the option P which can be used to send the | ||||||
| 580 | initial guess for the parameters (see C |
||||||
| 581 | |||||||
| 582 | =item INFO | ||||||
| 583 | |||||||
| 584 | Send a pdl reference for the output hash element C |
||||||
| 585 | (see C |
||||||
| 586 | |||||||
| 587 | =item RET | ||||||
| 588 | |||||||
| 589 | Send a pdl reference for the output hash element C |
||||||
| 590 | (see C |
||||||
| 591 | |||||||
| 592 | |||||||
| 593 | =item MAXITS | ||||||
| 594 | |||||||
| 595 | Maximum number of iterations to try before giving up. The default | ||||||
| 596 | is 100. | ||||||
| 597 | |||||||
| 598 | =item MU | ||||||
| 599 | |||||||
| 600 | The starting value of the parameter mu in the L-M algorithm. | ||||||
| 601 | |||||||
| 602 | =item EPS1, EPS2, EPS3 | ||||||
| 603 | |||||||
| 604 | Stopping thresholds for C<||J^T e||_inf>, C<||Dp||_2> and | ||||||
| 605 | C<||e||_2>. (see the document levmar.pdf by the author of | ||||||
| 606 | liblevmar and distributed with this module) The algorithm | ||||||
| 607 | stops when the first threshold is reached (or C |
||||||
| 608 | C |
||||||
| 609 | |||||||
| 610 | Here, C |
||||||
| 611 | the model function and C is the vector of parameters. |
||||||
| 612 | S<||J^T e||_inf> is the gradient of C
|
||||||
| 613 | at the current estimate of C ; C<||Dp||_2> is the amount |
||||||
| 614 | by which C is currently being shifted at each iteration; |
||||||
| 615 | C<||e||_2> is a measure of the error between the model function | ||||||
| 616 | at the current estimate for C and the data. |
||||||
| 617 | |||||||
| 618 | =item DELTA | ||||||
| 619 | |||||||
| 620 | This is a step size used in computing numeric derivatives. It is | ||||||
| 621 | not used if the analytic jacobian is used. | ||||||
| 622 | |||||||
| 623 | |||||||
| 624 | =item MKOBJ | ||||||
| 625 | |||||||
| 626 | command to compile source into object code. This option is actually set in | ||||||
| 627 | the Levmar::Func object, but can be given in calls to levmar(). | ||||||
| 628 | The default value is determined by the perl installation and can | ||||||
| 629 | be determined by examining the Levmar::Func object returned by | ||||||
| 630 | new or the output hash of a call to levmar. A typical value is | ||||||
| 631 | cc -c -O2 -fPIC -o %o %c | ||||||
| 632 | |||||||
| 633 | =item MKSO | ||||||
| 634 | |||||||
| 635 | command to convert object code to dynamic library code. | ||||||
| 636 | This option is actually set in the Levmar::Func object. A | ||||||
| 637 | typical default value is | ||||||
| 638 | cc -shared -L/usr/local/lib -fstack-protector %o -o %s | ||||||
| 639 | |||||||
| 640 | =item CTOP | ||||||
| 641 | |||||||
| 642 | The value of this string will be written at the top of the c code | ||||||
| 643 | written by Levmar::Func. This can be used to include headers and so forth. | ||||||
| 644 | This option is actually set in the Levmar::Func object. This code is also written | ||||||
| 645 | at the top of c code translated from lpp code. | ||||||
| 646 | |||||||
| 647 | |||||||
| 648 | =item FVERBOSE | ||||||
| 649 | |||||||
| 650 | If true (eg 1) Print the compiling and linking commands to STDERR when compiling fit functions. | ||||||
| 651 | This option is actually passed to Levmar::Func. Default is 0. | ||||||
| 652 | |||||||
| 653 | =item Default values | ||||||
| 654 | |||||||
| 655 | Here are the default values | ||||||
| 656 | of some options | ||||||
| 657 | |||||||
| 658 | |||||||
| 659 | $Levmar_defaults = { | ||||||
| 660 | FUNC => undef, # Levmar::Func object, or function def, or ... | ||||||
| 661 | JFUNC => undef, # must be ref to perl sub | ||||||
| 662 | MAXITS => 100, # maximum iterations | ||||||
| 663 | MU => LM_INIT_MU, # These are described in levmar docs | ||||||
| 664 | EPS1 => LM_STOP_THRESH, | ||||||
| 665 | EPS2 => LM_STOP_THRESH, | ||||||
| 666 | EPS3 => LM_STOP_THRESH, | ||||||
| 667 | DELTA => LM_DIFF_DELTA, | ||||||
| 668 | DERIVATIVE => 'analytic', | ||||||
| 669 | FIX => undef, | ||||||
| 670 | A => undef, | ||||||
| 671 | B => undef, | ||||||
| 672 | C => undef, | ||||||
| 673 | D => undef, | ||||||
| 674 | UB = undef, | ||||||
| 675 | LB => undef, | ||||||
| 676 | X => undef, | ||||||
| 677 | P => undef, | ||||||
| 678 | T => undef, | ||||||
| 679 | WGHTS => undef, | ||||||
| 680 | # meant to be private | ||||||
| 681 | LFUNC => undef, # only Levmar::Func object, made from FUNC | ||||||
| 682 | }; | ||||||
| 683 | |||||||
| 684 | =back | ||||||
| 685 | |||||||
| 686 | |||||||
| 687 | =head1 OUTPUT | ||||||
| 688 | |||||||
| 689 | This section describes the contents of the hash that | ||||||
| 690 | levmar takes as output. Do not confuse these hash keys with | ||||||
| 691 | the hash keys of the input options. It may be a good idea | ||||||
| 692 | to change the interface by prepending O to all of the output | ||||||
| 693 | keys that could be confused with options to levmar(). | ||||||
| 694 | |||||||
| 695 | =over 3 | ||||||
| 696 | |||||||
| 697 | =item P (output) | ||||||
| 698 | |||||||
| 699 | pdl containing the optimized parameters. It has the same shape | ||||||
| 700 | as the input parameters. | ||||||
| 701 | |||||||
| 702 | =item FUNC (output) | ||||||
| 703 | |||||||
| 704 | ref to the Levmar::Func object. This object may have been created | ||||||
| 705 | during the call to levmar(). For instance, if you pass a string | ||||||
| 706 | contiaining an C |
||||||
| 707 | information) is contained in $outh->{FUNC}. Don't confuse this with | ||||||
| 708 | the input parameter of the same name. | ||||||
| 709 | |||||||
| 710 | =item COVAR (output) | ||||||
| 711 | |||||||
| 712 | a pdl representing covariance matrix. | ||||||
| 713 | |||||||
| 714 | =item REASON | ||||||
| 715 | |||||||
| 716 | an integer code representing the reason for terminating the | ||||||
| 717 | fit. (call levmar_report($outh) for an interpretation. The interpretations | ||||||
| 718 | are listed here as well (see the liblevmar documentation if you don't | ||||||
| 719 | find an explanation somewhere here.) | ||||||
| 720 | |||||||
| 721 | 1 stopped by small gradient J^T e | ||||||
| 722 | 2 stopped by small Dp | ||||||
| 723 | 3 stopped by itmax | ||||||
| 724 | 4 singular matrix. Restart from current p with increased \mu | ||||||
| 725 | 5 no further error reduction is possible. Restart with increased \mu | ||||||
| 726 | 6 stopped by small ||e||_2 | ||||||
| 727 | |||||||
| 728 | |||||||
| 729 | =item ERRI, ERR1, ERR2, ERR3, ERR4 | ||||||
| 730 | |||||||
| 731 | ERRI is C<||e||_2> at the initial paramters. ERR1 through | ||||||
| 732 | ERR3 are the actual values on termination of the quantities | ||||||
| 733 | corresponding to the thresholds EPS1 through EPS3 described | ||||||
| 734 | in the options section. ERR4 is C |
||||||
| 735 | |||||||
| 736 | =item ITS | ||||||
| 737 | |||||||
| 738 | Number of iterations performed | ||||||
| 739 | |||||||
| 740 | =item NFUNC, NJAC, NLS | ||||||
| 741 | |||||||
| 742 | Number of function evaluations, number of jacobian evaluations | ||||||
| 743 | and number of linear systems solved. | ||||||
| 744 | |||||||
| 745 | =item INFO | ||||||
| 746 | |||||||
| 747 | Array containing ERRI,ERR1, ..., ERR4, ITS, REASON, NFUNC, NJAC, NLS. | ||||||
| 748 | |||||||
| 749 | =back | ||||||
| 750 | |||||||
| 751 | =head1 FIT FUNCTIONS | ||||||
| 752 | |||||||
| 753 | Fit functions, or model functions can be specified in the following | ||||||
| 754 | ways. | ||||||
| 755 | |||||||
| 756 | =over 3 | ||||||
| 757 | |||||||
| 758 | =item lpp | ||||||
| 759 | |||||||
| 760 | It is easier to learn to use C |
||||||
| 761 | |||||||
| 762 | C |
||||||
| 763 | the opening and closing parts of the function, alters a | ||||||
| 764 | small number of identifiers if they appear, and wraps some | ||||||
| 765 | of the code in a loop. C |
||||||
| 766 | must occur on a line with nothing else, not even comments. | ||||||
| 767 | |||||||
| 768 | First, the directives are explained, then the substitutions. | ||||||
| 769 | The directive lines have a strict format. All other lines | ||||||
| 770 | can contain any C code including comments and B |
||||||
| 771 | macros. They will be written to a function in C after the | ||||||
| 772 | substitutions described below. | ||||||
| 773 | |||||||
| 774 | =over 3 | ||||||
| 775 | |||||||
| 776 | =item C |
||||||
| 777 | |||||||
| 778 | The first line of the fit function definition must be | ||||||
| 779 | C |
||||||
| 780 | definition, if the jacobian is to be defined, is C | ||||||
| 781 | funcname>. The function names can be any valid C function | ||||||
| 782 | name. The names may also be omitted as they are never needed | ||||||
| 783 | by the user. The names can be identical. (Note that a | ||||||
| 784 | numeric suffix will be automatically added to the function | ||||||
| 785 | name if the .so file already exists. This is because, if | ||||||
| 786 | another Func object has already loaded the shared library | ||||||
| 787 | from an .so file, dlopen will use this loaded library for | ||||||
| 788 | all C |
||||||
| 789 | file has been overwritten, causing unexpected behavior) | ||||||
| 790 | |||||||
| 791 | =item C |
||||||
| 792 | |||||||
| 793 | The directive C |
||||||
| 794 | in the implicit loop, while all code following C |
||||||
| 795 | the implicit loop. If you omit the directive, then all the code | ||||||
| 796 | is wrapped in a loop. | ||||||
| 797 | |||||||
| 798 | =item C |
||||||
| 799 | |||||||
| 800 | The directive C |
||||||
| 801 | in the function. | ||||||
| 802 | |||||||
| 803 | =item Out-of-loop substitutions | ||||||
| 804 | |||||||
| 805 | These substitutions translate C |
||||||
| 806 | before the implied loop (or everywhere if there is no loop.) | ||||||
| 807 | In every case you can write the translated C code into your | ||||||
| 808 | function definition yourself and C |
||||||
| 809 | untouched. | ||||||
| 810 | |||||||
| 811 | =over 3 | ||||||
| 812 | |||||||
| 813 | =item pq -> p[q] | ||||||
| 814 | |||||||
| 815 | where q is a sequence of digits. | ||||||
| 816 | |||||||
| 817 | |||||||
| 818 | =item xq -> x[q] | ||||||
| 819 | |||||||
| 820 | where q is a sequence of digits. This is applied only in the fit function, | ||||||
| 821 | not in the jacobian. | ||||||
| 822 | |||||||
| 823 | |||||||
| 824 | =item dq[r] -> d[q+m*r] | ||||||
| 825 | |||||||
| 826 | (where m == $p->nelem), q and r are sequences of | ||||||
| 827 | digits. This applies only in the jacobian. You usually will | ||||||
| 828 | only use the fit functions with one value of m. It would | ||||||
| 829 | make faster code if you were to explicitly write, say C |
||||||
| 830 | for each derivative at each point. Presumably there is a | ||||||
| 831 | small number of data points since this is outside a | ||||||
| 832 | loop. Some provisions should be added to C |
||||||
| 833 | hard code the value of C |
||||||
| 834 | constructions involving this substitution. | ||||||
| 835 | |||||||
| 836 | |||||||
| 837 | =back | ||||||
| 838 | |||||||
| 839 | =item In-loop substitutions | ||||||
| 840 | |||||||
| 841 | These substitutions apply inside the implied loop. The loop variables are | ||||||
| 842 | i in the fit function and i and j in the jacobian. | ||||||
| 843 | |||||||
| 844 | =over 3 | ||||||
| 845 | |||||||
| 846 | =item t -> t[i] | ||||||
| 847 | |||||||
| 848 | (literal "i") You can also write t[i] or t[expression involving i] by hand. | ||||||
| 849 | Example: t*t -> t[i]*t[i]. | ||||||
| 850 | |||||||
| 851 | |||||||
| 852 | =item pq -> p[q] | ||||||
| 853 | |||||||
| 854 | where q is a sequence of digits. Example p3 -> p[3]. | ||||||
| 855 | |||||||
| 856 | |||||||
| 857 | =item x -> x[i] | ||||||
| 858 | |||||||
| 859 | only in fit function, not in jacobian. | ||||||
| 860 | |||||||
| 861 | |||||||
| 862 | =item (dr or dr[i]) -> d[j++] | ||||||
| 863 | |||||||
| 864 | where r is a sequence of digits. Note that r and i are | ||||||
| 865 | ignored. So you are required to list the derivatives in | ||||||
| 866 | order. An example is | ||||||
| 867 | |||||||
| 868 | d0 = t*t; // derivative w.r.t p[0] loop over all points | ||||||
| 869 | d1 = t; | ||||||
| 870 | |||||||
| 871 | If you write C |
||||||
| 872 | assign the derivative functions. | ||||||
| 873 | |||||||
| 874 | =back | ||||||
| 875 | |||||||
| 876 | |||||||
| 877 | =back | ||||||
| 878 | |||||||
| 879 | |||||||
| 880 | |||||||
| 881 | =item C Code | ||||||
| 882 | |||||||
| 883 | The jacobian name must start with 'jac' when a pure C function definition | ||||||
| 884 | is used. To see example of fit functions writen in C, call levmar | ||||||
| 885 | with lpp code and the option C |
||||||
| 886 | in the directory given by C |
||||||
| 887 | slightly before passing it to the compiler: It is copied twice, with | ||||||
| 888 | FLOAT defined in one case as C |
||||||
| 889 | The letter C |
||||||
| 890 | copy. The C code is parsed to find the fit function name and the | ||||||
| 891 | jacobian function name. | ||||||
| 892 | |||||||
| 893 | We should make it possible to pass the function names as a separate option | ||||||
| 894 | rather than parsing the C code. This will allow auxiallary functions to | ||||||
| 895 | be defined in the C code; something that is currently not possible. | ||||||
| 896 | |||||||
| 897 | |||||||
| 898 | =item Perl_Subroutines | ||||||
| 899 | |||||||
| 900 | This is how to use perl subroutines as fit functions... (see | ||||||
| 901 | the examples for now, e.g. L |
||||||
| 902 | fit function takes piddles $p,$x, and $t, with dimensions | ||||||
| 903 | m,n, and tn. (often tn ==n ). These are references with | ||||||
| 904 | storage already allocated (by the user and liblevmar). So | ||||||
| 905 | you must use C<.=> when setting values. The jacobian takes | ||||||
| 906 | piddles $p,$d, and $t, where $d, the piddle of derivatives | ||||||
| 907 | has dimensions (m,n). For example | ||||||
| 908 | |||||||
| 909 | $f = sub myexp { | ||||||
| 910 | my ($p,$x,$t) = @_; | ||||||
| 911 | my ($p0,$p1,$p2) = list($p); | ||||||
| 912 | $x .= exp($t/$p0); | ||||||
| 913 | $x *= $p1; | ||||||
| 914 | $x += $p2 | ||||||
| 915 | } | ||||||
| 916 | |||||||
| 917 | $jf = sub my expjac { | ||||||
| 918 | my ($p,$d,$t) = @_; | ||||||
| 919 | my ($p0,$p1,$p2) = list($p); | ||||||
| 920 | my $arg = $t/$p0; | ||||||
| 921 | my $ex = exp($arg); | ||||||
| 922 | $d((0)) .= -$p1*$ex*$arg/$p0; | ||||||
| 923 | $d((1)) .= $ex; | ||||||
| 924 | $d((2)) .= 1.0; | ||||||
| 925 | } | ||||||
| 926 | |||||||
| 927 | |||||||
| 928 | |||||||
| 929 | =back | ||||||
| 930 | |||||||
| 931 | |||||||
| 932 | =head1 PDL::Fit::Levmar::Func Objects | ||||||
| 933 | |||||||
| 934 | These objects are created every time you call levmar(). The hash | ||||||
| 935 | returned by levmar contains a ref to the Func object. For instance | ||||||
| 936 | if you do | ||||||
| 937 | |||||||
| 938 | $outh = levmar( FUNC => ..., @opts); | ||||||
| 939 | |||||||
| 940 | then $outh->{LFUNC} will contain a ref to the function object. The .so | ||||||
| 941 | file, if it exists, will not be deleted until the object is destroyed. | ||||||
| 942 | This will happen, for instance if you do C<$outh = undef>. | ||||||
| 943 | |||||||
| 944 | |||||||
| 945 | =head1 IMPLEMENTATION | ||||||
| 946 | |||||||
| 947 | This section currently only refers to the interface and not the fit algorithms. | ||||||
| 948 | |||||||
| 949 | =over 3 | ||||||
| 950 | |||||||
| 951 | =item C fit functions | ||||||
| 952 | |||||||
| 953 | The module does not use perl interfaces to dlopen or the C | ||||||
| 954 | compiler. The C compiler options are taken from | ||||||
| 955 | %Config. This is mostly because I had already written those | ||||||
| 956 | parts before I found the modules. I imagine the | ||||||
| 957 | implementation here has less overhead, but is less portable. | ||||||
| 958 | |||||||
| 959 | |||||||
| 960 | =item perl subroutine fit functions | ||||||
| 961 | |||||||
| 962 | Null pdls are created in C code before the fit starts. They | ||||||
| 963 | are passed in a struct to the C fit function and derivative | ||||||
| 964 | routines that wrap the user's perl code. At each call the | ||||||
| 965 | data pointers to the pdls are set to what liblevmar has sent | ||||||
| 966 | to the fit functions. The pdls are deleted after the fit. | ||||||
| 967 | Originally, all the information on the fit functions was | ||||||
| 968 | supposed to be handled by Levmar::Func. But when I added | ||||||
| 969 | perl subroutine support, it was less clumsy to move most of | ||||||
| 970 | the code for perl subs to the Levmar module. So the current | ||||||
| 971 | solution is not very clean. | ||||||
| 972 | |||||||
| 973 | =item Efficiency | ||||||
| 974 | |||||||
| 975 | Using C |
||||||
| 976 | faster than using L |
||||||
| 977 | done. For very large data sets, pure C was twice as fast as | ||||||
| 978 | perl subs and three times as fast as Fit::LM. Some | ||||||
| 979 | optimization problems have very small data sets and converge | ||||||
| 980 | very slowly. As the data sets become smaller and the number | ||||||
| 981 | of iterations increases the advantage of using pure C | ||||||
| 982 | increases as expected. Also, if I fit a small data set | ||||||
| 983 | (n=10) a large number of times (just looping over the same | ||||||
| 984 | problem), Pure C is ten times faster than Fit::LM, while | ||||||
| 985 | Levmar with perl subs is only about 1.15 times faster than | ||||||
| 986 | Fit::LM. All of this was observed on only two different | ||||||
| 987 | problems. | ||||||
| 988 | |||||||
| 989 | =back | ||||||
| 990 | |||||||
| 991 | =head1 FUNCTIONS | ||||||
| 992 | |||||||
| 993 | =head2 levmar() | ||||||
| 994 | |||||||
| 995 | =for ref | ||||||
| 996 | |||||||
| 997 | Perform Levenberg-Marquardt non-linear least squares fit | ||||||
| 998 | to data given a model function. | ||||||
| 999 | |||||||
| 1000 | =for usage | ||||||
| 1001 | |||||||
| 1002 | use PDL::Fit::Levmar; | ||||||
| 1003 | |||||||
| 1004 | $result_hash = levmar($p,$x,$t, FUNC => $func, %OPTIONS ); | ||||||
| 1005 | |||||||
| 1006 | $p is a pdl of input parameters | ||||||
| 1007 | $x is a pdl of ordinate data | ||||||
| 1008 | $t is an optional pdl of co-ordinate data | ||||||
| 1009 | |||||||
| 1010 | levmar() is the main function in the Levmar package. See the | ||||||
| 1011 | PDL::Fit::Levmar for a complete description. | ||||||
| 1012 | |||||||
| 1013 | =for signature | ||||||
| 1014 | |||||||
| 1015 | p(m); x(n); t(nt); int itmax(); | ||||||
| 1016 | [o] covar(m,m) ; int [o] returnval(); | ||||||
| 1017 | [o] pout(m); [o] info(q=10); | ||||||
| 1018 | |||||||
| 1019 | See the module documentation for information on passing | ||||||
| 1020 | these arguments to levmar. Threading is known to | ||||||
| 1021 | work with p(m) and x(n), but I have not tested the rest. In | ||||||
| 1022 | this case all of they output pdls get the correct number of | ||||||
| 1023 | dimensions (and correct values !). Notice that t(nt) has a | ||||||
| 1024 | different dimension than x(n). This is correct because in | ||||||
| 1025 | some problems there is no t at all, and in some it is | ||||||
| 1026 | pressed into the service of delivering other parameters to | ||||||
| 1027 | the fit routine. (Formally, even if you use t(n), they are | ||||||
| 1028 | parameters.) | ||||||
| 1029 | |||||||
| 1030 | |||||||
| 1031 | =head2 levmar_chkjac() | ||||||
| 1032 | |||||||
| 1033 | =for ref | ||||||
| 1034 | |||||||
| 1035 | Check the analytic jacobian of a function by computing | ||||||
| 1036 | the derivatives numerically. | ||||||
| 1037 | |||||||
| 1038 | =for signature | ||||||
| 1039 | |||||||
| 1040 | p(m); t(n); [o] err(n); | ||||||
| 1041 | This is the relevant part of the signature of the | ||||||
| 1042 | routine that does the work. | ||||||
| 1043 | |||||||
| 1044 | |||||||
| 1045 | =for usage | ||||||
| 1046 | |||||||
| 1047 | use PDL::Fit::Levmar; | ||||||
| 1048 | |||||||
| 1049 | $Gh = levmar_func(FUNC=>$Gf); | ||||||
| 1050 | |||||||
| 1051 | $err = levmar_chkjac($Gh,$p,$t); | ||||||
| 1052 | |||||||
| 1053 | $f is an object of type PDL::Fit::Levmar::Func | ||||||
| 1054 | $p is a pdl of input parameters | ||||||
| 1055 | $t is an pdl of co-ordinate data | ||||||
| 1056 | $err is a pdl of errors computed at the values $t. | ||||||
| 1057 | |||||||
| 1058 | Note: No data $x is supplied to this function | ||||||
| 1059 | |||||||
| 1060 | The Func object $Gh contains a function f, and a jacobian | ||||||
| 1061 | jf. The i_th element of $err measures the agreement between | ||||||
| 1062 | the numeric and analytic gradients of f with respect to $p | ||||||
| 1063 | at the i_th evaluation point f (normally determined by the | ||||||
| 1064 | i_th element of t). A value of 1 means that the analytic and | ||||||
| 1065 | numeric gradients agree well. A value of 0 mean they do not | ||||||
| 1066 | agree. | ||||||
| 1067 | |||||||
| 1068 | Sometimes the number of evaluation points n is hardcoded | ||||||
| 1069 | into the function (as in almost all the examples taken from | ||||||
| 1070 | liblevmar and appearing in t/liblevmar.t. In this case the | ||||||
| 1071 | values that f returns depend only on $p and not on any other | ||||||
| 1072 | external data (nameley t). In this case, you must pass the | ||||||
| 1073 | number n as a perl scalar in place of t. For example | ||||||
| 1074 | |||||||
| 1075 | $err = levmar_chkjac($Gh,$p,5); | ||||||
| 1076 | |||||||
| 1077 | |||||||
| 1078 | in the case that f is hardcoded to return five values. | ||||||
| 1079 | 7 | 7 | 96 | ||||
| 7 | 21 | ||||||
| 7 | 329 | ||||||
| 1080 | 7 | 7 | 4423 | Need to put the description from the C code in here. | |||
| 7 | 214 | ||||||
| 7 | 127 | ||||||
| 1081 | 7 | 7 | 1310 | ||||
| 7 | 15 | ||||||
| 7 | 535 | ||||||
| 1082 | 7 | 7 | 5655 | =head2 levmar_report() | |||
| 7 | 189808 | ||||||
| 7 | 60 | ||||||
| 1083 | 7 | 7 | 4142992 | ||||
| 7 | 36 | ||||||
| 7 | 109 | ||||||
| 1084 | 7 | 25947 | =for ref | ||||
| 1085 | 7 | 7 | 1390 | ||||
| 7 | 12 | ||||||
| 1086 | Make a human readable report from the hash ref returned | ||||||
| 1087 | by levmar(). | ||||||
| 1088 | |||||||
| 1089 | =for usage | ||||||
| 1090 | |||||||
| 1091 | use PDL::Fit::Levmar; | ||||||
| 1092 | |||||||
| 1093 | $h = levmar($p,$x,$t, $func); | ||||||
| 1094 | 0 | 0 | 0 | 0 | |||
| 1095 | print levmar_report($h); | ||||||
| 1096 | |||||||
| 1097 | |||||||
| 1098 | =head1 BUGS | ||||||
| 1099 | |||||||
| 1100 | With the levmar-2.5 code: Passing workspace currently does not work with | ||||||
| 1101 | linear inequality constraint. Some of the PDL threading no long works | ||||||
| 1102 | correctly. These are noted in the tests in t/thread.t. It is not clear | ||||||
| 1103 | if it is a threading issue or the fitting has changed. | ||||||
| 1104 | |||||||
| 1105 | |||||||
| 1106 | =cut | ||||||
| 1107 | |||||||
| 1108 | #-------------------------------------------------------------------- | ||||||
| 1109 | # Begining of module code | ||||||
| 1110 | |||||||
| 1111 | use strict; | ||||||
| 1112 | use PDL::Fit::Levmar::Func; | ||||||
| 1113 | use Carp; | ||||||
| 1114 | use PDL::NiceSlice; | ||||||
| 1115 | use PDL::Core ':Internal'; # For topdl() | ||||||
| 1116 | use vars ( '$Levmar_defaults', '$Levmar_defaults_order', | ||||||
| 1117 | '$Perl_func_wrapper', '$Perl_jac_wrapper', '$LPPEXT', '$DBLMAX' ); | ||||||
| 1118 | |||||||
| 1119 | # 'jac' refers to jacobian | ||||||
| 1120 | $Perl_func_wrapper = get_perl_func_wrapper(); | ||||||
| 1121 | $Perl_jac_wrapper = get_perl_jac_wrapper(); | ||||||
| 1122 | $DBLMAX = get_dbl_max(); | ||||||
| 1123 | |||||||
| 1124 | $LPPEXT = ".lpp"; | ||||||
| 1125 | |||||||
| 1126 | |||||||
| 1127 | sub deb { print STDERR $_[0],"\n"} | ||||||
| 1128 | |||||||
| 1129 | ===EOD===top_pm=== | ||||||
| 1130 | |||||||
| 1131 | pp_addpm({At=>'Top'},"\$PDL::Fit::Levmar::HAVE_LAPACK=$HAVE_LAPACK;\n"); | ||||||
| 1132 | |||||||
| 1133 | pp_addpm({At=>'Bot'},<<'===EOD===Authors==='); | ||||||
| 1134 | |||||||
| 1135 | |||||||
| 1136 | =head1 AUTHORS | ||||||
| 1137 | |||||||
| 1138 | PDL code for Levmar Copyright (C) 2006 John Lapeyre. C | ||||||
| 1139 | library code Copyright (C) 2006 Manolis Lourakis, licensed | ||||||
| 1140 | here under the Gnu Public License. | ||||||
| 1141 | |||||||
| 1142 | All rights reserved. There is no warranty. You are allowed | ||||||
| 1143 | to redistribute this software / documentation under certain | ||||||
| 1144 | conditions. For details, see the file COPYING in the PDL | ||||||
| 1145 | distribution. If this file is separated from the PDL | ||||||
| 1146 | distribution, the copyright notice should be included in the | ||||||
| 1147 | file. | ||||||
| 1148 | |||||||
| 1149 | =cut | ||||||
| 1150 | |||||||
| 1151 | ===EOD===Authors=== | ||||||
| 1152 | |||||||
| 1153 | pp_addhdr(' | ||||||
| 1154 | #include |
||||||
| 1155 | #include |
||||||
| 1156 | #include |
||||||
| 1157 | #include |
||||||
| 1158 | #include "pdlperlfunc.h" | ||||||
| 1159 | #include "levmar.h" | ||||||
| 1160 | '); | ||||||
| 1161 | |||||||
| 1162 | |||||||
| 1163 | pp_add_exported('', 'levmar', 'levmar_report', 'levmar_chkjac'); | ||||||
| 1164 | |||||||
| 1165 | |||||||
| 1166 | pp_addpm(<<'===EOD===pm_code===one'); | ||||||
| 1167 | |||||||
| 1168 | 1 | 1 | 0 | 10 | |||
| 1169 | 1 | 18 | # check if dims are equal in two pdls | ||||
| 1170 | 1 | 16 | sub chk_eq_dims { | ||||
| 1171 | 1 | 50 | 19 | my ($x,$y) = @_; | |||
| 1172 | 1 | 3 | my (@xd) = $x->dims(); | ||||
| 1173 | 1 | 7 | my (@yd) = $y->dims(); | ||||
| 1174 | 1 | 50 | 11 | return -2 if (scalar(@xd) != scalar(@yd) ); | |||
| 1175 | my $ret = 1; | ||||||
| 1176 | 1 | 10 | foreach (@xd) { | ||||
| 1177 | return -1 if ($_ != shift(@yd) ); | ||||||
| 1178 | } | ||||||
| 1179 | return $ret; | ||||||
| 1180 | } | ||||||
| 1181 | |||||||
| 1182 | @PDL::Fit::Levmar::reason_for_terminating = ( | ||||||
| 1183 | '', | ||||||
| 1184 | 'stopped by small gradient J^T e', | ||||||
| 1185 | 'stopped by small Dp', | ||||||
| 1186 | 'stopped by itmax', | ||||||
| 1187 | 'singular matrix. Restart from current p with increased \mu', | ||||||
| 1188 | 'no further error reduction is possible. Restart with increased \mu', | ||||||
| 1189 | 'stopped by small ||e||_2' | ||||||
| 1190 | 8 | 8 | 1 | 13372 | ); | ||
| 1191 | 8 | 78 | |||||
| 1192 | sub levmar_report { | ||||||
| 1193 | my $h = shift; | ||||||
| 1194 | make_report($h->{P},$h->{COVAR}, $h->{INFO}); | ||||||
| 1195 | } | ||||||
| 1196 | 8 | 8 | 0 | 30 | |||
| 1197 | 8 | 81 | # make a small report out of the results of the optimization | ||||
| 1198 | sub make_report { | ||||||
| 1199 | my ($p,$covar,$info) = @_; | ||||||
| 1200 | my @ninf = list($info); | ||||||
| 1201 | 8 | 300 | # for(my $i=0;$i<9; $i++) { # Tried to get threading to work, but no! | ||||
| 1202 | # $ninf[$i] = $info(($i)); | ||||||
| 1203 | 8 | 22 | # } | ||||
| 1204 | $ninf[6] = | ||||||
| 1205 | $PDL::Fit::Levmar::reason_for_terminating[$ninf[6]]; # replace int with string | ||||||
| 1206 | my $form = <<"EOFORM"; | ||||||
| 1207 | Estimated parameters: %s | ||||||
| 1208 | Covariance: %s | ||||||
| 1209 | ||e||_2 at initial parameters = %g | ||||||
| 1210 | Errors at estimated parameters: | ||||||
| 1211 | ||e||_2\t = %g | ||||||
| 1212 | ||J^T e||_inf\t= %g | ||||||
| 1213 | ||Dp||_2\t= %g | ||||||
| 1214 | \\mu/max[J^T J]_ii ]\t= %g | ||||||
| 1215 | number of iterations\t= %d | ||||||
| 1216 | reason for termination: = %s | ||||||
| 1217 | number of function evaluations\t= %d | ||||||
| 1218 | number of jacobian evaluations\t= %d | ||||||
| 1219 | 8 | 219 | number of linear systems solved\t= %d | ||||
| 1220 | EOFORM | ||||||
| 1221 | my $st = sprintf($form, $p,$covar,@ninf); | ||||||
| 1222 | |||||||
| 1223 | } | ||||||
| 1224 | |||||||
| 1225 | $Levmar_defaults_order = qw [ | ||||||
| 1226 | FUNC | ||||||
| 1227 | |||||||
| 1228 | |||||||
| 1229 | ]; | ||||||
| 1230 | |||||||
| 1231 | |||||||
| 1232 | $Levmar_defaults = { | ||||||
| 1233 | MAXITS => 100, # maximum iterations | ||||||
| 1234 | MU => LM_INIT_MU(), | ||||||
| 1235 | EPS1 => LM_STOP_THRESH(), | ||||||
| 1236 | EPS2 => LM_STOP_THRESH(), | ||||||
| 1237 | EPS3 => LM_STOP_THRESH(), | ||||||
| 1238 | DELTA => LM_DIFF_DELTA(), | ||||||
| 1239 | DERIVATIVE => 'analytic', | ||||||
| 1240 | NOCOVAR => undef, | ||||||
| 1241 | FIX => undef, | ||||||
| 1242 | FIXB => undef, | ||||||
| 1243 | A => undef, | ||||||
| 1244 | B => undef, | ||||||
| 1245 | C => undef, | ||||||
| 1246 | D => undef, | ||||||
| 1247 | UB => undef, | ||||||
| 1248 | LB => undef, | ||||||
| 1249 | FUNC => undef, # Levmar::Func object, or function def, or ... | ||||||
| 1250 | JFUNC => undef, # must be ref to perl sub | ||||||
| 1251 | X => undef, | ||||||
| 1252 | P => undef, | ||||||
| 1253 | T => undef, | ||||||
| 1254 | WGHTS => undef, | ||||||
| 1255 | COVAR => undef, # The next 5 params can be set to PDL->null | ||||||
| 1256 | POUT => undef, # ref for preallocated output parameters | ||||||
| 1257 | INFO => undef, | ||||||
| 1258 | RET => undef, | ||||||
| 1259 | # meant to be private | ||||||
| 1260 | LFUNC => undef, # only Levmar::Func object, made from FUNC | ||||||
| 1261 | }; | ||||||
| 1262 | 0 | 0 | 0 | 0 | |||
| 1263 | # This isn't meant to replace help. But for now its doing nothing. | ||||||
| 1264 | sub get_help_str { | ||||||
| 1265 | return ' | ||||||
| 1266 | This is the help string for levmar. | ||||||
| 1267 | |||||||
| 1268 | '; | ||||||
| 1269 | } | ||||||
| 1270 | 91 | 91 | 1 | 4628173 | |||
| 1271 | 91 | 0 | ################################################################# | ||||
| 1272 | sub levmar { | ||||||
| 1273 | my($p,$x,$t,$infunc); | ||||||
| 1274 | my $args; | ||||||
| 1275 | 91 | 305 | # get all args before the hash. p,x,t must come in that order | ||||
| 1276 | 178 | 328 | # but (t), or (t and x), or (t,x,and p) can be in the hash | ||||
| 1277 | 178 | 100 | 66 | 1466 | # the function can be anywhere before the hash | ||
| 66 | |||||||
| 1278 | 86 | 171 | while (1) { | ||||
| 86 | 190 | ||||||
| 1279 | $args = 0; | ||||||
| 1280 | 178 | 50 | 550 | if ( (not defined $p ) and (ref($_[0]) eq 'PDL' or ref($_[0]) eq 'ARRAY')) { | |||
| 1281 | 178 | 100 | 66 | 2222 | $p = shift ; $args++; | ||
| 66 | |||||||
| 1282 | 78 | 210 | } | ||||
| 78 | 161 | ||||||
| 1283 | last if ( @_ == 0 ); | ||||||
| 1284 | 178 | 50 | 573 | if ( (not defined $x ) and (ref($_[0]) eq 'PDL' or ref($_[0]) eq 'ARRAY')) { | |||
| 1285 | 178 | 100 | 66 | 3424 | $x = shift ; $args++; | ||
| 66 | |||||||
| 1286 | 41 | 92 | } | ||||
| 41 | 124 | ||||||
| 1287 | last if ( @_ == 0 ); | ||||||
| 1288 | 178 | 100 | 694 | if ( (not defined $t) and (ref($_[0]) eq 'PDL' or ref($_[0]) eq 'ARRAY')) { | |||
| 1289 | 171 | 100 | 100 | 1146 | $t = shift ; $args++; | ||
| 1290 | 21 | 52 | } | ||||
| 21 | 32 | ||||||
| 1291 | last if ( @_ == 0 ); | ||||||
| 1292 | 171 | 100 | 391 | if ( not defined $infunc and ref($_[0]) =~ /Func|CODE/ ) { | |||
| 1293 | 168 | 100 | 66 | 2141 | $infunc = shift; $args++; | ||
| 66 | |||||||
| 66 | |||||||
| 1294 | } | ||||||
| 1295 | 8 | 19 | last if ( @_ == 0 ); | ||||
| 8 | 11 | ||||||
| 1296 | if ( (not defined $infunc) and | ||||||
| 1297 | 168 | 100 | 100 | 1305 | ( not ref($_[0]) ) and ( $_[0] =~ /(\.c|$LPPEXT)$/o or $_[0] =~ /\n/ ) ) { | ||
| 1298 | $infunc = shift; $args++; | ||||||
| 1299 | 91 | 123 | } | ||||
| 1300 | 91 | 100 | 489 | last if ( @_ == 0 or $args == 0); | |||
| 1301 | 91 | 100 | 247 | } | |||
| 1302 | 91 | 100 | 245 | my $inh; | |||
| 1303 | 80 | 50 | 759 | $inh = shift if @_; # input parameter hash | |||
| 1304 | $inh = {} unless defined $inh; | ||||||
| 1305 | 91 | 50 | 375 | if(ref $inh ne 'HASH') { # turn list into anonymous hash | |||
| 1306 | 0 | 0 | $inh = defined $inh ? {$inh,@_} : {} ; | ||||
| 1307 | 0 | 0 | } | ||||
| 1308 | if( exists $inh->{HELP} ) { | ||||||
| 1309 | 91 | 100 | 1384 | my $s = get_help_str(); | |||
| 1310 | 1 | 90 | return $s; | ||||
| 1311 | 1 | 14 | } | ||||
| 1312 | if( exists $inh->{GETOPTS} ) { | ||||||
| 1313 | my %h = %$Levmar_defaults; | ||||||
| 1314 | 90 | 100 | 251 | return \%h; | |||
| 1315 | } | ||||||
| 1316 | 90 | 50 | 66 | 2511 | # should already use a ref to string here | ||
| 1317 | $inh->{FUNC} = $infunc if defined $infunc; | ||||||
| 1318 | die "levmar: neither FUNC nor CSRC defined" | ||||||
| 1319 | unless defined $inh->{FUNC} or defined $inh->{CSRC}; | ||||||
| 1320 | |||||||
| 1321 | ===EOD===pm_code===one | ||||||
| 1322 | |||||||
| 1323 | if (not $HAVE_LAPACK) { | ||||||
| 1324 | 90 | 278 | pp_addpm( q! | ||||
| 1325 | foreach (qw( A B C D FIX WGHT )) { | ||||||
| 1326 | 540 | 50 | 1438 | barf "PDL::Fit::Levmar not built with lapack. Found parameter $_" | |||
| 1327 | if exists $inh->{$_}; | ||||||
| 1328 | } | ||||||
| 1329 | !) | ||||||
| 1330 | } | ||||||
| 1331 | |||||||
| 1332 | pp_addpm(<<'===EOD===pm_code===two'); | ||||||
| 1333 | |||||||
| 1334 | 90 | 192 | |||||
| 1335 | 90 | 161 | ######## Handle parameters | ||||
| 1336 | 90 | 2058 | my $h = {}; # parameter hash to be built from $inh and defaults | ||||
| 1337 | 2430 | 6949 | my $funch = {}; # unrecognized parameter hash. This will be passed to Func. | ||||
| 1338 | foreach ( keys %$Levmar_defaults ){ # copy defaults to final hash | ||||||
| 1339 | 90 | 731 | $h->{$_} = $Levmar_defaults->{$_}; | ||||
| 1340 | 234 | 100 | 464 | } | |||
| 1341 | 221 | 443 | foreach my $k (keys %$inh ) { # replace defaults with input params | ||||
| 1342 | if ( exists $Levmar_defaults->{$k} ) { | ||||||
| 1343 | $h->{$k} = $inh->{$k}; | ||||||
| 1344 | 13 | 49 | } | ||||
| 1345 | else { # don't recognize, so pass to Func | ||||||
| 1346 | $funch->{$k} = $inh->{$k}; | ||||||
| 1347 | } | ||||||
| 1348 | } | ||||||
| 1349 | ########## Set up input and output variables | ||||||
| 1350 | 90 | 100 | 66 | 747 | |||
| 1351 | 90 | 100 | 66 | 414 | # These must come from parameters if not from the arg list | ||
| 1352 | 90 | 100 | 66 | 427 | $p = $h->{P} unless not defined $h->{P} and defined $p; | ||
| 1353 | $x = $h->{X} unless not defined $h->{X} and defined $p; | ||||||
| 1354 | 90 | 50 | 207 | $t = $h->{T} unless not defined $h->{T} and defined $p; | |||
| 1355 | |||||||
| 1356 | 0 | 0 | if ( not defined $p ) { # This looks like some kind of error thing that was | ||||
| 1357 | 0 | 0 | # not implemented consistently | ||||
| 1358 | 0 | 0 | my $st = "No parameter (P) pdl"; | ||||
| 1359 | warn $st; | ||||||
| 1360 | 90 | 50 | 193 | return {RET => -1, ERRS => [$st] }; | |||
| 1361 | 0 | 0 | } | ||||
| 1362 | 0 | 0 | if ( not defined $x ) { | ||||
| 1363 | 0 | 0 | my $st = "No data (X) pdl"; | ||||
| 1364 | warn $st; | ||||||
| 1365 | return {RET => -1, ERRS => [$st] }; | ||||||
| 1366 | } | ||||||
| 1367 | |||||||
| 1368 | 90 | 638 | #------------------------------------------------- | ||||
| 1369 | 90 | 771 | # Treat input and output piddles for pp_defs | ||||
| 1370 | 90 | 100 | 533 | $x = topdl($x); # in case they are refs to arrays | |||
| 1371 | 90 | 1347 | $p = topdl($p); | ||||
| 1372 | $t = PDL->zeroes($p->type, 1) unless defined $t; # sometimes $t not needed | ||||||
| 1373 | 90 | 586 | $t = topdl($t); | ||||
| 1374 | ### output variables | ||||||
| 1375 | 90 | 0 | my $pout; | ||||
| 1376 | 90 | 0 | my $info; | ||||
| 1377 | 90 | 0 | my $covar; | ||||
| 1378 | my $ret; | ||||||
| 1379 | my $wghts; | ||||||
| 1380 | 90 | 100 | 250 | ||||
| 1381 | 90 | 50 | 222 | # should put this stuff in a loop | |||
| 1382 | 90 | 50 | 197 | $covar = $h->{COVAR} if defined $h->{COVAR}; | |||
| 1383 | 90 | 50 | 240 | $pout = $h->{POUT} if defined $h->{POUT}; | |||
| 1384 | 90 | 50 | 295 | $info = $h->{INFO} if defined $h->{INFO}; | |||
| 1385 | $ret = $h->{RET} if defined $h->{RET}; | ||||||
| 1386 | $wghts = $h->{WGHTS} if defined $h->{WGHTS}; | ||||||
| 1387 | 90 | 100 | 1600 | ||||
| 1388 | 90 | 50 | 1404 | # If they are set here, then there will be no external ref. | |||
| 1389 | 90 | 50 | 1126 | $covar = PDL->null unless defined $covar; | |||
| 1390 | 90 | 50 | 916 | $pout = PDL->null unless defined $pout; | |||
| 1391 | 90 | 50 | 879 | $info = PDL->null unless defined $info; | |||
| 1392 | $ret = PDL->null unless defined $ret; | ||||||
| 1393 | $wghts = PDL->null unless defined $wghts; | ||||||
| 1394 | |||||||
| 1395 | # Careful about $m, it is used in construcing $A below (with fix). But this is | ||||||
| 1396 | 90 | 1007 | # not correct when using implicit threading. Except threading may still be working. | ||||
| 1397 | # Need to look into that. | ||||||
| 1398 | my $m = $p->nelem; | ||||||
| 1399 | |||||||
| 1400 | #-------------------------------------------------------- | ||||||
| 1401 | 90 | 50 | 340 | # Set up Func object | |||
| 1402 | 90 | 100 | 100 | 987 | #-------------------------------------------------------- | ||
| 1403 | croak "No FUNC in options to levmar." unless exists $h->{FUNC}; | ||||||
| 1404 | 63 | 252 | if ( ref($h->{FUNC}) =~ /CODE/ or | ||||
| 1405 | 63 | 368 | not ref($h->{FUNC}) ) { # probably a string, convert to func object | ||||
| 1406 | 63 | 50 | 10716003 | $funch->{FUNC} = $h->{FUNC}; | |||
| 1407 | 0 | 0 | my @ret = PDL::Fit::Levmar::Func::levmar_func($funch); | ||||
| 1408 | if ($ret[0] == -1 ) { # error in creating function | ||||||
| 1409 | 0 | 0 | shift(@ret); | ||||
| 1410 | # deb "Error: " . join("\n",@ret); # can turn this off and on | ||||||
| 1411 | 63 | 642 | return {RET => -1, ERRS => [@ret] } ; # just return all the other messages. | ||||
| 1412 | } | ||||||
| 1413 | $h->{LFUNC} = $ret[0]; | ||||||
| 1414 | 27 | 96 | } | ||||
| 1415 | 27 | 81 | else { # already a Func object | ||||
| 1416 | $h->{LFUNC} = $h->{FUNC} ; # copy ref | ||||||
| 1417 | my @k = keys %$funch; | ||||||
| 1418 | # It would be good to check for valid options. But if a user switches from a | ||||||
| 1419 | # string to a Func oject in the call to levmar(), he may not delete the | ||||||
| 1420 | 27 | 50 | 84 | # other keys. Halting on an error would bit frustrating or puzzling. | |||
| 1421 | 0 | 0 | 0 | # Even a warning is perhaps too much | |||
| 0 | 0 | ||||||
| 1422 | 0 | 0 | if ( @k ) { | ||||
| 1423 | 0 | 0 | my $s = ''; $s = 's' if @k>1; | ||||
| 1424 | 0 | 0 | my $str = "Unrecognized or useless option$s to levmar: \n"; | ||||
| 1425 | foreach ( @k ) { | ||||||
| 1426 | 0 | 0 | $str .= " '$_' => '" . $funch->{$_} . "'\n" ; | ||||
| 1427 | } | ||||||
| 1428 | warn $str .""; | ||||||
| 1429 | } | ||||||
| 1430 | } | ||||||
| 1431 | 90 | 649 | # C pointers to fit functions | ||||
| 1432 | 90 | 1463 | my ($funcn,$sfuncn,$jacn,$sjacn) = # single and double | ||||
| 1433 | $h->{LFUNC}->get_fit_pointers(); | ||||||
| 1434 | my $deriv = $h->{DERIVATIVE}; | ||||||
| 1435 | |||||||
| 1436 | 90 | 292 | # The DFP stuff is to wrap perl functions in C routines to pass to liblevmar. | ||||
| 1437 | # It's probably cleaner to move most of this stuff into Levmar::Func | ||||||
| 1438 | 90 | 100 | 687 | my $DFP = 0; # routines check for $DFP == 0 to bypass perl wrapper | |||
| 1439 | 8 | 15 | |||||
| 1440 | 8 | 75 | if ( ref($h->{FUNC}) =~ /CODE/) { # setup perl wrapper stuff | ||||
| 1441 | 8 | 100 | 66 | 95 | my $jfunc = 0; | ||
| 1442 | 6 | 16 | $DFP = DFP_create(); | ||||
| 1443 | if (defined $h->{JFUNC} and ref($h->{JFUNC}) =~ /CODE/) { | ||||||
| 1444 | 8 | 100 | 100 | 50 | $jfunc = $h->{JFUNC}; | ||
| 1445 | } | ||||||
| 1446 | 2 | 4 | if ( $deriv eq 'analytic' and $jfunc == 0 ) { | ||||
| 1447 | 2 | 2 | # warn "No jacobian function supplied, using numeric derivatives"; | ||||
| 1448 | $deriv = 'numeric'; | ||||||
| 1449 | 8 | 45 | $h->{DERIVATIVE} = 'numeric'; | ||||
| 1450 | 8 | 13 | } | ||||
| 1451 | 8 | 12 | DFP_set_perl_funcs($DFP, $h->{FUNC}, $h->{JFUNC}); | ||||
| 1452 | 8 | 10 | $funcn = $Perl_func_wrapper; | ||||
| 1453 | 8 | 14 | $jacn = $Perl_jac_wrapper; | ||||
| 1454 | $sfuncn = $Perl_func_wrapper; # Single and double can use same wrapper | ||||||
| 1455 | $sjacn = $Perl_jac_wrapper; | ||||||
| 1456 | } | ||||||
| 1457 | |||||||
| 1458 | 90 | 100 | 587 | ############ Do a few sanity checks | |||
| 50 | |||||||
| 1459 | 71 | 100 | 66 | 898 | |||
| 1460 | if ( $deriv eq 'analytic' ) { | ||||||
| 1461 | 1 | 15 | if (not defined $jacn or $jacn == 0 ) { | ||||
| 1462 | 1 | 35 | # warn "No jacobian function supplied, using numeric derivatives"; | ||||
| 1463 | $deriv = 'numeric'; | ||||||
| 1464 | $h->{DERIVATIVE} = 'numeric'; | ||||||
| 1465 | } | ||||||
| 1466 | 0 | 0 | } | ||||
| 1467 | elsif ( $deriv ne 'numeric' ) { | ||||||
| 1468 | croak "DERIVATIVE must be 'analytic' or 'numeric'"; | ||||||
| 1469 | } | ||||||
| 1470 | |||||||
| 1471 | # liblevmar uses 5 option for analytic and 6 for numeric. | ||||||
| 1472 | 90 | 100 | 1610 | my $opts = pdl($p->type, @$h{qw(MU EPS1 EPS2 EPS3)}, | |||
| 1473 | $h->{DERIVATIVE} eq 'analytic' ? () : $h->{DELTA} | ||||||
| 1474 | 90 | 13306 | ); | ||||
| 1475 | # We make an integer option array as well, for passing stuff , like maxits. | ||||||
| 1476 | my $iopts = pdl(long, $h->{MAXITS}); | ||||||
| 1477 | |||||||
| 1478 | ########### FIX holds some parameters constant using linear constraints. | ||||||
| 1479 | # It is a special case of more general constraints using A and b. | ||||||
| 1480 | # Notice that this fails if FIX has more than one dimension (ie, you are | ||||||
| 1481 | 90 | 50 | 6979 | # threading. FIXB does the same but using box constraints. | |||
| 100 | |||||||
| 1482 | 0 | 0 | |||||
| 1483 | 0 | 0 | 0 | if (defined $h->{FIX} ) { | |||
| 1484 | 0 | 0 | my $ip = topdl( $h->{FIX}); # take array ref or pdl | ||||
| 1485 | if ( chk_eq_dims($ip,$p) < 0 ) { | ||||||
| 1486 | 0 | 0 | croak "p and FIX must have the same dimensions"; | ||||
| 1487 | 0 | 0 | 0 | } | |||
| 1488 | 0 | 0 | my $nc = $ip->sum; # number of fixed vars | ||||
| 1489 | 0 | 0 | if ($nc > 0) { | ||||
| 1490 | 0 | 0 | my $A = zeroes($p->type, $m,$nc); | ||||
| 1491 | 0 | 0 | my $b = zeroes($p->type, $nc); | ||||
| 1492 | 0 | 0 | 0 | my $j=0; | |||
| 1493 | 0 | 0 | for(my $i=0; $i<$m; $i++) { | ||||
| 1494 | 0 | 0 | if ($ip->at($i) == 1) { | ||||
| 1495 | 0 | 0 | $A($i,$j) .= 1; | ||||
| 1496 | $b($j) .= $p->at($i); | ||||||
| 1497 | $j++; | ||||||
| 1498 | 0 | 0 | } | ||||
| 1499 | 0 | 0 | } | ||||
| 1500 | $h->{A} = $A; | ||||||
| 1501 | $h->{B} = $b; | ||||||
| 1502 | } | ||||||
| 1503 | 1 | 30 | } | ||||
| 1504 | 1 | 50 | 162 | elsif ( defined $h->{FIXB} ) { | |||
| 1505 | 0 | 0 | my $f = topdl( $h->{FIXB}); # take array ref or pdl | ||||
| 1506 | if ( chk_eq_dims($f,$p) < 0 ) { | ||||||
| 1507 | 1 | 50 | 12 | croak "p and FIX must have the same dimensions"; | |||
| 1508 | 1 | 50 | 4 | } | |||
| 1509 | 1 | 14 | $h->{UB} = ones($p) * $DBLMAX if not defined $h->{UB}; | ||||
| 1510 | 1 | 120 | $h->{LB} = ones($p) * -$DBLMAX if not defined $h->{LB}; | ||||
| 1511 | 1 | 454 | $_ = topdl($_) for @$h{qw(UB LB)}; | ||||
| 1512 | 1 | 391 | my $fi = PDL::Primitive::which($f == 1); # indices in p that we want to fix. | ||||
| 1513 | $h->{UB}->flat->index($fi) .= $p->flat->index($fi); | ||||||
| 1514 | $h->{LB}->flat->index($fi) .= $p->flat->index($fi); | ||||||
| 1515 | # so ub and lb are now at maximum bounds where not fixed and at value of | ||||||
| 1516 | 90 | 394 | # p where fixed | ||||
| 1517 | 90 | 50 | 1539 | } | |||
| 1518 | 0 | 0 | my $want_covar = 1; | ||||
| 1519 | if ( defined $h->{NOCOVAR} ) { | ||||||
| 1520 | $want_covar = 0; | ||||||
| 1521 | 90 | 2583 | } | ||||
| 1522 | 90 | 50 | 272 | ||||
| 1523 | my $errs = check_levmar_args($h); | ||||||
| 1524 | 0 | 0 | if ( @$errs > 0 ) { | ||||
| 1525 | # print @$errs; | ||||||
| 1526 | 90 | 326 | return {RET => -1, ERRS => $errs }; | ||||
| 1527 | } | ||||||
| 1528 | 90 | 50 | 254 | my ($func_key, $arg_list) = build_constraint_arg_combination($h); | |||
| 1529 | 0 | 0 | # print "func key '$func_key'\n"; | ||||
| 1530 | if ( not defined $func_key ) { | ||||||
| 1531 | 90 | 50 | 382 | croak "Could not find function key"; | |||
| 1532 | 0 | 0 | } | ||||
| 1533 | if ( not exists $PDL::Fit::Levmar::PDL_Levmar_funcs{$func_key} ) { | ||||||
| 1534 | 90 | 345 | croak "Could not find function for key"; | ||||
| 1535 | } | ||||||
| 1536 | my $pdl_levmar_func = $PDL::Fit::Levmar::PDL_Levmar_funcs{$func_key}; | ||||||
| 1537 | # print "func $pdl_levmar_func\n"; | ||||||
| 1538 | # my $nargs = @$arg_list; | ||||||
| 1539 | # print "Got $nargs args\n"; | ||||||
| 1540 | 90 | 100 | 468727 | &$pdl_levmar_func($p,$x,$t,@$arg_list,$iopts,$opts, | |||
| 1541 | $covar, $ret, $pout, $info, $funcn, $sfuncn, | ||||||
| 1542 | ($h->{DERIVATIVE} eq 'analytic' ? ( $jacn, $sjacn ) : ()), | ||||||
| 1543 | 90 | 100 | 26674330 | $DFP, $want_covar); | |||
| 1544 | |||||||
| 1545 | DFP_free($DFP) if $DFP; | ||||||
| 1546 | |||||||
| 1547 | my $hout = { | ||||||
| 1548 | RET => $ret, | ||||||
| 1549 | COVAR => $covar, | ||||||
| 1550 | P => $pout, | ||||||
| 1551 | ERRI => $info((0)), | ||||||
| 1552 | ERR1 => $info((1)), | ||||||
| 1553 | ERR2 => $info((2)), | ||||||
| 1554 | ERR3 => $info((3)), | ||||||
| 1555 | ERR4 => $info((4)), | ||||||
| 1556 | ITS => $info((5)), | ||||||
| 1557 | REASON => $info((6)), | ||||||
| 1558 | NFUNC => $info((7)), | ||||||
| 1559 | NJAC => $info((8)), | ||||||
| 1560 | NLS => $info((9)), | ||||||
| 1561 | 90 | 1986 | INFO => $info, | ||||
| 1562 | 90 | 44076 | FUNC => $h->{LFUNC}, | ||||
| 1563 | }; | ||||||
| 1564 | return $hout; | ||||||
| 1565 | |||||||
| 1566 | } # end levmar() | ||||||
| 1567 | 90 | 90 | 0 | 283 | |||
| 1568 | 90 | 1380 | |||||
| 1569 | 90 | 217 | sub PDL::Fit::Levmar::check_levmar_args { | ||||
| 1570 | 90 | 418 | my ($h) = @_; | ||||
| 1571 | 540 | 100 | 66 | 2385 | my @refargs = qw( LB UB A B C D ); | ||
| 1572 | 30 | 89 | my @errs = (); | ||||
| 1573 | 30 | 50 | 145 | foreach my $argname ( @refargs ) { | |||
| 1574 | 0 | 0 | if ( exists $h->{$argname} and defined $h->{$argname} ) { | ||||
| 1575 | my $arg = $h->{$argname}; | ||||||
| 1576 | if ( not ref($arg) ) { | ||||||
| 1577 | push @errs, "$argname must be a pdl or ref to array."; | ||||||
| 1578 | 90 | 736 | } | ||||
| 1579 | 90 | 199 | } | ||||
| 1580 | 180 | 463 | } | ||||
| 1581 | 180 | 274 | my @combs = ( [ 'A', 'B' ], [ 'C', 'D' ] ); | ||||
| 1582 | 180 | 323 | foreach my $comb (@combs ) { | ||||
| 1583 | 360 | 50 | 33 | 1606 | my $n = @$comb; | ||
| 1584 | my $nf = 0; | ||||||
| 1585 | 180 | 50 | 33 | 546 | foreach my $arg ( @$comb ) { | ||
| 1586 | 0 | 0 | $nf++ if exists $h->{$arg} and defined $h->{$arg}; | ||||
| 1587 | } | ||||||
| 1588 | if ( $nf != 0 and $n != $nf ) { | ||||||
| 1589 | 90 | 464 | push @errs, 'none or all of ' . join(' and ',@$comb) . ' must be defined.'; | ||||
| 1590 | } | ||||||
| 1591 | } | ||||||
| 1592 | return \@errs; | ||||||
| 1593 | } | ||||||
| 1594 | |||||||
| 1595 | |||||||
| 1596 | # make a list of strings of names of constraint args that | ||||||
| 1597 | 90 | 90 | 0 | 225 | # have been passed. | ||
| 1598 | 90 | 229 | # hash is arg hash to top level call | ||||
| 1599 | 90 | 247 | sub PDL::Fit::Levmar::build_constraint_arg_combination { | ||||
| 1600 | my ($h) = @_; | ||||||
| 1601 | 90 | 1117 | my @arg_comb = (); | ||||
| 1602 | 90 | 328 | my @arg_list = (); | ||||
| 1603 | 540 | 1302 | # order is important in following | ||||
| 1604 | my @possible_args = qw( LB UB A B C D ); | ||||||
| 1605 | 540 | 100 | 66 | 2065 | foreach ( @possible_args ) { | ||
| 1606 | 30 | 78 | my $ucarg = $_; | ||||
| 1607 | 30 | 233 | # $ucarg =~ tr/a-z/A-Z/; # should rewrite so that tr not needed | ||||
| 1608 | if ( exists $h->{$ucarg} and defined $h->{$ucarg} ) { | ||||||
| 1609 | push @arg_comb, $_; | ||||||
| 1610 | 90 | 180 | push @arg_list, topdl($h->{$ucarg}); | ||||
| 1611 | 90 | 100 | 315 | } | |||
| 1612 | 70 | 226 | } | ||||
| 1613 | my $deriv_type; | ||||||
| 1614 | if ($h->{DERIVATIVE} eq 'analytic' ) { | ||||||
| 1615 | 20 | 115 | $deriv_type = 'DER'; | ||||
| 1616 | } | ||||||
| 1617 | 90 | 50 | 33 | 727 | else { | ||
| 1618 | 90 | 478 | $deriv_type = 'DIFF'; | ||||
| 1619 | 90 | 535 | } | ||||
| 1620 | push @arg_list, topdl($h->{WGHTS}) if exists $h->{WGHTS} and defined $h->{WGHTS}; | ||||||
| 1621 | my $fk = make_pdl_levmar_func_key(make_hash_key_from_arg_comb(\@arg_comb), $deriv_type); | ||||||
| 1622 | return ($fk,\@arg_list); | ||||||
| 1623 | 90 | 90 | 0 | 227 | } | ||
| 1624 | 90 | 746 | |||||
| 1625 | sub PDL::Fit::Levmar::make_hash_key_from_arg_comb { | ||||||
| 1626 | my ( $arg_comb ) = @_; | ||||||
| 1627 | return join( '_', @$arg_comb); | ||||||
| 1628 | 90 | 90 | 0 | 293 | } | ||
| 1629 | 90 | 438 | |||||
| 1630 | |||||||
| 1631 | sub PDL::Fit::Levmar::make_pdl_levmar_func_key { | ||||||
| 1632 | my ($arg_str, $deriv_type) = @_; | ||||||
| 1633 | return $deriv_type . '_' . $arg_str; | ||||||
| 1634 | } | ||||||
| 1635 | |||||||
| 1636 | |||||||
| 1637 | %PDL::Fit::Levmar::PDL_Levmar_funcs = ( | ||||||
| 1638 | DER_ => \&PDL::levmar_der_, | ||||||
| 1639 | DIFF_ => \&PDL::levmar_diff_, | ||||||
| 1640 | DER_LB_C_D => \&PDL::levmar_der_lb_C_d, | ||||||
| 1641 | DIFF_LB_C_D => \&PDL::levmar_diff_lb_C_d, | ||||||
| 1642 | DER_A_B => \&PDL::levmar_der_A_b, | ||||||
| 1643 | DIFF_A_B => \&PDL::levmar_diff_A_b, | ||||||
| 1644 | DER_UB_A_B => \&PDL::levmar_der_ub_A_b, | ||||||
| 1645 | DIFF_UB_A_B => \&PDL::levmar_diff_ub_A_b, | ||||||
| 1646 | DER_UB => \&PDL::levmar_der_ub, | ||||||
| 1647 | DIFF_UB => \&PDL::levmar_diff_ub, | ||||||
| 1648 | DER_A_B_C_D => \&PDL::levmar_der_A_b_C_d, | ||||||
| 1649 | DIFF_A_B_C_D => \&PDL::levmar_diff_A_b_C_d, | ||||||
| 1650 | DER_LB_UB_A_B_C_D => \&PDL::levmar_der_lb_ub_A_b_C_d, | ||||||
| 1651 | DIFF_LB_UB_A_B_C_D => \&PDL::levmar_diff_lb_ub_A_b_C_d, | ||||||
| 1652 | DER_LB => \&PDL::levmar_der_lb, | ||||||
| 1653 | DIFF_LB => \&PDL::levmar_diff_lb, | ||||||
| 1654 | DER_LB_A_B_C_D => \&PDL::levmar_der_lb_A_b_C_d, | ||||||
| 1655 | DIFF_LB_A_B_C_D => \&PDL::levmar_diff_lb_A_b_C_d, | ||||||
| 1656 | DER_UB_A_B_C_D => \&PDL::levmar_der_ub_A_b_C_d, | ||||||
| 1657 | DIFF_UB_A_B_C_D => \&PDL::levmar_diff_ub_A_b_C_d, | ||||||
| 1658 | DER_LB_UB => \&PDL::levmar_der_lb_ub, | ||||||
| 1659 | DIFF_LB_UB => \&PDL::levmar_diff_lb_ub, | ||||||
| 1660 | DER_LB_A_B => \&PDL::levmar_der_lb_A_b, | ||||||
| 1661 | DIFF_LB_A_B => \&PDL::levmar_diff_lb_A_b, | ||||||
| 1662 | DER_UB_C_D => \&PDL::levmar_der_ub_C_d, | ||||||
| 1663 | DIFF_UB_C_D => \&PDL::levmar_diff_ub_C_d, | ||||||
| 1664 | DER_LB_UB_A_B => \&PDL::levmar_der_lb_ub_A_b, | ||||||
| 1665 | DIFF_LB_UB_A_B => \&PDL::levmar_diff_lb_ub_A_b, | ||||||
| 1666 | DER_LB_UB_C_D => \&PDL::levmar_der_lb_ub_C_d, | ||||||
| 1667 | DIFF_LB_UB_C_D => \&PDL::levmar_diff_lb_ub_C_d, | ||||||
| 1668 | 4 | 4 | 1 | 565702 | DER_C_D => \&PDL::levmar_der_C_d, | ||
| 1669 | 4 | 20 | DIFF_C_D => \&PDL::levmar_diff_C_d, | ||||
| 1670 | 4 | 50 | 30 | ); | |||
| 1671 | 0 | 0 | |||||
| 1672 | 0 | 0 | |||||
| 1673 | |||||||
| 1674 | 4 | 14 | |||||
| 1675 | 4 | 50 | 58 | sub levmar_chkjac { | |||
| 1676 | 0 | 0 | my ($f,$p,$t) = @_; | ||||
| 1677 | 0 | 0 | my $r = ref $f; | ||||
| 0 | 0 | ||||||
| 1678 | if ( not $r =~ /Levmar::Func/ ) { | ||||||
| 1679 | 4 | 13 | warn "levmar_chkjac: not a Levmar::Func object "; | ||||
| 1680 | 4 | 14 | return; | ||||
| 1681 | 4 | 100 | 17 | } | |||
| 1682 | 2 | 3 | my $N; | ||||
| 1683 | 2 | 13 | if ( not ref($t) =~ /PDL/ ) { | ||||
| 1684 | 2 | 50 | 33 | 21 | $N = $t; # in case there is no t for this func | ||
| 1685 | 0 | 0 | $t = zeroes( $p->type, 1); just some pdl | ||||
| 1686 | 0 | 0 | } | ||||
| 1687 | my $DFP = 0; | ||||||
| 1688 | 2 | 7 | my ($funcn,$sfuncn,$jacn,$sjacn); | ||||
| 1689 | 2 | 3 | if ( ref($f->{FUNC}) =~ /CODE/) { # setup perl wrapper stuff | ||||
| 1690 | 2 | 6 | my $jfunc = 0; | ||||
| 1691 | 2 | 2 | $DFP = DFP_create(); | ||||
| 1692 | 2 | 3 | if (not (defined $f->{JFUNC} and ref($f->{FUNC}) =~ /CODE/ ) ) { | ||||
| 1693 | warn "levmar_chkjac: no perl code jacobian supplied in JFUNC."; | ||||||
| 1694 | return undef; | ||||||
| 1695 | 2 | 27 | } | ||||
| 1696 | DFP_set_perl_funcs($DFP, $f->{FUNC}, $f->{JFUNC}); | ||||||
| 1697 | $funcn = $Perl_func_wrapper; | ||||||
| 1698 | 4 | 21 | $jacn = $Perl_jac_wrapper; | ||||
| 1699 | 4 | 50 | 14 | $sfuncn = $Perl_func_wrapper; | |||
| 1700 | 0 | 0 | $sjacn = $Perl_jac_wrapper; | ||||
| 1701 | } | ||||||
| 1702 | else { # pointers to native c functions. | ||||||
| 1703 | 4 | 196 | ($funcn,$sfuncn,$jacn,$sjacn) = | ||||
| 1704 | $f->get_fit_pointers(); | ||||||
| 1705 | 4 | 1125 | } | ||||
| 1706 | 4 | 10 | my $err; | ||||
| 1707 | if ( defined $N ) { | ||||||
| 1708 | $err = _levmar_chkjac_no_t($p,$funcn,$sfuncn,$jacn,$sjacn,$N,$DFP); | ||||||
| 1709 | } | ||||||
| 1710 | else { | ||||||
| 1711 | $err = _levmar_chkjac($p,$t,$funcn,$sfuncn,$jacn,$sjacn,$DFP); | ||||||
| 1712 | } | ||||||
| 1713 | DFP_free($DFP); | ||||||
| 1714 | return $err; | ||||||
| 1715 | } | ||||||
| 1716 | |||||||
| 1717 | ===EOD===pm_code===two | ||||||
| 1718 | |||||||
| 1719 | =pod | ||||||
| 1720 | |||||||
| 1721 | =begin comment | ||||||
| 1722 | |||||||
| 1723 | The following comments are not intended to appear in documentation. | ||||||
| 1724 | But short of removing them, I find it impossible to keep them from | ||||||
| 1725 | appearing in the documentation. | ||||||
| 1726 | |||||||
| 1727 | The following provides an interface to 12 functions in | ||||||
| 1728 | liblevmar. 2 (float or double) * 2 (numeric or analytic) | ||||||
| 1729 | * 3 (bc, lec, no constraint). There are 6 pp_defs. pp | ||||||
| 1730 | takes care of the float , double code itself (with some | ||||||
| 1731 | macros) You can't nest pp macros, so I use DUMI below. | ||||||
| 1732 | Note that I put a conditional in the thread loop. Not a | ||||||
| 1733 | big deal, I think, because the threadloop is calling a big | ||||||
| 1734 | routine with lots of conditionals and lots of calls to | ||||||
| 1735 | other similar routines. | ||||||
| 1736 | |||||||
| 1737 | I pass pdl of type long iopts for some | ||||||
| 1738 | parameters. Currently only maxits is there. I suppose I | ||||||
| 1739 | could also put want_covar in there, but now its an other | ||||||
| 1740 | parameter. Whatever is in iopts can be threaded. I suppose | ||||||
| 1741 | someone might want to thread whether to compute | ||||||
| 1742 | covariance. | ||||||
| 1743 | |||||||
| 1744 | =end comment | ||||||
| 1745 | |||||||
| 1746 | =cut | ||||||
| 1747 | |||||||
| 1748 | # Note very carefully the placement of trailing commas and semi-colons here. | ||||||
| 1749 | |||||||
| 1750 | sub find_levmar_func_name_from_args { | ||||||
| 1751 | my ($arglist, $arg_descr) = @_; | ||||||
| 1752 | my %seen = (); | ||||||
| 1753 | my $nargs = @$arglist; | ||||||
| 1754 | my $max_seen = 0; | ||||||
| 1755 | foreach my $arg ( @$arglist ) { | ||||||
| 1756 | foreach my $routine ( @{ $arg_descr->{$arg}->{ALLOWEDIN} } ) { | ||||||
| 1757 | $seen{$routine}++; | ||||||
| 1758 | $max_seen = $seen{$routine} if $max_seen < $seen{$routine}; | ||||||
| 1759 | } | ||||||
| 1760 | } | ||||||
| 1761 | my @routine_priority = qw( bc lec blec bleic ); | ||||||
| 1762 | my $routine = 'none'; | ||||||
| 1763 | foreach my $try_routine ( @routine_priority ) { | ||||||
| 1764 | if ( exists $seen{$try_routine} and $seen{$try_routine} == $max_seen ) { | ||||||
| 1765 | $routine = $try_routine; | ||||||
| 1766 | last; | ||||||
| 1767 | } | ||||||
| 1768 | } | ||||||
| 1769 | # print join(':',@$arglist)," => "; | ||||||
| 1770 | # print $routine, "\n"; | ||||||
| 1771 | return $routine; | ||||||
| 1772 | } | ||||||
| 1773 | |||||||
| 1774 | sub make_hash_key_from_arg_comb { | ||||||
| 1775 | my ( $arg_comb ) = @_; | ||||||
| 1776 | return join( '_', @$arg_comb); | ||||||
| 1777 | } | ||||||
| 1778 | |||||||
| 1779 | # Make the string for Pars => | ||||||
| 1780 | sub make_constraint_signature { | ||||||
| 1781 | my ( $arg_comb, $arg_descr ) = @_; | ||||||
| 1782 | my $sig_str = ''; | ||||||
| 1783 | foreach my $arg ( @$arg_comb ) { | ||||||
| 1784 | $sig_str .= $arg_descr->{$arg}->{SIGNATURE} . '; '; | ||||||
| 1785 | } | ||||||
| 1786 | $sig_str =~ s/;\s$//; | ||||||
| 1787 | return $sig_str; | ||||||
| 1788 | } | ||||||
| 1789 | |||||||
| 1790 | sub array_to_hash { | ||||||
| 1791 | my ($a) = @_; | ||||||
| 1792 | my $h = {}; | ||||||
| 1793 | foreach ( @$a) { | ||||||
| 1794 | $h->{$_} = 1; | ||||||
| 1795 | } | ||||||
| 1796 | return $h; | ||||||
| 1797 | } | ||||||
| 1798 | |||||||
| 1799 | # not working now, | ||||||
| 1800 | # need to use $levmar_routine_description | ||||||
| 1801 | # below to build correct call arguments | ||||||
| 1802 | # test if arg is present in arg_comb and write NULL , if not | ||||||
| 1803 | sub make_constraint_call_args { | ||||||
| 1804 | my ( $arg_comb, $arg_descr, $levmar_routine_description, $levmar_funtion_name ) = @_; | ||||||
| 1805 | my $route_descr = $levmar_routine_description->{$levmar_funtion_name}; | ||||||
| 1806 | my $args = $route_descr->{ARGS}; | ||||||
| 1807 | my $reqr = {}; | ||||||
| 1808 | my $arg_comb_hash = array_to_hash($arg_comb); | ||||||
| 1809 | $reqr = $route_descr->{REQR} if exists $route_descr->{REQR}; | ||||||
| 1810 | my $call_str = ''; | ||||||
| 1811 | foreach my $arg ( @$args ) { | ||||||
| 1812 | if ( exists $reqr->{$arg}) { | ||||||
| 1813 | if ( exists $arg_comb_hash->{$reqr->{$arg}} ) { | ||||||
| 1814 | $call_str .= "$arg,"; | ||||||
| 1815 | } | ||||||
| 1816 | else { | ||||||
| 1817 | $call_str .= '0,'; | ||||||
| 1818 | } | ||||||
| 1819 | next; | ||||||
| 1820 | } | ||||||
| 1821 | if ( not exists $arg_comb_hash->{$arg} ) { | ||||||
| 1822 | $call_str .= 'NULL,'; | ||||||
| 1823 | next; | ||||||
| 1824 | } | ||||||
| 1825 | $call_str .= $arg_descr->{$arg}->{CALLARG} . ', '; | ||||||
| 1826 | } | ||||||
| 1827 | # $call_str =~ s/,\s$//; | ||||||
| 1828 | return $call_str; | ||||||
| 1829 | } | ||||||
| 1830 | |||||||
| 1831 | # We will write 64 (perhaps) pdl function definitions. | ||||||
| 1832 | # For each constraint option (A,b,C... etc) we have the following: | ||||||
| 1833 | # SIGNATURE is the string that is part of the ppdef pdl signature | ||||||
| 1834 | # CALLARG is the pp_def argument in the call to the C routine | ||||||
| 1835 | # ALLOWEDIN is the list of levmar C routines that take this constraint as an argument | ||||||
| 1836 | sub make_argument_combinations { | ||||||
| 1837 | my $arg_descr = { | ||||||
| 1838 | A => { | ||||||
| 1839 | SIGNATURE => 'A(m,k)', | ||||||
| 1840 | CALLARG => '$P(A)', | ||||||
| 1841 | ALLOWEDIN => [qw( lec blec bleic )], | ||||||
| 1842 | }, | ||||||
| 1843 | b => { | ||||||
| 1844 | SIGNATURE => 'b(k)', | ||||||
| 1845 | CALLARG => '$P(b)', | ||||||
| 1846 | ALLOWEDIN => [qw( lec blec bleic )], | ||||||
| 1847 | }, | ||||||
| 1848 | ub => { | ||||||
| 1849 | SIGNATURE => 'ub(m)', | ||||||
| 1850 | CALLARG => '$P(ub)', | ||||||
| 1851 | ALLOWEDIN => [qw( bc blec bleic )], | ||||||
| 1852 | }, | ||||||
| 1853 | lb => { | ||||||
| 1854 | SIGNATURE => 'lb(m)', | ||||||
| 1855 | CALLARG => '$P(lb)', | ||||||
| 1856 | ALLOWEDIN => [qw( bc blec bleic )], | ||||||
| 1857 | }, | ||||||
| 1858 | C => { | ||||||
| 1859 | SIGNATURE => 'C(m,k2)', | ||||||
| 1860 | CALLARG => '$P(C)', | ||||||
| 1861 | ALLOWEDIN => [qw( bleic )], | ||||||
| 1862 | }, | ||||||
| 1863 | d => { | ||||||
| 1864 | SIGNATURE => 'd(k2)', | ||||||
| 1865 | CALLARG => '$P(d)', | ||||||
| 1866 | ALLOWEDIN => [qw( bleic )], | ||||||
| 1867 | }, | ||||||
| 1868 | # WGHTS => { | ||||||
| 1869 | # SIGNATURE => 'wghts(m)', | ||||||
| 1870 | # CALLARG => '$P(wghts)', | ||||||
| 1871 | # ALLOWEDIN => [qw( blec )], | ||||||
| 1872 | # }, | ||||||
| 1873 | }; | ||||||
| 1874 | |||||||
| 1875 | my $levmar_routine_description = { | ||||||
| 1876 | none => { ARGS => [] }, | ||||||
| 1877 | bc => { ARGS => [qw( lb ub )] }, | ||||||
| 1878 | lec => { ARGS => [ 'A', 'b', '$SIZE(k)' ], | ||||||
| 1879 | REQR => { '$SIZE(k)' => 'A' }, | ||||||
| 1880 | }, | ||||||
| 1881 | blec => { ARGS => [ 'lb', 'ub', 'A', 'b' , '$SIZE(k)' ], | ||||||
| 1882 | REQR => { '$SIZE(k)' => 'A' }, | ||||||
| 1883 | }, | ||||||
| 1884 | bleic => { ARGS => [ 'lb', 'ub', 'A', 'b', '$SIZE(k)', 'C', 'd', '$SIZE(k2)' ], | ||||||
| 1885 | REQR => { '$SIZE(k)' => 'A', '$SIZE(k2)' => 'C' }, | ||||||
| 1886 | } | ||||||
| 1887 | }; | ||||||
| 1888 | |||||||
| 1889 | |||||||
| 1890 | my %arg_combs_analysis =(); | ||||||
| 1891 | # These are intended to be legal constraint combinations | ||||||
| 1892 | # result should also be used to check if a call is legal | ||||||
| 1893 | # This should make all leval combinations | ||||||
| 1894 | my $arg_combs = []; | ||||||
| 1895 | foreach my $linear ( [ ] , $HAVE_LAPACK ? [ 'A', 'b' ] : () ) { | ||||||
| 1896 | foreach my $box ( [ ] , [ 'lb', 'ub' ] , [ 'lb' ], [ 'ub' ] ) { | ||||||
| 1897 | foreach my $ineq ( [ ] , $HAVE_LAPACK ? [ 'C', 'd' ] : () ) { | ||||||
| 1898 | push @$arg_combs, [ @$box, @$linear, @$ineq ]; | ||||||
| 1899 | } | ||||||
| 1900 | } | ||||||
| 1901 | } | ||||||
| 1902 | foreach my $arg_comb ( @$arg_combs ) { | ||||||
| 1903 | my $levmar_funtion_name = find_levmar_func_name_from_args( $arg_comb, $arg_descr ); | ||||||
| 1904 | my $comb_key = make_hash_key_from_arg_comb( $arg_comb ); | ||||||
| 1905 | my $constraint_signature = make_constraint_signature( $arg_comb, $arg_descr ); | ||||||
| 1906 | my $call_args = make_constraint_call_args( $arg_comb, $arg_descr, | ||||||
| 1907 | $levmar_routine_description, $levmar_funtion_name ); | ||||||
| 1908 | $arg_combs_analysis{$comb_key} = { | ||||||
| 1909 | LEVMAR_FUNCTION_NAME => $levmar_funtion_name, | ||||||
| 1910 | ARG_COMB => [ @$arg_comb ], | ||||||
| 1911 | SIGNATURE => $constraint_signature, | ||||||
| 1912 | CALLARGS => $call_args, | ||||||
| 1913 | PDL_FUNC_NAME_DER => make_pdl_levmar_func_name_from_strings($comb_key, 'der'), | ||||||
| 1914 | PDL_FUNC_NAME_DIFF => make_pdl_levmar_func_name_from_strings($comb_key, 'diff'), | ||||||
| 1915 | }; | ||||||
| 1916 | } | ||||||
| 1917 | # print Dumper(%arg_combs_analysis); | ||||||
| 1918 | return \%arg_combs_analysis; | ||||||
| 1919 | } | ||||||
| 1920 | |||||||
| 1921 | # for testing. This replaces the pdl pp_def sub | ||||||
| 1922 | |||||||
| 1923 | sub disable_ppdef { | ||||||
| 1924 | my $name = shift; | ||||||
| 1925 | my %ppdef = @_; | ||||||
| 1926 | $ppdef{NAME} = $name; | ||||||
| 1927 | print Dumper(\%ppdef); | ||||||
| 1928 | } | ||||||
| 1929 | |||||||
| 1930 | sub write_pp_defs { | ||||||
| 1931 | my ($arg_combs_analysis) = @_; | ||||||
| 1932 | foreach my $der ( 'analytic', 'numeric' ) { | ||||||
| 1933 | # foreach my $con ( 'none', 'bc', 'lec', 'blec', 'bleic','blic','leic','lic' ) { | ||||||
| 1934 | foreach my $argcomb ( keys %$arg_combs_analysis ) { | ||||||
| 1935 | # passing workspace is broken for some routines, so... | ||||||
| 1936 | my $arg_anal = $arg_combs_analysis->{$argcomb}; | ||||||
| 1937 | my $h = {NOWORK => 0}; # default | ||||||
| 1938 | if ($der eq 'analytic') { # analytic derivative | ||||||
| 1939 | $h->{OPAR} = ' IV jacn; IV sjacn; '; | ||||||
| 1940 | $h->{CALL} = 'der'; | ||||||
| 1941 | $h->{ARG} = 't$TFD(s,)jacn,'; | ||||||
| 1942 | $h->{DUMI}= 'void * tjacn = (void *) $COMP(jacn); | ||||||
| 1943 | void * tsjacn = (void *) $COMP(sjacn);'; | ||||||
| 1944 | $h->{WORKFAC} = 2; # needs less workspace than numeric | ||||||
| 1945 | } | ||||||
| 1946 | else { # numeric derivative | ||||||
| 1947 | $h->{OPAR} = ''; | ||||||
| 1948 | $h->{CALL} = 'dif'; | ||||||
| 1949 | $h->{ARG} = ''; | ||||||
| 1950 | $h->{DUMI}= ''; | ||||||
| 1951 | $h->{WORKFAC} = 4; | ||||||
| 1952 | } | ||||||
| 1953 | $h->{SIG} = $arg_anal->{SIGNATURE} . '; ' ; | ||||||
| 1954 | $h->{ARG2} = $arg_anal->{CALLARGS}; | ||||||
| 1955 | if ($arg_anal->{LEVMAR_FUNCTION_NAME} eq 'bleic' ) { | ||||||
| 1956 | $h->{NOWORK} = 1; | ||||||
| 1957 | } | ||||||
| 1958 | my $funcname = ''; | ||||||
| 1959 | $funcname = $arg_anal->{LEVMAR_FUNCTION_NAME} unless $arg_anal->{LEVMAR_FUNCTION_NAME} eq 'none'; | ||||||
| 1960 | $h->{CALL} = $funcname . '_' . $h->{CALL} unless $arg_anal->{LEVMAR_FUNCTION_NAME} eq 'none'; | ||||||
| 1961 | if ($arg_anal->{LEVMAR_FUNCTION_NAME} eq 'blec') { | ||||||
| 1962 | $h->{SIG} .= 'wghts(m); '; | ||||||
| 1963 | $h->{ARG2} .= '$P(wghts), '; | ||||||
| 1964 | } | ||||||
| 1965 | $h->{ARG2} .= 'NULL, ' if $arg_anal->{LEVMAR_FUNCTION_NAME} eq 'bc' and @{$arg_anal->{ARG_COMB}}; # as of levmar-2.6, a dscl arg | ||||||
| 1966 | my $pdl_func_name; | ||||||
| 1967 | $pdl_func_name = $arg_anal->{PDL_FUNC_NAME_DER} if $der eq 'analytic'; | ||||||
| 1968 | $pdl_func_name = $arg_anal->{PDL_FUNC_NAME_DIFF} if $der eq 'numeric'; | ||||||
| 1969 | pp_def( $pdl_func_name, | ||||||
| 1970 | Pars => " p(m); x(n); t(nt); $h->{SIG} int iopts(in); opts(nopt); [t] work(wn); | ||||||
| 1971 | [o] covar(m,m) ; int [o] returnval(); | ||||||
| 1972 | [o] pout(m); [o] info(q=10); ", | ||||||
| 1973 | OtherPars => " IV funcn; IV sfuncn; $h->{OPAR} IV indat; " | ||||||
| 1974 | . " int want_covar; ", | ||||||
| 1975 | RedoDimsCode => " | ||||||
| 1976 | int im = \$PDL(p)->dims[0]; | ||||||
| 1977 | int in = \$PDL(x)->dims[0]; | ||||||
| 1978 | int min = $h->{WORKFAC}*in + 4*im + in*im + im*im; | ||||||
| 1979 | int inw = \$PDL(work)->dims[0]; | ||||||
| 1980 | \$SIZE(wn) = inw >= min ? inw : min; | ||||||
| 1981 | ", | ||||||
| 1982 | GenericTypes => ['F','D'], Doc => undef, | ||||||
| 1983 | Code => " | ||||||
| 1984 | int * iopts; | ||||||
| 1985 | int maxits; | ||||||
| 1986 | void * tfuncn = (void *) \$COMP(funcn); | ||||||
| 1987 | void * tsfuncn = (void *) \$COMP(sfuncn); | ||||||
| 1988 | \$GENERIC(covar) * pcovar; | ||||||
| 1989 | \$GENERIC(work) * pwork; | ||||||
| 1990 | $h->{DUMI}; | ||||||
| 1991 | DFP *dat = (void *) \$COMP(indat); | ||||||
| 1992 | DFP_check( &dat, PDL_\$TFD(F,D), \$SIZE(m), \$SIZE(n), | ||||||
| 1993 | \$SIZE(nt), \$P(t) ); | ||||||
| 1994 | threadloop %{ | ||||||
| 1995 | loop(m) %{ | ||||||
| 1996 | \$pout() = \$p(); | ||||||
| 1997 | %} | ||||||
| 1998 | iopts = \$P(iopts); | ||||||
| 1999 | pcovar = \$COMP(want_covar) == 1 ? \$P(covar) : NULL; | ||||||
| 2000 | pwork = $h->{NOWORK} == 1 ? NULL : \$P(work); | ||||||
| 2001 | maxits = iopts[0]; /* for clarity. we hope optimized away */ | ||||||
| 2002 | \$returnval() = \$TFD(s,d)levmar_$h->{CALL} ( | ||||||
| 2003 | t\$TFD(s,)funcn , $h->{ARG} | ||||||
| 2004 | \$P(pout), \$P(x), \$SIZE(m), \$SIZE(n), $h->{ARG2} | ||||||
| 2005 | maxits, \$P(opts), \$P(info), pwork, pcovar, dat); | ||||||
| 2006 | %} | ||||||
| 2007 | " | ||||||
| 2008 | ); | ||||||
| 2009 | } | ||||||
| 2010 | } | ||||||
| 2011 | } | ||||||
| 2012 | |||||||
| 2013 | # same routine defined above, but in Levmar.pm code | ||||||
| 2014 | sub make_pdl_levmar_func_key { | ||||||
| 2015 | my ($arg_str, $deriv_type) = @_; | ||||||
| 2016 | return $deriv_type . '_' . $arg_str; | ||||||
| 2017 | } | ||||||
| 2018 | |||||||
| 2019 | |||||||
| 2020 | |||||||
| 2021 | sub make_pdl_levmar_func_name_from_strings { | ||||||
| 2022 | my ($arg_str, $deriv_type) = @_; | ||||||
| 2023 | return 'levmar_' . make_pdl_levmar_func_key($arg_str, $deriv_type); | ||||||
| 2024 | } | ||||||
| 2025 | |||||||
| 2026 | |||||||
| 2027 | my $a = make_argument_combinations(); | ||||||
| 2028 | write_pp_defs($a); | ||||||
| 2029 | |||||||
| 2030 | |||||||
| 2031 | |||||||
| 2032 | =pod | ||||||
| 2033 | |||||||
| 2034 | =begin comment | ||||||
| 2035 | |||||||
| 2036 | /* | ||||||
| 2037 | * Check the jacobian of a n-valued nonlinear function in m variables | ||||||
| 2038 | * evaluated at a point p, for consistency with the function itself. | ||||||
| 2039 | * | ||||||
| 2040 | * Based on fortran77 subroutine CHKDER by | ||||||
| 2041 | * Burton S. Garbow, Kenneth E. Hillstrom, Jorge J. More | ||||||
| 2042 | * Argonne National Laboratory. MINPACK project. March 1980. | ||||||
| 2043 | * | ||||||
| 2044 | * | ||||||
| 2045 | * func points to a function from R^m --> R^n: Given a p in R^m it yields hx in R^n | ||||||
| 2046 | * jacf points to a function implementing the jacobian of func, whose correctness | ||||||
| 2047 | * is to be tested. Given a p in R^m, jacf computes into the nxm matrix j the | ||||||
| 2048 | * jacobian of func at p. Note that row i of j corresponds to the gradient of | ||||||
| 2049 | * the i-th component of func, evaluated at p. | ||||||
| 2050 | * p is an input array of length m containing the point of evaluation. | ||||||
| 2051 | * m is the number of variables | ||||||
| 2052 | * n is the number of functions | ||||||
| 2053 | * adata points to possible additional data and is passed uninterpreted | ||||||
| 2054 | * to func, jacf. | ||||||
| 2055 | * err is an array of length n. On output, err contains measures | ||||||
| 2056 | * of correctness of the respective gradients. if there is | ||||||
| 2057 | * no severe loss of significance, then if err[i] is 1.0 the | ||||||
| 2058 | * i-th gradient is correct, while if err[i] is 0.0 the i-th | ||||||
| 2059 | * gradient is incorrect. For values of err between 0.0 and 1.0, | ||||||
| 2060 | * the categorization is less certain. In general, a value of | ||||||
| 2061 | * err[i] greater than 0.5 indicates that the i-th gradient is | ||||||
| 2062 | * probably correct, while a value of err[i] less than 0.5 | ||||||
| 2063 | * indicates that the i-th gradient is probably incorrect. | ||||||
| 2064 | * | ||||||
| 2065 | * | ||||||
| 2066 | * The function does not perform reliably if cancellation or | ||||||
| 2067 | * rounding errors cause a severe loss of significance in the | ||||||
| 2068 | * evaluation of a function. therefore, none of the components | ||||||
| 2069 | * of p should be unusually small (in particular, zero) or any | ||||||
| 2070 | * other value which may cause loss of significance. | ||||||
| 2071 | */ | ||||||
| 2072 | |||||||
| 2073 | =end comment | ||||||
| 2074 | |||||||
| 2075 | =cut | ||||||
| 2076 | |||||||
| 2077 | pp_def('_levmar_chkjac', Pars => ' p(m); t(n); [o] err(n); ', | ||||||
| 2078 | OtherPars => ' IV func; IV sfunc; IV jac; IV sjac; IV indat; ', | ||||||
| 2079 | GenericTypes => ['F','D'], Doc => undef, | ||||||
| 2080 | Code => ' | ||||||
| 2081 | void * f = (void *) $COMP(func); | ||||||
| 2082 | void * sf = (void *) $COMP(sfunc); | ||||||
| 2083 | void * j = (void *) $COMP(jac); | ||||||
| 2084 | void * sj = (void *) $COMP(sjac); | ||||||
| 2085 | DFP *dat = (void *) $COMP(indat); | ||||||
| 2086 | DFP_check( &dat, PDL_$TFD(F,D), $SIZE(m), $SIZE(n), $SIZE(n), $P(t) ); | ||||||
| 2087 | $TFD(s,d)levmar_chkjac ( | ||||||
| 2088 | $TFD(s,)f, $TFD(s,)j,$P(p),$SIZE(m),$SIZE(n),dat,$P(err) | ||||||
| 2089 | ); | ||||||
| 2090 | ' | ||||||
| 2091 | ); | ||||||
| 2092 | |||||||
| 2093 | # From perl5 internals, chapter 4 ... | ||||||
| 2094 | #Perl's integer type is not necessarily a C int; it's called | ||||||
| 2095 | #an IV, or Integer Value. The difference is that an IV is | ||||||
| 2096 | #guaranteed to hold a pointer. | ||||||
| 2097 | |||||||
| 2098 | |||||||
| 2099 | pp_def('_levmar_chkjac_no_t', Pars => ' p(m); [o] err(n); ', | ||||||
| 2100 | OtherPars => 'IV func; IV sfunc; IV jac; IV sjac; int N; IV indat; ', | ||||||
| 2101 | GenericTypes => ['F','D'], Doc => undef, | ||||||
| 2102 | RedoDimsCode => " | ||||||
| 2103 | int N = \$COMP(N); | ||||||
| 2104 | int nin = \$PDL(err)->dims[0]; | ||||||
| 2105 | \$SIZE(n) = nin >= N ? nin : N; | ||||||
| 2106 | ", | ||||||
| 2107 | Code => ' | ||||||
| 2108 | void * f = (void *) $COMP(func); | ||||||
| 2109 | void * sf = (void *) $COMP(sfunc); | ||||||
| 2110 | void * j = (void *) $COMP(jac); | ||||||
| 2111 | void * sj =(void *) $COMP(sjac); | ||||||
| 2112 | DFP *dat = (void *) $COMP(indat); | ||||||
| 2113 | DFP_check( &dat, PDL_$TFD(F,D), $SIZE(m), $SIZE(n), $SIZE(n), NULL ); | ||||||
| 2114 | $TFD(s,d)levmar_chkjac ( | ||||||
| 2115 | $TFD(s,)f, $TFD(s,)j,$P(p),$SIZE(m),$SIZE(n),dat,$P(err) | ||||||
| 2116 | ); | ||||||
| 2117 | ' | ||||||
| 2118 | ); | ||||||
| 2119 | |||||||
| 2120 | |||||||
| 2121 | =pod | ||||||
| 2122 | |||||||
| 2123 | =begin comment | ||||||
| 2124 | |||||||
| 2125 | No end of trouble cause by confusion over passing ints and chars | ||||||
| 2126 | and so forth. I am sticking with using ints for pointers for the | ||||||
| 2127 | time being. | ||||||
| 2128 | |||||||
| 2129 | =end comment | ||||||
| 2130 | |||||||
| 2131 | =cut | ||||||
| 2132 | |||||||
| 2133 | |||||||
| 2134 | pp_addxs( '', ' | ||||||
| 2135 | |||||||
| 2136 | |||||||
| 2137 | void * | ||||||
| 2138 | DFP_create() | ||||||
| 2139 | |||||||
| 2140 | CODE: | ||||||
| 2141 | DFP * dat; | ||||||
| 2142 | dat = (DFP *)malloc(sizeof( DFP )); | ||||||
| 2143 | if ( NULL == dat ) { | ||||||
| 2144 | fprintf(stderr, "Can\'t allocate storage for dat in DFP_create\n"); | ||||||
| 2145 | exit(1); | ||||||
| 2146 | } | ||||||
| 2147 | RETVAL = dat; | ||||||
| 2148 | OUTPUT: | ||||||
| 2149 | RETVAL | ||||||
| 2150 | |||||||
| 2151 | void | ||||||
| 2152 | DFP_free( dat ) | ||||||
| 2153 | IV dat | ||||||
| 2154 | |||||||
| 2155 | CODE: | ||||||
| 2156 | if ( (DFP *) dat) free( (DFP *) dat); | ||||||
| 2157 | |||||||
| 2158 | |||||||
| 2159 | void | ||||||
| 2160 | DFP_set_perl_funcs ( data, perl_fit_func, perl_jac_func ) | ||||||
| 2161 | IV data | ||||||
| 2162 | SV* perl_fit_func | ||||||
| 2163 | SV* perl_jac_func | ||||||
| 2164 | |||||||
| 2165 | CODE: | ||||||
| 2166 | DFP *dat = (DFP *) data; | ||||||
| 2167 | if ( dat == NULL ) { | ||||||
| 2168 | fprintf(stderr, "DFP_set_perl_funcs got null struct\n"); | ||||||
| 2169 | exit(1); | ||||||
| 2170 | } | ||||||
| 2171 | dat->perl_fit_func = perl_fit_func; | ||||||
| 2172 | dat->perl_jac_func = perl_jac_func; | ||||||
| 2173 | |||||||
| 2174 | |||||||
| 2175 | double | ||||||
| 2176 | get_dbl_max( ) | ||||||
| 2177 | CODE: | ||||||
| 2178 | RETVAL = DBL_MAX; | ||||||
| 2179 | OUTPUT: | ||||||
| 2180 | RETVAL | ||||||
| 2181 | |||||||
| 2182 | double | ||||||
| 2183 | LM_INIT_MU( ) | ||||||
| 2184 | CODE: | ||||||
| 2185 | RETVAL = LM_INIT_MU; | ||||||
| 2186 | OUTPUT: | ||||||
| 2187 | RETVAL | ||||||
| 2188 | |||||||
| 2189 | double | ||||||
| 2190 | LM_STOP_THRESH( ) | ||||||
| 2191 | CODE: | ||||||
| 2192 | RETVAL = LM_STOP_THRESH; | ||||||
| 2193 | OUTPUT: | ||||||
| 2194 | RETVAL | ||||||
| 2195 | |||||||
| 2196 | double | ||||||
| 2197 | LM_DIFF_DELTA( ) | ||||||
| 2198 | CODE: | ||||||
| 2199 | RETVAL = LM_DIFF_DELTA; | ||||||
| 2200 | OUTPUT: | ||||||
| 2201 | RETVAL | ||||||
| 2202 | |||||||
| 2203 | |||||||
| 2204 | =pod | ||||||
| 2205 | |||||||
| 2206 | |||||||
| 2207 | =begin comment | ||||||
| 2208 | |||||||
| 2209 | The next two routines just get pointers to functions from | ||||||
| 2210 | the C code and return them as SVs to perl. The functions | ||||||
| 2211 | are the C wrappers to the users _perl_ fit and jacobian | ||||||
| 2212 | functions. LEVFUNC and JLEVFUNC should be re-entrant so | ||||||
| 2213 | the following two routines can called once when the | ||||||
| 2214 | Levmar::Func module is loaded and can be shared by all | ||||||
| 2215 | object instances. | ||||||
| 2216 | |||||||
| 2217 | =end comment | ||||||
| 2218 | |||||||
| 2219 | =cut | ||||||
| 2220 | |||||||
| 2221 | void * | ||||||
| 2222 | get_perl_func_wrapper( ) | ||||||
| 2223 | |||||||
| 2224 | CODE: | ||||||
| 2225 | RETVAL = &LEVFUNC; | ||||||
| 2226 | OUTPUT: | ||||||
| 2227 | RETVAL | ||||||
| 2228 | |||||||
| 2229 | void * | ||||||
| 2230 | get_perl_jac_wrapper( ) | ||||||
| 2231 | |||||||
| 2232 | CODE: | ||||||
| 2233 | RETVAL = &JLEVFUNC; | ||||||
| 2234 | OUTPUT: | ||||||
| 2235 | RETVAL | ||||||
| 2236 | |||||||
| 2237 | |||||||
| 2238 | |||||||
| 2239 | '); | ||||||
| 2240 | |||||||
| 2241 | |||||||
| 2242 | pp_done(); | ||||||
| 2243 | |||||||
| 2244 |