.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "LM 3pm" .TH LM 3pm "2020-11-19" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" PDL::Fit::LM \-\- Levenberg\-Marquardt fitting routine for PDL .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module provides fitting functions for \s-1PDL.\s0 Currently, only Levenberg-Marquardt fitting is implemented. Other procedures should be added as required. For a fairly concise overview on fitting see Numerical Recipes, chapter 15 \*(L"Modeling of data\*(R". .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use PDL::Fit::LM; \& $ym = lmfit $x, $y, $sigma, \e&expfunc, $initp, {Maxiter => 300}; .Ve .SH "FUNCTIONS" .IX Header "FUNCTIONS" .SS "lmfit" .IX Subsection "lmfit" Levenberg-Marquardt fitting of a user supplied model function .PP .Vb 2 \& ($ym,$finalp,$covar,$iters) = \& lmfit $x, $y, $sigma, \e&expfunc, $initp, {Maxiter => 300, Eps => 1e\-3}; .Ve .PP where \f(CW$x\fR is the independent variable and \f(CW$y\fR the value of the dependent variable at each \f(CW$x\fR, \f(CW$sigma\fR is the estimate of the uncertainty (i.e., standard deviation) of \f(CW$y\fR at each data point, the fourth argument is a subroutine reference (see below), and \f(CW$initp\fR the initial values of the parameters to be adjusted. .PP Options: .PP .Vb 3 \& Maxiter: maximum number of iterations before giving up \& Eps: convergence criterion for fit; success when normalized change \& in chisquare smaller than Eps .Ve .PP The user supplied sub routine reference should accept 4 arguments .IP "\(bu" 4 a vector of independent values \f(CW$x\fR .IP "\(bu" 4 a vector of fitting parameters .IP "\(bu" 4 a vector of dependent variables that will be assigned upon return .IP "\(bu" 4 a matrix of partial derivatives with respect to the fitting parameters that will be assigned upon return .PP As an example take this definition of a single exponential with 3 parameters (width, amplitude, offset): .PP .Vb 11 \& sub expdec { \& my ($x,$par,$ym,$dyda) = @_; \& my ($width,$amp,$off) = map {$par\->slice("($_)")} (0..2); \& my $arg = $x/$width; \& my $ex = exp($arg); \& $ym .= $amp*$ex+$off; \& my (@dy) = map {$dyda\->slice(",($_)")} (0..2); \& $dy[0] .= \-$amp*$ex*$arg/$width; \& $dy[1] .= $ex; \& $dy[2] .= 1; \& } .Ve .PP Note usage of the \f(CW\*(C`.=\*(C'\fR operator for assignment .PP In scalar context returns a vector of the fitted dependent variable. In list context returns fitted y\-values, vector of fitted parameters, an estimate of the covariance matrix (as an indicator of goodness of fit) and number of iterations performed. .PP An extended example script that uses lmfit is included below. This nice example was provided by John Gehman and should help you to master the initial hurdles. It can also be found in the \fIExample/Fit\fR directory. .PP .Vb 4 \& use PDL; \& use PDL::Math; \& use PDL::Fit::LM; \& use strict; \& \& \& ### fit using pdl\*(Aqs lmfit (Marquardt\-Levenberg non\-linear least squares fitting) \& ### \& ### \`lmfit\*(Aq Syntax: \& ### \& ### ($ym,$finalp,$covar,$iters) \& ### = lmfit $x, $y, $sigma, \e&fn, $initp, {Maxiter => 300, Eps => 1e\-3}; \& ### \& ### Explanation of variables \& ### \& ### OUTPUT \& ### $ym = pdl of fitted values \& ### $finalp = pdl of parameters \& ### $covar = covariance matrix \& ### $iters = number of iterations actually used \& ### \& ### INPUT \& ### $x = x data \& ### $y = y data \& ### $sigma = piddle of y\-uncertainties for each value of $y (can be set to scalar 1 for equal weighting) \& ### \e&fn = reference to function provided by user (more on this below) \& ### $initp = initial values for floating parameters \& ### (needs to be explicitly set prior to use of lmfit) \& ### Maxiter = maximum iterations \& ### Eps = convergence criterion (maximum normalized change in Chi Sq.) \& \& ### Example: \& # make up experimental data: \& my $xdata = pdl sequence 5; \& my $ydata = pdl [1.1,1.9,3.05,4,4.9]; \& \& # set initial prameters in a pdl (order in accord with fit function below) \& my $initp = pdl [0,1]; \& \& # Weight all y data equally (else specify different uncertainties in a pdl) \& my $sigma = 1; \& \& # Use lmfit. Fourth input argument is reference to user\-defined \& # subroutine ( here \e&linefit ) detailed below. \& my ($yf,$pf,$cf,$if) = lmfit $xdata, $ydata, $sigma, \e&linefit, $initp; \& \& # Note output \& print "\enXDATA\en$xdata\enY DATA\en$ydata\en\enY DATA FIT\en$yf\en\en"; \& print "Slope and Intercept\en$pf\en\enCOVARIANCE MATRIX\en$cf\en\en"; \& print "NUMBER ITERATIONS\en$if\en\en"; \& \& \& # simple example of user defined fit function. Guidelines included on \& # how to write your own function subroutine. \& sub linefit { \& \& # leave this line as is \& my ($x,$par,$ym,$dyda) = @_; \& \& # $m and $c are fit parameters, internal to this function \& # call them whatever make sense to you, but replace (0..1) \& # with (0..x) where x is equal to your number of fit parameters \& # minus 1 \& my ($m,$c) = map { $par\->slice("($_)") } (0..1); \& \& # Write function with dependent variable $ym, \& # independent variable $x, and fit parameters as specified above. \& # Use the .= (dot equals) assignment operator to express the equality \& # (not just a plain equals) \& $ym .= $m * $x + $c; \& \& # Edit only the (0..1) part to (0..x) as above \& my (@dy) = map {$dyda \-> slice(",($_)") } (0..1); \& \& # Partial derivative of the function with respect to first \& # fit parameter ($m in this case). Again, note .= assignment \& # operator (not just "equals") \& $dy[0] .= $x; \& \& # Partial derivative of the function with respect to next \& # fit parameter ($y in this case) \& $dy[1] .= 1; \& \& # Add $dy[ ] .= () lines as necessary to supply \& # partial derivatives for all floating parameters. \& } .Ve .SS "tlmfit" .IX Subsection "tlmfit" threaded version of Levenberg-Marquardt fitting routine mfit .PP .Vb 2 \& tlmfit $x, $y, float(1)\->dummy(0), $na, float(200), float(1e\-4), \& $ym=null, $afit=null, \e&expdec; .Ve .PP .Vb 2 \& Signature: tlmfit(x(n);y(n);sigma(n);initp(m);iter();eps();[o] ym(n);[o] finalp(m); \& OtherPar => subref) .Ve .PP a threaded version of \f(CW\*(C`lmfit\*(C'\fR by using perl threading. Direct threading in \f(CW\*(C`lmfit\*(C'\fR seemed difficult since we have an if condition in the iteration. In principle that can be worked around by using \f(CW\*(C`where\*(C'\fR but .... Send a threaded \f(CW\*(C`lmfit\*(C'\fR version if you work it out! .PP Since we are using perl threading here speed is not really great but it is just convenient to have a threaded version for many applications (no explicit for-loops required, etc). Suffers from some of the current limitations of perl level threading. .SH "BUGS" .IX Header "BUGS" Not known yet. .SH "AUTHOR" .IX Header "AUTHOR" This file copyright (C) 1999, Christian Soeller (c.soeller@auckland.ac.nz). All rights reserved. There is no warranty. You are allowed to redistribute this software documentation under certain conditions. For details, see the file \s-1COPYING\s0 in the \s-1PDL\s0 distribution. If this file is separated from the \s-1PDL\s0 distribution, the copyright notice should be included in the file.