def as_real_imag(self, deep=True, **hints): from sympy.core.symbol import symbols from sympy.polys.polytools import poly from sympy.core.function import expand_multinomial if self.exp.is_Integer: exp = self.exp re, im = self.base.as_real_imag(deep=deep) if re.func == C.re or im.func == C.im: return self, S.Zero a, b = symbols('a b', cls=Dummy) if exp >= 0: if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial(self.base**exp) return expr.as_real_imag() expr = poly((a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re**2 + im**2 re, im = re/mag, -im/mag if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial((re + im*S.ImaginaryUnit)**-exp) return expr.as_real_imag() expr = poly((a + b)**-exp) # Terms with even b powers will be real r = [i for i in expr.terms() if not i[0][1] % 2] re_part = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) # Terms with odd b powers will be imaginary r = [i for i in expr.terms() if i[0][1] % 4 == 1] im_part1 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) r = [i for i in expr.terms() if i[0][1] % 4 == 3] im_part3 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) return (re_part.subs({a: re, b: S.ImaginaryUnit*im}), im_part1.subs({a: re, b: im}) + im_part3.subs({a: re, b: -im})) elif self.exp.is_Rational: # NOTE: This is not totally correct since for x**(p/q) with # x being imaginary there are actually q roots, but # only a single one is returned from here. re, im = self.base.as_real_imag(deep=deep) if re.func == C.re or im.func == C.im: return self, S.Zero r = Pow(Pow(re, 2) + Pow(im, 2), S.Half) t = C.atan2(im, re) rp, tp = Pow(r, self.exp), t*self.exp return (rp*C.cos(tp), rp*C.sin(tp)) else: if deep: hints['complex'] = False return (C.re(self.expand(deep, **hints)), C.im(self.expand(deep, **hints))) else: return (C.re(self), C.im(self))
def as_real_imag(self, deep=True, **hints): from sympy.core.symbol import symbols from sympy.polys.polytools import poly from sympy.core.function import expand_multinomial if self.exp.is_Integer: exp = self.exp re, im = self.base.as_real_imag(deep=deep) a, b = symbols('a b', cls=Dummy) if exp >= 0: if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial(self.base**exp) return expr.as_real_imag() expr = poly((a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re**2 + im**2 re, im = re/mag, -im/mag if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial((re + im*S.ImaginaryUnit)**-exp) return expr.as_real_imag() expr = poly((a + b)**-exp) # Terms with even b powers will be real r = [i for i in expr.terms() if not i[0][1] % 2] re_part = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) # Terms with odd b powers will be imaginary r = [i for i in expr.terms() if i[0][1] % 4 == 1] im_part1 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) r = [i for i in expr.terms() if i[0][1] % 4 == 3] im_part3 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) return (re_part.subs({a: re, b: S.ImaginaryUnit*im}), im_part1.subs({a: re, b: im}) + im_part3.subs({a: re, b: -im})) elif self.exp.is_Rational: # NOTE: This is not totally correct since for x**(p/q) with # x being imaginary there are actually q roots, but # only a single one is returned from here. re, im = self.base.as_real_imag(deep=deep) r = Pow(Pow(re, 2) + Pow(im, 2), S.Half) t = C.atan2(im, re) rp, tp = Pow(r, self.exp), t*self.exp return (rp*C.cos(tp), rp*C.sin(tp)) else: if deep: hints['complex'] = False return (C.re(self.expand(deep, complex=False)), C.im(self. expand(deep, **hints))) else: return (C.re(self), C.im(self))
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get("maxprec", DEFAULT_MAXPREC) options["maxprec"] = min(oldmaxprec, 2 * prec) try: mp.prec = 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 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 = C.Wild("A", exclude=[x]) B = C.Wild("B", exclude=[x]) D = C.Wild("D") m = func.match(C.cos(A * x + B) * D) if not m: m = func.match(C.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_) finally: options["maxprec"] = oldmaxprec mp.prec = orig 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 do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2 * prec) try: mp.prec = 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 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 = C.Wild('A', exclude=[x]) B = C.Wild('B', exclude=[x]) D = C.Wild('D') m = func.match(C.cos(A * x + B) * D) if not m: m = func.match(C.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_) finally: options['maxprec'] = oldmaxprec mp.prec = orig if have_part[0]: re = result.real._mpf_ if re == fzero: re = mpf_shift(fone, min(-prec, -max_real_term[0], -quadrature_error)) re_acc = -1 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 = mpf_shift(fone, min(-prec, -max_imag_term[0], -quadrature_error)) im_acc = -1 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