def test_function2(): for method in INTEGRAL_METHODS: res1, err1 = pyquad.quad(function2, 0., 1., (0.99, 2.1, 1.3), method=method) res2, err2 = scipy.integrate.quad(function2, 0., 1., (0.99, 2.1, 1.3), limit=200) assert np.abs(res1 - res2) < err1
def test_function3(): for method in INTEGRAL_METHODS: res1, err1 = pyquad.quad(function3, 0., 4., (0.23, 0.7, 0.13), method=method) res2, err2 = scipy.integrate.quad(function3, 0., 4., (0.23, 0.7, 0.13), limit=200) assert np.abs(res1 - res2) < err1
def test_integrand1(): """ A simple polynomial with terms x to x^-1 f(x) = a^2 * x + c*b - c*b / (x + 1e-5) integral: F(x) = a^2 * x^2 / 2 + c*b*x - c*b*ln(x + 1e-5) + C We repeat the integral N times with random numbers for a, b and c within the range [0.0, 10.0] There is a singularity at x = -1e-5, however the integral range that we consider here is only [0.0, 1.0] """ integrand = lambda x, a, b, c: x * a * a + c * b - c * b / (x + 1e-5) analytical_sol = lambda x0, x1, a, b, c: ( (a * a * x1 * x1 / 2 + c * b * x1 - c * b * np.log(x1 + 1e-5)) - (a * a * x0 * x0 / 2 + c * b * x0 - c * b * np.log(x0 + 1e-5))) x0 = 0.0 x1 = 1.0 for repeat in range(100): args = (np.random.uniform(0, 10.0), np.random.uniform(0, 10.0), np.random.uniform(0, 10.0)) for method in INTEGRAL_METHODS: ana_res = analytical_sol(x0, x1, *args) res1, err1 = pyquad.quad(integrand, x0, x1, args, method=method, limit=LIMIT) res2, err2 = scipy.integrate.quad(integrand, x0, x1, args, limit=LIMIT) # Ensure abs error is less than 1 part in a million of the result assert err1 < np.abs(ana_res) * 1e-6 # Ensure that scipy and pyquad agree within error assert np.abs(res1 - res2) < max(err2, err1) # Ensure pyquad agrees with the analytical solution assert np.abs(res1 - ana_res) < err1
def test_integrand2(): """ A difficult, oscillating, integrand taken from the SIAM 100-Digit Challenge f(x) = 1/(x+1e-5) * cos(1/(x+1e-5) * ln(x + 1e-5)) integral: UNKNOWN This is a very challenging, slowly convering integrand. In "qags" mode scipy and pyquad agree very well and pyquad "cquad" mode also agrees within a very large error. As these integrals are VERY slowly convering, they should raise a `UserWarning` within both pyquad and scipy to alert the user the answer is not converged! """ integrand = lambda x: 1 / (x + 1e-5) * np.cos(1 / (x + 1e-5) * np.log( x + 1e-5)) x0 = 0.0 x1 = 1.0 for method in INTEGRAL_METHODS: # Ignore any warnings at this stage, "just shut up and calculate" with warnings.catch_warnings(): warnings.simplefilter('ignore') res1, err1 = pyquad.quad(integrand, x0, x1, method=method, limit=LIMIT) res2, err2 = scipy.integrate.quad(integrand, x0, x1, limit=LIMIT) # Ensure that scipy and pyquad agree within error assert np.abs(res1 - res2) < max(err1, err2) # Re-do the integral and ensure that it raises the correct `UserWarning` args = (integrand, x0, x1) pytest.warns(UserWarning, pyquad.quad, *args) pytest.warns(UserWarning, scipy.integrate.quad, *args)
def test_function3(): res1, err1 = pyquad.quad(function3, 0., 4., (0.23, 0.7, 0.13)) res2, err2 = scipy.integrate.quad(function3, 0., 4., (0.23, 0.7, 0.13), limit=200) assert np.abs(res1 - res2) < err1
def test_function2(): res1, err1 = pyquad.quad(function2, 0., 1., (0.99, 2.1, 1.3)) res2, err2 = scipy.integrate.quad(function2, 0., 1., (0.99, 2.1, 1.3), limit=200) assert np.abs(res1 - res2) < err1
def test_function1(): res1, err1 = pyquad.quad(function1, 0., 1., (0.3, 0.1, 0.7)) res2, err2 = scipy.integrate.quad(function1, 0., 1., (0.3, 0.1, 0.7), limit=200) assert np.abs(res1 - res2) < err1