def main(Qstr): Q = float(Qstr) if shape == 'sphere': print("exact", NORM * sp.sas_3j1x_x(Q * RADIUS)**2) print("gauss-20", *gauss_quad_2d(Q, n=20)) print("gauss-76", *gauss_quad_2d(Q, n=76)) print("gauss-150", *gauss_quad_2d(Q, n=150)) print("gauss-500", *gauss_quad_2d(Q, n=500)) print("gauss-1025", *gauss_quad_2d(Q, n=1025)) print("gauss-2049", *gauss_quad_2d(Q, n=2049)) print("gauss-20 usub", *gauss_quad_usub(Q, n=20)) print("gauss-76 usub", *gauss_quad_usub(Q, n=76)) print("gauss-150 usub", *gauss_quad_usub(Q, n=150)) #gridded_2d(Q, n=2**8+1) gridded_2d(Q, n=2**10 + 1) #gridded_2d(Q, n=2**12+1) #gridded_2d(Q, n=2**15+1) if shape not in ('paracrystal', 'core_shell_parallelepiped'): # adaptive forms on models for which the calculations are fast enough print("dblquad", *scipy_dblquad_2d(Q)) print("semi-romberg-100", *semi_romberg_2d(Q, n=100)) print("romberg", *scipy_romberg_2d(Q)) with mp.workprec(100): print("mpmath", *mp_quad_2d(mp.mpf(Qstr), shape)) plot_2d(Q, n=200)
def apply(self, z, evaluation): '%(name)s[z__]' args = z.get_sequence() if len(args) != self.nargs: return # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): result = Expression(self.get_name(), *args).to_sympy() result = self.prepare_mathics(result) result = from_sympy(result) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] result = result.evaluate_leaves(evaluation) else: prec = min_prec(*args) with mpmath.workprec(prec): mpmath_args = [sympy2mpmath(x.to_sympy()) for x in args] if None in mpmath_args: return try: result = self.eval(*mpmath_args) result = from_sympy(mpmath2sympy(result, prec)) except ValueError, exc: text = str(exc) if text == 'gamma function pole': return Symbol('ComplexInfinity') else: raise except ZeroDivisionError: return except SpecialValueError, exc: return Symbol(exc.name)
def single_segment_score_pv(score, raw=True): """ Compute p-value for normalized local score of a single high scoring segment. Computes formula [1] in Karlin & Altschul, PNAS 1993 Prob(S' >= x) ~ 1 - exp(-exp(-x)) :param score: :param raw: return raw P-value instead of -log10(pv) :return: """ with mpm.workprec(NUM_PREC_KA_PV): x = mpm.convert(score) complement = mpm.convert('1') exponent = mpm.fneg(mpm.exp(mpm.fneg(x))) res = mpm.fsub(complement, mpm.exp(exponent)) if not raw: res = mpm.fneg(mpm.log10(res)) res = float(res) # Equivalent implementation using Python standard library: # # x = score # res = 1 - math.exp(-math.exp(-x)) # if not raw: # res = -1 * math.log10(res) return res
def apply_N(self, prec, evaluation): 'N[E, prec_]' prec = get_precision(prec, evaluation) if prec is not None: with workprec(prec): return Real(mpmath2gmpy(mpmath.e))
def _eval_evalf(self, prec): # The default code is insufficient for polar arguments. # mpmath provides an optional argument "r", which evaluates # G(z**(1/r)). I am not sure what its intended use is, but we hijack it # here in the following way: to evaluate at a number z of |argument| # less than (say) n*pi, we put r=1/n, compute z' = root(z, n) # (carefully so as not to loose the branch information), and evaluate # G(z'**(1/r)) = G(z'**n) = G(z). from sympy.functions import exp_polar, ceiling from sympy import Expr import mpmath znum = self.argument._eval_evalf(prec) if znum.has(exp_polar): znum, branch = znum.as_coeff_mul(exp_polar) if len(branch) != 1: return branch = branch[0].args[0] / I else: branch = S.Zero n = ceiling(abs(branch / S.Pi)) + 1 znum = znum**(S.One / n) * exp(I * branch / n) # Convert all args to mpf or mpc try: [z, r, ap, bq] = [ arg._to_mpmath(prec) for arg in [znum, 1 / n, self.args[0], self.args[1]] ] except ValueError: return with mpmath.workprec(prec): v = mpmath.meijerg(ap, bq, z, r) return Expr._from_mpmath(v, prec)
def single_segment_expect_pv(expect, raw=True): """ Compute p-value for an expect value of a single high scoring segment. Prob(E >= x) ~ 1 - exp(-E) This function is equivalent to single_segment_score_pv as long as identical units (log) are used to compute scores and expect :param expect: :param raw: return raw P-value instead of -log10(pv) :return: """ with mpm.workprec(NUM_PREC_KA_PV): x = mpm.convert(expect) complement = mpm.convert('1') res = mpm.fsub(complement, mpm.exp(mpm.fneg(x))) if not raw: res = mpm.fneg(mpm.log10(res)) res = float(res) return res
def _eval_evalf(self, prec): # The default code is insufficient for polar arguments. # mpmath provides an optional argument "r", which evaluates # G(z**(1/r)). I am not sure what its intended use is, but we hijack it # here in the following way: to evaluate at a number z of |argument| # less than (say) n*pi, we put r=1/n, compute z' = root(z, n) # (carefully so as not to loose the branch information), and evaluate # G(z'**(1/r)) = G(z'**n) = G(z). from sympy.functions import exp_polar, ceiling from sympy import Expr import mpmath z = self.argument znum = self.argument._eval_evalf(prec) if znum.has(exp_polar): znum, branch = znum.as_coeff_mul(exp_polar) if len(branch) != 1: return branch = branch[0].args[0]/I else: branch = S(0) n = ceiling(abs(branch/S.Pi)) + 1 znum = znum**(S(1)/n)*exp(I*branch / n) # Convert all args to mpf or mpc try: [z, r, ap, bq] = [arg._to_mpmath(prec) for arg in [znum, 1/n, self.args[0], self.args[1]]] except ValueError: return with mpmath.workprec(prec): v = mpmath.meijerg(ap, bq, z, r) return Expr._from_mpmath(v, prec)
def apply(self, z, evaluation): "%(name)s[z__]" args = z.get_sequence() if len(args) != self.nargs: return # if no arguments are inexact attempt to use sympy if len([True for x in args if Expression("InexactNumberQ", x).evaluate(evaluation).is_true()]) == 0: expr = Expression(self.get_name(), *args).to_sympy() result = from_sympy(expr) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] result = result.evaluate_leaves(evaluation) else: prec = min_prec(*args) with mpmath.workprec(prec): mpmath_args = [sympy2mpmath(x.to_sympy()) for x in args] if None in mpmath_args: return try: result = self.eval(*mpmath_args) result = from_sympy(mpmath2sympy(result, prec)) except ValueError, exc: text = str(exc) if text == "gamma function pole": return Symbol("ComplexInfinity") else: raise except ZeroDivisionError: return except SpecialValueError, exc: return Symbol(exc.name)
def _eval_evalf(self, prec): z = self.argument._to_mpmath(prec) ap = [a._to_mpmath(prec) for a in self.ap] bp = [b._to_mpmath(prec) for b in self.bq] with mpmath.workprec(prec): res = mpmath.hyper(ap, bp, z, eliminate=False) return Expr._from_mpmath(res, prec)
def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr z = self.args[0]._to_mpmath(prec) with workprec(prec): res = mp.airybi(z, derivative=1) return Expr._from_mpmath(res, prec)
def partition_functions_for_all_configurations(self): """ Sum the partition functions for all configurations. .. math:: Z_{\\text{all configs}}(T, V) = \\sum_{j} Z_{j}(T, V). :return: A vector, the partition function of each volume. """ try: import mpmath except ImportError: raise ImportError( "Install ``mpmath`` package to use {0} object!".format( self.__class__.__name__)) with mpmath.workprec(self.precision): # shape = (# of volumes,) return np.array([ mpmath.exp(d) for d in logsumexp( -self.aligned_free_energies_for_each_configuration.T / (K * self.temperature), axis=1, b=self.degeneracies) ])
def _w_tilde(self, u_bar): """Compute w_tilde, the threshold for the word-length w such that MSB = computeNaiveMSB if w >= w_tilde MSB = computeNaiveMSB+1 if w < w_tilde (this doesn't count into account the roundoff error, as in FxPF) See ARITH26 paper Parameters: - u_bar: vector of bounds on the inputs of the system Returns: a vector of thresholds w_tilde We use: w_tilde = 1 + ceil(log2(zeta_bar)) - floor(log2( 2^ceil(log2(zeta_bar)) - zeta_bar )) with zeta_bar = <<Hzeta>>.u_bar """ #TODO: test if zeta_bar is a power of 2 (should be +Inf in that case) zeta_bar = self.Hzeta.WCPG() * u_bar with mpmath.workprec(500): # TODO: compute how many bit we need !! wtilde = [ int(1 + mpmath.ceil(mpmath.log(x[0], 2)) - mpmath.floor( mpmath.log( mpmath.power(2, mpmath.ceil(mpmath.log(x[0], 2))) - x[0], 2))) for x in zeta_bar.tolist() ] return wtilde
def real_power(x, y): x = g_mpf(x) y = g_mpf(y) prec = min(x.getprec(), y.getprec()) with workprec(prec): x = gmpy2mpmath(x) y = gmpy2mpmath(y) return mpmath2gmpy(x**y)
def _eval_evalf(self, prec): if all(x.is_number for x in self.args): a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, z, mp.inf) return Expr._from_mpmath(res, prec) return self
def _eval_evalf(self, prec): m = self.args[0] if m.is_Integer and m.is_nonnegative: m = m._to_mpmath(prec) with workprec(prec): res = mp.eulernum(m) return Expr._from_mpmath(res, prec)
def _eval_evalf(self, prec): from mpmath import mp, workprec from ... import Expr a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, z, mp.inf) return Expr._from_mpmath(res, prec)
def real_power(x, y): x = g_mpf(x) y = g_mpf(y) prec = min(x.getprec(), y.getprec()) with workprec(prec): x = gmpy2mpmath(x) y = gmpy2mpmath(y) return mpmath2gmpy(x ** y)
def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, z, mp.inf) return Expr._from_mpmath(res, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0, verify=False) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = ax + S.ImaginaryUnit * by break if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break return Float._new(root.real._mpf_, prec) + I * Float._new(root.imag._mpf_, prec)
def apply(self, z, evaluation): '%(name)s[z__]' args = z.numerify(evaluation).get_sequence() mpmath_function = self.get_mpmath_function(args) result = None # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): result = Expression(self.get_name(), *args).to_sympy() result = self.prepare_mathics(result) result = from_sympy(result) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] return result.evaluate_leaves(evaluation) elif mpmath_function is None: return if not all(isinstance(arg, Number) for arg in args): return if any(arg.is_machine_precision() for arg in args): # if any argument has machine precision then the entire calculation # is done with machine precision. float_args = [ arg.round().get_float_value(permit_complex=True) for arg in args ] if None in float_args: return result = self.call_mpmath(mpmath_function, float_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): if mpmath.isinf(result) and isinstance(result, mpmath.mpc): result = Symbol('ComplexInfinity') elif mpmath.isinf(result) and result > 0: result = Expression('DirectedInfinity', Integer(1)) elif mpmath.isinf(result) and result < 0: result = Expression('DirectedInfinity', Integer(-1)) elif mpmath.isnan(result): result = Symbol('Indeterminate') else: result = Number.from_mpmath(result) else: prec = min_prec(*args) d = dps(prec) args = [ Expression('N', arg, Integer(d)).evaluate(evaluation) for arg in args ] with mpmath.workprec(prec): mpmath_args = [x.to_mpmath() for x in args] if None in mpmath_args: return result = self.call_mpmath(mpmath_function, mpmath_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): result = Number.from_mpmath(result, d) return result
def value_interval(self): with mpmath.workprec(self.wordlength + 1): # wl bits is enough if self.signed: return interval( -mpmath.ldexp(1, self.msb), mpmath.ldexp(1, self.msb) - mpmath.ldexp(1, self.lsb)) return interval( 0, mpmath.ldexp(1, self.msb) - mpmath.ldexp(1, self.lsb))
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: x0 = mpf(str(interval.center)) else: x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0, verify=False) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break if not (a < root < b): raise ValueError("Root not in the interval.") else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = ax + S.ImaginaryUnit*by break if not (ax < root.real < bx and ay < root.imag < by): raise ValueError("Root not in the interval.") except ValueError: interval = interval.refine() continue else: break return Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec)
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d), "mpmath") else: func = lambdify(g, self.expr, "mpmath") try: interval = self.interval except KeyError: return super()._eval_evalf(prec) while True: if self.is_extended_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) x0 = mpc(*map(str, interval.center)) if ax == bx and ay == by: root = x0 break try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. if self.is_extended_real: if (a <= root <= b): break elif (ax <= root.real <= bx and ay <= root.imag <= by and (interval.ay > 0 or interval.by < 0)): break except (ValueError, UnboundLocalError): pass self.refine() interval = self.interval return ((Float._new(root.real._mpf_, prec) if not self.is_imaginary else 0) + I * Float._new(root.imag._mpf_, prec))
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision.""" with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs({g: d}), "mpmath") else: func = lambdify(g, self.expr, "mpmath") try: interval = self.interval except DomainError: return super()._eval_evalf(prec) while True: if self.is_extended_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) x0 = mpc(*map(str, interval.center)) if ax == bx and ay == by: root = x0 break try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. if self.is_extended_real: if (a <= root <= b): break elif (ax <= root.real <= bx and ay <= root.imag <= by and (interval.ay > 0 or interval.by < 0)): break except (ValueError, UnboundLocalError): pass self.refine() interval = self.interval return ((Float._new(root.real._mpf_, prec) if not self.is_imaginary else 0) + I*Float._new(root.imag._mpf_, prec))
def apply_N(self, k, precision, evaluation): 'N[AiryBiZero[k_Integer], precision_]' prec = get_precision(precision, evaluation) k_int = k.get_int_value() with mpmath.workprec(prec): result = mpmath2sympy(mpmath.airybizero(k_int), prec) return from_sympy(result)
def minmax(self): """Gives the interval a variable of this FPF may belong to. Returns: a tuple (min, max) """ with workprec(self._wl+1): # wl bits is enough if self._signed: return -ldexp(1, self._msb), ldexp(1, self._msb) - ldexp(1, self.lsb) else: return 0, ldexp(1, self._msb+1) - ldexp(1, self.lsb)
def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr if all(x.is_number for x in self.args): a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, 0, z) return Expr._from_mpmath(res, prec) else: return self
def _eval_evalf(self, prec): # Note: works without this function by just calling # mpmath for Legendre polynomials. But using # the dedicated function directly is cleaner. from mpmath import mp, workprec n = self.args[0]._to_mpmath(prec) m = self.args[1]._to_mpmath(prec) theta = self.args[2]._to_mpmath(prec) phi = self.args[3]._to_mpmath(prec) with workprec(prec): res = mp.spherharm(n, m, theta, phi) return Expr._from_mpmath(res, prec)
def gmpy2mpmath(value): if isinstance(value, mpcomplex): return value.to_mpmath() else: if get_type(value) != 'f': value = g_mpf(value) with workprec(value.getprec()): value = str(g_mpf(value)) if value and value[0] == '-': return -mp_mpf(value[1:]) else: return mp_mpf(value)
def apply_inexact(self, n, k, evaluation): 'Binomial[n_?InexactNumberQ, k_?NumberQ]' with workprec(min_prec(n, k)): n = gmpy2mpmath(n.value) k = gmpy2mpmath(k.value) result = mpmath.binomial(n, k) try: result = mpmath2gmpy(result) except SpecialValueError, exc: return Symbol(exc.name) number = Number.from_mp(result) return number
def _eval_evalf(self, prec): # Note: works without this function by just calling # mpmath for Legendre polynomials. But using # the dedicated function directly is cleaner. from mpmath import mp, workprec from sympy import Expr n = self.args[0]._to_mpmath(prec) m = self.args[1]._to_mpmath(prec) theta = self.args[2]._to_mpmath(prec) phi = self.args[3]._to_mpmath(prec) with workprec(prec): res = mp.spherharm(n, m, theta, phi) return Expr._from_mpmath(res, prec)
def apply(self, z, evaluation): '%(name)s[z__]' args = z.numerify(evaluation).get_sequence() mpmath_function = self.get_mpmath_function(args) result = None # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): result = Expression(self.get_name(), *args).to_sympy() result = self.prepare_mathics(result) result = from_sympy(result) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] return result.evaluate_leaves(evaluation) elif mpmath_function is None: return if not all(isinstance(arg, Number) for arg in args): return if any(arg.is_machine_precision() for arg in args): # if any argument has machine precision then the entire calculation # is done with machine precision. float_args = [arg.round().get_float_value(permit_complex=True) for arg in args] if None in float_args: return result = self.call_mpmath(mpmath_function, float_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): if mpmath.isinf(result) and isinstance(result, mpmath.mpc): result = Symbol('ComplexInfinity') elif mpmath.isinf(result) and result > 0: result = Expression('DirectedInfinity', Integer(1)) elif mpmath.isinf(result) and result < 0: result = Expression('DirectedInfinity', Integer(-1)) elif mpmath.isnan(result): result = Symbol('Indeterminate') else: result = Number.from_mpmath(result) else: prec = min_prec(*args) d = dps(prec) args = [Expression('N', arg, Integer(d)).evaluate(evaluation) for arg in args] with mpmath.workprec(prec): mpmath_args = [x.to_mpmath() for x in args] if None in mpmath_args: return result = self.call_mpmath(mpmath_function, mpmath_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): result = Number.from_mpmath(result, d) return result
def multi_segment_score_pv(score, num_segments, raw=True): """ Compute p-value for normalized score when considering multiple high scoring segments. This functions considers the normalized score Sr', i.e., the normalized score of the HSP at rank r. For r=1, this formula is equivalent to single_segment_score_pv Computes formula [3] in Karlin & Altschul, PNAS 1993 Prob(Sr' >= x) ~ 1 - exp(-exp(-x)) * SUM (k=0 ... r - 1) { exp(-kx) / k! } Implementation detail: Python's range is not right-inclusive, go up to r, not r - 1 for summation :param score: :param num_segments: :param raw: return raw P-value instead of -log10(pv) :return: """ with mpm.workprec(NUM_PREC_KA_PV): def create_summand(sum_x, k): prec_k = mpm.convert(k) enum = mpm.exp(mpm.fneg(mpm.fmul(prec_k, sum_x))) denom = mpm.factorial(prec_k) summand = mpm.fdiv(enum, denom) return summand x = mpm.convert(score) r = num_segments complement = mpm.convert('1') factor1 = mpm.exp(mpm.fneg(mpm.exp(mpm.fneg(x)))) factor2 = mpm.fsum(map(lambda k: create_summand(x, k), range(0, r))) res = mpm.fsub(complement, mpm.fmul(factor1, factor2)) if not raw: res = mpm.fneg(mpm.log10(res)) res = float(res) # Equivalent implementation using Python standard library: # # x = score # r = num_segments # factor_1 = math.exp(-math.exp(-x)) # factor_2 = math.fsum(map(lambda k: math.exp(-k * x) / math.factorial(k), range(0, r))) # res = 1 - factor_1 * factor_2 # if not raw: # res = -1 * math.log10(res) return res
def computeNaiveMSB(self, u_bar, output_info=None): """Compute the MSB of t, x and y without taking into account the errors in the filter evaluation, and the errors in the computation of this MSB (the WCPG computation and the log2 associated) Returns a vector of MSB""" # compute the WCPG of Hzeta zeta_bar = self.Hzeta.WCPG(output_info) * u_bar with workprec( 500 ): # TODO: use right precision !! Or do it as it should be done, as in FxPF (see Nastia thesis p113) # and then the log2 msb = [int(ceil(log(x[0], 2))) for x in zeta_bar.tolist()] return msb
def apply_inexact(self, z, evaluation): '%(name)s[z_Real|z_Complex?InexactNumberQ]' with workprec(z.get_precision()): z = gmpy2mpmath(z.value) try: result = self.eval(z) except ValueError, exc: text = str(exc) if text == 'gamma function pole': return Symbol('ComplexInfinity') else: raise except ZeroDivisionError: return
def w_tilde(self, u_bar): """compute w_tilde, the threshold for the word-length w such that MSB = computeNaiveMSB if w >= w_tilde MSB = computeNaiveMSB+1 if w < w_tilde (this doesn't count into account the roundoff error, as in FxPF""" zeta_bar = self.Hzeta.WCPG() * u_bar with workprec(500): # TODO: compute how many bit we need !! wtilde = [ int(1 + ceil(log(x[0], 2)) - floor(log(power(2, ceil(log(x[0], 2))) - x[0], 2))) for x in zeta_bar.tolist() ] return wtilde
def apply_N(self, k, precision, evaluation): 'N[AiryBiZero[k_Integer], precision_]' try: d = get_precision(precision, evaluation) except PrecisionValueError: return if d is None: p = machine_precision else: p = _prec(d) k_int = k.get_int_value() with mpmath.workprec(p): result = mpmath.airybizero(k_int) return Number.from_mpmath(result, d)
def apply_N(self, k, precision, evaluation): "N[AiryBiZero[k_Integer], precision_]" try: d = get_precision(precision, evaluation) except PrecisionValueError: return if d is None: p = machine_precision else: p = _prec(d) k_int = k.get_int_value() with mpmath.workprec(p): result = mpmath.airybizero(k_int) return from_mpmath(result, d)
def apply_inexact(self, z, evaluation): '%(name)s[z_Real|z_Complex?InexactNumberQ]' prec = z.get_precision() with mpmath.workprec(prec): z = sympy2mpmath(z.to_sympy()) if z is None: return try: result = self.eval(z) result = mpmath2sympy(result, prec) except ValueError, exc: text = str(exc) if text == 'gamma function pole': return Symbol('ComplexInfinity') else: raise except ZeroDivisionError: return
def find_limit_reverse( func, limit, xstart=None, xstop=None, nulp=0, prec=None, ): fmt = ieee_format(prec) if xstart is None: xstart = fmt.min_value() if xstop is None: xstop = one def xstep(x): return x * two if nulp: def compare(fx, lx): return abs(fx - lx) > fmt.ulp(fx) else: compare = ne with workprec(prec or mp.prec): n_min, x_n = find_fp( func, limit, xstart, xstop, xstep, compare, max_steps=abs(fmt.min_exp()), ) n_min = abs(fmt.min_exp()) - n_min + 1 steps, limit = bisect_limit(func, limit, x_n / two, x_n, nulp, prec) return limit, n_min, steps
def test_main(): with mpmath.workprec(100): generate_cases()
def apply(self, items, evaluation): 'Times[items___]' items = items.numerify(evaluation).get_sequence() leaves = [] numbers = [] prec = min_prec(*items) is_machine_precision = any(item.is_machine_precision() for item in items) # find numbers and simplify Times -> Power for item in items: if isinstance(item, Number): numbers.append(item) elif leaves and item == leaves[-1]: leaves[-1] = Expression('Power', leaves[-1], Integer(2)) elif (leaves and item.has_form('Power', 2) and leaves[-1].has_form('Power', 2) and item.leaves[0].same(leaves[-1].leaves[0])): leaves[-1].leaves[1] = Expression( 'Plus', item.leaves[1], leaves[-1].leaves[1]) elif (leaves and item.has_form('Power', 2) and item.leaves[0].same(leaves[-1])): leaves[-1] = Expression( 'Power', leaves[-1], Expression('Plus', item.leaves[1], Integer(1))) elif (leaves and leaves[-1].has_form('Power', 2) and leaves[-1].leaves[0].same(item)): leaves[-1] = Expression('Power', item, Expression( 'Plus', Integer(1), leaves[-1].leaves[1])) else: leaves.append(item) if numbers: if prec is not None: if is_machine_precision: numbers = [item.to_mpmath() for item in numbers] number = mpmath.fprod(numbers) number = Number.from_mpmath(number) else: with mpmath.workprec(prec): numbers = [item.to_mpmath() for item in numbers] number = mpmath.fprod(numbers) number = Number.from_mpmath(number, dps(prec)) else: number = sympy.Mul(*[item.to_sympy() for item in numbers]) number = from_sympy(number) else: number = Integer(1) if number.same(Integer(1)): number = None elif number.is_zero: return number elif number.same(Integer(-1)) and leaves and leaves[0].has_form('Plus', None): leaves[0].leaves = [Expression('Times', Integer(-1), leaf) for leaf in leaves[0].leaves] number = None for leaf in leaves: leaf.last_evaluated = None if number is not None: leaves.insert(0, number) if not leaves: return Integer(1) elif len(leaves) == 1: return leaves[0] else: return Expression('Times', *leaves)
def apply(self, items, evaluation): 'Plus[items___]' items = items.numerify(evaluation).get_sequence() leaves = [] last_item = last_count = None prec = min_prec(*items) is_machine_precision = any(item.is_machine_precision() for item in items) numbers = [] def append_last(): if last_item is not None: if last_count == 1: leaves.append(last_item) else: if last_item.has_form('Times', None): last_item.leaves.insert(0, from_sympy(last_count)) leaves.append(last_item) else: leaves.append(Expression( 'Times', from_sympy(last_count), last_item)) for item in items: if isinstance(item, Number): numbers.append(item) else: count = rest = None if item.has_form('Times', None): for leaf in item.leaves: if isinstance(leaf, Number): count = leaf.to_sympy() rest = item.leaves[:] rest.remove(leaf) if len(rest) == 1: rest = rest[0] else: rest.sort() rest = Expression('Times', *rest) break if count is None: count = sympy.Integer(1) rest = item if last_item is not None and last_item == rest: last_count = last_count + count else: append_last() last_item = rest last_count = count append_last() if numbers: if prec is not None: if is_machine_precision: numbers = [item.to_mpmath() for item in numbers] number = mpmath.fsum(numbers) number = Number.from_mpmath(number) else: with mpmath.workprec(prec): numbers = [item.to_mpmath() for item in numbers] number = mpmath.fsum(numbers) number = Number.from_mpmath(number, dps(prec)) else: number = from_sympy(sum(item.to_sympy() for item in numbers)) else: number = Integer(0) if not number.same(Integer(0)): leaves.insert(0, number) if not leaves: return Integer(0) elif len(leaves) == 1: return leaves[0] else: leaves.sort() return Expression('Plus', *leaves)
def test_testfile_mpmath(self): # Run the mpmath module on the same material: consistency check during development. with mpmath.workprec(100) : self.test_testfile(mpmath, 1, 1)
def apply(self, items, evaluation): "Power[items__]" items_sequence = items.get_sequence() if len(items_sequence) == 2: x, y = items_sequence else: return Expression("Power", *items_sequence) if y.get_int_value() == 1: return x elif x.get_int_value() == 1: return x elif y.get_int_value() == 0: if x.get_int_value() == 0: evaluation.message("Power", "indet", Expression("Power", x, y)) return Symbol("Indeterminate") else: return Integer(1) elif x.has_form("Power", 2) and isinstance(y, Integer): return Expression("Power", x.leaves[0], Expression("Times", x.leaves[1], y)) elif x.has_form("Times", None) and isinstance(y, Integer): return Expression("Times", *[Expression("Power", leaf, y) for leaf in x.leaves]) elif isinstance(x, Number) and isinstance(y, Number) and not (x.is_inexact() or y.is_inexact()): sym_x, sym_y = x.to_sympy(), y.to_sympy() try: if sym_y >= 0: result = sym_x ** sym_y else: if sym_x == 0: evaluation.message("Power", "infy") return Symbol("ComplexInfinity") result = sympy.Integer(1) / (sym_x ** (-sym_y)) if isinstance(result, sympy.Pow): result = result.simplify() args = [from_sympy(expr) for expr in result.as_base_exp()] result = Expression("Power", *args) result = result.evaluate_leaves(evaluation) return result return from_sympy(result) except ValueError: return Expression("Power", x, y) except ZeroDivisionError: evaluation.message("Power", "infy") return Symbol("ComplexInfinity") elif isinstance(x, Number) and isinstance(y, Number) and (x.is_inexact() or y.is_inexact()): try: prec = min(max(x.get_precision(), 64), max(y.get_precision(), 64)) with mpmath.workprec(prec): mp_x = sympy2mpmath(x.to_sympy()) mp_y = sympy2mpmath(y.to_sympy()) result = mp_x ** mp_y if isinstance(result, mpmath.mpf): return Real(str(result), prec) elif isinstance(result, mpmath.mpc): return Complex(str(result.real), str(result.imag), prec) except ZeroDivisionError: evaluation.message("Power", "infy") return Symbol("ComplexInfinity") else: numerified_items = items.numerify(evaluation) return Expression("Power", *numerified_items.get_sequence())
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] if xlow == xhigh: xlow = xhigh = 0 elif x not in func.free_symbols: # only the difference in limits matters in this case # so if there is a symbol in common that will cancel # out when taking the difference, then use that # difference if xhigh.free_symbols & xlow.free_symbols: diff = xhigh - xlow if not diff.free_symbols: xlow, xhigh = 0, diff oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2*prec) with workprec(prec + 5): xlow = as_mpmath(xlow, prec + 15, options) xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing from sympy import cos, sin, Wild have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get('quad') == 'osc': A = Wild('A', exclude=[x]) B = Wild('B', exclude=[x]) D = Wild('D') m = func.match(cos(A*x + B)*D) if not m: m = func.match(sin(A*x + B)*D) if not m: raise ValueError("An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature") period = as_mpmath(2*S.Pi/m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) options['maxprec'] = oldmaxprec if have_part[0]: re = result.real._mpf_ if re == fzero: re, re_acc = scaled_zero( min(-prec, -max_real_term[0], -quadrature_error)) re = scaled_zero(re) # handled ok in evalf_integral else: re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im, im_acc = scaled_zero( min(-prec, -max_imag_term[0], -quadrature_error)) im = scaled_zero(im) # handled ok in evalf_integral else: im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result
def _eval_evalf(self, prec): """Evaluate this complex root to the given precision. """ with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') func = lambdify(d, self.expr.subs(g, d)) else: func = lambdify(g, self.expr) interval = self._get_interval() if not self.is_real: # For complex intervals, we need to keep refining until the # imaginary interval is disjunct with other roots, that is, # until both ends get refined. ay = interval.ay by = interval.by while interval.ay == ay or interval.by == by: interval = interval.refine() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: # the sign of the imaginary part will be assigned # according to the desired index using the fact that # roots are sorted with negative imag parts coming # before positive (and all imag roots coming after real # roots) deg = self.poly.degree() i = self.index # a positive attribute after creation if (deg - i) % 2: if ay < 0: ay = -ay else: if ay > 0: ay = -ay root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) try: root = findroot(func, x0) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real: if (a <= root <= b): break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() return (Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec))
def eval_approx(self, n): """Evaluate this complex root to the given precision. This uses secant method and root bounds are used to both generate an initial guess and to check that the root returned is valid. If ever the method converges outside the root bounds, the bounds will be made smaller and updated. """ prec = dps_to_prec(n) with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') if self.is_imaginary: d *= I func = lambdify(d, self.expr.subs(g, d)) else: expr = self.expr if self.is_imaginary: expr = self.expr.subs(g, I*g) func = lambdify(g, expr) interval = self._get_interval() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) x1 = x0 + mpf(str(interval.dx))/4 elif self.is_imaginary: a = mpf(str(interval.ay)) b = mpf(str(interval.by)) if a == b: root = mpc(mpf('0'), a) break x0 = mpf(str(interval.center[1])) x1 = x0 + mpf(str(interval.dy))/4 else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) x1 = x0 + mpc(*map(str, (interval.dx, interval.dy)))/4 try: # without a tolerance, this will return when (to within # the given precision) x_i == x_{i-1} root = findroot(func, (x0, x1)) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real or self.is_imaginary: if not bool(root.imag) == self.is_real and ( a <= root <= b): if self.is_imaginary: root = mpc(mpf('0'), root.real) break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() # update the interval so we at least (for this precision or # less) don't have much work to do to recompute the root self._set_interval(interval) return (Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec))
def _eval_evalf(self, prec): a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, z, mp.inf) return Expr._from_mpmath(res, prec)
def hypsum(expr, n, start, prec): """ Sum a rapidly convergent infinite hypergeometric series with given general term, e.g. e = hypsum(1/factorial(n), n). The quotient between successive terms must be a quotient of integer polynomials. """ from sympy import Float, hypersimp, lambdify if prec == float('inf'): raise NotImplementedError('does not support inf prec') if start: expr = expr.subs(n, n + start) hs = hypersimp(expr, n) if hs is None: raise NotImplementedError("a hypergeometric series is required") num, den = hs.as_numer_denom() func1 = lambdify(n, num) func2 = lambdify(n, den) h, g, p = check_convergence(num, den, n) if h < 0: raise ValueError("Sum diverges like (n!)^%i" % (-h)) term = expr.subs(n, 0) if not term.is_Rational: raise NotImplementedError("Non rational term functionality is not implemented.") # Direct summation if geometric or faster if h > 0 or (h == 0 and abs(g) > 1): term = (MPZ(term.p) << prec) // term.q s = term k = 1 while abs(term) > 5: term *= MPZ(func1(k - 1)) term //= MPZ(func2(k - 1)) s += term k += 1 return from_man_exp(s, -prec) else: alt = g < 0 if abs(g) < 1: raise ValueError("Sum diverges like (%i)^n" % abs(1/g)) if p < 1 or (p == 1 and not alt): raise ValueError("Sum diverges like n^%i" % (-p)) # We have polynomial convergence: use Richardson extrapolation vold = None ndig = prec_to_dps(prec) while True: # Need to use at least quad precision because a lot of cancellation # might occur in the extrapolation process; we check the answer to # make sure that the desired precision has been reached, too. prec2 = 4*prec term0 = (MPZ(term.p) << prec2) // term.q def summand(k, _term=[term0]): if k: k = int(k) _term[0] *= MPZ(func1(k - 1)) _term[0] //= MPZ(func2(k - 1)) return make_mpf(from_man_exp(_term[0], -prec2)) with workprec(prec): v = nsum(summand, [0, mpmath_inf], method='richardson') vf = Float(v, ndig) if vold is not None and vold == vf: break prec += prec # double precision each time vold = vf return v._mpf_