def lmdif(fcn, x0, xmin, xmax, ftol=EPSILON, xtol=EPSILON, gtol=EPSILON, maxfev=None, epsfcn=EPSILON, factor=100.0, verbose=0): def par_at_boundary( low, val, high, tol ): for par_min, par_val, par_max in izip( low, val, high ): if sao_fcmp( par_val, par_min, tol ) == 0: return True if sao_fcmp( par_val, par_max, tol ) == 0: return True return False x, xmin, xmax = _check_args(x0, xmin, xmax) if maxfev is None: maxfev = 256 * len(x) def stat_cb0( pars ): return fcn( pars )[ 0 ] def stat_cb1( pars ): return fcn( pars )[ 1 ] m = numpy.asanyarray(stat_cb1(x)).size orig_fcn = stat_cb1 error = [] def stat_cb1(x_new, iflag): fvec = None try: ## if _outside_limits(x_new, xmin, xmax) or _my_is_nan(x_new): ## fvec = numpy.empty((m,), x_new.dtype, numpy.isfortran(x_new)) ## fvec[:] = numpy.sqrt(FUNC_MAX / m) ## else: fvec = orig_fcn(x_new) except: error.append(sys.exc_info()[1]) fvec = numpy.zeros((m,), x_new.dtype, numpy.isfortran(x_new)) iflag = -1 return fvec, iflag info, nfev, fval, covarerr = _minpack.mylmdif(stat_cb1, m, x, ftol, xtol, gtol, maxfev, epsfcn, factor, verbose, xmin, xmax) if par_at_boundary( xmin, x, xmax, xtol ): nm_result = neldermead( fcn, x, xmin, xmax, ftol=numpy.sqrt(ftol), maxfev=maxfev-nfev, finalsimplex=2, iquad=0, verbose=0 ) nfev += nm_result[ 4 ][ 'nfev' ] x = nm_result[ 1 ] fval = nm_result[ 2 ] ## if nm_result[ 2 ] < fval: ## x = nm_result[ 1 ] ## fval = nm_result[ 2 ] ## info, mynfev, fval, covarerr = _minpack.mylmdif(stat_cb1, m, x, ftol, xtol, gtol, maxfev-nfev, epsfcn, factor, verbose, xmin, xmax) ## nfev += mynfev if error: raise error.pop() key = { 0: (False, 'improper input parameters'), 1: (True, ('both actual and predicted relative reductions in the sum ' + 'of squares are at most ftol=%g') % ftol), 2: (True, ('relative error between two consecutive iterates is at ' + 'most xtol=%g') % xtol), 4: (True, ('the cosine of the angle between fvec and any column of ' + 'the jacobian is at most gtol=%g in absolute value') % gtol), 5: (False, ('number of calls to function has reached or exceeded '+ 'maxfev=%d') % maxfev), 6: (False, ('ftol=%g is too small; no further reduction in the sum of ' + 'squares is possible') % ftol), 7: (False, ('xtol=%g is too small; no further improvement in the ' + 'approximate solution is possible') % xtol), 8: (False, ('gtol=%g is too small; fvec is orthogonal to the columns ' + 'of the jacobian to machine precision') % gtol), } key[3] = (True, key[1][1] + ' and ' + key[2][1]) status, msg = key.get(info, (False, 'unknown status flag (%d)' % info)) if 0 == info: info = 1 elif info >= 1 or info <= 4: info = 0 else: info = 3 status, msg = _get_saofit_msg( maxfev, info ) rv = (status, x, fval) print_covar_err = False if print_covar_err: rv += (msg, {'info': info, 'nfev': nfev, 'covarerr': covarerr}) else: rv += (msg, {'info': info, 'nfev': nfev}) return rv
def lmdif(fcn, x0, xmin, xmax, ftol=EPSILON, xtol=EPSILON, gtol=EPSILON, maxfev=None, epsfcn=EPSILON, factor=100.0, verbose=0): x, xmin, xmax = _check_args(x0, xmin, xmax) if maxfev is None: maxfev = 256 * len(x) def stat_cb0( pars ): return fcn( pars )[ 0 ] def stat_cb1( pars ): return fcn( pars )[ 1 ] m = numpy.asanyarray(stat_cb1(x)).size orig_fcn = stat_cb1 error = [] def stat_cb1(x_new, iflag): fvec = None try: ## if _outside_limits(x_new, xmin, xmax) or _my_is_nan(x_new): ## fvec = numpy.empty((m,), x_new.dtype, numpy.isfortran(x_new)) ## fvec[:] = numpy.sqrt(FUNC_MAX / m) ## else: fvec = orig_fcn(x_new) except: error.append(sys.exc_info()[1]) fvec = numpy.zeros((m,), x_new.dtype, numpy.isfortran(x_new)) iflag = -1 return fvec, iflag def myfdjac( myx, myfvec, myfjac, myxmax, myiflag, myepsfcn ): eps = numpy.sqrt( max( [ EPSILON, myepsfcn ] ) ) n = len( myx ) def fdjac( xxx, origxxx, fvec, upbound, iflag, epsilon ): myn = len( xxx ) diffs = [] for jj in xrange( myn ): temp = xxx[ jj ] h = epsilon * abs( xxx[ jj ] ) if 0.0 == h: h = eps if xxx[ jj ] + h > upbound[ jj ]: h = - h xxx[ jj ] = temp + h wa, iflag = fcn( origxxx, iflag ) xxx[ jj ] = temp diff = ( wa - fvec ) / h diff = numpy.append( diff, iflag ) diffs.append( diff ) return diffs diffs = divide_run_parallel( fdjac, myx, myx, myfvec, myxmax, myiflag, eps ) for jj in range( n ): myfjac[ 0:, jj ] = diffs[ jj ][:-1].copy() if diffs[ jj ][ -1 ] < 0: myiflag = diffs[ jj ][ -1 ] return myiflag, myfjac multicore = 0 info, nfev, fval, covarerr = _minpack.mylmdif(stat_cb1, m, x, ftol, xtol, gtol, maxfev, epsfcn, factor, verbose, xmin, xmax, multicore, myfdjac) if error: raise error.pop() key = { 0: (False, 'improper input parameters'), 1: (True, ('both actual and predicted relative reductions in the sum ' + 'of squares are at most ftol=%g') % ftol), 2: (True, ('relative error between two consecutive iterates is at ' + 'most xtol=%g') % xtol), 4: (True, ('the cosine of the angle between fvec and any column of ' + 'the jacobian is at most gtol=%g in absolute value') % gtol), 5: (False, ('number of calls to function has reached or exceeded '+ 'maxfev=%d') % maxfev), 6: (False, ('ftol=%g is too small; no further reduction in the sum of ' + 'squares is possible') % ftol), 7: (False, ('xtol=%g is too small; no further improvement in the ' + 'approximate solution is possible') % xtol), 8: (False, ('gtol=%g is too small; fvec is orthogonal to the columns ' + 'of the jacobian to machine precision') % gtol), } key[3] = (True, key[1][1] + ' and ' + key[2][1]) status, msg = key.get(info, (False, 'unknown status flag (%d)' % info)) if 0 == info: info = 1 elif info >= 1 or info <= 4: info = 0 else: info = 3 status, msg = _get_saofit_msg( maxfev, info ) rv = (status, x, fval) print_covar_err = False if print_covar_err: rv += (msg, {'info': info, 'nfev': nfev, 'covarerr': covarerr}) else: rv += (msg, {'info': info, 'nfev': nfev}) return rv