aboutsummaryrefslogtreecommitdiff
path: root/vquad/test/test_core.py
diff options
context:
space:
mode:
Diffstat (limited to 'vquad/test/test_core.py')
-rw-r--r--vquad/test/test_core.py207
1 files changed, 160 insertions, 47 deletions
diff --git a/vquad/test/test_core.py b/vquad/test/test_core.py
index 46fd823..f5fce6d 100644
--- a/vquad/test/test_core.py
+++ b/vquad/test/test_core.py
@@ -3,41 +3,170 @@
# This file is part of Vquad. It is subject to the license terms in the file
# LICENSE.rst found in the top-level directory of this distribution.
+from math import exp, log, log10
import numpy as np
from numpy.testing import assert_allclose
from pytest import raises
from .. import core
-def f0(x):
- return x * np.sin(1/x) * np.sqrt(abs(1 - x))
+def f1(x):
+ return np.exp(x)
+
+def f2(x):
+ return x >= 0.3
+
+def f3(x):
+ return np.sqrt(x)
+
+def f4(x):
+ return 23/25 * np.cosh(x) - np.cos(x)
+
+def f5(x):
+ xx = x*x
+ return 1 / ( xx * (xx + 1) + 0.9)
+
+def f6(x):
+ return x * np.sqrt(x)
def f7(x):
- return x**-0.5
+ return 1 / np.sqrt(x)
+def f8(x):
+ xx = x*x
+ return 1 / (1 + xx*xx)
-def f24(x):
- return np.floor(np.exp(x))
+def f9(x):
+ return 2 / (2 + np.sin(10 * np.pi * x))
+
+def f10(x):
+ return 1 / (1 + x)
+
+def f11(x):
+ return 1 / (1 + np.exp(x))
+
+def f12(x):
+ return x / (np.exp(x) - 1)
+
+def f13(x):
+ return np.sin(100 * np.pi * x) / (np.pi * x)
+
+def f14(x):
+ return np.sqrt(50) * np.exp(-50 * np.pi * x * x)
+def f15(x):
+ return 25 * np.exp(-25 * x)
+
+def f16(x):
+ return 50 / np.pi * (2500 * x*x + 1)
+
+def f17(x):
+ t = 50 * np.pi * x
+ t = np.sin(t) / t
+ return 50 * t * t
+
+def f18(x):
+ return np.cos( np.cos(x) + 3 * np.sin(x) + 2 * np.cos(2*x)
+ + 3 * np.sin(2*x) + 3 * np.cos(3*x) )
+
+def f19(x):
+ return np.log(x)
+
+def f20(x):
+ return 1 / (1.005 + x*x)
def f21(x):
- y = 0
- for i in range(1, 4):
- y += 1 / np.cosh(20**i * (x - 2 * i / 10))
- return y
+ return sum(1 / np.cosh(20**i * (x - 2*i/10)) for i in range(1, 4))
+def f22(x):
+ return 4 * np.pi**2 * x * np.sin(20 * np.pi * x) * np.cos(2 * np.pi * x)
-def f63(x, alpha, beta):
- return abs(x - beta) ** alpha
+def f23(x):
+ t = 230 * x - 30
+ return 1 / (1 + t*t)
+def f24(x):
+ return np.floor(np.exp(x))
-def F63(x, alpha, beta):
- return (x - beta) * abs(x - beta) ** alpha / (alpha + 1)
+def f25(x):
+ return ((x + 1) * (x < 1)
+ + (3 - x) * ((1 <= x) & (x <= 3))
+ + 2 * (x > 3))
+
+battery = [
+ (f1, (0, 1), 1.7182818284590452354),
+ (f2, (0, 1), 0.7),
+ (f3, (0, 1), 2/3),
+ (f4, (-1, 1), 0.4794282266888016674),
+ (f5, (-1, 1), 1.5822329637296729331),
+ (f6, (0, 1), 0.4),
+ (f7, (0, 1), 2),
+ (f8, (0, 1), 0.86697298733991103757),
+ (f9, (0, 1), 1.1547005383792515290),
+ (f10, (0, 1), 0.69314718055994530942),
+ (f11, (0, 1), 0.3798854930417224753),
+ (f12, (0, 1), 0.77750463411224827640),
+ (f13, (0, 1), 0.49898680869304550249),
+ (f14, (0, 10), 0.5),
+ (f15, (0, 10), 1),
+ (f16, (0, 10), 0.13263071079267703209e+08),
+ (f17, (0, 1), 0.49898680869304550249),
+ (f18, (0, np.pi), 0.83867634269442961454),
+ (f19, (0, 1), -1),
+ (f20, (-1, 1), 1.5643964440690497731),
+ (f21, (0, 1), 0.16349494301863722618),
+ (f22, (0, 1), -0.63466518254339257343),
+ (f23, (0, 1), 0.013492485649467772692),
+ (f24, (0, 3), 17.664383539246514971),
+ (f25, (0, 5), 7.5),
+]
+
+def test_battery():
+ """Test and gather statistics on a battery of difficult integrands
+
+ The battery is used as listed on page 168 of Pedro Gonnet's thesis.
+
+ Reference:
+ W. Gander and W. Gautschi. Adaptive quadrature — revisited.
+ Technical Report 306, Department of Computer Science, ETH
+ Zurich, Switzerland, 1998.
+ """
+ def ff(x):
+ nonlocal neval
+ neval += len(x)
+ return f(x)
+ old_settings = np.seterr(all='ignore')
-def fdiv(x):
- return abs(x - 0.987654321) ** -1.1
+ rtols = [1e-3, 1e-6, 1e-9, 1e-12]
+ sum_log_neval = 0
+ sum_extra_digits = 0
+ sum_nonrep_digits = 0
+ for f, (a, b), exact in battery:
+ for rtol in rtols:
+ neval = 0
+ igral, err = core.vquad(ff, a, b, rtol)
+ sum_log_neval += log(neval)
+ extra_digits = min(16, log10(rtol / abs((igral - exact) / exact)))
+ sum_extra_digits += extra_digits
+ nonrep_digits = min(16, log10(err / abs(igral - exact)))
+ sum_nonrep_digits += nonrep_digits
+ if not (f is f21 and rtol > 1e-11):
+ assert extra_digits > 0
+ assert nonrep_digits > 0
+
+ n = len(rtols) * len(battery)
+ print("geom. mean of number of evaluations:",
+ round(exp(sum_log_neval / n), 2), "(cquad: 237.92)")
+ print("mean non-requested significant digits:",
+ round(sum_extra_digits / n, 3),
+ "(cquad: 5.989)")
+ print("mean non-reported significant digits:",
+ round(sum_nonrep_digits / n, 3),
+ "(cquad: 4.056)")
+
+ np.seterr(**old_settings)
def f_one_with_nan(x):
@@ -47,6 +176,14 @@ def f_one_with_nan(x):
return result
+def test_one_with_nan():
+ rtol = 1e-12
+ exact = 2
+ igral, err = core.vquad(f_one_with_nan, -1, 1, rtol)
+ assert_allclose(igral, exact, rtol)
+ assert err / exact < rtol
+
+
def test_coeffs(level=3):
vals = np.abs(core.tbls.nodes[level])
vals[1::2] = np.nan
@@ -61,38 +198,6 @@ def test_coeffs(level=3):
assert_allclose(vals_from_c, vals, rtol=0, atol=1e-15)
-def test_integration():
- old_settings = np.seterr(all='ignore')
-
- igral, err = core.vquad(f0, 0, 3, 1e-5)
- assert_allclose(igral, 1.98194117954329, 1e-15)
- assert_allclose(err, 1.9563545589988155e-05, 1e-10)
-
- igral, err = core.vquad(f7, 0, 1, 1e-6)
- assert_allclose(igral, 1.9999998579359648, 1e-15)
- assert_allclose(err, 1.8561437334964041e-06, 1e-10)
-
- igral, err = core.vquad(f24, 0, 3, 1e-3)
- assert_allclose(igral, 17.664696186312934, 1e-15)
- assert_allclose(err, 0.017602618074957457, 1e-10)
-
- igral, err = core.vquad(f21, 0, 1, 1e-3)
- assert_allclose(igral, 0.16310022131213361, 1e-15)
- assert_allclose(err, 0.00011848806384952786, 1e-10)
-
- igral, err = core.vquad(f_one_with_nan, -1, 1, 1e-12)
- assert_allclose(igral, 2, 1e-15)
- assert_allclose(err, 2.4237853822937613e-15, 1e-7)
-
- try:
- igral, err = core.vquad(fdiv, 0, 1, 1e-6)
- except core.DivergentIntegralError as e:
- assert e.igral == np.inf
- assert e.err is None
-
- np.seterr(**old_settings)
-
-
def test_interpolation():
vquad = core.Vquad(f24, 0, 3)
vquad.improve_until(1e-6)
@@ -108,6 +213,14 @@ def test_interpolation():
raises(ValueError, vquad, x)
+def f63(x, alpha, beta):
+ return abs(x - beta) ** alpha
+
+
+def F63(x, alpha, beta):
+ return (x - beta) * abs(x - beta) ** alpha / (alpha + 1)
+
+
def test_analytic(n=200):
def f(x):
return f63(x, alpha, beta)