def call_minpack(fun, x0, jac, ftol, xtol, gtol, max_nfev, x_scale, diff_step): n = x0.size if diff_step is None: epsfcn = EPS else: epsfcn = diff_step**2 # Compute MINPACK's `diag`, which is inverse of our `x_scale` and # ``x_scale='jac'`` corresponds to ``diag=None``. if isinstance(x_scale, string_types) and x_scale == 'jac': diag = None else: diag = 1 / x_scale full_output = True col_deriv = False factor = 100.0 if jac is None: if max_nfev is None: # n squared to account for Jacobian evaluations. max_nfev = 100 * n * (n + 1) x, info, status = _minpack._lmdif(fun, x0, (), full_output, ftol, xtol, gtol, max_nfev, epsfcn, factor, diag) else: if max_nfev is None: max_nfev = 100 * n x, info, status = _minpack._lmder(fun, jac, x0, (), full_output, col_deriv, ftol, xtol, gtol, max_nfev, factor, diag) f = info['fvec'] if callable(jac): J = jac(x) else: J = np.atleast_2d(approx_derivative(fun, x)) cost = 0.5 * np.dot(f, f) g = J.T.dot(f) g_norm = norm(g, ord=np.inf) nfev = info['nfev'] njev = info.get('njev', None) status = FROM_MINPACK_TO_COMMON[status] active_mask = np.zeros_like(x0, dtype=int) return OptimizeResult(x=x, cost=cost, fun=f, jac=J, grad=g, optimality=g_norm, active_mask=active_mask, nfev=nfev, njev=njev, status=status)
def call_minpack(fun, x0, jac, ftol, xtol, gtol, max_nfev, scaling, diff_step): n = x0.size if diff_step is None: epsfcn = EPS else: epsfcn = diff_step ** 2 if isinstance(scaling, string_types) and scaling == "jac": scaling = None full_output = True col_deriv = False factor = 100.0 if jac is None: if max_nfev is None: # n squared to account for Jacobian evaluations. max_nfev = 100 * n * (n + 1) x, info, status = _minpack._lmdif(fun, x0, (), full_output, ftol, xtol, gtol, max_nfev, epsfcn, factor, scaling) else: if max_nfev is None: max_nfev = 100 * n x, info, status = _minpack._lmder( fun, jac, x0, (), full_output, col_deriv, ftol, xtol, gtol, max_nfev, factor, scaling ) f = info["fvec"] if callable(jac): J = jac(x) else: J = np.atleast_2d(approx_derivative(fun, x)) cost = 0.5 * np.dot(f, f) g = J.T.dot(f) g_norm = norm(g, ord=np.inf) nfev = info["nfev"] njev = info.get("njev", None) status = FROM_MINPACK_TO_COMMON[status] active_mask = np.zeros_like(x0, dtype=int) return OptimizeResult( x=x, cost=cost, fun=f, jac=J, grad=g, optimality=g_norm, active_mask=active_mask, nfev=nfev, njev=njev, status=status, )
def call_minpack(fun, x0, jac, ftol, xtol, gtol, max_nfev, x_scale, diff_step): n = x0.size if diff_step is None: epsfcn = EPS else: epsfcn = diff_step**2 # Compute MINPACK's `diag`, which is inverse of our `x_scale` and # ``x_scale='jac'`` corresponds to ``diag=None``. if isinstance(x_scale, string_types) and x_scale == 'jac': diag = None else: diag = 1 / x_scale full_output = True col_deriv = False factor = 100.0 if jac is None: if max_nfev is None: # n squared to account for Jacobian evaluations. max_nfev = 100 * n * (n + 1) x, info, status = _minpack._lmdif( fun, x0, (), full_output, ftol, xtol, gtol, max_nfev, epsfcn, factor, diag) else: if max_nfev is None: max_nfev = 100 * n x, info, status = _minpack._lmder( fun, jac, x0, (), full_output, col_deriv, ftol, xtol, gtol, max_nfev, factor, diag) f = info['fvec'] if callable(jac): J = jac(x) else: J = np.atleast_2d(approx_derivative(fun, x)) cost = 0.5 * np.dot(f, f) g = J.T.dot(f) g_norm = norm(g, ord=np.inf) nfev = info['nfev'] njev = info.get('njev', None) status = FROM_MINPACK_TO_COMMON[status] active_mask = np.zeros_like(x0, dtype=int) return OptimizeResult( x=x, cost=cost, fun=f, jac=J, grad=g, optimality=g_norm, active_mask=active_mask, nfev=nfev, njev=njev, status=status)
def call_minpack(fun, x0, jac, ftol, xtol, gtol, max_nfev, scaling, diff_step): n = x0.size if diff_step is None: epsfcn = EPS else: epsfcn = diff_step**2 if scaling == 'jac': scaling = None full_output = True col_deriv = False factor = 100.0 if jac is None: if max_nfev is None: # n squared to account for Jacobian evaluations. max_nfev = 100 * n * (n + 1) x, info, status = _minpack._lmdif( fun, x0, (), full_output, ftol, xtol, gtol, max_nfev, epsfcn, factor, scaling) else: if max_nfev is None: max_nfev = 100 * n x, info, status = _minpack._lmder( fun, jac, x0, (), full_output, col_deriv, ftol, xtol, gtol, max_nfev, factor, scaling) f = info['fvec'] if callable(jac): J = jac(x) else: J = np.atleast_2d(approx_derivative(fun, x)) cost = 0.5 * np.dot(f, f) g = J.T.dot(f) g_norm = norm(g, ord=np.inf) nfev = info['nfev'] njev = info.get('njev', None) status = FROM_MINPACK_TO_COMMON[status] active_mask = np.zeros_like(x0, dtype=int) return OptimizeResult( x=x, cost=cost, fun=f, jac=J, grad=g, optimality=g_norm, active_mask=active_mask, nfev=nfev, njev=njev, status=status)
def fit_with_gauss(x, y): # It is better to start as close as possible to the real solution. So I # take the maximum value of the y's as a prior for the amplitude, and # the location of the peak as a prior for the mu peak = np.argmax(y) p0 = [y[peak], x[peak], 1., 0.0] #p0 = [1., 0., 1., 0.] #coeff, var_matrix = curve_fit(fgauss.gauss, x, y, p0=p0) #coeff, var_matrix = curve_fit(gauss, x, y, p0=p0) #coeff = leastsq(fgauss.gauss_res, p0, args=(x,y), maxfev=500, full_output=True) #coeff = leastsq(fgauss.gauss_res, p0, args=(x,y), Dfun=fgauss.gauss_jacob, col_deriv=1, maxfev=500)[0] #coeff = minpack._lmdif(fgauss.gauss_res, p0, (x,y), 0, 1.49012e-8, 1.49012e-8, # 0.0, 500, 0.0, 100, None)[0] coeff = minpack._lmder(fgauss.gauss_res, fgauss.gauss_jacob, p0, (x, y), 0, 1, 1.49012e-8, 1.49012e-8, 0.0, 500, 100, None)[0] return coeff
def leastsqbound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=0.0, factor=100, diag=None): """ Bounded minimization of the sum of squares of a set of equations. :: x = arg min(sum(func(y)**2,axis=0)) y Parameters ---------- func : callable should take at least one (possibly length N vector) argument and returns M floating point numbers. x0 : ndarray The starting estimate for the minimization. args : tuple Any extra arguments to func are placed in this tuple. bounds : list ``(min, max)`` pairs for each element in ``x``, defining the bounds on that parameter. Use None for one of ``min`` or ``max`` when there is no bound in that direction. Dfun : callable A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated. full_output : bool non-zero to return all optional outputs. col_deriv : bool non-zero to specify that the Jacobian function computes derivatives down the columns (faster, because there is no transpose operation). ftol : float Relative error desired in the sum of squares. xtol : float Relative error desired in the approximate solution. gtol : float Orthogonality desired between the function vector and the columns of the Jacobian. maxfev : int The maximum number of calls to the function. If zero, then 100*(N+1) is the maximum where N is the number of elements in x0. epsfcn : float A suitable step length for the forward-difference approximation of the Jacobian (for Dfun=None). If epsfcn is less than the machine precision, it is assumed that the relative errors in the functions are of the order of the machine precision. factor : float A parameter determining the initial step bound (``factor * || diag * x||``). Should be in interval ``(0.1, 100)``. diag : sequence N positive entries that serve as a scale factors for the variables. Returns ------- x : ndarray The solution (or the result of the last iteration for an unsuccessful call). cov_x : ndarray Uses the fjac and ipvt optional outputs to construct an estimate of the jacobian around the solution. ``None`` if a singular matrix encountered (indicates very flat curvature in some direction). This matrix must be multiplied by the residual standard deviation to get the covariance of the parameter estimates -- see curve_fit. infodict : dict a dictionary of optional outputs with the key s:: - 'nfev' : the number of function calls - 'fvec' : the function evaluated at the output - 'fjac' : A permutation of the R matrix of a QR factorization of the final approximate Jacobian matrix, stored column wise. Together with ipvt, the covariance of the estimate can be approximated. - 'ipvt' : an integer array of length N which defines a permutation matrix, p, such that fjac*p = q*r, where r is upper triangular with diagonal elements of nonincreasing magnitude. Column j of p is column ipvt(j) of the identity matrix. - 'qtf' : the vector (transpose(q) * fvec). mesg : str A string message giving information about the cause of failure. ier : int An integer flag. If it is equal to 1, 2, 3 or 4, the solution was found. Otherwise, the solution was not found. In either case, the optional output variable 'mesg' gives more information. Notes ----- "leastsq" is a wrapper around MINPACK's lmdif and lmder algorithms. cov_x is a Jacobian approximation to the Hessian of the least squares objective function. This approximation assumes that the objective function is based on the difference between some observed target data (ydata) and a (non-linear) function of the parameters `f(xdata, params)` :: func(params) = ydata - f(xdata, params) so that the objective function is :: min sum((ydata - f(xdata, params))**2, axis=0) params Contraints on the parameters are enforced using an internal parameter list with appropiate transformations such that these internal parameters can be optimized without constraints. The transfomation between a given internal parameter, p_i, and a external parameter, p_e, are as follows: With ``min`` and ``max`` bounds defined :: p_i = arcsin((2 * (p_e - min) / (max - min)) - 1.) p_e = min + ((max - min) / 2.) * (sin(p_i) + 1.) With only ``max`` defined :: p_i = sqrt((max - p_e + 1.)**2 - 1.) p_e = max + 1. - sqrt(p_i**2 + 1.) With only ``min`` defined :: p_i = sqrt((p_e - min + 1.)**2 - 1.) p_e = min - 1. + sqrt(p_i**2 + 1.) These transfomations are used in the MINUIT package, and described in detail in the section 1.3.1 of the MINUIT User's Guide. To Do ----- Currently the ``factor`` and ``diag`` parameters scale the internal parameter list, but should scale the external parameter list. The `qtf` vector in the infodic dictionary reflects internal parameter list, it should be correct to reflect the external parameter list. References ---------- * F. James and M. Winkler. MINUIT User's Guide, July 16, 2004. """ # use leastsq if no bounds are present if bounds is None: return leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) # create function which convert between internal and external parameters i2e = _internal2external_func(bounds) e2i = _external2internal_func(bounds) x0 = array(x0, ndmin=1) i0 = e2i(x0) n = len(x0) if len(bounds) != n: raise ValueError('length of x0 != length of bounds') if type(args) != type(()): args = (args, ) m = _check_func('leastsq', 'func', func, x0, args, n)[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) # define a wrapped func which accept internal parameters, converts them # to external parameters and calls func def wfunc(x, *args): return func(i2e(x), *args) if Dfun is None: if (maxfev == 0): maxfev = 200 * (n + 1) retval = _minpack._lmdif(wfunc, i0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if (maxfev == 0): maxfev = 100 * (n + 1) def wDfun(x, *args): # wrapped Dfun return Dfun(i2e(x), *args) retval = _minpack._lmder(func, wDfun, i0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = { 0: ["Improper input parameters.", TypeError], 1: [ "Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None ], 2: [ "The relative error between two consecutive " "iterates is at most %f" % xtol, None ], 3: [ "Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None ], 4: [ "The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None ], 5: [ "Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError ], 6: [ "ftol=%f is too small, no further reduction " "in the sum of squares\n is possible." "" % ftol, ValueError ], 7: [ "xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError ], 8: [ "gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError ], 'unknown': ["Unknown error.", TypeError] } info = retval[-1] # The FORTRAN return value if (info not in [1, 2, 3, 4] and not full_output): if info in [5, 6, 7, 8]: warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) # internal params to external params if full_output: # convert fjac from internal params to external grad = _internal2external_grad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except LinAlgError: pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)
def leastsqbound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): """ Bounded minimization of the sum of squares of a set of equations. :: x = arg min(sum(func(y)**2,axis=0)) y Parameters ---------- func : callable should take at least one (possibly length N vector) argument and returns M floating point numbers. x0 : ndarray The starting estimate for the minimization. args : tuple Any extra arguments to func are placed in this tuple. bounds : list ``(min, max)`` pairs for each element in ``x``, defining the bounds on that parameter. Use None for one of ``min`` or ``max`` when there is no bound in that direction. Dfun : callable A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated. full_output : bool non-zero to return all optional outputs. col_deriv : bool non-zero to specify that the Jacobian function computes derivatives down the columns (faster, because there is no transpose operation). ftol : float Relative error desired in the sum of squares. xtol : float Relative error desired in the approximate solution. gtol : float Orthogonality desired between the function vector and the columns of the Jacobian. maxfev : int The maximum number of calls to the function. If zero, then 100*(N+1) is the maximum where N is the number of elements in x0. epsfcn : float A suitable step length for the forward-difference approximation of the Jacobian (for Dfun=None). If epsfcn is less than the machine precision, it is assumed that the relative errors in the functions are of the order of the machine precision. factor : float A parameter determining the initial step bound (``factor * || diag * x||``). Should be in interval ``(0.1, 100)``. diag : sequence N positive entries that serve as a scale factors for the variables. Returns ------- x : ndarray The solution (or the result of the last iteration for an unsuccessful call). cov_x : ndarray Uses the fjac and ipvt optional outputs to construct an estimate of the jacobian around the solution. ``None`` if a singular matrix encountered (indicates very flat curvature in some direction). This matrix must be multiplied by the residual standard deviation to get the covariance of the parameter estimates -- see curve_fit. infodict : dict a dictionary of optional outputs with the key s:: - 'nfev' : the number of function calls - 'fvec' : the function evaluated at the output - 'fjac' : A permutation of the R matrix of a QR factorization of the final approximate Jacobian matrix, stored column wise. Together with ipvt, the covariance of the estimate can be approximated. - 'ipvt' : an integer array of length N which defines a permutation matrix, p, such that fjac*p = q*r, where r is upper triangular with diagonal elements of nonincreasing magnitude. Column j of p is column ipvt(j) of the identity matrix. - 'qtf' : the vector (transpose(q) * fvec). mesg : str A string message giving information about the cause of failure. ier : int An integer flag. If it is equal to 1, 2, 3 or 4, the solution was found. Otherwise, the solution was not found. In either case, the optional output variable 'mesg' gives more information. Notes ----- "leastsq" is a wrapper around MINPACK's lmdif and lmder algorithms. cov_x is a Jacobian approximation to the Hessian of the least squares objective function. This approximation assumes that the objective function is based on the difference between some observed target data (ydata) and a (non-linear) function of the parameters `f(xdata, params)` :: func(params) = ydata - f(xdata, params) so that the objective function is :: min sum((ydata - f(xdata, params))**2, axis=0) params Contraints on the parameters are enforced using an internal parameter list with appropiate transformations such that these internal parameters can be optimized without constraints. The transfomation between a given internal parameter, p_i, and a external parameter, p_e, are as follows: With ``min`` and ``max`` bounds defined :: p_i = arcsin((2 * (p_e - min) / (max - min)) - 1.) p_e = min + ((max - min) / 2.) * (sin(p_i) + 1.) With only ``max`` defined :: p_i = sqrt((max - p_e + 1.)**2 - 1.) p_e = max + 1. - sqrt(p_i**2 + 1.) With only ``min`` defined :: p_i = sqrt((p_e - min + 1.)**2 - 1.) p_e = min - 1. + sqrt(p_i**2 + 1.) These transfomations are used in the MINUIT package, and described in detail in the section 1.3.1 of the MINUIT User's Guide. To Do ----- Currently the ``factor`` and ``diag`` parameters scale the internal parameter list, but should scale the external parameter list. The `qtf` vector in the infodic dictionary reflects internal parameter list, it should be correct to reflect the external parameter list. References ---------- * F. James and M. Winkler. MINUIT User's Guide, July 16, 2004. """ # use leastsq if no bounds are present if bounds is None: return leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) # create function which convert between internal and external parameters i2e = _internal2external_func(bounds) e2i = _external2internal_func(bounds) x0 = asarray(x0).flatten() i0 = e2i(x0) n = len(x0) if len(bounds) != n: raise ValueError('length of x0 != length of bounds') if not isinstance(args, tuple): args = (args,) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = finfo(dtype).eps # define a wrapped func which accept internal parameters, converts them # to external parameters and calls func def wfunc(x, *args): return func(i2e(x), *args) if Dfun is None: if (maxfev == 0): maxfev = 200 * (n + 1) retval = _minpack._lmdif(wfunc, i0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if (maxfev == 0): maxfev = 100 * (n + 1) def wDfun(x, *args): # wrapped Dfun return Dfun(i2e(x), *args) retval = _minpack._lmder(wfunc, wDfun, i0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = {0: ["Improper input parameters.", TypeError], 1: ["Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None], 2: ["The relative error between two consecutive " "iterates is at most %f" % xtol, None], 3: ["Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None], 4: ["The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None], 5: ["Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError], 6: ["ftol=%f is too small, no further reduction " "in the sum of squares\n is possible.""" % ftol, ValueError], 7: ["xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError], 8: ["gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError], 'unknown': ["Unknown error.", TypeError]} info = retval[-1] # The FORTRAN return value if (info not in [1, 2, 3, 4] and not full_output): if info in [5, 6, 7, 8]: warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) # internal params to external params if full_output: # convert fjac from internal params to external grad = _internal2external_grad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except LinAlgError: pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)
def leastsqBound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): from scipy.optimize import _minpack """ Non-linear least square fitting (Levenberg-Marquardt method) with bounded parameters. the codes of transformation between int <-> ext refers to the work of Jonathan J. Helmus: https://github.com/jjhelmus/leastsqbound-scipy other codes refers to the source code of minpack.py: ..\Lib\site-packages\scipy\optimize\minpack.py An internal parameter list is used to enforce contraints on the fitting parameters. The transfomation is based on that of MINUIT package. please see: F. James and M. Winkler. MINUIT User's Guide, 2004. bounds : list (min, max) pairs for each parameter, use None for 'min' or 'max' when there is no bound in that direction. For example: if there are two parameters needed to be fitting, then bounds is [(min1,max1), (min2,max2)] This function is based on 'leastsq' of minpack.py, the annotation of other parameters can be found in 'leastsq'. ..\Lib\site-packages\scipy\optimize\minpack.py """ def _check_func(checker, argname, thefunc, x0, args, numinputs, output_shape=None): """The same as that of minpack.py""" res = np.atleast_1d(thefunc(*((x0[:numinputs],) + args))) if (output_shape is not None) and (shape(res) != output_shape): if (output_shape[0] != 1): if len(output_shape) > 1: if output_shape[1] == 1: return shape(res) msg = "%s: there is a mismatch between the input and output " \ "shape of the '%s' argument" % (checker, argname) func_name = getattr(thefunc, '__name__', None) if func_name: msg += " '%s'." % func_name else: msg += "." raise TypeError(msg) if np.issubdtype(res.dtype, np.inexact): dt = res.dtype else: dt = dtype(float) return shape(res), dt def _int2extGrad(p_int, bounds): """Calculate the gradients of transforming the internal (unconstrained) to external (constrained) parameter.""" grad = np.empty_like(p_int) for i, (x, bound) in enumerate(zip(p_int, bounds)): lower, upper = bound if lower is None and upper is None: # No constraints grad[i] = 1.0 elif upper is None: # only lower bound grad[i] = x/np.sqrt(x*x + 1.0) elif lower is None: # only upper bound grad[i] = -x/np.sqrt(x*x + 1.0) else: # lower and upper bounds grad[i] = (upper - lower)*np.cos(x)/2.0 return grad def _int2extFunc(bounds): """transform internal parameters into external parameters.""" local = [_int2extLocal(b) for b in bounds] def _transform_i2e(p_int): p_ext = np.empty_like(p_int) p_ext[:] = [i(j) for i, j in zip(local, p_int)] return p_ext return _transform_i2e def _ext2intFunc(bounds): """transform external parameters into internal parameters.""" local = [_ext2intLocal(b) for b in bounds] def _transform_e2i(p_ext): p_int = np.empty_like(p_ext) p_int[:] = [i(j) for i, j in zip(local, p_ext)] return p_int return _transform_e2i def _int2extLocal(bound): """transform a single internal parameter to an external parameter.""" lower, upper = bound if lower is None and upper is None: # no constraints return lambda x: x elif upper is None: # only lower bound return lambda x: lower - 1.0 + np.sqrt(x*x + 1.0) elif lower is None: # only upper bound return lambda x: upper + 1.0 - np.sqrt(x*x + 1.0) else: return lambda x: lower + ((upper - lower)/2.0)*(np.sin(x) + 1.0) def _ext2intLocal(bound): """transform a single external parameter to an internal parameter.""" lower, upper = bound if lower is None and upper is None: # no constraints return lambda x: x elif upper is None: # only lower bound return lambda x: np.sqrt((x - lower + 1.0)**2 - 1.0) elif lower is None: # only upper bound return lambda x: np.sqrt((x - upper - 1.0)**2 - 1.0) else: return lambda x: np.arcsin((2.0*(x - lower)/(upper - lower)) - 1.0) i2e = _int2extFunc(bounds) e2i = _ext2intFunc(bounds) x0 = np.asarray(x0).flatten() n = len(x0) if len(bounds) != n: raise ValueError('the length of bounds is inconsistent with the number of parameters ') if not isinstance(args, tuple): args = (args,) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = np.finfo(dtype).eps def funcWarp(x, *args): return func(i2e(x), *args) xi0 = e2i(x0) if Dfun is None: if maxfev == 0: maxfev = 200*(n + 1) retval = _minpack._lmdif(funcWarp, xi0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if maxfev == 0: maxfev = 100*(n + 1) def DfunWarp(x, *args): return Dfun(i2e(x), *args) retval = _minpack._lmder(funcWarp, DfunWarp, xi0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = {0: ["Improper input parameters.", TypeError], 1: ["Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None], 2: ["The relative error between two consecutive " "iterates is at most %f" % xtol, None], 3: ["Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None], 4: ["The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None], 5: ["Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError], 6: ["ftol=%f is too small, no further reduction " "in the sum of squares\n is possible.""" % ftol, ValueError], 7: ["xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError], 8: ["gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError], 'unknown': ["Unknown error.", TypeError]} info = retval[-1] # The FORTRAN return value if info not in [1, 2, 3, 4] and not full_output: if info in [5, 6, 7, 8]: np.warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) if full_output: grad = _int2extGrad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / np.take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = np.take(np.eye(n), retval[1]['ipvt'] - 1, 0) r = np.triu(np.transpose(retval[1]['fjac'])[:n, :]) R = np.dot(r, perm) try: cov_x = inv(np.dot(np.transpose(R), R)) except LinAlgError as inverror: print(inverror) pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)
def leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): """ Minimize the sum of squares of a set of equations. :: x = arg min(sum(func(y)**2,axis=0)) y Parameters ---------- func : callable should take at least one (possibly length N vector) argument and returns M floating point numbers. It must not return NaNs or fitting might fail. x0 : ndarray The starting estimate for the minimization. args : tuple, optional Any extra arguments to func are placed in this tuple. Dfun : callable, optional A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated. full_output : bool, optional non-zero to return all optional outputs. col_deriv : bool, optional non-zero to specify that the Jacobian function computes derivatives down the columns (faster, because there is no transpose operation). ftol : float, optional Relative error desired in the sum of squares. xtol : float, optional Relative error desired in the approximate solution. gtol : float, optional Orthogonality desired between the function vector and the columns of the Jacobian. maxfev : int, optional The maximum number of calls to the function. If `Dfun` is provided then the default `maxfev` is 100*(N+1) where N is the number of elements in x0, otherwise the default `maxfev` is 200*(N+1). epsfcn : float, optional A variable used in determining a suitable step length for the forward- difference approximation of the Jacobian (for Dfun=None). Normally the actual step length will be sqrt(epsfcn)*x If epsfcn is less than the machine precision, it is assumed that the relative errors are of the order of the machine precision. factor : float, optional A parameter determining the initial step bound (``factor * || diag * x||``). Should be in interval ``(0.1, 100)``. diag : sequence, optional N positive entries that serve as a scale factors for the variables. Returns ------- x : ndarray The solution (or the result of the last iteration for an unsuccessful call). cov_x : ndarray The inverse of the Hessian. `fjac` and `ipvt` are used to construct an estimate of the Hessian. A value of None indicates a singular matrix, which means the curvature in parameters `x` is numerically flat. To obtain the covariance matrix of the parameters `x`, `cov_x` must be multiplied by the variance of the residuals -- see curve_fit. infodict : dict a dictionary of optional outputs with the keys: ``nfev`` The number of function calls ``fvec`` The function evaluated at the output ``fjac`` A permutation of the R matrix of a QR factorization of the final approximate Jacobian matrix, stored column wise. Together with ipvt, the covariance of the estimate can be approximated. ``ipvt`` An integer array of length N which defines a permutation matrix, p, such that fjac*p = q*r, where r is upper triangular with diagonal elements of nonincreasing magnitude. Column j of p is column ipvt(j) of the identity matrix. ``qtf`` The vector (transpose(q) * fvec). mesg : str A string message giving information about the cause of failure. ier : int An integer flag. If it is equal to 1, 2, 3 or 4, the solution was found. Otherwise, the solution was not found. In either case, the optional output variable 'mesg' gives more information. See Also -------- least_squares : Newer interface to solve nonlinear least-squares problems with bounds on the variables. See ``method=='lm'`` in particular. Notes ----- "leastsq" is a wrapper around MINPACK's lmdif and lmder algorithms. cov_x is a Jacobian approximation to the Hessian of the least squares objective function. This approximation assumes that the objective function is based on the difference between some observed target data (ydata) and a (non-linear) function of the parameters `f(xdata, params)` :: func(params) = ydata - f(xdata, params) so that the objective function is :: min sum((ydata - f(xdata, params))**2, axis=0) params The solution, `x`, is always a 1D array, regardless of the shape of `x0`, or whether `x0` is a scalar. """ x0 = asarray(x0).flatten() n = len(x0) if not isinstance(args, tuple): args = (args, ) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = finfo(dtype).eps if Dfun is None: if maxfev == 0: maxfev = 200 * (n + 1) retval = _minpack._lmdif(func, x0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if maxfev == 0: maxfev = 100 * (n + 1) retval = _minpack._lmder(func, Dfun, x0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = { 0: ["Improper input parameters.", TypeError], 1: [ "Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None ], 2: [ "The relative error between two consecutive " "iterates is at most %f" % xtol, None ], 3: [ "Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None ], 4: [ "The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None ], 5: [ "Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError ], 6: [ "ftol=%f is too small, no further reduction " "in the sum of squares\n is possible." % ftol, ValueError ], 7: [ "xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError ], 8: [ "gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError ] } # The FORTRAN return value (possible return values are >= 0 and <= 8) info = retval[-1] if full_output: cov_x = None if info in LEASTSQ_SUCCESS: from numpy.dual import inv perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except (LinAlgError, ValueError): pass return (retval[0], cov_x) + retval[1:-1] + (errors[info][0], info) else: if info in LEASTSQ_FAILURE: warnings.warn(errors[info][0], RuntimeWarning) elif info == 0: raise errors[info][1](errors[info][0]) return retval[0], info
def leastsq(func, x0, args=(), Dfun=None, ftol=1.e-7, xtol=1.e-7, gtol=1.e-7, maxfev=0, epsfcn=None, factor=100, diag=None): """ Minimize the sum of squares of a set of equations. Adopted from scipy.optimize.leastsq :: x = arg min(sum(func(y)**2,axis=0)) y Parameters ---------- func : callable should take at least one (possibly length N vector) argument and returns M floating point numbers. x0 : ndarray The starting estimate for the minimization. args : tuple Any extra arguments to func are placed in this tuple. Dfun : callable A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated. ftol : float Relative error desired in the sum of squares. xtol : float Relative error desired in the approximate solution. gtol : float Orthogonality desired between the function vector and the columns of the Jacobian. maxfev : int The maximum number of calls to the function. If zero, then 100*(N+1) is the maximum where N is the number of elements in x0. epsfcn : float A suitable step length for the forward-difference approximation of the Jacobian (for Dfun=None). If epsfcn is less than the machine precision, it is assumed that the relative errors in the functions are of the order of the machine precision. factor : float A parameter determining the initial step bound (``factor * || diag * x||``). Should be in interval ``(0.1, 100)``. diag : sequence N positive entries that serve as a scale factors for the variables. Returns ------- x : ndarray The solution (or the result of the last iteration for an unsuccessful call). cov_x : ndarray Uses the fjac and ipvt optional outputs to construct an estimate of the jacobian around the solution. ``None`` if a singular matrix encountered (indicates very flat curvature in some direction). This matrix must be multiplied by the residual variance to get the covariance of the parameter estimates -- see curve_fit. infodict : dict a dictionary of optional outputs with the key s:: - 'nfev' : the number of function calls - 'fvec' : the function evaluated at the output - 'fjac' : A permutation of the R matrix of a QR factorization of the final approximate Jacobian matrix, stored column wise. Together with ipvt, the covariance of the estimate can be approximated. - 'ipvt' : an integer array of length N which defines a permutation matrix, p, such that fjac*p = q*r, where r is upper triangular with diagonal elements of nonincreasing magnitude. Column j of p is column ipvt(j) of the identity matrix. - 'qtf' : the vector (transpose(q) * fvec). mesg : str A string message giving information about the cause of failure. ier : int An integer flag. If it is equal to 1, 2, 3 or 4, the solution was found. Otherwise, the solution was not found. In either case, the optional output variable 'mesg' gives more information. Notes ----- "leastsq" is a wrapper around MINPACK's lmdif and lmder algorithms. cov_x is a Jacobian approximation to the Hessian of the least squares objective function. This approximation assumes that the objective function is based on the difference between some observed target data (ydata) and a (non-linear) function of the parameters `f(xdata, params)` :: func(params) = ydata - f(xdata, params) so that the objective function is :: min sum((ydata - f(xdata, params))**2, axis=0) params """ x0 = asarray(x0).flatten() n = len(x0) if not isinstance(args, tuple): args = (args, ) shape = _check_func('leastsq', 'func', func, x0, args, n) if isinstance(shape, tuple) and len(shape) > 1: # older versions returned only shape # newer versions return (shape, dtype) shape = shape[0] m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if maxfev == 0: maxfev = 200 * (n + 1) if epsfcn is None: epsfcn = 2.e-5 # a relatively large value!! if Dfun is None: retval = _minpack._lmdif(func, x0, args, 1, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) retval = _minpack._lmder(func, Dfun, x0, args, 1, 0, ftol, xtol, gtol, maxfev, factor, diag) errors = { 0: ["Improper input parameters.", TypeError], 1: [ "Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None ], 2: [ "The relative error between two consecutive " "iterates is at most %f" % xtol, None ], 3: [ "Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None ], 4: [ "The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None ], 5: [ "Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError ], 6: [ "ftol=%f is too small, no further reduction " "in the sum of squares\n is possible." "" % ftol, ValueError ], 7: [ "xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError ], 8: [ "gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError ], 'unknown': ["Unknown error.", TypeError] } info = retval[-1] # The FORTRAN return value mesg = errors[info][0] cov_x = None if info in [1, 2, 3, 4]: perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except (LinAlgError, ValueError): pass return (retval[0], cov_x) + retval[1:-1] + (mesg, info)
def leastsqBound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): from scipy.optimize import _minpack """ Non-linear least square fitting (Levenberg-Marquardt method) with bounded parameters. the codes of transformation between int <-> ext refers to the work of Jonathan J. Helmus: https://github.com/jjhelmus/leastsqbound-scipy other codes refers to the source code of minpack.py: ..\Lib\site-packages\scipy\optimize\minpack.py An internal parameter list is used to enforce contraints on the fitting parameters. The transfomation is based on that of MINUIT package. please see: F. James and M. Winkler. MINUIT User's Guide, 2004. bounds : list (min, max) pairs for each parameter, use None for 'min' or 'max' when there is no bound in that direction. For example: if there are two parameters needed to be fitting, then bounds is [(min1,max1), (min2,max2)] This function is based on 'leastsq' of minpack.py, the annotation of other parameters can be found in 'leastsq'. ..\Lib\site-packages\scipy\optimize\minpack.py """ def _check_func(checker, argname, thefunc, x0, args, numinputs, output_shape=None): """The same as that of minpack.py""" res = np.atleast_1d(thefunc(*((x0[:numinputs], ) + args))) if (output_shape is not None) and (shape(res) != output_shape): if (output_shape[0] != 1): if len(output_shape) > 1: if output_shape[1] == 1: return shape(res) msg = "%s: there is a mismatch between the input and output " \ "shape of the '%s' argument" % (checker, argname) func_name = getattr(thefunc, '__name__', None) if func_name: msg += " '%s'." % func_name else: msg += "." raise TypeError(msg) if np.issubdtype(res.dtype, np.inexact): dt = res.dtype else: dt = dtype(float) return shape(res), dt def _int2extGrad(p_int, bounds): """Calculate the gradients of transforming the internal (unconstrained) to external (constrained) parameter.""" grad = np.empty_like(p_int) for i, (x, bound) in enumerate(zip(p_int, bounds)): lower, upper = bound if lower is None and upper is None: # No constraints grad[i] = 1.0 elif upper is None: # only lower bound grad[i] = x / np.sqrt(x * x + 1.0) elif lower is None: # only upper bound grad[i] = -x / np.sqrt(x * x + 1.0) else: # lower and upper bounds grad[i] = (upper - lower) * np.cos(x) / 2.0 return grad def _int2extFunc(bounds): """transform internal parameters into external parameters.""" local = [_int2extLocal(b) for b in bounds] def _transform_i2e(p_int): p_ext = np.empty_like(p_int) p_ext[:] = [i(j) for i, j in zip(local, p_int)] return p_ext return _transform_i2e def _ext2intFunc(bounds): """transform external parameters into internal parameters.""" local = [_ext2intLocal(b) for b in bounds] def _transform_e2i(p_ext): p_int = np.empty_like(p_ext) p_int[:] = [i(j) for i, j in zip(local, p_ext)] return p_int return _transform_e2i def _int2extLocal(bound): """transform a single internal parameter to an external parameter.""" lower, upper = bound if lower is None and upper is None: # no constraints return lambda x: x elif upper is None: # only lower bound return lambda x: lower - 1.0 + np.sqrt(x * x + 1.0) elif lower is None: # only upper bound return lambda x: upper + 1.0 - np.sqrt(x * x + 1.0) else: return lambda x: lower + ( (upper - lower) / 2.0) * (np.sin(x) + 1.0) def _ext2intLocal(bound): """transform a single external parameter to an internal parameter.""" lower, upper = bound if lower is None and upper is None: # no constraints return lambda x: x elif upper is None: # only lower bound return lambda x: np.sqrt((x - lower + 1.0)**2 - 1.0) elif lower is None: # only upper bound return lambda x: np.sqrt((x - upper - 1.0)**2 - 1.0) else: return lambda x: np.arcsin((2.0 * (x - lower) / (upper - lower)) - 1.0) i2e = _int2extFunc(bounds) e2i = _ext2intFunc(bounds) x0 = np.asarray(x0).flatten() n = len(x0) if len(bounds) != n: raise ValueError( 'the length of bounds is inconsistent with the number of parameters ' ) if not isinstance(args, tuple): args = (args, ) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = np.finfo(dtype).eps def funcWarp(x, *args): return func(i2e(x), *args) xi0 = e2i(x0) if Dfun is None: if maxfev == 0: maxfev = 200 * (n + 1) retval = _minpack._lmdif(funcWarp, xi0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if maxfev == 0: maxfev = 100 * (n + 1) def DfunWarp(x, *args): return Dfun(i2e(x), *args) retval = _minpack._lmder(funcWarp, DfunWarp, xi0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = { 0: ["Improper input parameters.", TypeError], 1: [ "Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None ], 2: [ "The relative error between two consecutive " "iterates is at most %f" % xtol, None ], 3: [ "Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None ], 4: [ "The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None ], 5: [ "Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError ], 6: [ "ftol=%f is too small, no further reduction " "in the sum of squares\n is possible." "" % ftol, ValueError ], 7: [ "xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError ], 8: [ "gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError ], 'unknown': ["Unknown error.", TypeError] } info = retval[-1] # The FORTRAN return value if info not in [1, 2, 3, 4] and not full_output: if info in [5, 6, 7, 8]: np.warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) if full_output: grad = _int2extGrad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / np.take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = np.take(np.eye(n), retval[1]['ipvt'] - 1, 0) r = np.triu(np.transpose(retval[1]['fjac'])[:n, :]) R = np.dot(r, perm) try: cov_x = inv(np.dot(np.transpose(R), R)) except LinAlgError as inverror: print(inverror) pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)
def leastsqbound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): # use leastsq if no bounds are present if bounds is None: return leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) # create function which convert between internal and external parameters i2e = _internal2external_func(bounds) e2i = _external2internal_func(bounds) x0 = asarray(x0).flatten() i0 = e2i(x0) n = len(x0) if len(bounds) != n: raise ValueError('length of x0 != length of bounds') if not isinstance(args, tuple): args = (args, ) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = finfo(dtype).eps # define a wrapped func which accept internal parameters, converts them # to external parameters and calls func def wfunc(x, *args): return func(i2e(x), *args) if Dfun is None: if (maxfev == 0): maxfev = 200 * (n + 1) retval = _minpack._lmdif(wfunc, i0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if (maxfev == 0): maxfev = 100 * (n + 1) def wDfun(x, *args): # wrapped Dfun return Dfun(i2e(x), *args) retval = _minpack._lmder(wfunc, wDfun, i0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = { 0: ["Improper input parameters.", TypeError], 1: [ "Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None ], 2: [ "The relative error between two consecutive " "iterates is at most %f" % xtol, None ], 3: [ "Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None ], 4: [ "The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None ], 5: [ "Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError ], 6: [ "ftol=%f is too small, no further reduction " "in the sum of squares\n is possible." "" % ftol, ValueError ], 7: [ "xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError ], 8: [ "gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError ], 'unknown': ["Unknown error.", TypeError] } info = retval[-1] # The FORTRAN return value if (info not in [1, 2, 3, 4] and not full_output): if info in [5, 6, 7, 8]: pass #warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) # internal params to external params if full_output: # convert fjac from internal params to external grad = _internal2external_grad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except LinAlgError: pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)
def leastsq(func, x0, args=(), Dfun=None, ftol=1.e-7, xtol=1.e-7, gtol=1.e-7, maxfev=0, epsfcn=None, factor=100, diag=None): """ Minimize the sum of squares of a set of equations. Adopted from scipy.optimize.leastsq :: x = arg min(sum(func(y)**2,axis=0)) y Parameters ---------- func : callable should take at least one (possibly length N vector) argument and returns M floating point numbers. x0 : ndarray The starting estimate for the minimization. args : tuple Any extra arguments to func are placed in this tuple. Dfun : callable A function or method to compute the Jacobian of func with derivatives across the rows. If this is None, the Jacobian will be estimated. ftol : float Relative error desired in the sum of squares. xtol : float Relative error desired in the approximate solution. gtol : float Orthogonality desired between the function vector and the columns of the Jacobian. maxfev : int The maximum number of calls to the function. If zero, then 100*(N+1) is the maximum where N is the number of elements in x0. epsfcn : float A suitable step length for the forward-difference approximation of the Jacobian (for Dfun=None). If epsfcn is less than the machine precision, it is assumed that the relative errors in the functions are of the order of the machine precision. factor : float A parameter determining the initial step bound (``factor * || diag * x||``). Should be in interval ``(0.1, 100)``. diag : sequence N positive entries that serve as a scale factors for the variables. Returns ------- x : ndarray The solution (or the result of the last iteration for an unsuccessful call). cov_x : ndarray Uses the fjac and ipvt optional outputs to construct an estimate of the jacobian around the solution. ``None`` if a singular matrix encountered (indicates very flat curvature in some direction). This matrix must be multiplied by the residual variance to get the covariance of the parameter estimates -- see curve_fit. infodict : dict a dictionary of optional outputs with the key s:: - 'nfev' : the number of function calls - 'fvec' : the function evaluated at the output - 'fjac' : A permutation of the R matrix of a QR factorization of the final approximate Jacobian matrix, stored column wise. Together with ipvt, the covariance of the estimate can be approximated. - 'ipvt' : an integer array of length N which defines a permutation matrix, p, such that fjac*p = q*r, where r is upper triangular with diagonal elements of nonincreasing magnitude. Column j of p is column ipvt(j) of the identity matrix. - 'qtf' : the vector (transpose(q) * fvec). mesg : str A string message giving information about the cause of failure. ier : int An integer flag. If it is equal to 1, 2, 3 or 4, the solution was found. Otherwise, the solution was not found. In either case, the optional output variable 'mesg' gives more information. Notes ----- "leastsq" is a wrapper around MINPACK's lmdif and lmder algorithms. cov_x is a Jacobian approximation to the Hessian of the least squares objective function. This approximation assumes that the objective function is based on the difference between some observed target data (ydata) and a (non-linear) function of the parameters `f(xdata, params)` :: func(params) = ydata - f(xdata, params) so that the objective function is :: min sum((ydata - f(xdata, params))**2, axis=0) params """ x0 = asarray(x0).flatten() n = len(x0) if not isinstance(args, tuple): args = (args,) shape = _check_func('leastsq', 'func', func, x0, args, n) if isinstance(shape, tuple) and len(shape) > 1: # older versions returned only shape # newer versions return (shape, dtype) shape = shape[0] m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if maxfev == 0: maxfev = 200*(n + 1) if epsfcn is None: epsfcn = 2.e-5 # a relatively large value!! if Dfun is None: retval = _minpack._lmdif(func, x0, args, 1, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) retval = _minpack._lmder(func, Dfun, x0, args, 1, 0, ftol, xtol, gtol, maxfev, factor, diag) errors = {0:["Improper input parameters.", TypeError], 1:["Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None], 2:["The relative error between two consecutive " "iterates is at most %f" % xtol, None], 3:["Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol,xtol), None], 4:["The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None], 5:["Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError], 6:["ftol=%f is too small, no further reduction " "in the sum of squares\n is possible.""" % ftol, ValueError], 7:["xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError], 8:["gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError], 'unknown':["Unknown error.", TypeError]} info = retval[-1] # The FORTRAN return value mesg = errors[info][0] cov_x = None if info in [1,2,3,4]: perm = take(eye(n),retval[1]['ipvt']-1,0) r = triu(transpose(retval[1]['fjac'])[:n,:]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R),R)) except (LinAlgError, ValueError): pass return (retval[0], cov_x) + retval[1:-1] + (mesg, info)
def leastsqbound(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None): # use leastsq if no bounds are present if bounds is None: return leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) # create function which convert between internal and external parameters i2e = _internal2external_func(bounds) e2i = _external2internal_func(bounds) x0 = asarray(x0).flatten() i0 = e2i(x0) n = len(x0) if len(bounds) != n: raise ValueError('length of x0 != length of bounds') if not isinstance(args, tuple): args = (args,) shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) m = shape[0] if n > m: raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) if epsfcn is None: epsfcn = finfo(dtype).eps # define a wrapped func which accept internal parameters, converts them # to external parameters and calls func def wfunc(x, *args): return func(i2e(x), *args) if Dfun is None: if (maxfev == 0): maxfev = 200 * (n + 1) retval = _minpack._lmdif(wfunc, i0, args, full_output, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) else: if col_deriv: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (n, m)) else: _check_func('leastsq', 'Dfun', Dfun, x0, args, n, (m, n)) if (maxfev == 0): maxfev = 100 * (n + 1) def wDfun(x, *args): # wrapped Dfun return Dfun(i2e(x), *args) retval = _minpack._lmder(wfunc, wDfun, i0, args, full_output, col_deriv, ftol, xtol, gtol, maxfev, factor, diag) errors = {0: ["Improper input parameters.", TypeError], 1: ["Both actual and predicted relative reductions " "in the sum of squares\n are at most %f" % ftol, None], 2: ["The relative error between two consecutive " "iterates is at most %f" % xtol, None], 3: ["Both actual and predicted relative reductions in " "the sum of squares\n are at most %f and the " "relative error between two consecutive " "iterates is at \n most %f" % (ftol, xtol), None], 4: ["The cosine of the angle between func(x) and any " "column of the\n Jacobian is at most %f in " "absolute value" % gtol, None], 5: ["Number of calls to function has reached " "maxfev = %d." % maxfev, ValueError], 6: ["ftol=%f is too small, no further reduction " "in the sum of squares\n is possible.""" % ftol, ValueError], 7: ["xtol=%f is too small, no further improvement in " "the approximate\n solution is possible." % xtol, ValueError], 8: ["gtol=%f is too small, func(x) is orthogonal to the " "columns of\n the Jacobian to machine " "precision." % gtol, ValueError], 'unknown': ["Unknown error.", TypeError]} info = retval[-1] # The FORTRAN return value if (info not in [1, 2, 3, 4] and not full_output): if info in [5, 6, 7, 8]: pass #warnings.warn(errors[info][0], RuntimeWarning) else: try: raise errors[info][1](errors[info][0]) except KeyError: raise errors['unknown'][1](errors['unknown'][0]) mesg = errors[info][0] x = i2e(retval[0]) # internal params to external params if full_output: # convert fjac from internal params to external grad = _internal2external_grad(retval[0], bounds) retval[1]['fjac'] = (retval[1]['fjac'].T / take(grad, retval[1]['ipvt'] - 1)).T cov_x = None if info in [1, 2, 3, 4]: from numpy.dual import inv from numpy.linalg import LinAlgError perm = take(eye(n), retval[1]['ipvt'] - 1, 0) r = triu(transpose(retval[1]['fjac'])[:n, :]) R = dot(r, perm) try: cov_x = inv(dot(transpose(R), R)) except LinAlgError: pass return (x, cov_x) + retval[1:-1] + (mesg, info) else: return (x, info)