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 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 fold(self, x, l): # computes fold(x, l) with the internal _fold function. will start # its evaluation machine precision, and will escalate to arbitrary # precision if or symbolical evaluation only if necessary. folded # items already computed are carried over to new evaluation modes. yield x # initial state init = None operands = list(self._operands(x, l)) spans = self._spans(operands) for mode in (self.FLOAT, self.MPMATH, self.SYMBOLIC): s_operands = [y[1:] for y in operands[spans[mode]]] if not s_operands: continue if mode == self.MPMATH: from mathics.core.numbers import min_prec precision = min_prec(*[t for t in chain(*s_operands) if t is not None]) working_precision = mpmath.workprec else: @contextmanager def working_precision(_): yield precision = None if mode == self.FLOAT: def out(z): return Real(z) elif mode == self.MPMATH: def out(z): return Real(z, precision) else: def out(z): return z as_operand = self.operands.get(mode) def converted_operands(): for y in s_operands: yield tuple(as_operand(t) for t in y) with working_precision(precision): c_operands = converted_operands() if init is not None: c_init = tuple((None if t is None else as_operand(from_python(t))) for t in init) else: c_init = next(c_operands) init = tuple((None if t is None else out(t)) for t in c_init) generator = self._fold( c_init, c_operands, self.math.get(mode)) for y in generator: y = tuple(out(t) for t in y) yield y init = y
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 apply(self, items, evaluation): 'Times[items___]' #TODO: Clean this up and optimise it items = items.numerify(evaluation).get_sequence() number = (sympy.Integer(1), sympy.Integer(0)) leaves = [] prec = min_prec(*items) is_real = all([not isinstance(i, Complex) for i in items]) for item in items: if isinstance(item, Number): if isinstance(item, Complex): sym_real, sym_imag = item.real.to_sympy(), item.imag.to_sympy() else: sym_real, sym_imag = item.to_sympy(), sympy.Integer(0) if prec is not None: sym_real = sym_real.n(dps(prec)) sym_imag = sym_imag.n(dps(prec)) if sym_real.is_zero and sym_imag.is_zero and prec is None: return Integer('0') number = (number[0]*sym_real - number[1]*sym_imag, number[0]*sym_imag + number[1]*sym_real) 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 number == (1, 0): number = None elif number == (-1, 0) 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 if number is not None: if number[1].is_zero and is_real: leaves.insert(0, Number.from_mp(number[0], prec)) elif number[1].is_zero and number[1].is_Integer and prec is None: leaves.insert(0, Number.from_mp(number[0], prec)) else: leaves.insert(0, Complex(from_sympy(number[0]), from_sympy(number[1]), prec)) if not leaves: return Integer(1) elif len(leaves) == 1: return leaves[0] else: return Expression('Times', *leaves)
def apply_inexact(self, n, k, evaluation): 'Binomial[n_?InexactNumberQ, k_?NumberQ]' prec = min_prec(n, k) n = n.to_sympy() k = k.to_sympy() result = sympy.binomial(n, k).n(dps(prec)) if result == sympy.Float('inf'): return Symbol('ComplexInfinity') return Real(result, prec)
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 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 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 sympy.re(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_prec(x, y) 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 apply(self, items, evaluation): 'Times[items___]' # TODO: Clean this up and optimise it items = items.numerify(evaluation).get_sequence() number = (sympy.Integer(1), sympy.Integer(0)) leaves = [] prec = min_prec(*items) is_real = all([not isinstance(i, Complex) for i in items]) for item in items: if isinstance(item, Number): if isinstance(item, Complex): sym_real, sym_imag = item.real.to_sympy( ), item.imag.to_sympy() else: sym_real, sym_imag = item.to_sympy(), sympy.Integer(0) if prec is not None: sym_real = sym_real.n(dps(prec)) sym_imag = sym_imag.n(dps(prec)) if sym_real.is_zero and sym_imag.is_zero and prec is None: return Integer('0') number = (number[0] * sym_real - number[1] * sym_imag, number[0] * sym_imag + number[1] * sym_real) 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 number == (1, 0): number = None elif number == (-1, 0) 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 if number is not None: if number[1].is_zero and is_real: leaves.insert(0, Number.from_mp(number[0], prec)) elif number[1].is_zero and number[1].is_Integer and prec is None: leaves.insert(0, Number.from_mp(number[0], prec)) else: leaves.insert( 0, Complex(from_sympy(number[0]), from_sympy(number[1]), prec)) 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_real = all([not isinstance(i, Complex) for i in items]) if prec is None: number = (sympy.Integer(0), sympy.Integer(0)) else: number = (sympy.Float('0.0', dps(prec)), sympy.Float('0.0', dps(prec))) 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, Number.from_mp(last_count)) leaves.append(last_item) else: leaves.append( Expression('Times', Number.from_mp(last_count), last_item)) for item in items: if isinstance(item, Number): # TODO: Optimise this for the case of adding many real numbers if isinstance(item, Complex): sym_real, sym_imag = item.real.to_sympy( ), item.imag.to_sympy() else: sym_real, sym_imag = item.to_sympy(), sympy.Integer(0) if prec is not None: sym_real = sym_real.n(dps(prec)) sym_imag = sym_imag.n(dps(prec)) number = (number[0] + sym_real, number[1] + sym_imag) 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 = add(last_count, count) else: append_last() last_item = rest last_count = count append_last() if prec is not None or number != (0, 0): if number[1].is_zero and is_real: leaves.insert(0, Number.from_mp(number[0], prec)) elif number[1].is_zero and number[1].is_Integer and prec is None: leaves.insert(0, Number.from_mp(number[0], prec)) else: leaves.insert(0, Complex(number[0], number[1], prec)) if not leaves: return Integer(0) elif len(leaves) == 1: return leaves[0] else: leaves.sort() return Expression('Plus', *leaves)
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 fold(self, x, l): # computes fold(x, l) with the internal _fold function. will start # its evaluation machine precision, and will escalate to arbitrary # precision if or symbolical evaluation only if necessary. folded # items already computed are carried over to new evaluation modes. yield x # initial state init = None operands = list(self._operands(x, l)) spans = self._spans(operands) for mode in (self.FLOAT, self.MPMATH, self.SYMBOLIC): s_operands = [y[1:] for y in operands[spans[mode]]] if not s_operands: continue if mode == self.MPMATH: from mathics.core.numbers import min_prec precision = min_prec( *[t for t in chain(*s_operands) if t is not None]) working_precision = mpmath.workprec else: @contextmanager def working_precision(_): yield precision = None if mode == self.FLOAT: def out(z): return Real(z) elif mode == self.MPMATH: def out(z): return Real(z, precision) else: def out(z): return z as_operand = self.operands.get(mode) def converted_operands(): for y in s_operands: yield tuple(as_operand(t) for t in y) with working_precision(precision): c_operands = converted_operands() if init is not None: c_init = tuple( (None if t is None else as_operand(from_python(t))) for t in init) else: c_init = next(c_operands) init = tuple( (None if t is None else out(t)) for t in c_init) generator = self._fold(c_init, c_operands, self.math.get(mode)) for y in generator: y = tuple(out(t) for t in y) yield y init = y
def apply(self, items, evaluation): "Plus[items___]" items = items.numerify(evaluation).get_sequence() leaves = [] last_item = last_count = None prec = min_prec(*items) is_real = all([not isinstance(i, Complex) for i in items]) if prec is None: number = (sympy.Integer(0), sympy.Integer(0)) else: number = (sympy.Float("0.0", dps(prec)), sympy.Float("0.0", dps(prec))) 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, Number.from_mp(last_count)) leaves.append(last_item) else: leaves.append(Expression("Times", Number.from_mp(last_count), last_item)) for item in items: if isinstance(item, Number): # TODO: Optimise this for the case of adding many real numbers if isinstance(item, Complex): sym_real, sym_imag = item.real.to_sympy(), item.imag.to_sympy() else: sym_real, sym_imag = item.to_sympy(), sympy.Integer(0) if prec is not None: sym_real = sym_real.n(dps(prec)) sym_imag = sym_imag.n(dps(prec)) number = (number[0] + sym_real, number[1] + sym_imag) 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 = add(last_count, count) else: append_last() last_item = rest last_count = count append_last() if prec is not None or number != (0, 0): if number[1].is_zero and is_real: leaves.insert(0, Number.from_mp(number[0], prec)) elif number[1].is_zero and number[1].is_Integer and prec is None: leaves.insert(0, Number.from_mp(number[0], prec)) else: leaves.insert(0, Complex(number[0], number[1], prec)) if not leaves: return Integer(0) elif len(leaves) == 1: return leaves[0] else: leaves.sort() return Expression("Plus", *leaves)
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 sympy.re(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_prec(x, y) with mpmath.workprec(prec): mp_x = sympy2mpmath(x.to_sympy(), prec) mp_y = sympy2mpmath(y.to_sympy(), prec) 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 apply(self, items, evaluation): "Times[items___]" items = items.numerify(evaluation).get_sequence() leaves = [] numbers = [] infinity_factor = False 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].sameQ(leaves[-1].leaves[0])): leaves[-1] = Expression( "Power", leaves[-1].leaves[0], Expression("Plus", item.leaves[1], leaves[-1].leaves[1]), ) elif (leaves and item.has_form("Power", 2) and item.leaves[0].sameQ(leaves[-1])): leaves[-1] = Expression( "Power", leaves[-1], Expression("Plus", item.leaves[1], Integer1)) elif (leaves and leaves[-1].has_form("Power", 2) and leaves[-1].leaves[0].sameQ(item)): leaves[-1] = Expression( "Power", item, Expression("Plus", Integer1, leaves[-1].leaves[1])) elif item.get_head().sameQ(SymbolDirectedInfinity): infinity_factor = True if len(item.leaves) > 1: direction = item.leaves[0] if isinstance(direction, Number): numbers.append(direction) else: leaves.append(direction) elif item.sameQ(SymbolInfinity) or item.sameQ( SymbolComplexInfinity): infinity_factor = True 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 = from_mpmath(number) else: with mpmath.workprec(prec): numbers = [item.to_mpmath() for item in numbers] number = mpmath.fprod(numbers) number = from_mpmath(number, dps(prec)) else: number = sympy.Mul(*[item.to_sympy() for item in numbers]) number = from_sympy(number) else: number = Integer1 if number.sameQ(Integer1): number = None elif number.is_zero: if infinity_factor: return Symbol("Indeterminate") return number elif number.sameQ(Integer(-1)) and leaves and leaves[0].has_form( "Plus", None): leaves[0] = Expression( leaves[0].get_head(), *[ Expression("Times", Integer(-1), leaf) for leaf in leaves[0].leaves ], ) number = None for leaf in leaves: leaf.clear_cache() if number is not None: leaves.insert(0, number) if not leaves: if infinity_factor: return SymbolComplexInfinity return Integer1 if len(leaves) == 1: ret = leaves[0] else: ret = Expression("Times", *leaves) if infinity_factor: return Expression(SymbolDirectedInfinity, ret) else: return ret