def evans_webster_weights(omega, g, d_g, x, basis, *args, **kwds): def psi(t, k): return d_g(t, *args, **kwds) * basis(t, k) j_w = 1j * omega n = len(x) a_matrix = np.zeros((n, n), dtype=complex) rhs = np.zeros((n,), dtype=complex) dbasis = basis.derivative lim_g = Limit(g) b_1 = np.exp(j_w * lim_g(1, *args, **kwds)) if np.isnan(b_1): b_1 = 0.0 a_1 = np.exp(j_w * lim_g(-1, *args, **kwds)) if np.isnan(a_1): a_1 = 0.0 lim_psi = Limit(psi) for k in range(n): rhs[k] = basis(1, k) * b_1 - basis(-1, k) * a_1 a_matrix[k] = (dbasis(x, k, n=1) + j_w * lim_psi(x, k)) solution = linalg.lstsq(a_matrix, rhs, rcond=None) return solution[0]
def evans_webster_weights(omega, gg, dgg, x, basis, *args, **kwds): def Psi(t, k): return dgg(t, *args, **kwds) * basis(t, k) j_w = 1j * omega nn = len(x) A = np.zeros((nn, nn), dtype=complex) F = np.zeros((nn, ), dtype=complex) dbasis = basis.derivative lim_gg = Limit(gg) b1 = np.exp(j_w * lim_gg(1, *args, **kwds)) if np.isnan(b1): b1 = 0.0 a1 = np.exp(j_w * lim_gg(-1, *args, **kwds)) if np.isnan(a1): a1 = 0.0 lim_Psi = Limit(Psi) for k in range(nn): F[k] = basis(1, k) * b1 - basis(-1, k) * a1 A[k] = (dbasis(x, k, n=1) + j_w * lim_Psi(x, k)) LS = linalg.lstsq(A, F) return LS[0]
def test_difficult_limit(self): def k(x): return (x * np.exp(x) - np.exp(x) + 1) / x**2 lim, err = Limit(k, full_output=True)(0) assert_allclose(lim, 0.5) self.assertTrue(err.error_estimate < 1e-8)
def test_residue(self): def h(z): return -z / (np.expm1(2 * z)) lim, err = Limit(h, full_output=True)(0) assert_allclose(lim, -0.5) self.assertTrue(err.error_estimate < 1e-14)
def test_residue_1_div_1_minus_exp_x(self): def fun(z): return -z / (np.expm1(2 * z)) lim, err = Limit(fun, full_output=True)(0) assert_allclose(lim, -0.5) self.assertTrue(err.error_estimate < 1e-14)
def test_derivative_of_cos(self): x0 = np.pi / 2 def g(x): return (np.cos(x0 + x) - np.cos(x0)) / x lim, err = Limit(g, full_output=True)(0) assert_allclose(lim, -1) self.assertTrue(err.error_estimate < 1e-14)
def _quad_osc(self, f, g, dg, a, b, omega, *args, **kwds): if a == b: Q = b - a err = b - a return Q, err abseps = 10**-self.precision max_iter = self.maxiter basis = self.basis if self.endpoints: xq = chebyshev_extrema(self.s) else: xq = chebyshev_roots(self.s) # xq = tanh_sinh_open_nodes(self.s) # One interval hh = (b - a) / 2 x = (a + b) / 2 + hh * xq # Nodes dtype = complex Q0 = np.zeros((max_iter, 1), dtype=dtype) # Quadrature Q1 = np.zeros((max_iter, 1), dtype=dtype) # First extrapolation Q2 = np.zeros((max_iter, 1), dtype=dtype) # Second extrapolation lim_f = Limit(f) ab = np.hstack([a, b]) wq = osc_weights(omega, g, dg, xq, basis, ab, *args, **kwds) Q0[0] = hh * np.sum(wq * lim_f(x, *args, **kwds)) # Successive bisection of intervals nq = len(xq) n = nq for k in range(1, max_iter): n += nq * 2**k hh = hh / 2 x = np.hstack([x + a, x + b]) / 2 ab = np.hstack([ab + a, ab + b]) / 2 wq = osc_weights(omega, g, dg, xq, basis, ab, *args, **kwds) Q0[k] = hh * np.sum(wq * lim_f(x, *args, **kwds)) Q, err = self._extrapolate(k, Q0, Q1, Q2) convergence = (err <= abseps) | ~np.isfinite(Q) if convergence: break else: warnings.warn('Max number of iterations reached ' 'without convergence.') if ~np.isfinite(Q): warnings.warn('Integral approximation is Infinite or NaN.') # The error estimate should not be zero err += 2 * np.finfo(Q).eps return Q, self.info(err, n)
def test_derivative_of_cos(self): x0 = np.pi / 2 def fun(x): return (np.cos(x0 + x) - np.cos(x0)) / x lim, err = Limit(fun, step=CStepGenerator(), full_output=True)(0) assert_allclose(lim, -1) assert err.error_estimate < 1e-14
def test_sinx_divx(self): def f(x): return np.sin(x) / x lim_f = Limit(f, full_output=True) x = np.arange(-10, 10) / np.pi lim_f0, err = lim_f(x * np.pi) assert_array_almost_equal(lim_f0, np.sinc(x)) self.assertTrue(np.all(err.error_estimate < 1.0e-14))
def _quad_osc(self, f, g, dg, a, b, omega, *args, **kwds): if a == b: q_val = b - a err = np.abs(b - a) return q_val, err abseps = 10**-self.precision max_iter = self.maxiter basis = self.basis if self.endpoints: x_n = chebyshev_extrema(self.s) else: x_n = chebyshev_roots(self.s) # x_n = tanh_sinh_open_nodes(self.s) # One interval hh = (b - a) / 2 x = (a + b) / 2 + hh * x_n # Nodes dtype = complex val0 = np.zeros((max_iter, 1), dtype=dtype) # Quadrature val1 = np.zeros((max_iter, 1), dtype=dtype) # First extrapolation val2 = np.zeros((max_iter, 1), dtype=dtype) # Second extrapolation lim_f = Limit(f) a_b = np.hstack([a, b]) wq = osc_weights(omega, g, dg, x_n, basis, a_b, *args, **kwds) val0[0] = hh * np.sum(wq * lim_f(x, *args, **kwds)) # Successive bisection of intervals nq = len(x_n) n = nq for k in range(1, max_iter): n += nq * 2**k hh = hh / 2 x = np.hstack([x + a, x + b]) / 2 a_b = np.hstack([a_b + a, a_b + b]) / 2 wq = osc_weights(omega, g, dg, x_n, basis, a_b, *args, **kwds) val0[k] = hh * np.sum(wq * lim_f(x, *args, **kwds)) q_val, err = self._extrapolate(k, val0, val1, val2) converged = (err <= abseps) | ~np.isfinite(q_val) if converged: break _assert_warn(converged, 'Max number of iterations reached ' 'without convergence.') _assert_warn(np.isfinite(q_val), 'Integral approximation is Infinite or NaN.') # The error estimate should not be zero err += 2 * np.finfo(q_val).eps return q_val, self.info(err, n)
def test_difficult_limit(self): def fun(x): return (x * np.exp(x) - np.expm1(x)) / x**2 for path in [ 'radial', ]: lim, err = Limit(fun, path=path, full_output=True)(0) assert_allclose(lim, 0.5) self.assertTrue(err.error_estimate < 1e-8)
def test_sinx_div_x(self): def fun(x): return np.sin(x) / x for path in ['radial', 'spiral']: lim_f = Limit(fun, path=path, full_output=True) x = np.arange(-10, 10) / np.pi lim_f0, err = lim_f(x * np.pi) assert_array_almost_equal(lim_f0, np.sinc(x)) self.assertTrue(np.all(err.error_estimate < 1.0e-14))
def _a_levin(omega, f, g, d_g, x, s, basis, *args, **kwds): def psi(t, k): return d_g(t, *args, **kwds) * basis(t, k) j_w = 1j * omega nu = np.ones((len(x),), dtype=int) nu[0] = nu[-1] = s S = np.cumsum(np.hstack((nu, 0))) S[-1] = 0 n = int(S[-2]) a_matrix = np.zeros((n, n), dtype=complex) rhs = np.zeros((n,)) dff = Limit(nda.Derivative(f)) d_psi = Limit(nda.Derivative(psi)) dbasis = basis.derivative for r, t in enumerate(x): for j in range(S[r - 1], S[r]): order = ((j - S[r - 1]) % nu[r]) # derivative order dff.fun.n = order rhs[j] = dff(t, *args, **kwds) d_psi.fun.n = order for k in range(n): a_matrix[j, k] = (dbasis(t, k, n=order + 1) + j_w * d_psi(t, k)) k1 = np.flatnonzero(1 - np.isfinite(rhs)) if k1.size > 0: # Remove singularities warnings.warn('Singularities detected! ') a_matrix[k1] = 0 rhs[k1] = 0 solution = linalg.lstsq(a_matrix, rhs) v = basis.eval([-1, 1], solution[0]) lim_g = Limit(g) g_b = np.exp(j_w * lim_g(1, *args, **kwds)) if np.isnan(g_b): g_b = 0 g_a = np.exp(j_w * lim_g(-1, *args, **kwds)) if np.isnan(g_a): g_a = 0 return v[1] * g_b - v[0] * g_a
def aLevinTQ(omega, ff, gg, dgg, x, s, basis, *args, **kwds): def Psi(t, k): return dgg(t, *args, **kwds) * basis(t, k) j_w = 1j * omega nu = np.ones((len(x), ), dtype=int) nu[0] = nu[-1] = s S = np.cumsum(np.hstack((nu, 0))) S[-1] = 0 nn = int(S[-2]) A = np.zeros((nn, nn), dtype=complex) F = np.zeros((nn, )) dff = Limit(nda.Derivative(ff)) dPsi = Limit(nda.Derivative(Psi)) dbasis = basis.derivative for r, t in enumerate(x): for j in range(S[r - 1], S[r]): order = ((j - S[r - 1]) % nu[r]) # derivative order dff.f.n = order F[j] = dff(t, *args, **kwds) dPsi.f.n = order for k in range(nn): A[j, k] = (dbasis(t, k, n=order + 1) + j_w * dPsi(t, k)) k1 = np.flatnonzero(1 - np.isfinite(F)) if k1.size > 0: # Remove singularities warnings.warn('Singularities detected! ') A[k1] = 0 F[k1] = 0 LS = linalg.lstsq(A, F) v = basis.eval([-1, 1], LS[0]) lim_gg = Limit(gg) gb = np.exp(j_w * lim_gg(1, *args, **kwds)) if np.isnan(gb): gb = 0 ga = np.exp(j_w * lim_gg(-1, *args, **kwds)) if np.isnan(ga): ga = 0 NR = (v[1] * gb - v[0] * ga) return NR
def _a_levin(self, omega, ff, gg, dgg, x, s, basis, *args, **kwds): w = evans_webster_weights(omega, gg, dgg, x, basis, *args, **kwds) f = Limit(ff)(x, *args, **kwds) return np.sum(f * w)
def aLevinTQ(self, omega, ff, gg, dgg, x, s, basis, *args, **kwds): w = evans_webster_weights(omega, gg, dgg, x, basis, *args, **kwds) f = Limit(ff)(x, *args, **kwds) NR = np.sum(f * w) return NR