def test_curvefit_simplecovariance(self): def func(x, a, b): return a * np.exp(-b * x) def jac(x, a, b): e = np.exp(-b * x) return np.vstack((e, -a * x * e)).T np.random.seed(0) xdata = np.linspace(0, 4, 50) y = func(xdata, 2.5, 1.3) ydata = y + 0.2 * np.random.normal(size=len(xdata)) sigma = np.zeros(len(xdata)) + 0.2 covar = np.diag(sigma**2) for jac1, jac2 in [(jac, jac), (None, None)]: for absolute_sigma in [False, True]: popt1, pcov1 = curve_fit(func, xdata, ydata, sigma=sigma, jac=jac1, absolute_sigma=absolute_sigma) popt2, pcov2 = curve_fit(func, xdata, ydata, sigma=covar, jac=jac2, absolute_sigma=absolute_sigma) assert_allclose(popt1, popt2, atol=1e-14) assert_allclose(pcov1, pcov2, atol=1e-14)
def test_bounds(self): def f(x, a, b): return a * np.exp(-b * x) xdata = np.linspace(0, 1, 11) ydata = f(xdata, 2., 2.) # The minimum w/out bounds is at [2., 2.], # and with bounds it's at [1.5, smth]. bounds = ([1., 0], [1.5, 3.]) for method in [None, 'trf', 'dogbox']: popt, pcov = curve_fit(f, xdata, ydata, bounds=bounds, method=method) assert_allclose(popt[0], 1.5) # With bounds, the starting estimate is feasible. popt, pcov = curve_fit(f, xdata, ydata, method='trf', bounds=([0., 0], [0.6, np.inf])) assert_allclose(popt[0], 0.6) # method='lm' doesn't support bounds. assert_raises(ValueError, curve_fit, f, xdata, ydata, bounds=bounds, method='lm')
def test_dtypes2(self): # regression test for gh-7117: curve_fit fails if # both inputs are float32 def hyperbola(x, s_1, s_2, o_x, o_y, c): b_2 = (s_1 + s_2) / 2 b_1 = (s_2 - s_1) / 2 return o_y + b_1 * (x - o_x) + b_2 * np.sqrt( (x - o_x)**2 + c**2 / 4) min_fit = np.array([-3.0, 0.0, -2.0, -10.0, 0.0]) max_fit = np.array([0.0, 3.0, 3.0, 0.0, 10.0]) guess = np.array([-2.5 / 3.0, 4 / 3.0, 1.0, -4.0, 0.5]) params = [-2, .4, -1, -5, 9.5] xdata = np.array([-32, -16, -8, 4, 4, 8, 16, 32]) ydata = hyperbola(xdata, *params) # run optimization twice, with xdata being float32 and float64 popt_64, _ = curve_fit(f=hyperbola, xdata=xdata, ydata=ydata, p0=guess, bounds=(min_fit, max_fit)) xdata = xdata.astype(np.float32) ydata = hyperbola(xdata, *params) popt_32, _ = curve_fit(f=hyperbola, xdata=xdata, ydata=ydata, p0=guess, bounds=(min_fit, max_fit)) assert_allclose(popt_32, popt_64, atol=2e-5)
def test_curvefit_covariance(self): def funcp(x, a, b): rotn = np.array([[1. / np.sqrt(2), -1. / np.sqrt(2), 0], [1. / np.sqrt(2), 1. / np.sqrt(2), 0], [0, 0, 1.0]]) return rotn.dot(a * np.exp(-b * x)) def jacp(x, a, b): rotn = np.array([[1. / np.sqrt(2), -1. / np.sqrt(2), 0], [1. / np.sqrt(2), 1. / np.sqrt(2), 0], [0, 0, 1.0]]) e = np.exp(-b * x) return rotn.dot(np.vstack((e, -a * x * e)).T) def func(x, a, b): return a * np.exp(-b * x) def jac(x, a, b): e = np.exp(-b * x) return np.vstack((e, -a * x * e)).T np.random.seed(0) xdata = np.arange(1, 4) y = func(xdata, 2.5, 1.0) ydata = y + 0.2 * np.random.normal(size=len(xdata)) sigma = np.zeros(len(xdata)) + 0.2 covar = np.diag(sigma**2) # Get a rotation matrix, and obtain ydatap = R ydata # Chisq = ydata^T C^{-1} ydata # = ydata^T R^T R C^{-1} R^T R ydata # = ydatap^T Cp^{-1} ydatap # Cp^{-1} = R C^{-1} R^T # Cp = R C R^T, since R^-1 = R^T rotn = np.array([[1. / np.sqrt(2), -1. / np.sqrt(2), 0], [1. / np.sqrt(2), 1. / np.sqrt(2), 0], [0, 0, 1.0]]) ydatap = rotn.dot(ydata) covarp = rotn.dot(covar).dot(rotn.T) for jac1, jac2 in [(jac, jacp), (None, None)]: for absolute_sigma in [False, True]: popt1, pcov1 = curve_fit(func, xdata, ydata, sigma=sigma, jac=jac1, absolute_sigma=absolute_sigma) popt2, pcov2 = curve_fit(funcp, xdata, ydatap, sigma=covarp, jac=jac2, absolute_sigma=absolute_sigma) assert_allclose(popt1, popt2, rtol=1.2e-7, atol=1e-14) assert_allclose(pcov1, pcov2, rtol=1.2e-7, atol=1e-14)
def test_args_in_kwargs(self): # Ensure that `args` cannot be passed as keyword argument to `curve_fit` def func(x, a, b): return a * x + b with assert_raises(ValueError): curve_fit(func, xdata=[1, 2, 3, 4], ydata=[5, 9, 13, 17], p0=[1], args=(1, ))
def test_broadcast_y(self): xdata = np.arange(10) target = 4.7 * xdata**2 + 3.5 * xdata + np.random.rand(len(xdata)) fit_func = lambda x, a, b: a * x**2 + b * x - target for method in ['lm', 'trf', 'dogbox']: popt0, pcov0 = curve_fit(fit_func, xdata=xdata, ydata=np.zeros_like(xdata), method=method) popt1, pcov1 = curve_fit(fit_func, xdata=xdata, ydata=0, method=method) assert_allclose(pcov0, pcov1)
def test_regression_2639(self): # This test fails if epsfcn in leastsq is too large. x = [ 574.14200000000005, 574.154, 574.16499999999996, 574.17700000000002, 574.18799999999999, 574.19899999999996, 574.21100000000001, 574.22199999999998, 574.23400000000004, 574.245 ] y = [ 859.0, 997.0, 1699.0, 2604.0, 2013.0, 1964.0, 2435.0, 1550.0, 949.0, 841.0 ] guess = [ 574.1861428571428, 574.2155714285715, 1302.0, 1302.0, 0.0035019999999983615, 859.0 ] good = [ 5.74177150e+02, 5.74209188e+02, 1.74187044e+03, 1.58646166e+03, 1.0068462e-02, 8.57450661e+02 ] def f_double_gauss(x, x0, x1, A0, A1, sigma, c): return (A0 * np.exp(-(x - x0)**2 / (2. * sigma**2)) + A1 * np.exp(-(x - x1)**2 / (2. * sigma**2)) + c) popt, pcov = curve_fit(f_double_gauss, x, y, guess, maxfev=10000) assert_allclose(popt, good, rtol=1e-5)
def test_array_like(self): # Test sequence input. Regression test for gh-3037. def f_linear(x, a, b): return a * x + b x = [1, 2, 3, 4] y = [3, 5, 7, 9] assert_allclose(curve_fit(f_linear, x, y)[0], [2, 1], atol=1e-10)
def test_maxfev_and_bounds(self): # gh-6340: with no bounds, curve_fit accepts parameter maxfev (via leastsq) # but with bounds, the parameter is `max_nfev` (via least_squares) x = np.arange(0, 10) y = 2 * x popt1, _ = curve_fit(lambda x, p: p * x, x, y, bounds=(0, 3), maxfev=100) popt2, _ = curve_fit(lambda x, p: p * x, x, y, bounds=(0, 3), max_nfev=100) assert_allclose(popt1, 2, atol=1e-14) assert_allclose(popt2, 2, atol=1e-14)
def test_one_argument(self): def func(x, a): return x**a popt, pcov = curve_fit(func, self.x, self.y) assert_(len(popt) == 1) assert_(pcov.shape == (1, 1)) assert_almost_equal(popt[0], 1.9149, decimal=4) assert_almost_equal(pcov[0, 0], 0.0016, decimal=4) # Test if we get the same with full_output. Regression test for #1415. # Also test if check_finite can be turned off. res = curve_fit(func, self.x, self.y, full_output=1, check_finite=False) (popt2, pcov2, infodict, errmsg, ier) = res assert_array_almost_equal(popt, popt2)
def test_two_argument(self): def func(x, a, b): return b * x**a popt, pcov = curve_fit(func, self.x, self.y) assert_(len(popt) == 2) assert_(pcov.shape == (2, 2)) assert_array_almost_equal(popt, [1.7989, 1.1642], decimal=4) assert_array_almost_equal(pcov, [[0.0852, -0.1260], [-0.1260, 0.1912]], decimal=4)
def test_jac(self): # Test that Jacobian callable is handled correctly and # weighted if sigma is provided. def f(x, a, b): return a * np.exp(-b * x) def jac(x, a, b): e = np.exp(-b * x) return np.vstack((e, -a * x * e)).T xdata = np.linspace(0, 1, 11) ydata = f(xdata, 2., 2.) # Test numerical options for least_squares backend. for method in ['trf', 'dogbox']: for scheme in ['2-point', '3-point', 'cs']: popt, pcov = curve_fit(f, xdata, ydata, jac=scheme, method=method) assert_allclose(popt, [2, 2]) # Test the analytic option. for method in ['lm', 'trf', 'dogbox']: popt, pcov = curve_fit(f, xdata, ydata, method=method, jac=jac) assert_allclose(popt, [2, 2]) # Now add an outlier and provide sigma. ydata[5] = 100 sigma = np.ones(xdata.shape[0]) sigma[5] = 200 for method in ['lm', 'trf', 'dogbox']: popt, pcov = curve_fit(f, xdata, ydata, sigma=sigma, method=method, jac=jac) # Still the optimization process is influenced somehow, # have to set rtol=1e-3. assert_allclose(popt, [2, 2], rtol=1e-3)
def test_bounds_p0(self): # This test is for issue #5719. The problem was that an initial guess # was ignored when 'trf' or 'dogbox' methods were invoked. def f(x, a): return np.sin(x + a) xdata = np.linspace(-2 * np.pi, 2 * np.pi, 40) ydata = np.sin(xdata) bounds = (-3 * np.pi, 3 * np.pi) for method in ['trf', 'dogbox']: popt_1, _ = curve_fit(f, xdata, ydata, p0=2.1 * np.pi) popt_2, _ = curve_fit(f, xdata, ydata, p0=2.1 * np.pi, bounds=bounds, method=method) # If the initial guess is ignored, then popt_2 would be close 0. assert_allclose(popt_1, popt_2)
def test_method_argument(self): def f(x, a, b): return a * np.exp(-b * x) xdata = np.linspace(0, 1, 11) ydata = f(xdata, 2., 2.) for method in ['trf', 'dogbox', 'lm', None]: popt, pcov = curve_fit(f, xdata, ydata, method=method) assert_allclose(popt, [2., 2.]) assert_raises(ValueError, curve_fit, f, xdata, ydata, method='unknown')
def test_func_is_classmethod(self): class test_self: """This class tests if curve_fit passes the correct number of arguments when the model function is a class instance method. """ def func(self, x, a, b): return b * x**a test_self_inst = test_self() popt, pcov = curve_fit(test_self_inst.func, self.x, self.y) assert_(pcov.shape == (2, 2)) assert_array_almost_equal(popt, [1.7989, 1.1642], decimal=4) assert_array_almost_equal(pcov, [[0.0852, -0.1260], [-0.1260, 0.1912]], decimal=4)
def test_dtypes(self): # regression test for gh-9581: curve_fit fails if x and y dtypes differ x = np.arange(-3, 5) y = 1.5 * x + 3.0 + 0.5 * np.sin(x) def func(x, a, b): return a * x + b for method in ['lm', 'trf', 'dogbox']: for dtx in [np.float32, np.float64]: for dty in [np.float32, np.float64]: x = x.astype(dtx) y = y.astype(dty) with warnings.catch_warnings(): warnings.simplefilter("error", OptimizeWarning) p, cov = curve_fit(func, x, y, method=method) assert np.isfinite(cov).all() assert not np.allclose(p, 1) # curve_fit's initial value
def test_full_output(self): def f(x, a, b): return a * np.exp(-b * x) xdata = np.linspace(0, 1, 11) ydata = f(xdata, 2., 2.) for method in ['trf', 'dogbox', 'lm', None]: popt, pcov, infodict, errmsg, ier = curve_fit(f, xdata, ydata, method=method, full_output=True) assert_allclose(popt, [2., 2.]) assert "nfev" in infodict assert "fvec" in infodict if method == 'lm' or method is None: assert "fjac" in infodict assert "ipvt" in infodict assert "qtf" in infodict assert isinstance(errmsg, str) assert ier in (1, 2, 3, 4)
def test_pcov(self): xdata = np.array([0, 1, 2, 3, 4, 5]) ydata = np.array([1, 1, 5, 7, 8, 12]) sigma = np.array([1, 2, 1, 2, 1, 2]) def f(x, a, b): return a * x + b for method in ['lm', 'trf', 'dogbox']: popt, pcov = curve_fit(f, xdata, ydata, p0=[2, 0], sigma=sigma, method=method) perr_scaled = np.sqrt(np.diag(pcov)) assert_allclose(perr_scaled, [0.20659803, 0.57204404], rtol=1e-3) popt, pcov = curve_fit(f, xdata, ydata, p0=[2, 0], sigma=3 * sigma, method=method) perr_scaled = np.sqrt(np.diag(pcov)) assert_allclose(perr_scaled, [0.20659803, 0.57204404], rtol=1e-3) popt, pcov = curve_fit(f, xdata, ydata, p0=[2, 0], sigma=sigma, absolute_sigma=True, method=method) perr = np.sqrt(np.diag(pcov)) assert_allclose(perr, [0.30714756, 0.85045308], rtol=1e-3) popt, pcov = curve_fit(f, xdata, ydata, p0=[2, 0], sigma=3 * sigma, absolute_sigma=True, method=method) perr = np.sqrt(np.diag(pcov)) assert_allclose(perr, [3 * 0.30714756, 3 * 0.85045308], rtol=1e-3) # infinite variances def f_flat(x, a, b): return a * x pcov_expected = np.array([np.inf] * 4).reshape(2, 2) with suppress_warnings() as sup: sup.filter(OptimizeWarning, "Covariance of the parameters could not be estimated") popt, pcov = curve_fit(f_flat, xdata, ydata, p0=[2, 0], sigma=sigma) popt1, pcov1 = curve_fit(f, xdata[:2], ydata[:2], p0=[2, 0]) assert_(pcov.shape == (2, 2)) assert_array_equal(pcov, pcov_expected) assert_(pcov1.shape == (2, 2)) assert_array_equal(pcov1, pcov_expected)
def test_data_point_number_validation(self): def func(x, a, b, c, d, e): return a * np.exp(-b * x) + c + d + e with assert_raises(TypeError, match="The number of func parameters="): curve_fit(func, xdata=[1, 2, 3, 4], ydata=[5, 9, 13, 17])
def test_None_x(self): # Added in GH10196 popt, pcov = curve_fit(lambda _, a: a * np.arange(10), None, 2 * np.arange(10)) assert_allclose(popt, [2.])