public static void lsfitcreatefgh(double[,] x, double[] y, double[] c, out lsfitstate state) { int n; int m; int k; if( (ap.rows(x)!=ap.len(y))) throw new alglibexception("Error while calling 'lsfitcreatefgh': looks like one of arguments has wrong size"); state = new lsfitstate(); n = ap.rows(x); m = ap.cols(x); k = ap.len(c); lsfit.lsfitcreatefgh(x, y, c, n, m, k, state.innerobj); return; }
/************************************************************************* Nonlinear least squares fitting using gradient/Hessian without individual weights. See LSFitNonlinearWFGH() for more information. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitnonlinearfgh(ref double[,] x, ref double[] y, ref double[] c, int n, int m, int k, ref lsfitstate state) { int i = 0; int i_ = 0; state.n = n; state.m = m; state.k = k; lsfitnonlinearsetcond(ref state, 0.0, 0.0, 0); lsfitnonlinearsetstpmax(ref state, 0.0); state.cheapfg = true; state.havehess = true; if( n>=1 & m>=1 & k>=1 ) { state.taskx = new double[n, m]; state.tasky = new double[n]; state.w = new double[n]; state.c = new double[k]; for(i_=0; i_<=k-1;i_++) { state.c[i_] = c[i_]; } for(i=0; i<=n-1; i++) { for(i_=0; i_<=m-1;i_++) { state.taskx[i,i_] = x[i,i_]; } state.tasky[i] = y[i]; state.w[i] = 1; } } state.rstate.ia = new int[4+1]; state.rstate.ra = new double[1+1]; state.rstate.stage = -1; }
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state between calls and which is used for reverse communication. Must be initialized with LSFitNonLinearCreate???() StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ public static void lsfitnonlinearsetstpmax(ref lsfitstate state, double stpmax) { System.Diagnostics.Debug.Assert((double)(stpmax)>=(double)(0), "LSFitNonlinearSetStpMax: StpMax<0!"); state.stpmax = stpmax; }
/************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. On success following fields are set: * R2 non-adjusted coefficient of determination (non-weighted) * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). ERRORS IN PARAMETERS This solver also calculates different kinds of errors in parameters and fills corresponding fields of report: * Rep.CovPar covariance matrix for parameters, array[K,K]. * Rep.ErrPar errors in parameters, array[K], errpar = sqrt(diag(CovPar)) * Rep.ErrCurve vector of fit errors - standard deviations of empirical best-fit curve from "ideal" best-fit curve built with infinite number of samples, array[N]. errcurve = sqrt(diag(J*CovPar*J')), where J is Jacobian matrix. * Rep.Noise vector of per-point estimates of noise, array[N] IMPORTANT: errors in parameters are calculated without taking into account boundary/linear constraints! Presence of constraints changes distribution of errors, but there is no easy way to account for constraints when you calculate covariance matrix. NOTE: noise in the data is estimated as follows: * for fitting without user-supplied weights all points are assumed to have same level of noise, which is estimated from the data * for fitting with user-supplied weights we assume that noise level in I-th point is inversely proportional to Ith weight. Coefficient of proportionality is estimated from the data. NOTE: we apply small amount of regularization when we invert squared Jacobian and calculate covariance matrix. It guarantees that algorithm won't divide by zero during inversion, but skews error estimates a bit (fractional error is about 10^-9). However, we believe that this difference is insignificant for all practical purposes except for the situation when you want to compare ALGLIB results with "reference" implementation up to the last significant digit. NOTE: covariance matrix is estimated using correction for degrees of freedom (covariances are divided by N-M instead of dividing by N). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitresults(lsfitstate state, ref int info, ref double[] c, lsfitreport rep) { int i = 0; int j = 0; int i_ = 0; info = 0; c = new double[0]; clearreport(rep); info = state.repterminationtype; rep.varidx = state.repvaridx; if( info>0 ) { c = new double[state.k]; for(i_=0; i_<=state.k-1;i_++) { c[i_] = state.c[i_]; } rep.rmserror = state.reprmserror; rep.wrmserror = state.repwrmserror; rep.avgerror = state.repavgerror; rep.avgrelerror = state.repavgrelerror; rep.maxerror = state.repmaxerror; rep.iterationscount = state.repiterationscount; rep.covpar = new double[state.k, state.k]; rep.errpar = new double[state.k]; rep.errcurve = new double[state.npoints]; rep.noise = new double[state.npoints]; rep.r2 = state.rep.r2; for(i=0; i<=state.k-1; i++) { for(j=0; j<=state.k-1; j++) { rep.covpar[i,j] = state.rep.covpar[i,j]; } rep.errpar[i] = state.rep.errpar[i]; } for(i=0; i<=state.npoints-1; i++) { rep.errcurve[i] = state.rep.errcurve[i]; rep.noise[i] = state.rep.noise[i]; } } }
/************************************************************************* Nonlinear least squares fitting results. Called after LSFitNonlinearIteration() returned False. INPUT PARAMETERS: State - algorithm state (used by LSFitNonlinearIteration). OUTPUT PARAMETERS: Info - completetion code: * -1 incorrect parameters were specified * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken C - array[0..K-1], solution Rep - optimization report. Following fields are set: * Rep.TerminationType completetion code: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitnonlinearresults(ref lsfitstate state, ref int info, ref double[] c, ref lsfitreport rep) { int i_ = 0; info = state.repterminationtype; if( info>0 ) { c = new double[state.k]; for(i_=0; i_<=state.k-1;i_++) { c[i_] = state.c[i_]; } rep.rmserror = state.reprmserror; rep.avgerror = state.repavgerror; rep.avgrelerror = state.repavgrelerror; rep.maxerror = state.repmaxerror; } }
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetxrep(lsfitstate state, bool needxrep) { state.xrep = needxrep; }
/************************************************************************* This function sets boundary constraints for underlying optimizer Boundary constraints are inactive by default (after initial creation). They are preserved until explicitly turned off with another SetBC() call. INPUT PARAMETERS: State - structure stores algorithm state BndL - lower bounds, array[K]. If some (all) variables are unbounded, you may specify very small number or -INF (latter is recommended because it will allow solver to use better algorithm). BndU - upper bounds, array[K]. If some (all) variables are unbounded, you may specify very large number or +INF (latter is recommended because it will allow solver to use better algorithm). NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. NOTE 2: unlike other constrained optimization algorithms, this solver has following useful properties: * bound constraints are always satisfied exactly * function is evaluated only INSIDE area specified by bound constraints -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetbc(lsfitstate state, double[] bndl, double[] bndu) { int i = 0; int k = 0; k = state.k; alglib.ap.assert(alglib.ap.len(bndl)>=k, "LSFitSetBC: Length(BndL)<K"); alglib.ap.assert(alglib.ap.len(bndu)>=k, "LSFitSetBC: Length(BndU)<K"); for(i=0; i<=k-1; i++) { alglib.ap.assert(math.isfinite(bndl[i]) || Double.IsNegativeInfinity(bndl[i]), "LSFitSetBC: BndL contains NAN or +INF"); alglib.ap.assert(math.isfinite(bndu[i]) || Double.IsPositiveInfinity(bndu[i]), "LSFitSetBC: BndU contains NAN or -INF"); if( math.isfinite(bndl[i]) && math.isfinite(bndu[i]) ) { alglib.ap.assert((double)(bndl[i])<=(double)(bndu[i]), "LSFitSetBC: BndL[i]>BndU[i]"); } state.bndl[i] = bndl[i]; state.bndu[i] = bndu[i]; } }
/************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completetion code: * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. Following fields are set: * Rep.TerminationType completetion code: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitresults(lsfitstate state, out int info, out double[] c, out lsfitreport rep) { info = 0; c = new double[0]; rep = new lsfitreport(); lsfit.lsfitresults(state.innerobj, ref info, ref c, rep.innerobj); return; }
/************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitcreatefgh(double[,] x, double[] y, double[] c, int n, int m, int k, lsfitstate state) { int i = 0; int i_ = 0; ap.assert(n>=1, "LSFitCreateFGH: N<1!"); ap.assert(m>=1, "LSFitCreateFGH: M<1!"); ap.assert(k>=1, "LSFitCreateFGH: K<1!"); ap.assert(ap.len(c)>=k, "LSFitCreateFGH: length(C)<K!"); ap.assert(apserv.isfinitevector(c, k), "LSFitCreateFGH: C contains infinite or NaN values!"); ap.assert(ap.len(y)>=n, "LSFitCreateFGH: length(Y)<N!"); ap.assert(apserv.isfinitevector(y, n), "LSFitCreateFGH: Y contains infinite or NaN values!"); ap.assert(ap.rows(x)>=n, "LSFitCreateFGH: rows(X)<N!"); ap.assert(ap.cols(x)>=m, "LSFitCreateFGH: cols(X)<M!"); ap.assert(apserv.apservisfinitematrix(x, n, m), "LSFitCreateFGH: X contains infinite or NaN values!"); state.n = n; state.m = m; state.k = k; lsfitsetcond(state, 0.0, 0.0, 0); lsfitsetstpmax(state, 0.0); lsfitsetxrep(state, false); state.taskx = new double[n, m]; state.tasky = new double[n]; state.w = new double[n]; state.c = new double[k]; state.h = new double[k, k]; state.x = new double[m]; state.g = new double[k]; for(i_=0; i_<=k-1;i_++) { state.c[i_] = c[i_]; } for(i=0; i<=n-1; i++) { for(i_=0; i_<=m-1;i_++) { state.taskx[i,i_] = x[i,i_]; } state.tasky[i] = y[i]; state.w[i] = 1; } minlm.minlmcreatefgh(k, state.c, state.optstate); lsfitclearrequestfields(state); state.rstate.ia = new int[4+1]; state.rstate.ra = new double[1+1]; state.rstate.stage = -1; }
/************************************************************************* This function provides reverse communication interface Reverse communication interface is not documented or recommended to use. See below for functions which provide better documented API *************************************************************************/ public static bool lsfititeration(lsfitstate state) { bool result = lsfit.lsfititeration(state.innerobj); return result; }
public static void lsfitfit(lsfitstate state, ndimensional_pfunc func, ndimensional_pgrad grad, ndimensional_phess hess, ndimensional_rep rep, object obj) { if( func==null ) throw new alglibexception("ALGLIB: error in 'lsfitfit()' (func is null)"); if( grad==null ) throw new alglibexception("ALGLIB: error in 'lsfitfit()' (grad is null)"); if( hess==null ) throw new alglibexception("ALGLIB: error in 'lsfitfit()' (hess is null)"); while( alglib.lsfititeration(state) ) { if( state.needf ) { func(state.c, state.x, ref state.innerobj.f, obj); continue; } if( state.needfg ) { grad(state.c, state.x, ref state.innerobj.f, state.innerobj.g, obj); continue; } if( state.needfgh ) { hess(state.c, state.x, ref state.innerobj.f, state.innerobj.g, state.innerobj.h, obj); continue; } if( state.innerobj.xupdated ) { if( rep!=null ) rep(state.innerobj.x, state.innerobj.f, obj); continue; } throw new alglibexception("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); } }
/************************************************************************* This function turns on/off reporting. INPUT PARAMETERS: State - structure which stores algorithm state NeedXRep- whether iteration reports are needed or not When reports are needed, State.C (current parameters) and State.F (current value of fitting function) are reported. -- ALGLIB -- Copyright 15.08.2010 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetxrep(lsfitstate state, bool needxrep) { lsfit.lsfitsetxrep(state.innerobj, needxrep); return; }
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetstpmax(lsfitstate state, double stpmax) { lsfit.lsfitsetstpmax(state.innerobj, stpmax); return; }
/************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - stopping criterion. Algorithm stops if |X(k+1)-X(k)| <= EpsX*(1+|X(k)|) MaxIts - stopping criterion. Algorithm stops after MaxIts iterations. MaxIts=0 means no stopping criterion. NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetcond(lsfitstate state, double epsf, double epsx, int maxits) { lsfit.lsfitsetcond(state.innerobj, epsf, epsx, maxits); return; }
/************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - >=0 The subroutine finishes its work if on k+1-th iteration the condition |v|<=EpsX is fulfilled, where: * |.| means Euclidian norm * v - scaled step vector, v[i]=dx[i]/s[i] * dx - ste pvector, dx=X(k+1)-X(k) * s - scaling coefficients set by LSFitSetScale() MaxIts - maximum number of iterations. If MaxIts=0, the number of iterations is unlimited. Only Levenberg-Marquardt iterations are counted (L-BFGS/CG iterations are NOT counted because their cost is very low compared to that of LM). NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetcond(lsfitstate state, double epsf, double epsx, int maxits) { alglib.ap.assert(math.isfinite(epsf), "LSFitSetCond: EpsF is not finite!"); alglib.ap.assert((double)(epsf)>=(double)(0), "LSFitSetCond: negative EpsF!"); alglib.ap.assert(math.isfinite(epsx), "LSFitSetCond: EpsX is not finite!"); alglib.ap.assert((double)(epsx)>=(double)(0), "LSFitSetCond: negative EpsX!"); alglib.ap.assert(maxits>=0, "LSFitSetCond: negative MaxIts!"); state.epsf = epsf; state.epsx = epsx; state.maxits = maxits; }
/************************************************************************* Weighted nonlinear least squares fitting using gradient only. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]) and its gradient. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted CheapFG - boolean flag, which is: * True if both function and gradient calculation complexity are less than O(M^2). An improved algorithm can be used which corresponds to FGJ scheme from MINLM unit. * False otherwise. Standard Jacibian-bases Levenberg-Marquardt algo will be used (FJ scheme). OUTPUT PARAMETERS: State - structure which stores algorithm state See also: LSFitResults LSFitCreateFG (fitting without weights) LSFitCreateWFGH (fitting using Hessian) LSFitCreateFGH (fitting using Hessian, without weights) -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitcreatewfg(double[,] x, double[] y, double[] w, double[] c, int n, int m, int k, bool cheapfg, lsfitstate state) { int i = 0; int i_ = 0; ap.assert(n >= 1, "LSFitCreateWFG: N<1!"); ap.assert(m >= 1, "LSFitCreateWFG: M<1!"); ap.assert(k >= 1, "LSFitCreateWFG: K<1!"); ap.assert(ap.len(c) >= k, "LSFitCreateWFG: length(C)<K!"); ap.assert(apserv.isfinitevector(c, k), "LSFitCreateWFG: C contains infinite or NaN values!"); ap.assert(ap.len(y) >= n, "LSFitCreateWFG: length(Y)<N!"); ap.assert(apserv.isfinitevector(y, n), "LSFitCreateWFG: Y contains infinite or NaN values!"); ap.assert(ap.len(w) >= n, "LSFitCreateWFG: length(W)<N!"); ap.assert(apserv.isfinitevector(w, n), "LSFitCreateWFG: W contains infinite or NaN values!"); ap.assert(ap.rows(x) >= n, "LSFitCreateWFG: rows(X)<N!"); ap.assert(ap.cols(x) >= m, "LSFitCreateWFG: cols(X)<M!"); ap.assert(apserv.apservisfinitematrix(x, n, m), "LSFitCreateWFG: X contains infinite or NaN values!"); state.npoints = n; state.nweights = n; state.wkind = 1; state.m = m; state.k = k; lsfitsetcond(state, 0.0, 0.0, 0); lsfitsetstpmax(state, 0.0); lsfitsetxrep(state, false); state.taskx = new double[n, m]; state.tasky = new double[n]; state.w = new double[n]; state.c = new double[k]; state.x = new double[m]; state.g = new double[k]; for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = c[i_]; } for(i_ = 0; i_ <= n - 1; i_++) { state.w[i_] = w[i_]; } for(i = 0; i <= n - 1; i++) { for(i_ = 0; i_ <= m - 1; i_++) { state.taskx[i, i_] = x[i, i_]; } state.tasky[i] = y[i]; } state.s = new double[k]; state.bndl = new double[k]; state.bndu = new double[k]; for(i = 0; i <= k - 1; i++) { state.s[i] = 1.0; state.bndl[i] = Double.NegativeInfinity; state.bndu[i] = Double.PositiveInfinity; } state.optalgo = 1; state.prevnpt = -1; state.prevalgo = -1; if(cheapfg) { minlm.minlmcreatevgj(k, n, state.c, state.optstate); } else { minlm.minlmcreatevj(k, n, state.c, state.optstate); } lsfitclearrequestfields(state); state.rstate.ia = new int[4 + 1]; state.rstate.ra = new double[2 + 1]; state.rstate.stage = -1; }
/************************************************************************* This function sets maximum step length INPUT PARAMETERS: State - structure which stores algorithm state StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't want to limit step length. Use this subroutine when you optimize target function which contains exp() or other fast growing functions, and optimization algorithm makes too large steps which leads to overflow. This function allows us to reject steps that are too large (and therefore expose us to the possible overflow) without actually calculating function value at the x+stp*d. NOTE: non-zero StpMax leads to moderate performance degradation because intermediate step of preconditioned L-BFGS optimization is incompatible with limits on step size. -- ALGLIB -- Copyright 02.04.2010 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetstpmax(lsfitstate state, double stpmax) { alglib.ap.assert((double)(stpmax)>=(double)(0), "LSFitSetStpMax: StpMax<0!"); state.stpmax = stpmax; }
/************************************************************************* NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static bool lsfititeration(lsfitstate state) { bool result = new bool(); int n = 0; int m = 0; int k = 0; int i = 0; int j = 0; double v = 0; double vv = 0; double relcnt = 0; int i_ = 0; // // Reverse communication preparations // I know it looks ugly, but it works the same way // anywhere from C++ to Python. // // This code initializes locals by: // * random values determined during code // generation - on first subroutine call // * values from previous call - on subsequent calls // if(state.rstate.stage >= 0) { n = state.rstate.ia[0]; m = state.rstate.ia[1]; k = state.rstate.ia[2]; i = state.rstate.ia[3]; j = state.rstate.ia[4]; v = state.rstate.ra[0]; vv = state.rstate.ra[1]; relcnt = state.rstate.ra[2]; } else { n = -983; m = -989; k = -834; i = 900; j = -287; v = 364; vv = 214; relcnt = -338; } if(state.rstate.stage == 0) { goto lbl_0; } if(state.rstate.stage == 1) { goto lbl_1; } if(state.rstate.stage == 2) { goto lbl_2; } if(state.rstate.stage == 3) { goto lbl_3; } if(state.rstate.stage == 4) { goto lbl_4; } if(state.rstate.stage == 5) { goto lbl_5; } if(state.rstate.stage == 6) { goto lbl_6; } // // Routine body // // // init // if(state.wkind == 1) { ap.assert(state.npoints == state.nweights, "LSFitFit: number of points is not equal to the number of weights"); } n = state.npoints; m = state.m; k = state.k; minlm.minlmsetcond(state.optstate, 0.0, state.epsf, state.epsx, state.maxits); minlm.minlmsetstpmax(state.optstate, state.stpmax); minlm.minlmsetxrep(state.optstate, state.xrep); minlm.minlmsetscale(state.optstate, state.s); minlm.minlmsetbc(state.optstate, state.bndl, state.bndu); // // Optimize // lbl_7: if(!minlm.minlmiteration(state.optstate)) { goto lbl_8; } if(!state.optstate.needfi) { goto lbl_9; } // // calculate f[] = wi*(f(xi,c)-yi) // i = 0; lbl_11: if(i > n - 1) { goto lbl_13; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 0; goto lbl_rcomm; lbl_0: state.needf = false; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.fi[i] = vv * (state.f - state.tasky[i]); i = i + 1; goto lbl_11; lbl_13: goto lbl_7; lbl_9: if(!state.optstate.needf) { goto lbl_14; } // // calculate F = sum (wi*(f(xi,c)-yi))^2 // state.optstate.f = 0; i = 0; lbl_16: if(i > n - 1) { goto lbl_18; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 1; goto lbl_rcomm; lbl_1: state.needf = false; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f + math.sqr(vv * (state.f - state.tasky[i])); i = i + 1; goto lbl_16; lbl_18: goto lbl_7; lbl_14: if(!state.optstate.needfg) { goto lbl_19; } // // calculate F/gradF // state.optstate.f = 0; for(i = 0; i <= k - 1; i++) { state.optstate.g[i] = 0; } i = 0; lbl_21: if(i > n - 1) { goto lbl_23; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 2; goto lbl_rcomm; lbl_2: state.needfg = false; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f + math.sqr(vv * (state.f - state.tasky[i])); v = math.sqr(vv) * 2 * (state.f - state.tasky[i]); for(i_ = 0; i_ <= k - 1; i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v * state.g[i_]; } i = i + 1; goto lbl_21; lbl_23: goto lbl_7; lbl_19: if(!state.optstate.needfij) { goto lbl_24; } // // calculate Fi/jac(Fi) // i = 0; lbl_26: if(i > n - 1) { goto lbl_28; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 3; goto lbl_rcomm; lbl_3: state.needfg = false; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.fi[i] = vv * (state.f - state.tasky[i]); for(i_ = 0; i_ <= k - 1; i_++) { state.optstate.j[i, i_] = vv * state.g[i_]; } i = i + 1; goto lbl_26; lbl_28: goto lbl_7; lbl_24: if(!state.optstate.needfgh) { goto lbl_29; } // // calculate F/grad(F)/hess(F) // state.optstate.f = 0; for(i = 0; i <= k - 1; i++) { state.optstate.g[i] = 0; } for(i = 0; i <= k - 1; i++) { for(j = 0; j <= k - 1; j++) { state.optstate.h[i, j] = 0; } } i = 0; lbl_31: if(i > n - 1) { goto lbl_33; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfgh = true; state.rstate.stage = 4; goto lbl_rcomm; lbl_4: state.needfgh = false; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f + math.sqr(vv * (state.f - state.tasky[i])); v = math.sqr(vv) * 2 * (state.f - state.tasky[i]); for(i_ = 0; i_ <= k - 1; i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v * state.g[i_]; } for(j = 0; j <= k - 1; j++) { v = 2 * math.sqr(vv) * state.g[j]; for(i_ = 0; i_ <= k - 1; i_++) { state.optstate.h[j, i_] = state.optstate.h[j, i_] + v * state.g[i_]; } v = 2 * math.sqr(vv) * (state.f - state.tasky[i]); for(i_ = 0; i_ <= k - 1; i_++) { state.optstate.h[j, i_] = state.optstate.h[j, i_] + v * state.h[j, i_]; } } i = i + 1; goto lbl_31; lbl_33: goto lbl_7; lbl_29: if(!state.optstate.xupdated) { goto lbl_34; } // // Report new iteration // for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.optstate.x[i_]; } state.f = state.optstate.f; lsfitclearrequestfields(state); state.xupdated = true; state.rstate.stage = 5; goto lbl_rcomm; lbl_5: state.xupdated = false; goto lbl_7; lbl_34: goto lbl_7; lbl_8: minlm.minlmresults(state.optstate, ref state.c, state.optrep); state.repterminationtype = state.optrep.terminationtype; state.repiterationscount = state.optrep.iterationscount; // // calculate errors // if(state.repterminationtype <= 0) { goto lbl_36; } state.reprmserror = 0; state.repwrmserror = 0; state.repavgerror = 0; state.repavgrelerror = 0; state.repmaxerror = 0; relcnt = 0; i = 0; lbl_38: if(i > n - 1) { goto lbl_40; } for(i_ = 0; i_ <= k - 1; i_++) { state.c[i_] = state.c[i_]; } for(i_ = 0; i_ <= m - 1; i_++) { state.x[i_] = state.taskx[i, i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 6; goto lbl_rcomm; lbl_6: state.needf = false; v = state.f; if(state.wkind == 1) { vv = state.w[i]; } else { vv = 1.0; } state.reprmserror = state.reprmserror + math.sqr(v - state.tasky[i]); state.repwrmserror = state.repwrmserror + math.sqr(vv * (v - state.tasky[i])); state.repavgerror = state.repavgerror + Math.Abs(v - state.tasky[i]); if((double)(state.tasky[i]) != (double)(0)) { state.repavgrelerror = state.repavgrelerror + Math.Abs(v - state.tasky[i]) / Math.Abs(state.tasky[i]); relcnt = relcnt + 1; } state.repmaxerror = Math.Max(state.repmaxerror, Math.Abs(v - state.tasky[i])); i = i + 1; goto lbl_38; lbl_40: state.reprmserror = Math.Sqrt(state.reprmserror / n); state.repwrmserror = Math.Sqrt(state.repwrmserror / n); state.repavgerror = state.repavgerror / n; if((double)(relcnt) != (double)(0)) { state.repavgrelerror = state.repavgrelerror / relcnt; } lbl_36: result = false; return result; // // Saving state // lbl_rcomm: result = true; state.rstate.ia[0] = n; state.rstate.ia[1] = m; state.rstate.ia[2] = k; state.rstate.ia[3] = i; state.rstate.ia[4] = j; state.rstate.ra[0] = v; state.rstate.ra[1] = vv; state.rstate.ra[2] = relcnt; return result; }
/************************************************************************* This function sets scaling coefficients for underlying optimizer. ALGLIB optimizers use scaling matrices to test stopping conditions (step size and gradient are scaled before comparison with tolerances). Scale of the I-th variable is a translation invariant measure of: a) "how large" the variable is b) how large the step should be to make significant changes in the function Generally, scale is NOT considered to be a form of preconditioner. But LM optimizer is unique in that it uses scaling matrix both in the stopping condition tests and as Marquardt damping factor. Proper scaling is very important for the algorithm performance. It is less important for the quality of results, but still has some influence (it is easier to converge when variables are properly scaled, so premature stopping is possible when very badly scalled variables are combined with relaxed stopping conditions). INPUT PARAMETERS: State - structure stores algorithm state S - array[N], non-zero scaling coefficients S[i] may be negative, sign doesn't matter. -- ALGLIB -- Copyright 14.01.2011 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetscale(lsfitstate state, double[] s) { int i = 0; alglib.ap.assert(alglib.ap.len(s)>=state.k, "LSFitSetScale: Length(S)<K"); for(i=0; i<=state.k-1; i++) { alglib.ap.assert(math.isfinite(s[i]), "LSFitSetScale: S contains infinite or NAN elements"); alglib.ap.assert((double)(s[i])!=(double)(0), "LSFitSetScale: S contains infinite or NAN elements"); state.s[i] = Math.Abs(s[i]); } }
/************************************************************************* NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static bool lsfititeration(lsfitstate state) { bool result = new bool(); double lx = 0; double lf = 0; double ld = 0; double rx = 0; double rf = 0; double rd = 0; int n = 0; int m = 0; int k = 0; double v = 0; double vv = 0; double relcnt = 0; int i = 0; int j = 0; int i_ = 0; // // Reverse communication preparations // I know it looks ugly, but it works the same way // anywhere from C++ to Python. // // This code initializes locals by: // * random values determined during code // generation - on first subroutine call // * values from previous call - on subsequent calls // if( state.rstate.stage>=0 ) { n = state.rstate.ia[0]; m = state.rstate.ia[1]; k = state.rstate.ia[2]; i = state.rstate.ia[3]; j = state.rstate.ia[4]; lx = state.rstate.ra[0]; lf = state.rstate.ra[1]; ld = state.rstate.ra[2]; rx = state.rstate.ra[3]; rf = state.rstate.ra[4]; rd = state.rstate.ra[5]; v = state.rstate.ra[6]; vv = state.rstate.ra[7]; relcnt = state.rstate.ra[8]; } else { n = -983; m = -989; k = -834; i = 900; j = -287; lx = 364; lf = 214; ld = -338; rx = -686; rf = 912; rd = 585; v = 497; vv = -271; relcnt = -581; } if( state.rstate.stage==0 ) { goto lbl_0; } if( state.rstate.stage==1 ) { goto lbl_1; } if( state.rstate.stage==2 ) { goto lbl_2; } if( state.rstate.stage==3 ) { goto lbl_3; } if( state.rstate.stage==4 ) { goto lbl_4; } if( state.rstate.stage==5 ) { goto lbl_5; } if( state.rstate.stage==6 ) { goto lbl_6; } if( state.rstate.stage==7 ) { goto lbl_7; } if( state.rstate.stage==8 ) { goto lbl_8; } if( state.rstate.stage==9 ) { goto lbl_9; } // // Routine body // // // Init // if( state.wkind==1 ) { alglib.ap.assert(state.npoints==state.nweights, "LSFitFit: number of points is not equal to the number of weights"); } state.repvaridx = -1; n = state.npoints; m = state.m; k = state.k; minlm.minlmsetcond(state.optstate, 0.0, state.epsf, state.epsx, state.maxits); minlm.minlmsetstpmax(state.optstate, state.stpmax); minlm.minlmsetxrep(state.optstate, state.xrep); minlm.minlmsetscale(state.optstate, state.s); minlm.minlmsetbc(state.optstate, state.bndl, state.bndu); // // Check, that transferred derivative value is right // lsfitclearrequestfields(state); if( !((double)(state.teststep)>(double)(0) && state.optalgo==1) ) { goto lbl_10; } for(i=0; i<=k-1; i++) { if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } } state.needfg = true; i = 0; lbl_12: if( i>k-1 ) { goto lbl_14; } alglib.ap.assert((double)(state.bndl[i])<=(double)(state.c[i]) && (double)(state.c[i])<=(double)(state.bndu[i]), "LSFitIteration: internal error(State.C is out of bounds)"); v = state.c[i]; j = 0; lbl_15: if( j>n-1 ) { goto lbl_17; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[j,i_]; } state.c[i] = v-state.teststep*state.s[i]; if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } lx = state.c[i]; state.rstate.stage = 0; goto lbl_rcomm; lbl_0: lf = state.f; ld = state.g[i]; state.c[i] = v+state.teststep*state.s[i]; if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } rx = state.c[i]; state.rstate.stage = 1; goto lbl_rcomm; lbl_1: rf = state.f; rd = state.g[i]; state.c[i] = (lx+rx)/2; if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } state.rstate.stage = 2; goto lbl_rcomm; lbl_2: state.c[i] = v; if( !optserv.derivativecheck(lf, ld, rf, rd, state.f, state.g[i], rx-lx) ) { state.repvaridx = i; state.repterminationtype = -7; result = false; return result; } j = j+1; goto lbl_15; lbl_17: i = i+1; goto lbl_12; lbl_14: state.needfg = false; lbl_10: // // Optimize // lbl_18: if( !minlm.minlmiteration(state.optstate) ) { goto lbl_19; } if( !state.optstate.needfi ) { goto lbl_20; } // // calculate f[] = wi*(f(xi,c)-yi) // i = 0; lbl_22: if( i>n-1 ) { goto lbl_24; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 3; goto lbl_rcomm; lbl_3: state.needf = false; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.fi[i] = vv*(state.f-state.tasky[i]); i = i+1; goto lbl_22; lbl_24: goto lbl_18; lbl_20: if( !state.optstate.needf ) { goto lbl_25; } // // calculate F = sum (wi*(f(xi,c)-yi))^2 // state.optstate.f = 0; i = 0; lbl_27: if( i>n-1 ) { goto lbl_29; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 4; goto lbl_rcomm; lbl_4: state.needf = false; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); i = i+1; goto lbl_27; lbl_29: goto lbl_18; lbl_25: if( !state.optstate.needfg ) { goto lbl_30; } // // calculate F/gradF // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } i = 0; lbl_32: if( i>n-1 ) { goto lbl_34; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 5; goto lbl_rcomm; lbl_5: state.needfg = false; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); v = math.sqr(vv)*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } i = i+1; goto lbl_32; lbl_34: goto lbl_18; lbl_30: if( !state.optstate.needfij ) { goto lbl_35; } // // calculate Fi/jac(Fi) // i = 0; lbl_37: if( i>n-1 ) { goto lbl_39; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 6; goto lbl_rcomm; lbl_6: state.needfg = false; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.fi[i] = vv*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.j[i,i_] = vv*state.g[i_]; } i = i+1; goto lbl_37; lbl_39: goto lbl_18; lbl_35: if( !state.optstate.needfgh ) { goto lbl_40; } // // calculate F/grad(F)/hess(F) // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { state.optstate.h[i,j] = 0; } } i = 0; lbl_42: if( i>n-1 ) { goto lbl_44; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfgh = true; state.rstate.stage = 7; goto lbl_rcomm; lbl_7: state.needfgh = false; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); v = math.sqr(vv)*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } for(j=0; j<=k-1; j++) { v = 2*math.sqr(vv)*state.g[j]; for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.g[i_]; } v = 2*math.sqr(vv)*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.h[j,i_]; } } i = i+1; goto lbl_42; lbl_44: goto lbl_18; lbl_40: if( !state.optstate.xupdated ) { goto lbl_45; } // // Report new iteration // for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } state.f = state.optstate.f; lsfitclearrequestfields(state); state.xupdated = true; state.rstate.stage = 8; goto lbl_rcomm; lbl_8: state.xupdated = false; goto lbl_18; lbl_45: goto lbl_18; lbl_19: minlm.minlmresults(state.optstate, ref state.c, state.optrep); state.repterminationtype = state.optrep.terminationtype; state.repiterationscount = state.optrep.iterationscount; // // calculate errors // if( state.repterminationtype<=0 ) { goto lbl_47; } state.reprmserror = 0; state.repwrmserror = 0; state.repavgerror = 0; state.repavgrelerror = 0; state.repmaxerror = 0; relcnt = 0; i = 0; lbl_49: if( i>n-1 ) { goto lbl_51; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.c[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 9; goto lbl_rcomm; lbl_9: state.needf = false; v = state.f; if( state.wkind==1 ) { vv = state.w[i]; } else { vv = 1.0; } state.reprmserror = state.reprmserror+math.sqr(v-state.tasky[i]); state.repwrmserror = state.repwrmserror+math.sqr(vv*(v-state.tasky[i])); state.repavgerror = state.repavgerror+Math.Abs(v-state.tasky[i]); if( (double)(state.tasky[i])!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror+Math.Abs(v-state.tasky[i])/Math.Abs(state.tasky[i]); relcnt = relcnt+1; } state.repmaxerror = Math.Max(state.repmaxerror, Math.Abs(v-state.tasky[i])); i = i+1; goto lbl_49; lbl_51: state.reprmserror = Math.Sqrt(state.reprmserror/n); state.repwrmserror = Math.Sqrt(state.repwrmserror/n); state.repavgerror = state.repavgerror/n; if( (double)(relcnt)!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror/relcnt; } lbl_47: result = false; return result; // // Saving state // lbl_rcomm: result = true; state.rstate.ia[0] = n; state.rstate.ia[1] = m; state.rstate.ia[2] = k; state.rstate.ia[3] = i; state.rstate.ia[4] = j; state.rstate.ra[0] = lx; state.rstate.ra[1] = lf; state.rstate.ra[2] = ld; state.rstate.ra[3] = rx; state.rstate.ra[4] = rf; state.rstate.ra[5] = rd; state.rstate.ra[6] = v; state.rstate.ra[7] = vv; state.rstate.ra[8] = relcnt; return result; }
/************************************************************************* NOTES: 1. this algorithm is somewhat unusual because it works with parameterized function f(C,X), where X is a function argument (we have many points which are characterized by different argument values), and C is a parameter to fit. For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then x will be argument, and {c0,c1} will be parameters. It is important to understand that this algorithm finds minimum in the space of function PARAMETERS (not arguments), so it needs derivatives of f() with respect to C, not X. In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. 2. Callback functions accept C as the first parameter, and X as the second 3. If state was created with LSFitCreateFG(), algorithm needs just function and its gradient, but if state was created with LSFitCreateFGH(), algorithm will need function, gradient and Hessian. According to the said above, there ase several versions of this function, which accept different sets of callbacks. This flexibility opens way to subtle errors - you may create state with LSFitCreateFGH() (optimization using Hessian), but call function which does not accept Hessian. So when algorithm will request Hessian, there will be no callback to call. In this case exception will be thrown. Be careful to avoid such errors because there is no way to find them at compile time - you can see them at runtime only. -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static bool lsfititeration(lsfitstate state) { bool result = new bool(); double lx = 0; double lf = 0; double ld = 0; double rx = 0; double rf = 0; double rd = 0; int n = 0; int m = 0; int k = 0; double v = 0; double vv = 0; double relcnt = 0; int i = 0; int j = 0; int j1 = 0; int info = 0; int i_ = 0; // // Reverse communication preparations // I know it looks ugly, but it works the same way // anywhere from C++ to Python. // // This code initializes locals by: // * random values determined during code // generation - on first subroutine call // * values from previous call - on subsequent calls // if( state.rstate.stage>=0 ) { n = state.rstate.ia[0]; m = state.rstate.ia[1]; k = state.rstate.ia[2]; i = state.rstate.ia[3]; j = state.rstate.ia[4]; j1 = state.rstate.ia[5]; info = state.rstate.ia[6]; lx = state.rstate.ra[0]; lf = state.rstate.ra[1]; ld = state.rstate.ra[2]; rx = state.rstate.ra[3]; rf = state.rstate.ra[4]; rd = state.rstate.ra[5]; v = state.rstate.ra[6]; vv = state.rstate.ra[7]; relcnt = state.rstate.ra[8]; } else { n = -983; m = -989; k = -834; i = 900; j = -287; j1 = 364; info = 214; lx = -338; lf = -686; ld = 912; rx = 585; rf = 497; rd = -271; v = -581; vv = 745; relcnt = -533; } if( state.rstate.stage==0 ) { goto lbl_0; } if( state.rstate.stage==1 ) { goto lbl_1; } if( state.rstate.stage==2 ) { goto lbl_2; } if( state.rstate.stage==3 ) { goto lbl_3; } if( state.rstate.stage==4 ) { goto lbl_4; } if( state.rstate.stage==5 ) { goto lbl_5; } if( state.rstate.stage==6 ) { goto lbl_6; } if( state.rstate.stage==7 ) { goto lbl_7; } if( state.rstate.stage==8 ) { goto lbl_8; } if( state.rstate.stage==9 ) { goto lbl_9; } if( state.rstate.stage==10 ) { goto lbl_10; } if( state.rstate.stage==11 ) { goto lbl_11; } if( state.rstate.stage==12 ) { goto lbl_12; } if( state.rstate.stage==13 ) { goto lbl_13; } // // Routine body // // // Init // if( state.wkind==1 ) { alglib.ap.assert(state.npoints==state.nweights, "LSFitFit: number of points is not equal to the number of weights"); } state.repvaridx = -1; n = state.npoints; m = state.m; k = state.k; minlm.minlmsetcond(state.optstate, 0.0, state.epsf, state.epsx, state.maxits); minlm.minlmsetstpmax(state.optstate, state.stpmax); minlm.minlmsetxrep(state.optstate, state.xrep); minlm.minlmsetscale(state.optstate, state.s); minlm.minlmsetbc(state.optstate, state.bndl, state.bndu); // // Check that user-supplied gradient is correct // lsfitclearrequestfields(state); if( !((double)(state.teststep)>(double)(0) && state.optalgo==1) ) { goto lbl_14; } for(i=0; i<=k-1; i++) { if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } } state.needfg = true; i = 0; lbl_16: if( i>k-1 ) { goto lbl_18; } alglib.ap.assert((double)(state.bndl[i])<=(double)(state.c[i]) && (double)(state.c[i])<=(double)(state.bndu[i]), "LSFitIteration: internal error(State.C is out of bounds)"); v = state.c[i]; j = 0; lbl_19: if( j>n-1 ) { goto lbl_21; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[j,i_]; } state.c[i] = v-state.teststep*state.s[i]; if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } lx = state.c[i]; state.rstate.stage = 0; goto lbl_rcomm; lbl_0: lf = state.f; ld = state.g[i]; state.c[i] = v+state.teststep*state.s[i]; if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } rx = state.c[i]; state.rstate.stage = 1; goto lbl_rcomm; lbl_1: rf = state.f; rd = state.g[i]; state.c[i] = (lx+rx)/2; if( math.isfinite(state.bndl[i]) ) { state.c[i] = Math.Max(state.c[i], state.bndl[i]); } if( math.isfinite(state.bndu[i]) ) { state.c[i] = Math.Min(state.c[i], state.bndu[i]); } state.rstate.stage = 2; goto lbl_rcomm; lbl_2: state.c[i] = v; if( !optserv.derivativecheck(lf, ld, rf, rd, state.f, state.g[i], rx-lx) ) { state.repvaridx = i; state.repterminationtype = -7; result = false; return result; } j = j+1; goto lbl_19; lbl_21: i = i+1; goto lbl_16; lbl_18: state.needfg = false; lbl_14: // // Fill WCur by weights: // * for WKind=0 unit weights are chosen // * for WKind=1 we use user-supplied weights stored in State.TaskW // apserv.rvectorsetlengthatleast(ref state.wcur, n); for(i=0; i<=n-1; i++) { state.wcur[i] = 1.0; if( state.wkind==1 ) { state.wcur[i] = state.taskw[i]; } } // // Optimize // lbl_22: if( !minlm.minlmiteration(state.optstate) ) { goto lbl_23; } if( !state.optstate.needfi ) { goto lbl_24; } // // calculate f[] = wi*(f(xi,c)-yi) // i = 0; lbl_26: if( i>n-1 ) { goto lbl_28; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 3; goto lbl_rcomm; lbl_3: state.needf = false; vv = state.wcur[i]; state.optstate.fi[i] = vv*(state.f-state.tasky[i]); i = i+1; goto lbl_26; lbl_28: goto lbl_22; lbl_24: if( !state.optstate.needf ) { goto lbl_29; } // // calculate F = sum (wi*(f(xi,c)-yi))^2 // state.optstate.f = 0; i = 0; lbl_31: if( i>n-1 ) { goto lbl_33; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 4; goto lbl_rcomm; lbl_4: state.needf = false; vv = state.wcur[i]; state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); i = i+1; goto lbl_31; lbl_33: goto lbl_22; lbl_29: if( !state.optstate.needfg ) { goto lbl_34; } // // calculate F/gradF // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } i = 0; lbl_36: if( i>n-1 ) { goto lbl_38; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 5; goto lbl_rcomm; lbl_5: state.needfg = false; vv = state.wcur[i]; state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); v = math.sqr(vv)*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } i = i+1; goto lbl_36; lbl_38: goto lbl_22; lbl_34: if( !state.optstate.needfij ) { goto lbl_39; } // // calculate Fi/jac(Fi) // i = 0; lbl_41: if( i>n-1 ) { goto lbl_43; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfg = true; state.rstate.stage = 6; goto lbl_rcomm; lbl_6: state.needfg = false; vv = state.wcur[i]; state.optstate.fi[i] = vv*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.j[i,i_] = vv*state.g[i_]; } i = i+1; goto lbl_41; lbl_43: goto lbl_22; lbl_39: if( !state.optstate.needfgh ) { goto lbl_44; } // // calculate F/grad(F)/hess(F) // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { state.optstate.h[i,j] = 0; } } i = 0; lbl_46: if( i>n-1 ) { goto lbl_48; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needfgh = true; state.rstate.stage = 7; goto lbl_rcomm; lbl_7: state.needfgh = false; vv = state.wcur[i]; state.optstate.f = state.optstate.f+math.sqr(vv*(state.f-state.tasky[i])); v = math.sqr(vv)*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } for(j=0; j<=k-1; j++) { v = 2*math.sqr(vv)*state.g[j]; for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.g[i_]; } v = 2*math.sqr(vv)*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.h[j,i_]; } } i = i+1; goto lbl_46; lbl_48: goto lbl_22; lbl_44: if( !state.optstate.xupdated ) { goto lbl_49; } // // Report new iteration // for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } state.f = state.optstate.f; lsfitclearrequestfields(state); state.xupdated = true; state.rstate.stage = 8; goto lbl_rcomm; lbl_8: state.xupdated = false; goto lbl_22; lbl_49: goto lbl_22; lbl_23: minlm.minlmresults(state.optstate, ref state.c, state.optrep); state.repterminationtype = state.optrep.terminationtype; state.repiterationscount = state.optrep.iterationscount; // // calculate errors // if( state.repterminationtype<=0 ) { goto lbl_51; } // // Calculate RMS/Avg/Max/... errors // state.reprmserror = 0; state.repwrmserror = 0; state.repavgerror = 0; state.repavgrelerror = 0; state.repmaxerror = 0; relcnt = 0; i = 0; lbl_53: if( i>n-1 ) { goto lbl_55; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.c[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(state); state.needf = true; state.rstate.stage = 9; goto lbl_rcomm; lbl_9: state.needf = false; v = state.f; vv = state.wcur[i]; state.reprmserror = state.reprmserror+math.sqr(v-state.tasky[i]); state.repwrmserror = state.repwrmserror+math.sqr(vv*(v-state.tasky[i])); state.repavgerror = state.repavgerror+Math.Abs(v-state.tasky[i]); if( (double)(state.tasky[i])!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror+Math.Abs(v-state.tasky[i])/Math.Abs(state.tasky[i]); relcnt = relcnt+1; } state.repmaxerror = Math.Max(state.repmaxerror, Math.Abs(v-state.tasky[i])); i = i+1; goto lbl_53; lbl_55: state.reprmserror = Math.Sqrt(state.reprmserror/n); state.repwrmserror = Math.Sqrt(state.repwrmserror/n); state.repavgerror = state.repavgerror/n; if( (double)(relcnt)!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror/relcnt; } // // Calculate covariance matrix // apserv.rmatrixsetlengthatleast(ref state.tmpjac, n, k); apserv.rvectorsetlengthatleast(ref state.tmpf, n); apserv.rvectorsetlengthatleast(ref state.tmp, k); if( (double)(state.diffstep)<=(double)(0) ) { goto lbl_56; } // // Compute Jacobian by means of numerical differentiation // lsfitclearrequestfields(state); state.needf = true; i = 0; lbl_58: if( i>n-1 ) { goto lbl_60; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; state.rstate.stage = 10; goto lbl_rcomm; lbl_10: state.tmpf[i] = state.f; j = 0; lbl_61: if( j>k-1 ) { goto lbl_63; } v = state.c[j]; lx = v-state.diffstep*state.s[j]; state.c[j] = lx; if( math.isfinite(state.bndl[j]) ) { state.c[j] = Math.Max(state.c[j], state.bndl[j]); } state.rstate.stage = 11; goto lbl_rcomm; lbl_11: lf = state.f; rx = v+state.diffstep*state.s[j]; state.c[j] = rx; if( math.isfinite(state.bndu[j]) ) { state.c[j] = Math.Min(state.c[j], state.bndu[j]); } state.rstate.stage = 12; goto lbl_rcomm; lbl_12: rf = state.f; state.c[j] = v; if( (double)(rx)!=(double)(lx) ) { state.tmpjac[i,j] = (rf-lf)/(rx-lx); } else { state.tmpjac[i,j] = 0; } j = j+1; goto lbl_61; lbl_63: i = i+1; goto lbl_58; lbl_60: state.needf = false; goto lbl_57; lbl_56: // // Jacobian is calculated with user-provided analytic gradient // lsfitclearrequestfields(state); state.needfg = true; i = 0; lbl_64: if( i>n-1 ) { goto lbl_66; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; state.rstate.stage = 13; goto lbl_rcomm; lbl_13: state.tmpf[i] = state.f; for(j=0; j<=k-1; j++) { state.tmpjac[i,j] = state.g[j]; } i = i+1; goto lbl_64; lbl_66: state.needfg = false; lbl_57: for(i=0; i<=k-1; i++) { state.tmp[i] = 0.0; } estimateerrors(state.tmpjac, state.tmpf, state.tasky, state.wcur, state.tmp, state.s, n, k, state.rep, ref state.tmpjacw, 0); lbl_51: result = false; return result; // // Saving state // lbl_rcomm: result = true; state.rstate.ia[0] = n; state.rstate.ia[1] = m; state.rstate.ia[2] = k; state.rstate.ia[3] = i; state.rstate.ia[4] = j; state.rstate.ia[5] = j1; state.rstate.ia[6] = info; state.rstate.ra[0] = lx; state.rstate.ra[1] = lf; state.rstate.ra[2] = ld; state.rstate.ra[3] = rx; state.rstate.ra[4] = rf; state.rstate.ra[5] = rd; state.rstate.ra[6] = v; state.rstate.ra[7] = vv; state.rstate.ra[8] = relcnt; return result; }
/************************************************************************* Nonlinear least squares fitting results. Called after return from LSFitFit(). INPUT PARAMETERS: State - algorithm state OUTPUT PARAMETERS: Info - completetion code: * -7 gradient verification failed. See LSFitSetGradientCheck() for more information. * 1 relative function improvement is no more than EpsF. * 2 relative step is no more than EpsX. * 4 gradient norm is no more than EpsG * 5 MaxIts steps was taken * 7 stopping conditions are too stringent, further improvement is impossible C - array[0..K-1], solution Rep - optimization report. Following fields are set: * Rep.TerminationType completetion code: * RMSError rms error on the (X,Y). * AvgError average error on the (X,Y). * AvgRelError average relative error on the non-zero Y * MaxError maximum error NON-WEIGHTED ERRORS ARE CALCULATED * WRMSError weighted rms error on the (X,Y). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitresults(lsfitstate state, ref int info, ref double[] c, lsfitreport rep) { int i_ = 0; info = 0; c = new double[0]; info = state.repterminationtype; rep.varidx = state.repvaridx; if( info>0 ) { c = new double[state.k]; for(i_=0; i_<=state.k-1;i_++) { c[i_] = state.c[i_]; } rep.rmserror = state.reprmserror; rep.wrmserror = state.repwrmserror; rep.avgerror = state.repavgerror; rep.avgrelerror = state.repavgrelerror; rep.maxerror = state.repmaxerror; rep.iterationscount = state.repiterationscount; } }
/************************************************************************* This subroutine turns on verification of the user-supplied analytic gradient: * user calls this subroutine before fitting begins * LSFitFit() is called * prior to actual fitting, for each point in data set X_i and each component of parameters being fited C_j algorithm performs following steps: * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], where C_j is j-th parameter and S[j] is a scale of j-th parameter * if needed, steps are bounded with respect to constraints on C[] * F(X_i|C) is evaluated at these trial points * we perform one more evaluation in the middle point of the interval * we build cubic model using function values and derivatives at trial points and we compare its prediction with actual value in the middle point * in case difference between prediction and actual value is higher than some predetermined threshold, algorithm stops with completion code -7; Rep.VarIdx is set to index of the parameter with incorrect derivative. * after verification is over, algorithm proceeds to the actual optimization. NOTE 1: verification needs N*K (points count * parameters count) gradient evaluations. It is very costly and you should use it only for low dimensional problems, when you want to be sure that you've correctly calculated analytic derivatives. You should not use it in the production code (unless you want to check derivatives provided by some third party). NOTE 2: you should carefully choose TestStep. Value which is too large (so large that function behaviour is significantly non-cubic) will lead to false alarms. You may use different step for different parameters by means of setting scale with LSFitSetScale(). NOTE 3: this function may lead to false positives. In case it reports that I-th derivative was calculated incorrectly, you may decrease test step and try one more time - maybe your function changes too sharply and your step is too large for such rapidly chanding function. NOTE 4: this function works only for optimizers created with LSFitCreateWFG() or LSFitCreateFG() constructors. INPUT PARAMETERS: State - structure used to store algorithm state TestStep - verification step: * TestStep=0 turns verification off * TestStep>0 activates verification -- ALGLIB -- Copyright 15.06.2012 by Bochkanov Sergey *************************************************************************/ public static void lsfitsetgradientcheck(lsfitstate state, double teststep) { alglib.ap.assert(math.isfinite(teststep), "LSFitSetGradientCheck: TestStep contains NaN or Infinite"); alglib.ap.assert((double)(teststep)>=(double)(0), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)"); state.teststep = teststep; }
public override alglib.apobject make_copy() { lsfitstate _result = new lsfitstate(); _result.optalgo = optalgo; _result.m = m; _result.k = k; _result.epsf = epsf; _result.epsx = epsx; _result.maxits = maxits; _result.stpmax = stpmax; _result.xrep = xrep; _result.s = (double[])s.Clone(); _result.bndl = (double[])bndl.Clone(); _result.bndu = (double[])bndu.Clone(); _result.taskx = (double[,])taskx.Clone(); _result.tasky = (double[])tasky.Clone(); _result.npoints = npoints; _result.taskw = (double[])taskw.Clone(); _result.nweights = nweights; _result.wkind = wkind; _result.wits = wits; _result.diffstep = diffstep; _result.teststep = teststep; _result.xupdated = xupdated; _result.needf = needf; _result.needfg = needfg; _result.needfgh = needfgh; _result.pointindex = pointindex; _result.x = (double[])x.Clone(); _result.c = (double[])c.Clone(); _result.f = f; _result.g = (double[])g.Clone(); _result.h = (double[,])h.Clone(); _result.wcur = (double[])wcur.Clone(); _result.tmp = (double[])tmp.Clone(); _result.tmpf = (double[])tmpf.Clone(); _result.tmpjac = (double[,])tmpjac.Clone(); _result.tmpjacw = (double[,])tmpjacw.Clone(); _result.tmpnoise = tmpnoise; _result.invrep = (matinv.matinvreport)invrep.make_copy(); _result.repiterationscount = repiterationscount; _result.repterminationtype = repterminationtype; _result.repvaridx = repvaridx; _result.reprmserror = reprmserror; _result.repavgerror = repavgerror; _result.repavgrelerror = repavgrelerror; _result.repmaxerror = repmaxerror; _result.repwrmserror = repwrmserror; _result.rep = (lsfitreport)rep.make_copy(); _result.optstate = (minlm.minlmstate)optstate.make_copy(); _result.optrep = (minlm.minlmreport)optrep.make_copy(); _result.prevnpt = prevnpt; _result.prevalgo = prevalgo; _result.rstate = (rcommstate)rstate.make_copy(); return _result; }
/************************************************************************* Internal subroutine *************************************************************************/ private static void lsfitclearrequestfields(ref lsfitstate state) { state.needf = false; state.needfg = false; state.needfgh = false; }
/************************************************************************* Weighted nonlinear least squares fitting using function values only. Combination of numerical differentiation and secant updates is used to obtain function Jacobian. Nonlinear task min(F(c)) is solved, where F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * w is an N-dimensional vector of weight coefficients, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses only f(c,x[i]). INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. W - weights, array[0..N-1] C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted DiffStep- numerical differentiation step; should not be very small or large; large = loss of accuracy small = growth of round-off errors OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 18.10.2008 by Bochkanov Sergey *************************************************************************/ public static void lsfitcreatewf(double[,] x, double[] y, double[] w, double[] c, int n, int m, int k, double diffstep, lsfitstate state) { int i = 0; int i_ = 0; alglib.ap.assert(n>=1, "LSFitCreateWF: N<1!"); alglib.ap.assert(m>=1, "LSFitCreateWF: M<1!"); alglib.ap.assert(k>=1, "LSFitCreateWF: K<1!"); alglib.ap.assert(alglib.ap.len(c)>=k, "LSFitCreateWF: length(C)<K!"); alglib.ap.assert(apserv.isfinitevector(c, k), "LSFitCreateWF: C contains infinite or NaN values!"); alglib.ap.assert(alglib.ap.len(y)>=n, "LSFitCreateWF: length(Y)<N!"); alglib.ap.assert(apserv.isfinitevector(y, n), "LSFitCreateWF: Y contains infinite or NaN values!"); alglib.ap.assert(alglib.ap.len(w)>=n, "LSFitCreateWF: length(W)<N!"); alglib.ap.assert(apserv.isfinitevector(w, n), "LSFitCreateWF: W contains infinite or NaN values!"); alglib.ap.assert(alglib.ap.rows(x)>=n, "LSFitCreateWF: rows(X)<N!"); alglib.ap.assert(alglib.ap.cols(x)>=m, "LSFitCreateWF: cols(X)<M!"); alglib.ap.assert(apserv.apservisfinitematrix(x, n, m), "LSFitCreateWF: X contains infinite or NaN values!"); alglib.ap.assert(math.isfinite(diffstep), "LSFitCreateWF: DiffStep is not finite!"); alglib.ap.assert((double)(diffstep)>(double)(0), "LSFitCreateWF: DiffStep<=0!"); state.teststep = 0; state.diffstep = diffstep; state.npoints = n; state.nweights = n; state.wkind = 1; state.m = m; state.k = k; lsfitsetcond(state, 0.0, 0.0, 0); lsfitsetstpmax(state, 0.0); lsfitsetxrep(state, false); state.taskx = new double[n, m]; state.tasky = new double[n]; state.taskw = new double[n]; state.c = new double[k]; state.x = new double[m]; for(i_=0; i_<=k-1;i_++) { state.c[i_] = c[i_]; } for(i_=0; i_<=n-1;i_++) { state.taskw[i_] = w[i_]; } for(i=0; i<=n-1; i++) { for(i_=0; i_<=m-1;i_++) { state.taskx[i,i_] = x[i,i_]; } state.tasky[i] = y[i]; } state.s = new double[k]; state.bndl = new double[k]; state.bndu = new double[k]; for(i=0; i<=k-1; i++) { state.s[i] = 1.0; state.bndl[i] = Double.NegativeInfinity; state.bndu[i] = Double.PositiveInfinity; } state.optalgo = 0; state.prevnpt = -1; state.prevalgo = -1; minlm.minlmcreatev(k, n, state.c, diffstep, state.optstate); lsfitclearrequestfields(state); state.rstate.ia = new int[6+1]; state.rstate.ra = new double[8+1]; state.rstate.stage = -1; }
/************************************************************************* Stopping conditions for nonlinear least squares fitting. INPUT PARAMETERS: State - structure which stores algorithm state between calls and which is used for reverse communication. Must be initialized with LSFitNonLinearCreate???() EpsF - stopping criterion. Algorithm stops if |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} EpsX - stopping criterion. Algorithm stops if |X(k+1)-X(k)| <= EpsX*(1+|X(k)|) MaxIts - stopping criterion. Algorithm stops after MaxIts iterations. MaxIts=0 means no stopping criterion. NOTE Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic stopping criterion selection (according to the scheme used by MINLM unit). -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitnonlinearsetcond(ref lsfitstate state, double epsf, double epsx, int maxits) { System.Diagnostics.Debug.Assert((double)(epsf)>=(double)(0), "LSFitNonlinearSetCond: negative EpsF!"); System.Diagnostics.Debug.Assert((double)(epsx)>=(double)(0), "LSFitNonlinearSetCond: negative EpsX!"); System.Diagnostics.Debug.Assert(maxits>=0, "LSFitNonlinearSetCond: negative MaxIts!"); state.epsf = epsf; state.epsx = epsx; state.maxits = maxits; }
/************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitcreatefgh(double[,] x, double[] y, double[] c, int n, int m, int k, lsfitstate state) { int i = 0; int i_ = 0; alglib.ap.assert(n>=1, "LSFitCreateFGH: N<1!"); alglib.ap.assert(m>=1, "LSFitCreateFGH: M<1!"); alglib.ap.assert(k>=1, "LSFitCreateFGH: K<1!"); alglib.ap.assert(alglib.ap.len(c)>=k, "LSFitCreateFGH: length(C)<K!"); alglib.ap.assert(apserv.isfinitevector(c, k), "LSFitCreateFGH: C contains infinite or NaN values!"); alglib.ap.assert(alglib.ap.len(y)>=n, "LSFitCreateFGH: length(Y)<N!"); alglib.ap.assert(apserv.isfinitevector(y, n), "LSFitCreateFGH: Y contains infinite or NaN values!"); alglib.ap.assert(alglib.ap.rows(x)>=n, "LSFitCreateFGH: rows(X)<N!"); alglib.ap.assert(alglib.ap.cols(x)>=m, "LSFitCreateFGH: cols(X)<M!"); alglib.ap.assert(apserv.apservisfinitematrix(x, n, m), "LSFitCreateFGH: X contains infinite or NaN values!"); state.teststep = 0; state.diffstep = 0; state.npoints = n; state.wkind = 0; state.m = m; state.k = k; lsfitsetcond(state, 0.0, 0.0, 0); lsfitsetstpmax(state, 0.0); lsfitsetxrep(state, false); state.taskx = new double[n, m]; state.tasky = new double[n]; state.c = new double[k]; state.h = new double[k, k]; state.x = new double[m]; state.g = new double[k]; for(i_=0; i_<=k-1;i_++) { state.c[i_] = c[i_]; } for(i=0; i<=n-1; i++) { for(i_=0; i_<=m-1;i_++) { state.taskx[i,i_] = x[i,i_]; } state.tasky[i] = y[i]; } state.s = new double[k]; state.bndl = new double[k]; state.bndu = new double[k]; for(i=0; i<=k-1; i++) { state.s[i] = 1.0; state.bndl[i] = Double.NegativeInfinity; state.bndu[i] = Double.PositiveInfinity; } state.optalgo = 2; state.prevnpt = -1; state.prevalgo = -1; minlm.minlmcreatefgh(k, state.c, state.optstate); lsfitclearrequestfields(state); state.rstate.ia = new int[6+1]; state.rstate.ra = new double[8+1]; state.rstate.stage = -1; }
/************************************************************************* Nonlinear least squares fitting. Algorithm iteration. Called after inialization of the State structure with LSFitNonlinearXXX() subroutine. See HTML docs for examples. INPUT PARAMETERS: State - structure which stores algorithm state between subsequent calls and which is used for reverse communication. Must be initialized with LSFitNonlinearXXX() call first. RESULT 1. If subroutine returned False, iterative algorithm has converged. 2. If subroutine returned True, then if: * if State.NeedF=True, function value F(X,C) is required * if State.NeedFG=True, function value F(X,C) and gradient dF/dC(X,C) are required * if State.NeedFGH=True function value F(X,C), gradient dF/dC(X,C) and Hessian are required One and only one of this fields can be set at time. Function, its gradient and Hessian are calculated at (X,C), where X is stored in State.X[0..M-1] and C is stored in State.C[0..K-1]. Results are stored: * function value - in State.F * gradient - in State.G[0..K-1] * Hessian - in State.H[0..K-1,0..K-1] -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static bool lsfitnonlineariteration(ref lsfitstate state) { bool result = new bool(); int n = 0; int m = 0; int k = 0; int i = 0; int j = 0; double v = 0; double relcnt = 0; int i_ = 0; // // Reverse communication preparations // I know it looks ugly, but it works the same way // anywhere from C++ to Python. // // This code initializes locals by: // * random values determined during code // generation - on first subroutine call // * values from previous call - on subsequent calls // if( state.rstate.stage>=0 ) { n = state.rstate.ia[0]; m = state.rstate.ia[1]; k = state.rstate.ia[2]; i = state.rstate.ia[3]; j = state.rstate.ia[4]; v = state.rstate.ra[0]; relcnt = state.rstate.ra[1]; } else { n = -983; m = -989; k = -834; i = 900; j = -287; v = 364; relcnt = 214; } if( state.rstate.stage==0 ) { goto lbl_0; } if( state.rstate.stage==1 ) { goto lbl_1; } if( state.rstate.stage==2 ) { goto lbl_2; } if( state.rstate.stage==3 ) { goto lbl_3; } if( state.rstate.stage==4 ) { goto lbl_4; } // // Routine body // // // check params // if( state.n<1 | state.m<1 | state.k<1 | (double)(state.epsf)<(double)(0) | (double)(state.epsx)<(double)(0) | state.maxits<0 ) { state.repterminationtype = -1; result = false; return result; } // // init // n = state.n; m = state.m; k = state.k; state.x = new double[m]; state.g = new double[k]; if( state.havehess ) { state.h = new double[k, k]; } // // initialize LM optimizer // if( state.havehess ) { // // use Hessian. // transform stopping conditions. // minlm.minlmcreatefgh(k, ref state.c, ref state.optstate); } else { // // use one of gradient-based schemes (depending on gradient cost). // transform stopping conditions. // if( state.cheapfg ) { minlm.minlmcreatefgj(k, n, ref state.c, ref state.optstate); } else { minlm.minlmcreatefj(k, n, ref state.c, ref state.optstate); } } minlm.minlmsetcond(ref state.optstate, 0.0, state.epsf, state.epsx, state.maxits); minlm.minlmsetstpmax(ref state.optstate, state.stpmax); // // Optimize // lbl_5: if( ! minlm.minlmiteration(ref state.optstate) ) { goto lbl_6; } if( ! state.optstate.needf ) { goto lbl_7; } // // calculate F = sum (wi*(f(xi,c)-yi))^2 // state.optstate.f = 0; i = 0; lbl_9: if( i>n-1 ) { goto lbl_11; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(ref state); state.needf = true; state.rstate.stage = 0; goto lbl_rcomm; lbl_0: state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i])); i = i+1; goto lbl_9; lbl_11: goto lbl_5; lbl_7: if( ! state.optstate.needfg ) { goto lbl_12; } // // calculate F/gradF // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } i = 0; lbl_14: if( i>n-1 ) { goto lbl_16; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(ref state); state.needfg = true; state.rstate.stage = 1; goto lbl_rcomm; lbl_1: state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i])); v = AP.Math.Sqr(state.w[i])*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } i = i+1; goto lbl_14; lbl_16: goto lbl_5; lbl_12: if( ! state.optstate.needfij ) { goto lbl_17; } // // calculate Fi/jac(Fi) // i = 0; lbl_19: if( i>n-1 ) { goto lbl_21; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(ref state); state.needfg = true; state.rstate.stage = 2; goto lbl_rcomm; lbl_2: state.optstate.fi[i] = state.w[i]*(state.f-state.tasky[i]); v = state.w[i]; for(i_=0; i_<=k-1;i_++) { state.optstate.j[i,i_] = v*state.g[i_]; } i = i+1; goto lbl_19; lbl_21: goto lbl_5; lbl_17: if( ! state.optstate.needfgh ) { goto lbl_22; } // // calculate F/grad(F)/hess(F) // state.optstate.f = 0; for(i=0; i<=k-1; i++) { state.optstate.g[i] = 0; } for(i=0; i<=k-1; i++) { for(j=0; j<=k-1; j++) { state.optstate.h[i,j] = 0; } } i = 0; lbl_24: if( i>n-1 ) { goto lbl_26; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.optstate.x[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(ref state); state.needfgh = true; state.rstate.stage = 3; goto lbl_rcomm; lbl_3: state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i])); v = AP.Math.Sqr(state.w[i])*2*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_]; } for(j=0; j<=k-1; j++) { v = 2*AP.Math.Sqr(state.w[i])*state.g[j]; for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.g[i_]; } v = 2*AP.Math.Sqr(state.w[i])*(state.f-state.tasky[i]); for(i_=0; i_<=k-1;i_++) { state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.h[j,i_]; } } i = i+1; goto lbl_24; lbl_26: goto lbl_5; lbl_22: goto lbl_5; lbl_6: minlm.minlmresults(ref state.optstate, ref state.c, ref state.optrep); state.repterminationtype = state.optrep.terminationtype; // // calculate errors // if( state.repterminationtype<=0 ) { goto lbl_27; } state.reprmserror = 0; state.repavgerror = 0; state.repavgrelerror = 0; state.repmaxerror = 0; relcnt = 0; i = 0; lbl_29: if( i>n-1 ) { goto lbl_31; } for(i_=0; i_<=k-1;i_++) { state.c[i_] = state.c[i_]; } for(i_=0; i_<=m-1;i_++) { state.x[i_] = state.taskx[i,i_]; } state.pointindex = i; lsfitclearrequestfields(ref state); state.needf = true; state.rstate.stage = 4; goto lbl_rcomm; lbl_4: v = state.f; state.reprmserror = state.reprmserror+AP.Math.Sqr(v-state.tasky[i]); state.repavgerror = state.repavgerror+Math.Abs(v-state.tasky[i]); if( (double)(state.tasky[i])!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror+Math.Abs(v-state.tasky[i])/Math.Abs(state.tasky[i]); relcnt = relcnt+1; } state.repmaxerror = Math.Max(state.repmaxerror, Math.Abs(v-state.tasky[i])); i = i+1; goto lbl_29; lbl_31: state.reprmserror = Math.Sqrt(state.reprmserror/n); state.repavgerror = state.repavgerror/n; if( (double)(relcnt)!=(double)(0) ) { state.repavgrelerror = state.repavgrelerror/relcnt; } lbl_27: result = false; return result; // // Saving state // lbl_rcomm: result = true; state.rstate.ia[0] = n; state.rstate.ia[1] = m; state.rstate.ia[2] = k; state.rstate.ia[3] = i; state.rstate.ia[4] = j; state.rstate.ra[0] = v; state.rstate.ra[1] = relcnt; return result; }
/************************************************************************* Nonlinear least squares fitting using gradient/Hessian, without individial weights. Nonlinear task min(F(c)) is solved, where F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, * N is a number of points, * M is a dimension of a space points belong to, * K is a dimension of a space of parameters being fitted, * x is a set of N points, each of them is an M-dimensional vector, * c is a K-dimensional vector of parameters being fitted This subroutine uses f(c,x[i]), its gradient and its Hessian. INPUT PARAMETERS: X - array[0..N-1,0..M-1], points (one row = one point) Y - array[0..N-1], function values. C - array[0..K-1], initial approximation to the solution, N - number of points, N>1 M - dimension of space K - number of parameters being fitted OUTPUT PARAMETERS: State - structure which stores algorithm state -- ALGLIB -- Copyright 17.08.2009 by Bochkanov Sergey *************************************************************************/ public static void lsfitcreatefgh(double[,] x, double[] y, double[] c, int n, int m, int k, out lsfitstate state) { state = new lsfitstate(); lsfit.lsfitcreatefgh(x, y, c, n, m, k, state.innerobj); return; }