import numpy as np from numpy import cos, sin, pi from numpy.testing import (assert_equal, assert_almost_equal, assert_allclose, assert_, suppress_warnings) from scipy.integrate import (quadrature, romberg, romb, newton_cotes, cumulative_trapezoid, cumtrapz, trapz, trapezoid, quad, simpson, simps, fixed_quad, AccuracyWarning) class TestFixedQuad(object): def test_scalar(self): n = 4 func = lambda x: x**(2*n - 1) expected = 1/(2*n) got, _ = fixed_quad(func, 0, 1, n=n) # quadrature exact for this input assert_allclose(got, expected, rtol=1e-12) def test_vector(self): n = 4 p = np.arange(1, 2*n) func = lambda x: x**p[:,None] expected = 1/(p + 1) got, _ = fixed_quad(func, 0, 1, n=n) assert_allclose(got, expected, rtol=1e-12) class TestQuadrature(object): def quad(self, x, a, b, args): raise NotImplementedError def test_quadrature(self): # Typical function with two extra arguments: def myfunc(x, n, z): # Bessel function integrand return cos(n*x-z*sin(x))/pi val, err = quadrature(myfunc, 0, pi, (2, 1.8)) table_val = 0.30614353532540296487 assert_almost_equal(val, table_val, decimal=7) def test_quadrature_rtol(self): def myfunc(x, n, z): # Bessel function integrand return 1e90 * cos(n*x-z*sin(x))/pi val, err = quadrature(myfunc, 0, pi, (2, 1.8), rtol=1e-10) table_val = 1e90 * 0.30614353532540296487 assert_allclose(val, table_val, rtol=1e-10) def test_quadrature_miniter(self): # Typical function with two extra arguments: def myfunc(x, n, z): # Bessel function integrand return cos(n*x-z*sin(x))/pi table_val = 0.30614353532540296487 for miniter in [5, 52]: val, err = quadrature(myfunc, 0, pi, (2, 1.8), miniter=miniter) assert_almost_equal(val, table_val, decimal=7) assert_(err < 1.0) def test_quadrature_single_args(self): def myfunc(x, n): return 1e90 * cos(n*x-1.8*sin(x))/pi val, err = quadrature(myfunc, 0, pi, args=2, rtol=1e-10) table_val = 1e90 * 0.30614353532540296487 assert_allclose(val, table_val, rtol=1e-10) def test_romberg(self): # Typical function with two extra arguments: def myfunc(x, n, z): # Bessel function integrand return cos(n*x-z*sin(x))/pi val = romberg(myfunc, 0, pi, args=(2, 1.8)) table_val = 0.30614353532540296487 assert_almost_equal(val, table_val, decimal=7) def test_romberg_rtol(self): # Typical function with two extra arguments: def myfunc(x, n, z): # Bessel function integrand return 1e19*cos(n*x-z*sin(x))/pi val = romberg(myfunc, 0, pi, args=(2, 1.8), rtol=1e-10) table_val = 1e19*0.30614353532540296487 assert_allclose(val, table_val, rtol=1e-10) def test_romb(self): assert_equal(romb(np.arange(17)), 128) def test_romb_gh_3731(self): # Check that romb makes maximal use of data points x = np.arange(2**4+1) y = np.cos(0.2*x) val = romb(y) val2, err = quad(lambda x: np.cos(0.2*x), x.min(), x.max()) assert_allclose(val, val2, rtol=1e-8, atol=0) # should be equal to romb with 2**k+1 samples with suppress_warnings() as sup: sup.filter(AccuracyWarning, "divmax .4. exceeded") val3 = romberg(lambda x: np.cos(0.2*x), x.min(), x.max(), divmax=4) assert_allclose(val, val3, rtol=1e-12, atol=0) def test_non_dtype(self): # Check that we work fine with functions returning float import math valmath = romberg(math.sin, 0, 1) expected_val = 0.45969769413185085 assert_almost_equal(valmath, expected_val, decimal=7) def test_newton_cotes(self): """Test the first few degrees, for evenly spaced points.""" n = 1 wts, errcoff = newton_cotes(n, 1) assert_equal(wts, n*np.array([0.5, 0.5])) assert_almost_equal(errcoff, -n**3/12.0) n = 2 wts, errcoff = newton_cotes(n, 1) assert_almost_equal(wts, n*np.array([1.0, 4.0, 1.0])/6.0) assert_almost_equal(errcoff, -n**5/2880.0) n = 3 wts, errcoff = newton_cotes(n, 1) assert_almost_equal(wts, n*np.array([1.0, 3.0, 3.0, 1.0])/8.0) assert_almost_equal(errcoff, -n**5/6480.0) n = 4 wts, errcoff = newton_cotes(n, 1) assert_almost_equal(wts, n*np.array([7.0, 32.0, 12.0, 32.0, 7.0])/90.0) assert_almost_equal(errcoff, -n**7/1935360.0) def test_newton_cotes2(self): """Test newton_cotes with points that are not evenly spaced.""" x = np.array([0.0, 1.5, 2.0]) y = x**2 wts, errcoff = newton_cotes(x) exact_integral = 8.0/3 numeric_integral = np.dot(wts, y) assert_almost_equal(numeric_integral, exact_integral) x = np.array([0.0, 1.4, 2.1, 3.0]) y = x**2 wts, errcoff = newton_cotes(x) exact_integral = 9.0 numeric_integral = np.dot(wts, y) assert_almost_equal(numeric_integral, exact_integral) def test_simpson(self): y = np.arange(17) assert_equal(simpson(y), 128) assert_equal(simpson(y, dx=0.5), 64) assert_equal(simpson(y, x=np.linspace(0, 4, 17)), 32) y = np.arange(4) x = 2**y assert_equal(simpson(y, x=x, even='avg'), 13.875) assert_equal(simpson(y, x=x, even='first'), 13.75) assert_equal(simpson(y, x=x, even='last'), 14) def test_simps(self): # Basic coverage test for the alias y = np.arange(4) x = 2**y assert_equal(simpson(y, x=x, dx=0.5, even='first'), simps(y, x=x, dx=0.5, even='first')) class TestCumulative_trapezoid(object): def test_1d(self): x = np.linspace(-2, 2, num=5) y = x y_int = cumulative_trapezoid(y, x, initial=0) y_expected = [0., -1.5, -2., -1.5, 0.] assert_allclose(y_int, y_expected) y_int = cumulative_trapezoid(y, x, initial=None) assert_allclose(y_int, y_expected[1:]) def test_y_nd_x_nd(self): x = np.arange(3 * 2 * 4).reshape(3, 2, 4) y = x y_int = cumulative_trapezoid(y, x, initial=0) y_expected = np.array([[[0., 0.5, 2., 4.5], [0., 4.5, 10., 16.5]], [[0., 8.5, 18., 28.5], [0., 12.5, 26., 40.5]], [[0., 16.5, 34., 52.5], [0., 20.5, 42., 64.5]]]) assert_allclose(y_int, y_expected) # Try with all axes shapes = [(2, 2, 4), (3, 1, 4), (3, 2, 3)] for axis, shape in zip([0, 1, 2], shapes): y_int = cumulative_trapezoid(y, x, initial=3.45, axis=axis) assert_equal(y_int.shape, (3, 2, 4)) y_int = cumulative_trapezoid(y, x, initial=None, axis=axis) assert_equal(y_int.shape, shape) def test_y_nd_x_1d(self): y = np.arange(3 * 2 * 4).reshape(3, 2, 4) x = np.arange(4)**2 # Try with all axes ys_expected = ( np.array([[[4., 5., 6., 7.], [8., 9., 10., 11.]], [[40., 44., 48., 52.], [56., 60., 64., 68.]]]), np.array([[[2., 3., 4., 5.]], [[10., 11., 12., 13.]], [[18., 19., 20., 21.]]]), np.array([[[0.5, 5., 17.5], [4.5, 21., 53.5]], [[8.5, 37., 89.5], [12.5, 53., 125.5]], [[16.5, 69., 161.5], [20.5, 85., 197.5]]])) for axis, y_expected in zip([0, 1, 2], ys_expected): y_int = cumulative_trapezoid(y, x=x[:y.shape[axis]], axis=axis, initial=None) assert_allclose(y_int, y_expected) def test_x_none(self): y = np.linspace(-2, 2, num=5) y_int = cumulative_trapezoid(y) y_expected = [-1.5, -2., -1.5, 0.] assert_allclose(y_int, y_expected) y_int = cumulative_trapezoid(y, initial=1.23) y_expected = [1.23, -1.5, -2., -1.5, 0.] assert_allclose(y_int, y_expected) y_int = cumulative_trapezoid(y, dx=3) y_expected = [-4.5, -6., -4.5, 0.] assert_allclose(y_int, y_expected) y_int = cumulative_trapezoid(y, dx=3, initial=1.23) y_expected = [1.23, -4.5, -6., -4.5, 0.] assert_allclose(y_int, y_expected) def test_cumtrapz(self): # Basic coverage test for the alias x = np.arange(3 * 2 * 4).reshape(3, 2, 4) y = x assert_allclose(cumulative_trapezoid(y, x, dx=0.5, axis=0, initial=0), cumtrapz(y, x, dx=0.5, axis=0, initial=0), rtol=1e-14) class TestTrapezoid(): """This function is tested in NumPy more extensive, just do some basic due diligence here.""" def test_trapezoid(self): y = np.arange(17) assert_equal(trapezoid(y), 128) assert_equal(trapezoid(y, dx=0.5), 64) assert_equal(trapezoid(y, x=np.linspace(0, 4, 17)), 32) y = np.arange(4) x = 2**y assert_equal(trapezoid(y, x=x, dx=0.1), 13.5) def test_trapz(self): # Basic coverage test for the alias y = np.arange(4) x = 2**y assert_equal(trapezoid(y, x=x, dx=0.5, axis=0), trapz(y, x=x, dx=0.5, axis=0))