def check_poly(self, func, cls, param_ranges=[], x_range=[], nn=10, nparam=10, nx=10, rtol=1e-8): np.random.seed(1234) dataset = [] for n in np.arange(nn): params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges] params = np.asarray(params).T if not param_ranges: params = [0] for p in params: if param_ranges: p = (n,) + tuple(p) else: p = (n,) x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx) x[0] = x_range[0] # always include domain start point x[1] = x_range[1] # always include domain end point poly = np.poly1d(cls(*p)) z = np.c_[np.tile(p, (nx,1)), x, poly(x)] dataset.append(z) dataset = np.concatenate(dataset, axis=0) def polyfunc(*p): p = (p[0].astype(int),) + p[1:] return func(*p) olderr = np.seterr(all='raise') try: ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1, rtol=rtol) ds.check() finally: np.seterr(**olderr)
def test_smallpcdf(self): epsilon = 0.5**np.arange(1, 55, 3) # kolmogi(1-p) == _kolmogci(p) if 1-(1-p) == p, but not necessarily otherwise # Use epsilon s.t. 1-(1-epsilon)) == epsilon, so can use same x-array for both results x = np.array([ 0.8275735551899077, 0.5345255069097583, 0.4320114038786941, 0.3736868442620478, 0.3345161714909591, 0.3057833329315859, 0.2835052890528936, 0.2655578150208676, 0.2506869966107999, 0.2380971058736669, 0.2272549289962079, 0.2177876361600040, 0.2094254686862041, 0.2019676748836232, 0.1952612948137504, 0.1891874239646641, 0.1836520225050326, 0.1785795904846466 ]) dataset = np.column_stack([1 - epsilon, x]) FuncData(kolmogi, dataset, (0, ), 1, rtol=_rtol).check() dataset = np.column_stack([epsilon, x]) FuncData(_kolmogci, dataset, (0, ), 1, rtol=_rtol).check()
def test_hyp2f1_strange_points(): pts = [ (2,-1,-1,0.7), (2,-2,-2,0.7), ] kw = dict(eliminate=True) dataset = [p + (float(mpmath.hyp2f1(*p, **kw)),) for p in pts] dataset = np.array(dataset, dtype=np.float_) FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-10).check()
def test_realpart(): # Test that the real parts of loggamma and gammaln agree on the # real axis. x = np.r_[-np.logspace(10, -10), np.logspace(-10, 10)] + 0.5 dataset = np.vstack((x, gammaln(x))).T def f(z): return loggamma(z).real FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_consistency(): """ Make sure the implementation of digamma for real arguments agrees with the implementation of digamma for complex arguments. """ # It's all poles after -1e16 x = np.r_[-np.logspace(15, -30, 200), np.logspace(-30, 300, 200)] dataset = np.vstack((x + 0j, digamma(x))).T FuncData(digamma, dataset, 0, 1, rtol=5e-14, nan_ok=True).check()
def test_smallpsf(self): epsilon = 0.5**np.arange(1, 55, 3) # kolmogi(p) == _kolmogci(1-p) if 1-(1-p) == p, but not necessarily otherwise # Use epsilon s.t. 1-(1-epsilon)) == epsilon, so can use same x-array for both results x = np.array([ 0.8275735551899077, 1.3163786275161036, 1.6651092133663343, 1.9525136345289607, 2.2027324540033235, 2.4272929437460848, 2.6327688477341593, 2.8233300509220260, 3.0018183401530627, 3.1702735084088891, 3.3302184446307912, 3.4828258153113318, 3.6290214150152051, 3.7695513262825959, 3.9050272690877326, 4.0359582187082550, 4.1627730557884890, 4.2858371743264527 ]) dataset = np.column_stack([epsilon, x]) FuncData(kolmogi, dataset, (0, ), 1, rtol=_rtol).check() dataset = np.column_stack([1 - epsilon, x]) FuncData(_kolmogci, dataset, (0, ), 1, rtol=_rtol).check()
def test_round_trip(self): def _sm_smi(n, p): return smirnov(n, smirnovi(n, p)) dataset = [(1, 0.4, 0.4), (1, 0.6, 0.6), (2, 0.875, 0.875), (3, 0.875, 0.875), (3, 0.125, 0.125), (10, 0.999, 0.999), (10, 0.0001, 0.0001)] dataset = np.asarray(dataset) FuncData(_sm_smi, dataset, (0, 1), 2, rtol=_rtol).check()
def test_oneminusoneovern(self): # Check derivative at x=1-1/n n = np.arange(1, 20) x = 1.0 / n xm1 = 1 - 1.0 / n pp1 = -n * x**(n - 1) pp1 -= (1 - np.sign(n - 2)** 2) * 0.5 # n=2, x=0.5, 1-1/n = 0.5, need to adjust dataset1 = np.column_stack([n, xm1, pp1]) FuncData(_smirnovp, dataset1, (0, 1), 2, rtol=_rtol).check(dtypes=[int, float, float])
def test_smallx(self): epsilon = 0.1**np.arange(1, 14) x = np.array([ 0.571173265106, 0.441027698518, 0.374219690278, 0.331392659217, 0.300820537459, 0.277539353999, 0.259023494805, 0.243829561254, 0.231063086389, 0.220135543236, 0.210641372041, 0.202290283658, 0.19487060742 ]) dataset = np.column_stack([x, 1 - epsilon]) FuncData(kolmogorov, dataset, (0, ), 1, rtol=_rtol).check()
def check(self): # Generate values for the arguments args = get_args(self.argspec, self.n) param_filter = self.get_param_filter() param_columns = tuple(range(args.shape[1])) result_columns = args.shape[1] args = np.hstack((args, args[:,self.index].reshape(args.shape[0], 1))) FuncData(self.idmap, args, param_columns=param_columns, result_columns=result_columns, rtol=self.rtol, atol=self.atol, vectorized=False, param_filter=param_filter).check()
def test_identities1(): # test the identity exp(loggamma(z)) = gamma(z) x = np.array([-99.5, -9.5, -0.5, 0.5, 9.5, 99.5]) y = x.copy() x, y = np.meshgrid(x, y) z = (x + 1J * y).flatten() dataset = np.vstack((z, gamma(z))).T def f(z): return np.exp(loggamma(z)) FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_complex_dispatch_realpart(): # Test that the real parts of loggamma and gammaln agree on the # real axis. x = np.r_[-np.logspace(10, -10), np.logspace(-10, 10)] + 0.5 dataset = np.vstack((x, gammaln(x))).T def f(z): z = np.array(z, dtype='complex128') return loggamma(z).real FuncData(f, dataset, 0, 1, rtol=1e-14, atol=1e-14).check()
def test_lpmv(): pts = [] for x in [-0.99, -0.557, 1e-6, 0.132, 1]: pts.extend([ (1, 1, x), (1, -1, x), (-1, 1, x), (-1, -2, x), (1, 1.7, x), (1, -1.7, x), (-1, 1.7, x), (-1, -2.7, x), (1, 10, x), (1, 11, x), (3, 8, x), (5, 11, x), (-3, 8, x), (-5, 11, x), (3, -8, x), (5, -11, x), (-3, -8, x), (-5, -11, x), (3, 8.3, x), (5, 11.3, x), (-3, 8.3, x), (-5, 11.3, x), (3, -8.3, x), (5, -11.3, x), (-3, -8.3, x), (-5, -11.3, x), ]) def mplegenp(nu, mu, x): if mu == int(mu) and x == 1: # mpmath 0.17 gets this wrong if mu == 0: return 1 else: return 0 return mpmath.legenp(nu, mu, x) dataset = [p + (mplegenp(p[1], p[0], p[2]), ) for p in pts] dataset = np.array(dataset, dtype=np.float_) def evf(mu, nu, x): return sc.lpmv(mu.astype(int), nu, x) olderr = np.seterr(invalid='ignore') try: FuncData(evf, dataset, (0, 1, 2), 3, rtol=1e-10, atol=1e-14).check() finally: np.seterr(**olderr)
def test_linspace(self): x = np.linspace(0, 2.0, 21) dataset = [1.0000000000000000, 1.0000000000000000, 0.9999999999994950, 0.9999906941986655, 0.9971923267772983, 0.9639452436648751, 0.8642827790506042, 0.7112351950296890, 0.5441424115741981, 0.3927307079406543, 0.2699996716773546, 0.1777181926064012, 0.1122496666707249, 0.0680922218447664, 0.0396818795381144, 0.0222179626165251, 0.0119520432391966, 0.0061774306344441, 0.0030676213475797, 0.0014636048371873, 0.0006709252557797] dataset_c = [0.0000000000000000, 6.609305242245699e-53, 5.050407338670114e-13, 9.305801334566668e-06, 0.0028076732227017, 0.0360547563351249, 0.1357172209493958, 0.2887648049703110, 0.4558575884258019, 0.6072692920593457, 0.7300003283226455, 0.8222818073935988, 0.8877503333292751, 0.9319077781552336, 0.9603181204618857, 0.9777820373834749, 0.9880479567608034, 0.9938225693655559, 0.9969323786524203, 0.9985363951628127, 0.9993290747442203] dataset = np.column_stack([x, dataset]) FuncData(kolmogorov, dataset, (0,), 1, rtol=_rtol).check() dataset_c = np.column_stack([x, dataset_c]) FuncData(_kolmogc, dataset_c, (0,), 1, rtol=_rtol).check()
def test_linspacei(self): p = np.linspace(0, 1.0, 21, endpoint=True) dataset = [np.inf, 1.3580986393225507, 1.2238478702170823, 1.1379465424937751, 1.0727491749396481, 1.0191847202536859, 0.9730633753323726, 0.9320695842357622, 0.8947644549851197, 0.8601710725555463, 0.8275735551899077, 0.7964065373291559, 0.7661855555617682, 0.7364542888171910, 0.7067326523068980, 0.6764476915028201, 0.6448126061663567, 0.6105590999244391, 0.5711732651063401, 0.5196103791686224, 0.0000000000000000] dataset_c = [0.0000000000000000, 0.5196103791686225, 0.5711732651063401, 0.6105590999244391, 0.6448126061663567, 0.6764476915028201, 0.7067326523068980, 0.7364542888171910, 0.7661855555617682, 0.7964065373291559, 0.8275735551899077, 0.8601710725555463, 0.8947644549851196, 0.9320695842357622, 0.9730633753323727, 1.0191847202536859, 1.0727491749396481, 1.1379465424937754, 1.2238478702170825, 1.3580986393225509, np.inf] dataset = np.column_stack([p[1:], dataset[1:]]) FuncData(kolmogi, dataset, (0,), 1, rtol=_rtol).check() dataset_c = np.column_stack([p[:-1], dataset_c[:-1]]) FuncData(_kolmogci, dataset_c, (0,), 1, rtol=_rtol).check()
def test_hyp2f1_real_some(): dataset = [] for a in [-10, -5, -1.8, 1.8, 5, 10]: for b in [-2.5, -1, 1, 7.4]: for c in [-9, -1.8, 5, 20.4]: for z in [-10, -1.01, -0.99, 0, 0.6, 0.95, 1.5, 10]: try: v = float(mpmath.hyp2f1(a, b, c, z)) except: continue dataset.append((a, b, c, z, v)) dataset = np.array(dataset, dtype=np.float_) FuncData(sc.hyp2f1, dataset, (0,1,2,3), 4, rtol=1e-9).check()
def test_sici_consistency(): # Make sure the implementation of sici for real arguments agrees # with the implementation of sici for complex arguments. # On the negative real axis Cephes drops the imaginary part in ci def sici(x): si, ci = sc.sici(x + 0j) return si.real, ci.real x = np.r_[-np.logspace(8, -30, 200), 0, np.logspace(-30, 8, 200)] si, ci = sc.sici(x) dataset = np.column_stack((x, si, ci)) FuncData(sici, dataset, 0, (1, 2), rtol=1e-12).check()
def test_special_values(): # Test special values from Gauss's digamma theorem. See # # https://en.wikipedia.org/wiki/Digamma_function dataset = [(1, -euler), (0.5, -2*log(2) - euler), (1/3, -pi/(2*sqrt(3)) - 3*log(3)/2 - euler), (1/4, -pi/2 - 3*log(2) - euler), (1/6, -pi*sqrt(3)/2 - 2*log(2) - 3*log(3)/2 - euler), (1/8, -pi/2 - 4*log(2) - (pi + log(2 + sqrt(2)) - log(2 - sqrt(2)))/sqrt(2) - euler)] dataset = np.asarray(dataset) FuncData(sc.digamma, dataset, 0, 1, rtol=1e-14).check()
def test_basic(self): dataset = [(0.000000, -0.0), (0.200000, -1.532420541338916e-10), (0.400000, -0.1012254419260496), (0.600000, -1.324123244249925), (0.800000, -1.627024345636592), (1.000000, -1.071948558356941), (1.200000, -0.538512430720529), (1.400000, -0.2222133182429472), (1.600000, -0.07649302775520538), (1.800000, -0.02208687346347873), (2.000000, -0.005367402045629683)] dataset = np.asarray(dataset) FuncData(_kolmogp, dataset, (0, ), 1, rtol=_rtol).check()
def test_shichi_consistency(): # Make sure the implementation of shichi for real arguments agrees # with the implementation of shichi for complex arguments. # On the negative real axis Cephes drops the imaginary part in chi def shichi(x): shi, chi = sc.shichi(x + 0j) return shi.real, chi.real # Overflow happens quickly, so limit range x = np.r_[-np.logspace(np.log10(700), -30, 200), 0, np.logspace(-30, np.log10(700), 200)] shi, chi = sc.shichi(x) dataset = np.column_stack((x, shi, chi)) FuncData(shichi, dataset, 0, (1, 2), rtol=1e-14).check()
def check_poly(self, func, param_ranges=[], x_range=[], nn=10, nparam=10, nx=10, rtol=1e-8): np.random.seed(1234) dataset = [] for n in np.arange(nn): params = [a + (b-a)*np.random.rand(nparam) for a,b in param_ranges] params = np.asarray(params).T if not param_ranges: params = [0] for p in params: if param_ranges: p = (n,) + tuple(p) else: p = (n,) x = x_range[0] + (x_range[1] - x_range[0])*np.random.rand(nx) x[0] = x_range[0] # always include domain start point x[1] = x_range[1] # always include domain end point kw = dict(sig=(len(p)+1)*'d'+'->d') z = np.c_[np.tile(p, (nx,1)), x, func(*(p + (x,)), **kw)] dataset.append(z) dataset = np.concatenate(dataset, axis=0) def polyfunc(*p): p = (p[0].astype(int),) + p[1:] kw = dict(sig='l'+(len(p)-1)*'d'+'->d') return func(*p, **kw) olderr = np.seterr(all='raise') try: ds = FuncData(polyfunc, dataset, list(range(len(param_ranges)+2)), -1, rtol=rtol) ds.check() finally: np.seterr(**olderr)
def test_special_points(): """Check against known values of Spence's function.""" phi = (1 + sqrt(5))/2 dataset = [(1, 0), (2, -pi**2/12), (0.5, pi**2/12 - log(2)**2/2), (0, pi**2/6), (-1, pi**2/4 - 1j*pi*log(2)), ((-1 + sqrt(5))/2, pi**2/15 - log(phi)**2), ((3 - sqrt(5))/2, pi**2/10 - log(phi)**2), (phi, -pi**2/15 + log(phi)**2/2), # Corrected from Zagier, "The Dilogarithm Function" ((3 + sqrt(5))/2, -pi**2/10 - log(phi)**2)] dataset = np.asarray(dataset) FuncData(spence, dataset, 0, 1, rtol=1e-14).check()
def test_against_mathematica(self): # Results obtained from Mathematica by computing # # PDF[VoigtDistribution[gamma, sigma], x] # points = np.array([[-7.89, 45.06, 6.66, 0.0077921073660388806401], [-0.05, 7.98, 24.13, 0.012068223646769913478], [-13.98, 16.83, 42.37, 0.0062442236362132357833], [-12.66, 0.21, 6.32, 0.010052516161087379402], [11.34, 4.25, 21.96, 0.0113698923627278917805], [-11.56, 20.40, 30.53, 0.0076332760432097464987], [-9.17, 25.61, 8.32, 0.011646345779083005429], [16.59, 18.05, 2.50, 0.013637768837526809181], [9.11, 2.12, 39.33, 0.0076644040807277677585], [-43.33, 0.30, 45.68, 0.0036680463875330150996]]) FuncData(sc.voigt_profile, points, (0, 1, 2), 3, atol=0, rtol=1e-15).check()
def test_hyp2f1_some_points_2(): # Taken from mpmath unit tests -- this point failed for mpmath 0.13 but # was fixed in their SVN since then pts = [ (112, (51, 10), (-9, 10), -0.99999), (10, -900, 10.5, 0.99), (10, -900, -10.5, 0.99), ] def fev(x): if isinstance(x, tuple): return float(x[0]) / x[1] else: return x dataset = [tuple(map(fev, p)) + (float(mpmath.hyp2f1(*p)), ) for p in pts] dataset = np.array(dataset, dtype=np.float_) FuncData(sc.hyp2f1, dataset, (0, 1, 2, 3), 4, rtol=1e-10).check()
def test_lpmv(): pts = [] for x in [-0.99, -0.557, 1e-6, 0.132, 1]: pts.extend([ (1, 1, x), (1, -1, x), (-1, 1, x), (-1, -2, x), (1, 1.7, x), (1, -1.7, x), (-1, 1.7, x), (-1, -2.7, x), (1, 10, x), (1, 11, x), (3, 8, x), (5, 11, x), (-3, 8, x), (-5, 11, x), (3, -8, x), (5, -11, x), (-3, -8, x), (-5, -11, x), (3, 8.3, x), (5, 11.3, x), (-3, 8.3, x), (-5, 11.3, x), (3, -8.3, x), (5, -11.3, x), (-3, -8.3, x), (-5, -11.3, x), ]) dataset = [p + (mpmath.legenp(p[1], p[0], p[2]), ) for p in pts] dataset = np.array(dataset, dtype=np.float_) evf = lambda mu, nu, x: sc.lpmv(mu.astype(int), nu, x) olderr = np.seterr(invalid='ignore') try: FuncData(evf, dataset, (0, 1, 2), 3, rtol=1e-10, atol=1e-14).check() finally: np.seterr(**olderr)
def test_line(): # Test on the line a = x where a simpler asymptotic expansion # (analog of DLMF 8.12.15) is available. def gammainc_line(x): c = np.array([-1/3, -1/540, 25/6048, 101/155520, -3184811/3695155200, -2745493/8151736420]) res = 0 xfac = 1 for ck in c: res -= ck*xfac xfac /= x res /= np.sqrt(2*np.pi*x) res += 0.5 return res x = np.logspace(np.log10(25), 300, 500) a = x.copy() dataset = np.vstack((a, x, gammainc_line(x))).T FuncData(gammainc, dataset, (0, 1), 2, rtol=1e-11).check()
def test_hyp2f1_real_some(): dataset = [] for a in [-10, -5, -1.8, 1.8, 5, 10]: for b in [-2.5, -1, 1, 7.4]: for c in [-9, -1.8, 5, 20.4]: for z in [-10, -1.01, -0.99, 0, 0.6, 0.95, 1.5, 10]: try: v = float(mpmath.hyp2f1(a, b, c, z)) except: continue dataset.append((a, b, c, z, v)) dataset = np.array(dataset, dtype=np.float_) olderr = np.seterr(invalid='ignore') try: FuncData(sc.hyp2f1, dataset, (0, 1, 2, 3), 4, rtol=1e-9, ignore_inf_sign=True).check() finally: np.seterr(**olderr)
def test_hyp2f1_real_random(): dataset = [] npoints = 500 dataset = np.zeros((npoints, 5), np.float_) np.random.seed(1234) dataset[:, 0] = np.random.pareto(1.5, npoints) dataset[:, 1] = np.random.pareto(1.5, npoints) dataset[:, 2] = np.random.pareto(1.5, npoints) dataset[:, 3] = 2 * np.random.rand(npoints) - 1 dataset[:, 0] *= (-1)**np.random.randint(2, npoints) dataset[:, 1] *= (-1)**np.random.randint(2, npoints) dataset[:, 2] *= (-1)**np.random.randint(2, npoints) for ds in dataset: if mpmath.__version__ < '0.14': # mpmath < 0.14 fails for c too much smaller than a, b if abs(ds[:2]).max() > abs(ds[2]): ds[2] = abs(ds[:2]).max() ds[4] = float(mpmath.hyp2f1(*tuple(ds[:4]))) FuncData(sc.hyp2f1, dataset, (0, 1, 2, 3), 4, rtol=1e-9).check()
def data_local(func, dataname, *a, **kw): kw.setdefault('dataname', dataname) return FuncData(func, DATASETS_LOCAL[dataname], *a, **kw)
def data_gsl(func, dataname, *a, **kw): kw.setdefault('dataname', dataname) return FuncData(func, DATASETS_GSL[dataname], *a, **kw)
def test_line(self): x = np.logspace(np.log10(25), 300, 500) a = x dataset = np.vstack((a, x, self.gammainc_line(x))).T FuncData(sc.gammainc, dataset, (0, 1), 2, rtol=1e-11).check()