def _print_Mul(self, expr): prec = precedence(expr) try: numerator, denom_sq, post_factor = derationalize_denom(expr) if post_factor == S.One: return "%s/√%s" % (numerator, denom_sq) else: if numerator == 1: return "%s / √%s" % ( self.parenthesize(post_factor, prec), denom_sq, ) else: return "(%s/√%s) %s" % ( numerator, denom_sq, self.parenthesize(post_factor, prec), ) except ValueError: pass # Continue below c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if (item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative): if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [str(self.parenthesize(x, prec)) for x in a] b_str = [str(self.parenthesize(x, prec)) for x in b] if len(b) == 0: return sign + ' '.join(a_str) elif len(b) == 1: return sign + ' '.join(a_str) + "/" + b_str[0] else: return sign + ' '.join(a_str) + "/(%s)" % ' '.join(b_str)
def is_log_deriv_k_t_radical(fa, fd, DE, Df=True): """ Checks if Df is the logarithmic derivative of a k(t)-radical. b in k(t) can be written as the logarithmic derivative of a k(t) radical if there exist n in ZZ and u in k(t) with n, u != 0 such that n*b == Du/u. Either returns (ans, u, n, const) or None, which means that Df cannot be written as the logarithmic derivative of a k(t)-radical. ans is a list of tuples such that Mul(*[i**j for i, j in ans]) == u. This is useful for seeing exactly what elements of k(t) produce u. This function uses the structure theorem approach, which says that for any f in K, Df is the logarithmic derivative of a K-radical if and only if there are ri in QQ such that:: --- --- Dt \ r * Dt + \ r * i / i i / i --- = Df. --- --- t i in L i in E i K/C(x) K/C(x) Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of hyperexponential monomials of K over C(x)). If K is an elementary extension over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the transcendence degree of K over C(x). Furthermore, because Const_D(K) == Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) and L_K/C(x) are disjoint. The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed recursively using this same function. Therefore, it is required to pass them as indices to D (or T). L_args are the arguments of the logarithms indexed by L_K (i.e., if i is in L_K, then T[i] == log(L_args[i])). This is needed to compute the final answer u such that n*f == Du/u. exp(f) will be the same as u up to a multiplicative constant. This is because they will both behave the same as monomials. For example, both exp(x) and exp(x + 1) == E*exp(x) satisfy Dt == t. Therefore, the term const is returned. const is such that exp(const)*f == u. This is calculated by subtracting the arguments of one exponential from the other. Therefore, it is necessary to pass the arguments of the exponential terms in E_args. To handle the case where we are given Df, not f, use is_log_deriv_k_t_radical_in_field(). """ H = [] if Df: dfa, dfd = (fd * derivation(fa, DE) - fa * derivation(fd, DE)).cancel( fd**2, include=True) else: dfa, dfd = fa, fd # Our assumption here is that each monomial is recursively transcendental if len(DE.L_K) + len(DE.E_K) != len(DE.D) - 1: if [i for i in DE.cases if i == 'tan'] or \ set([i for i in DE.cases if i == 'primitive']) - set(DE.L_K): raise NotImplementedError( "Real version of the structure " "theorems with hypertangent support is not yet implemented.") # TODO: What should really be done in this case? raise NotImplementedError("Nonelementary extensions not supported " "in the structure theorems.") E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.E_K] L_part = [DE.D[i].as_expr() for i in DE.L_K] lhs = Matrix([E_part + L_part]) rhs = Matrix([dfa.as_expr() / dfd.as_expr()]) A, u = constant_system(lhs, rhs, DE) if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: # If the elements of u are not all constant # Note: See comment in constant_system # Also note: derivation(basic=True) calls cancel() return None else: if not all(i.is_Rational for i in u): # TODO: But maybe we can tell if they're not rational, like # log(2)/log(3). Also, there should be an option to continue # anyway, even if the result might potentially be wrong. raise NotImplementedError("Cannot work with non-rational " "coefficients in this case.") else: n = reduce(ilcm, [i.as_numer_denom()[1] for i in u]) u *= n terms = [DE.T[i] for i in DE.E_K] + DE.L_args ans = list(zip(terms, u)) result = Mul(*[Pow(i, j) for i, j in ans]) # exp(f) will be the same as result up to a multiplicative # constant. We now find the log of that constant. argterms = DE.E_args + [DE.T[i] for i in DE.L_K] const = cancel(fa.as_expr() / fd.as_expr() - Add(*[Mul(i, j / n) for i, j in zip(argterms, u)])) return (ans, result, n, const)
def _print_Mul(self, expr): # print complex numbers nicely in Octave if (expr.is_number and expr.is_imaginary and (S.ImaginaryUnit * expr).is_Integer): return "%si" % self._print(-S.ImaginaryUnit * expr) # cribbed from str.py prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [ ] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if (item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative): if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance( item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec) for x in a] b_str = [self.parenthesize(x, prec) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] # from here it differs from str.py to deal with "*" and ".*" def multjoin(a, a_str): # here we probably are assuming the constants will come first r = a_str[0] for i in range(1, len(a)): mulsym = '*' if a[i - 1].is_number else '.*' r = r + mulsym + a_str[i] return r if not b: return sign + multjoin(a, a_str) elif len(b) == 1: divsym = '/' if b[0].is_number else './' return sign + multjoin(a, a_str) + divsym + b_str[0] else: divsym = '/' if all([bi.is_number for bi in b]) else './' return (sign + multjoin(a, a_str) + divsym + "(%s)" % multjoin(b, b_str))
def _parallel_dict_from_expr_no_gens(exprs, opt): """Transform expressions into a multinomial form and figure out generators. """ if opt.domain is not None: def _is_coeff(factor): return factor in opt.domain elif opt.extension is True: def _is_coeff(factor): return factor.is_algebraic elif opt.greedy is not False: def _is_coeff(factor): return False else: def _is_coeff(factor): return factor.is_number gens, reprs = set([]), [] for expr in exprs: terms = [] if expr.is_Equality: expr = expr.lhs - expr.rhs for term in Add.make_args(expr): coeff, elements = [], {} for factor in Mul.make_args(term): if not _not_a_coeff(factor) and (factor.is_Number or _is_coeff(factor)): coeff.append(factor) else: if opt.series is False: base, exp = decompose_power(factor) if exp < 0: exp, base = -exp, Pow(base, -S.One) else: base, exp = decompose_power_rat(factor) elements[base] = elements.setdefault(base, 0) + exp gens.add(base) terms.append((coeff, elements)) reprs.append(terms) gens = _sort_gens(gens, opt=opt) k, indices = len(gens), {} for i, g in enumerate(gens): indices[g] = i polys = [] for terms in reprs: poly = {} for coeff, term in terms: monom = [0] * k for base, exp in term.items(): monom[indices[base]] = exp monom = tuple(monom) if monom in poly: poly[monom] += Mul(*coeff) else: poly[monom] = Mul(*coeff) polys.append(poly) return polys, tuple(gens)
if A is None: return None n, u = A elif case == 'base': # TODO: we can use more efficient residue reduction from ratint() if not fd.is_sqf or fa.degree() >= fd.degree(): # f is the logarithmic derivative in the base case if and only if # f = fa/fd, fd is square-free, deg(fa) < deg(fd), and # gcd(fa, fd) == 1. The last condition is handled by cancel() above. return None # Note: if residueterms = [], returns (1, 1) # f had better be 0 in that case. n = reduce(ilcm, [i.as_numer_denom()[1] for _, i in residueterms], S(1)) u = Mul(*[Pow(i, j * n) for i, j in residueterms]) return (n, u) elif case == 'tan': raise NotImplementedError( "The hypertangent case is " "not yet implemented for is_log_deriv_k_t_radical_in_field()") elif case in ['other_linear', 'other_nonlinear']: # XXX: If these are supported by the structure theorems, change to NotImplementedError. raise ValueError("The %s case is not supported in this function." % case) else: raise ValueError("case must be one of {'primitive', 'exp', 'tan', " "'base', 'auto'}, not %s" % case)
def eval(cls, *_args): """.""" if not _args: return if not len(_args) == 1: raise ValueError('Expecting one argument') expr = _args[0] if isinstance(expr, Add): args = [cls.eval(a) for a in expr.args] return Add(*args) elif isinstance(expr, Mul): coeffs = [a for a in expr.args if isinstance(a, _coeffs_registery)] vectors = [a for a in expr.args if not(a in coeffs)] a = S.One if coeffs: a = Mul(*coeffs) b = S.One if vectors: try: if len(vectors) == 1: f = vectors[0] b = cls(f) elif len(vectors) == 2: f,g = vectors b = f*cls(g) + g*cls(f) else: left = vectors[0] right = Mul(*vectors[1:]) f_left = cls(left, evaluate=True) f_right = cls(right, evaluate=True) b = left * f_right + f_left * right except: b = cls(Mul(*vectors), evaluate=False) return Mul(a, b) elif isinstance(expr, Pow): # TODO: fix this for the case where e is not a number b = expr.base e = expr.exp return e*cls(b)*Pow(b, e-1) elif isinstance(expr, Dot): try: a,b = expr._args return Cross(a, Curl(b)) - Cross(Curl(a), b) + Convect(a,b) + Convect(b,a) except: return cls(expr, evaluate=False) elif isinstance(expr, _coeffs_registery): return S.Zero # ... check consistency between space type and the operator if _is_sympde_atom(expr): if not isinstance(expr.space.kind, (UndefinedSpaceType, H1SpaceType)): msg = '> Wrong space kind, given {}'.format(expr.space.kind) raise ArgumentTypeError(msg) # ... return cls(expr, evaluate=False)
def fraction(expr, exact=False): """Returns a pair with expression's numerator and denominator. If the given expression is not a fraction then this function will return the tuple (expr, 1). This function will not make any attempt to simplify nested fractions or to do any term rewriting at all. If only one of the numerator/denominator pair is needed then use numer(expr) or denom(expr) functions respectively. >>> from sympy import fraction, Rational, Symbol >>> from sympy.abc import x, y >>> fraction(x/y) (x, y) >>> fraction(x) (x, 1) >>> fraction(1/y**2) (1, y**2) >>> fraction(x*y/2) (x*y, 2) >>> fraction(Rational(1, 2)) (1, 2) This function will also work fine with assumptions: >>> k = Symbol('k', negative=True) >>> fraction(x * y**k) (x, y**(-k)) If we know nothing about sign of some exponent and 'exact' flag is unset, then structure this exponent's structure will be analyzed and pretty fraction will be returned: >>> from sympy import exp, Mul >>> fraction(2*x**(-y)) (2, x**y) >>> fraction(exp(-x)) (1, exp(x)) >>> fraction(exp(-x), exact=True) (exp(-x), 1) The `exact` flag will also keep any unevaluated Muls from being evaluated: >>> u = Mul(2, x + 1, evaluate=False) >>> fraction(u) (2*x + 2, 1) >>> fraction(u, exact=True) (2*(x + 1), 1) """ expr = sympify(expr) numer, denom = [], [] for term in Mul.make_args(expr): if term.is_commutative and (term.is_Pow or isinstance(term, exp)): b, ex = term.as_base_exp() if ex.is_negative: if ex is S.NegativeOne: denom.append(b) elif exact: if ex.is_constant(): denom.append(Pow(b, -ex)) else: numer.append(term) else: denom.append(Pow(b, -ex)) elif ex.is_positive: numer.append(term) elif not exact and ex.is_Mul: n, d = term.as_numer_denom() numer.append(n) denom.append(d) else: numer.append(term) elif term.is_Rational: n, d = term.as_numer_denom() numer.append(n) denom.append(d) else: numer.append(term) if exact: return Mul(*numer, evaluate=False), Mul(*denom, evaluate=False) else: return Mul(*numer), Mul(*denom)
def _print_Mul(self, expr): # print complex numbers nicely in Octave if (expr.is_number and expr.is_imaginary and expr.as_coeff_Mul()[0].is_integer): return "%si" % self._print(-S.ImaginaryUnit * expr) # cribbed from str.py prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if (item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative): if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = list(map(lambda x: self.parenthesize(x, prec), a)) b_str = list(map(lambda x: self.parenthesize(x, prec), b)) # from here it differs from str.py to deal with "*" and ".*" def multjoin(a, a_str): # here we probably are assuming the constants will come first r = a_str[0] for i in range(1, len(a)): mulsym = '*' if a[i - 1].is_number else '.*' r = r + mulsym + a_str[i] return r if len(b) == 0: return sign + multjoin(a, a_str) elif len(b) == 1: divsym = '/' if b[0].is_number else './' return sign + multjoin(a, a_str) + divsym + b_str[0] else: divsym = '/' if all([bi.is_number for bi in b]) else './' return (sign + multjoin(a, a_str) + divsym + "(%s)" % multjoin(b, b_str))
def _print_Mul(self, expr): prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [ ] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance( item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) else: a.append(item) a = a or [S.One] if len(a) == 1 and sign == "-": # Unary minus does not have a SymPy class, and hence there's no # precedence weight associated with it, Python's unary minus has # an operator precedence between multiplication and exponentiation, # so we use this to compute a weight. a_str = [ self.parenthesize( a[0], 0.5 * (PRECEDENCE["Pow"] + PRECEDENCE["Mul"])) ] else: a_str = [self.parenthesize(x, prec) for x in a] b_str = [self.parenthesize(x, prec) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
def test_issue_17450(): assert (erf(cosh(1)**7)**I).is_real is None assert (erf(cosh(1)**7)**I).is_imaginary is False assert (Pow(exp(1+sqrt(2)), ((1-sqrt(2))*I*pi), evaluate=False)).is_real is None assert ((-10)**(10*I*pi/3)).is_real is False assert ((-5)**(4*I*pi)).is_real is False
def _parallel_dict_from_expr_no_gens(exprs, opt): """Transform expressions into a multinomial form and figure out generators. """ if opt.domain is not None: def _is_coeff(factor): return factor in opt.domain elif opt.extension is True: def _is_coeff(factor): return ask(Q.algebraic(factor)) elif opt.greedy is not False: def _is_coeff(factor): return False else: def _is_coeff(factor): return factor.is_number gens, reprs = set([]), [] for expr in exprs: terms = [] for term in Add.make_args(expr): coeff, elements = [], {} for factor in Mul.make_args(term): if factor.is_Number or _is_coeff(factor): coeff.append(factor) else: base, exp = decompose_power(factor) if exp < 0: exp, base = -exp, Pow(base, -S.One) elements[base] = exp gens.add(base) terms.append((coeff, elements)) reprs.append(terms) if not gens: if len(exprs) == 1: arg = exprs[0] else: arg = (exprs, ) raise GeneratorsNeeded("specify generators to give %s a meaning" % arg) gens = _sort_gens(gens, opt=opt) k, indices = len(gens), {} for i, g in enumerate(gens): indices[g] = i polys = [] for terms in reprs: poly = {} for coeff, term in terms: monom = [0] * k for base, exp in term.iteritems(): monom[indices[base]] = exp monom = tuple(monom) if monom in poly: poly[monom] += Mul(*coeff) else: poly[monom] = Mul(*coeff) polys.append(poly) return polys, tuple(gens)
def test_AccumBounds_pow(): assert B(0, 2)**2 == B(0, 4) assert B(-1, 1)**2 == B(0, 1) assert B(1, 2)**2 == B(1, 4) assert B(-1, 2)**3 == B(-1, 8) assert B(-1, 1)**0 == 1 assert B(1, 2)**Rational(5, 2) == B(1, 4 * sqrt(2)) assert B(0, 2)**S.Half == B(0, sqrt(2)) neg = Symbol('neg', negative=True) assert unchanged(Pow, B(neg, 1), S.Half) nn = Symbol('nn', nonnegative=True) assert B(nn, nn + 1)**S.Half == B(sqrt(nn), sqrt(nn + 1)) assert B(nn, nn + 1)**nn == B(nn**nn, (nn + 1)**nn) assert unchanged(Pow, B(nn, nn + 1), x) i = Symbol('i', integer=True) assert B(1, 2)**i == B(Min(1, 2**i), Max(1, 2**i)) i = Symbol('i', integer=True, nonnegative=True) assert B(1, 2)**i == B(1, 2**i) assert B(0, 1)**i == B(0**i, 1) assert B(1, 5)**(-2) == B(Rational(1, 25), 1) assert B(-1, 3)**(-2) == B(0, oo) assert B(0, 2)**(-3) == B(Rational(1, 8), oo) assert B(-2, 0)**(-3) == B(-oo, -Rational(1, 8)) assert B(0, 2)**(-2) == B(Rational(1, 4), oo) assert B(-1, 2)**(-3) == B(-oo, oo) assert B(-3, -2)**(-3) == B(Rational(-1, 8), Rational(-1, 27)) assert B(-3, -2)**(-2) == B(Rational(1, 9), Rational(1, 4)) assert B(0, oo)**S.Half == B(0, oo) assert B(-oo, 0)**(-2) == B(0, oo) assert B(-2, 0)**(-2) == B(Rational(1, 4), oo) assert B(Rational(1, 3), S.Half)**oo is S.Zero assert B(0, S.Half)**oo is S.Zero assert B(S.Half, 1)**oo == B(0, oo) assert B(0, 1)**oo == B(0, oo) assert B(2, 3)**oo is oo assert B(1, 2)**oo == B(0, oo) assert B(S.Half, 3)**oo == B(0, oo) assert B(Rational(-1, 3), Rational(-1, 4))**oo is S.Zero assert B(-1, Rational(-1, 2))**oo is S.NaN assert B(-3, -2)**oo is zoo assert B(-2, -1)**oo is S.NaN assert B(-2, Rational(-1, 2))**oo is S.NaN assert B(Rational(-1, 2), S.Half)**oo is S.Zero assert B(Rational(-1, 2), 1)**oo == B(0, oo) assert B(Rational(-2, 3), 2)**oo == B(0, oo) assert B(-1, 1)**oo == B(-oo, oo) assert B(-1, S.Half)**oo == B(-oo, oo) assert B(-1, 2)**oo == B(-oo, oo) assert B(-2, S.Half)**oo == B(-oo, oo) assert B(1, 2)**x == Pow(B(1, 2), x, evaluate=False) assert B(2, 3)**(-oo) is S.Zero assert B(0, 2)**(-oo) == B(0, oo) assert B(-1, 2)**(-oo) == B(-oo, oo) assert (tan(x)**sin(2*x)).subs(x, B(0, pi/2)) == \ Pow(B(-oo, oo), B(0, 1))
def time_pow100(self): Pow(x, 100)
def time_pow2(self): Pow(x, 2)
def test_add(): with evaluate(False): p = oo - oo assert isinstance(p, Add) and p.args == (oo, -oo) p = 5 - oo assert isinstance(p, Add) and p.args == (-oo, 5) p = oo - 5 assert isinstance(p, Add) and p.args == (oo, -5) p = oo + 5 assert isinstance(p, Add) and p.args == (oo, 5) p = 5 + oo assert isinstance(p, Add) and p.args == (oo, 5) p = -oo + 5 assert isinstance(p, Add) and p.args == (-oo, 5) p = -5 - oo assert isinstance(p, Add) and p.args == (-oo, -5) with evaluate(False): expr = x + x assert isinstance(expr, Add) assert expr.args == (x, x) with evaluate(True): assert (x + x).args == (2, x) assert (x + x).args == (x, x) assert isinstance(x + x, Mul) with evaluate(False): assert S.One + 1 == Add(1, 1) assert 1 + S.One == Add(1, 1) assert S(4) - 3 == Add(4, -3) assert -3 + S(4) == Add(4, -3) assert S(2) * 4 == Mul(2, 4) assert 4 * S(2) == Mul(2, 4) assert S(6) / 3 == Mul(6, S.One / 3) assert S.One / 3 * 6 == Mul(S.One / 3, 6) assert 9**S(2) == Pow(9, 2) assert S(2)**9 == Pow(2, 9) assert S(2) / 2 == Mul(2, S.One / 2) assert S.One / 2 * 2 == Mul(S.One / 2, 2) assert S(2) / 3 + 1 == Add(S(2) / 3, 1) assert 1 + S(2) / 3 == Add(1, S(2) / 3) assert S(4) / 7 - 3 == Add(S(4) / 7, -3) assert -3 + S(4) / 7 == Add(-3, S(4) / 7) assert S(2) / 4 * 4 == Mul(S(2) / 4, 4) assert 4 * (S(2) / 4) == Mul(4, S(2) / 4) assert S(6) / 3 == Mul(6, S.One / 3) assert S.One / 3 * 6 == Mul(S.One / 3, 6) assert S.One / 3 + sqrt(3) == Add(S.One / 3, sqrt(3)) assert sqrt(3) + S.One / 3 == Add(sqrt(3), S.One / 3) assert S.One / 2 * 10.333 == Mul(S.One / 2, 10.333) assert 10.333 * S.One / 2 == Mul(10.333, S.One / 2) assert sqrt(2) * sqrt(2) == Mul(sqrt(2), sqrt(2)) assert S.One / 2 + x == Add(S.One / 2, x) assert x + S.One / 2 == Add(x, S.One / 2) assert S.One / x * x == Mul(S.One / x, x) assert x * S.One / x == Mul(x, S.One / x)
def test_sympy_parser(): x = Symbol("x") inputs = { "2*x": 2 * x, "3.00": Float(3), "22/7": Rational(22, 7), "2+3j": 2 + 3 * I, "exp(x)": exp(x), "x!": factorial(x), "x!!": factorial2(x), "(x + 1)! - 1": factorial(x + 1) - 1, "3.[3]": Rational(10, 3), ".0[3]": Rational(1, 30), "3.2[3]": Rational(97, 30), "1.3[12]": Rational(433, 330), "1 + 3.[3]": Rational(13, 3), "1 + .0[3]": Rational(31, 30), "1 + 3.2[3]": Rational(127, 30), ".[0011]": Rational(1, 909), "0.1[00102] + 1": Rational(366697, 333330), "1.[0191]": Rational(10190, 9999), "10!": 3628800, "-(2)": -Integer(2), "[-1, -2, 3]": [Integer(-1), Integer(-2), Integer(3)], 'Symbol("x").free_symbols': x.free_symbols, "S('S(3).n(n=3)')": 3.00, "factorint(12, visual=True)": Mul(Pow(2, 2, evaluate=False), Pow(3, 1, evaluate=False), evaluate=False), 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir="-"), } for text, result in inputs.items(): assert parse_expr(text) == result raises(TypeError, lambda: parse_expr("x", standard_transformations)) raises(TypeError, lambda: parse_expr("x", transformations=lambda x, y: 1)) raises(TypeError, lambda: parse_expr("x", transformations=(lambda x, y: 1, ))) raises(TypeError, lambda: parse_expr("x", transformations=((), ))) raises(TypeError, lambda: parse_expr("x", {}, [], [])) raises(TypeError, lambda: parse_expr("x", [], [], {})) raises(TypeError, lambda: parse_expr("x", [], [], {}))
def _print_Mul(self, expr): prec = precedence(expr) # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. args = expr.args if args[0] is S.One or any( isinstance(a, Number) or a.is_Pow and all(ai.is_Integer for ai in a.args) for a in args[1:]): d, n = sift(args, lambda x: isinstance(x, Pow) and bool( x.exp.as_coeff_Mul()[0] < 0), binary=True) for i, di in enumerate(d): if di.exp.is_Number: e = -di.exp else: dargs = list(di.exp.args) dargs[0] = -dargs[0] e = Mul._from_args(dargs) d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base # don't parenthesize first factor if negative if _coeff_isneg(n[0]): pre = [str(n.pop(0))] else: pre = [] nfactors = pre + [ self.parenthesize(a, prec, strict=False) for a in n ] # don't parenthesize first of denominator unless singleton if len(d) > 1 and _coeff_isneg(d[0]): pre = [str(d.pop(0))] else: pre = [] dfactors = pre + [ self.parenthesize(a, prec, strict=False) for a in d ] n = '*'.join(nfactors) d = '*'.join(dfactors) if len(dfactors) > 1: return '%s/(%s)' % (n, d) elif dfactors: return '%s/%s' % (n, d) return n c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [ ] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator def apow(i): b, e = i.as_base_exp() eargs = list(Mul.make_args(e)) if eargs[0] is S.NegativeOne: eargs = eargs[1:] else: eargs[0] = -eargs[0] e = Mul._from_args(eargs) if isinstance(i, Pow): return i.func(b, e, evaluate=False) return i.func(e, evaluate=False) for item in args: if (item.is_commutative and isinstance(item, Pow) and bool(item.exp.as_coeff_Mul()[0] < 0)): if item.exp is not S.NegativeOne: b.append(apow(item)) else: if (len(item.args[0].args) != 1 and isinstance(item.base, (Mul, Pow))): # To avoid situations like #14160 pow_paren.append(item) b.append(item.base) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec, strict=False) for x in a] b_str = [self.parenthesize(x, prec, strict=False) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
def _real_to_rational(expr, tolerance=None, rational_conversion='base10'): """ Replace all reals in expr with rationals. >>> from sympy import Rational >>> from sympy.simplify.simplify import _real_to_rational >>> from sympy.abc import x >>> _real_to_rational(.76 + .1*x**.5) sqrt(x)/10 + 19/25 If rational_conversion='base10', this uses the base-10 string. If rational_conversion='exact', the exact, base-2 representation is used. >>> _real_to_rational(0.333333333333333, rational_conversion='exact') 6004799503160655/18014398509481984 >>> _real_to_rational(0.333333333333333) 1/3 """ expr = _sympify(expr) inf = Float('inf') p = expr reps = {} reduce_num = None if tolerance is not None and tolerance < 1: reduce_num = ceiling(1 / tolerance) for fl in p.atoms(Float): key = fl if reduce_num is not None: r = Rational(fl).limit_denominator(reduce_num) elif (tolerance is not None and tolerance >= 1 and fl.is_Integer is False): r = Rational(tolerance * round(fl / tolerance)).limit_denominator( int(tolerance)) else: if rational_conversion == 'exact': r = Rational(fl) reps[key] = r continue elif rational_conversion != 'base10': raise ValueError( "rational_conversion must be 'base10' or 'exact'") r = nsimplify(fl, rational=False) # e.g. log(3).n() -> log(3) instead of a Rational if fl and not r: r = Rational(fl) elif not r.is_Rational: if fl == inf or fl == -inf: r = S.ComplexInfinity elif fl < 0: fl = -fl d = Pow(10, int((mpmath.log(fl) / mpmath.log(10)))) r = -Rational(str(fl / d)) * d elif fl > 0: d = Pow(10, int((mpmath.log(fl) / mpmath.log(10)))) r = Rational(str(fl / d)) * d else: r = Integer(0) reps[key] = r return p.subs(reps, simultaneous=True)
def collect(expr, syms, func=None, evaluate=None, exact=False, distribute_order_term=True): """ Collect additive terms of an expression. This function collects additive terms of an expression with respect to a list of expression up to powers with rational exponents. By the term symbol here are meant arbitrary expressions, which can contain powers, products, sums etc. In other words symbol is a pattern which will be searched for in the expression's terms. The input expression is not expanded by :func:`collect`, so user is expected to provide an expression is an appropriate form. This makes :func:`collect` more predictable as there is no magic happening behind the scenes. However, it is important to note, that powers of products are converted to products of powers using the :func:`expand_power_base` function. There are two possible types of output. First, if ``evaluate`` flag is set, this function will return an expression with collected terms or else it will return a dictionary with expressions up to rational powers as keys and collected coefficients as values. Examples ======== >>> from sympy import S, collect, expand, factor, Wild >>> from sympy.abc import a, b, c, x, y, z This function can collect symbolic coefficients in polynomials or rational expressions. It will manage to find all integer or rational powers of collection variable:: >>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x) c + x**2*(a + b) + x*(a - b) The same result can be achieved in dictionary form:: >>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False) >>> d[x**2] a + b >>> d[x] a - b >>> d[S.One] c You can also work with multivariate polynomials. However, remember that this function is greedy so it will care only about a single symbol at time, in specification order:: >>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y]) x**2*(y + 1) + x*y + y*(a + 1) Also more complicated expressions can be used as patterns:: >>> from sympy import sin, log >>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x)) (a + b)*sin(2*x) >>> collect(a*x*log(x) + b*(x*log(x)), x*log(x)) x*(a + b)*log(x) You can use wildcards in the pattern:: >>> w = Wild('w1') >>> collect(a*x**y - b*x**y, w**y) x**y*(a - b) It is also possible to work with symbolic powers, although it has more complicated behavior, because in this case power's base and symbolic part of the exponent are treated as a single symbol:: >>> collect(a*x**c + b*x**c, x) a*x**c + b*x**c >>> collect(a*x**c + b*x**c, x**c) x**c*(a + b) However if you incorporate rationals to the exponents, then you will get well known behavior:: >>> collect(a*x**(2*c) + b*x**(2*c), x**c) x**(2*c)*(a + b) Note also that all previously stated facts about :func:`collect` function apply to the exponential function, so you can get:: >>> from sympy import exp >>> collect(a*exp(2*x) + b*exp(2*x), exp(x)) (a + b)*exp(2*x) If you are interested only in collecting specific powers of some symbols then set ``exact`` flag in arguments:: >>> collect(a*x**7 + b*x**7, x, exact=True) a*x**7 + b*x**7 >>> collect(a*x**7 + b*x**7, x**7, exact=True) x**7*(a + b) You can also apply this function to differential equations, where derivatives of arbitrary order can be collected. Note that if you collect with respect to a function or a derivative of a function, all derivatives of that function will also be collected. Use ``exact=True`` to prevent this from happening:: >>> from sympy import Derivative as D, collect, Function >>> f = Function('f') (x) >>> collect(a*D(f,x) + b*D(f,x), D(f,x)) (a + b)*Derivative(f(x), x) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f) (a + b)*Derivative(f(x), (x, 2)) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True) a*Derivative(f(x), (x, 2)) + b*Derivative(f(x), (x, 2)) >>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f) (a + b)*f(x) + (a + b)*Derivative(f(x), x) Or you can even match both derivative order and exponent at the same time:: >>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x)) (a + b)*Derivative(f(x), (x, 2))**2 Finally, you can apply a function to each of the collected coefficients. For example you can factorize symbolic coefficients of polynomial:: >>> f = expand((x + a + 1)**3) >>> collect(f, x, factor) x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3 .. note:: Arguments are expected to be in expanded form, so you might have to call :func:`expand` prior to calling this function. See Also ======== collect_const, collect_sqrt, rcollect """ expr = sympify(expr) syms = list(syms) if iterable(syms) else [syms] if evaluate is None: evaluate = global_evaluate[0] def make_expression(terms): product = [] for term, rat, sym, deriv in terms: if deriv is not None: var, order = deriv while order > 0: term, order = Derivative(term, var), order - 1 if sym is None: if rat is S.One: product.append(term) else: product.append(Pow(term, rat)) else: product.append(Pow(term, rat * sym)) return Mul(*product) def parse_derivative(deriv): # scan derivatives tower in the input expression and return # underlying function and maximal differentiation order expr, sym, order = deriv.expr, deriv.variables[0], 1 for s in deriv.variables[1:]: if s == sym: order += 1 else: raise NotImplementedError( 'Improve MV Derivative support in collect') while isinstance(expr, Derivative): s0 = expr.variables[0] for s in expr.variables: if s != s0: raise NotImplementedError( 'Improve MV Derivative support in collect') if s0 == sym: expr, order = expr.expr, order + len(expr.variables) else: break return expr, (sym, Rational(order)) def parse_term(expr): """Parses expression expr and outputs tuple (sexpr, rat_expo, sym_expo, deriv) where: - sexpr is the base expression - rat_expo is the rational exponent that sexpr is raised to - sym_expo is the symbolic exponent that sexpr is raised to - deriv contains the derivatives the the expression for example, the output of x would be (x, 1, None, None) the output of 2**x would be (2, 1, x, None) """ rat_expo, sym_expo = S.One, None sexpr, deriv = expr, None if expr.is_Pow: if isinstance(expr.base, Derivative): sexpr, deriv = parse_derivative(expr.base) else: sexpr = expr.base if expr.exp.is_Number: rat_expo = expr.exp else: coeff, tail = expr.exp.as_coeff_Mul() if coeff.is_Number: rat_expo, sym_expo = coeff, tail else: sym_expo = expr.exp elif isinstance(expr, exp): arg = expr.args[0] if arg.is_Rational: sexpr, rat_expo = S.Exp1, arg elif arg.is_Mul: coeff, tail = arg.as_coeff_Mul(rational=True) sexpr, rat_expo = exp(tail), coeff elif isinstance(expr, Derivative): sexpr, deriv = parse_derivative(expr) return sexpr, rat_expo, sym_expo, deriv def parse_expression(terms, pattern): """Parse terms searching for a pattern. terms is a list of tuples as returned by parse_terms; pattern is an expression treated as a product of factors """ pattern = Mul.make_args(pattern) if len(terms) < len(pattern): # pattern is longer than matched product # so no chance for positive parsing result return None else: pattern = [parse_term(elem) for elem in pattern] terms = terms[:] # need a copy elems, common_expo, has_deriv = [], None, False for elem, e_rat, e_sym, e_ord in pattern: if elem.is_Number and e_rat == 1 and e_sym is None: # a constant is a match for everything continue for j in range(len(terms)): if terms[j] is None: continue term, t_rat, t_sym, t_ord = terms[j] # keeping track of whether one of the terms had # a derivative or not as this will require rebuilding # the expression later if t_ord is not None: has_deriv = True if (term.match(elem) is not None and (t_sym == e_sym or t_sym is not None and e_sym is not None and t_sym.match(e_sym) is not None)): if exact is False: # we don't have to be exact so find common exponent # for both expression's term and pattern's element expo = t_rat / e_rat if common_expo is None: # first time common_expo = expo else: # common exponent was negotiated before so # there is no chance for a pattern match unless # common and current exponents are equal if common_expo != expo: common_expo = 1 else: # we ought to be exact so all fields of # interest must match in every details if e_rat != t_rat or e_ord != t_ord: continue # found common term so remove it from the expression # and try to match next element in the pattern elems.append(terms[j]) terms[j] = None break else: # pattern element not found return None return [_f for _f in terms if _f], elems, common_expo, has_deriv if evaluate: if expr.is_Add: o = expr.getO() or 0 expr = expr.func(*[ collect(a, syms, func, True, exact, distribute_order_term) for a in expr.args if a != o ]) + o elif expr.is_Mul: return expr.func(*[ collect(term, syms, func, True, exact, distribute_order_term) for term in expr.args ]) elif expr.is_Pow: b = collect(expr.base, syms, func, True, exact, distribute_order_term) return Pow(b, expr.exp) syms = [expand_power_base(i, deep=False) for i in syms] order_term = None if distribute_order_term: order_term = expr.getO() if order_term is not None: if order_term.has(*syms): order_term = None else: expr = expr.removeO() summa = [expand_power_base(i, deep=False) for i in Add.make_args(expr)] collected, disliked = defaultdict(list), S.Zero for product in summa: c, nc = product.args_cnc(split_1=False) args = list(ordered(c)) + nc terms = [parse_term(i) for i in args] small_first = True for symbol in syms: if SYMPY_DEBUG: print("DEBUG: parsing of expression %s with symbol %s " % (str(terms), str(symbol))) if isinstance(symbol, Derivative) and small_first: terms = list(reversed(terms)) small_first = not small_first result = parse_expression(terms, symbol) if SYMPY_DEBUG: print("DEBUG: returned %s" % str(result)) if result is not None: if not symbol.is_commutative: raise AttributeError( "Can not collect noncommutative symbol") terms, elems, common_expo, has_deriv = result # when there was derivative in current pattern we # will need to rebuild its expression from scratch if not has_deriv: margs = [] for elem in elems: if elem[2] is None: e = elem[1] else: e = elem[1] * elem[2] margs.append(Pow(elem[0], e)) index = Mul(*margs) else: index = make_expression(elems) terms = expand_power_base(make_expression(terms), deep=False) index = expand_power_base(index, deep=False) collected[index].append(terms) break else: # none of the patterns matched disliked += product # add terms now for each key collected = {k: Add(*v) for k, v in collected.items()} if disliked is not S.Zero: collected[S.One] = disliked if order_term is not None: for key, val in collected.items(): collected[key] = val + order_term if func is not None: collected = dict([(key, func(val)) for key, val in collected.items()]) if evaluate: return Add(*[key * val for key, val in collected.items()]) else: return collected
def periodicity(f, symbol, check=False): """ Tests the given function for periodicity in the given symbol. Parameters ========== f : :py:class:`~.Expr`. The concerned function. symbol : :py:class:`~.Symbol` The variable for which the period is to be determined. check : bool, optional The flag to verify whether the value being returned is a period or not. Returns ======= period The period of the function is returned. ``None`` is returned when the function is aperiodic or has a complex period. The value of $0$ is returned as the period of a constant function. Raises ====== NotImplementedError The value of the period computed cannot be verified. Notes ===== Currently, we do not support functions with a complex period. The period of functions having complex periodic values such as ``exp``, ``sinh`` is evaluated to ``None``. The value returned might not be the "fundamental" period of the given function i.e. it may not be the smallest periodic value of the function. The verification of the period through the ``check`` flag is not reliable due to internal simplification of the given expression. Hence, it is set to ``False`` by default. Examples ======== >>> from sympy import periodicity, Symbol, sin, cos, tan, exp >>> x = Symbol('x') >>> f = sin(x) + sin(2*x) + sin(3*x) >>> periodicity(f, x) 2*pi >>> periodicity(sin(x)*cos(x), x) pi >>> periodicity(exp(tan(2*x) - 1), x) pi/2 >>> periodicity(sin(4*x)**cos(2*x), x) pi >>> periodicity(exp(x), x) """ if symbol.kind is not NumberKind: raise NotImplementedError("Cannot use symbol of kind %s" % symbol.kind) temp = Dummy('x', real=True) f = f.subs(symbol, temp) symbol = temp def _check(orig_f, period): '''Return the checked period or raise an error.''' new_f = orig_f.subs(symbol, symbol + period) if new_f.equals(orig_f): return period else: raise NotImplementedError( filldedent(''' The period of the given function cannot be verified. When `%s` was replaced with `%s + %s` in `%s`, the result was `%s` which was not recognized as being the same as the original function. So either the period was wrong or the two forms were not recognized as being equal. Set check=False to obtain the value.''' % (symbol, symbol, period, orig_f, new_f))) orig_f = f period = None if isinstance(f, Relational): f = f.lhs - f.rhs f = f.simplify() if symbol not in f.free_symbols: return S.Zero if isinstance(f, TrigonometricFunction): try: period = f.period(symbol) except NotImplementedError: pass if isinstance(f, Abs): arg = f.args[0] if isinstance(arg, (sec, csc, cos)): # all but tan and cot might have a # a period that is half as large # so recast as sin arg = sin(arg.args[0]) period = periodicity(arg, symbol) if period is not None and isinstance(arg, sin): # the argument of Abs was a trigonometric other than # cot or tan; test to see if the half-period # is valid. Abs(arg) has behaviour equivalent to # orig_f, so use that for test: orig_f = Abs(arg) try: return _check(orig_f, period / 2) except NotImplementedError as err: if check: raise NotImplementedError(err) # else let new orig_f and period be # checked below if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): f = Pow(S.Exp1, expand_mul(f.exp)) if im(f) != 0: period_real = periodicity(re(f), symbol) period_imag = periodicity(im(f), symbol) if period_real is not None and period_imag is not None: period = lcim([period_real, period_imag]) if f.is_Pow and f.base != S.Exp1: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if base_has_sym and not expo_has_sym: period = periodicity(base, symbol) elif expo_has_sym and not base_has_sym: period = periodicity(expo, symbol) else: period = _periodicity(f.args, symbol) elif f.is_Mul: coeff, g = f.as_independent(symbol, as_Add=False) if isinstance(g, TrigonometricFunction) or coeff is not S.One: period = periodicity(g, symbol) else: period = _periodicity(g.args, symbol) elif f.is_Add: k, g = f.as_independent(symbol) if k is not S.Zero: return periodicity(g, symbol) period = _periodicity(g.args, symbol) elif isinstance(f, Mod): a, n = f.args if a == symbol: period = n elif isinstance(a, TrigonometricFunction): period = periodicity(a, symbol) #check if 'f' is linear in 'symbol' elif (a.is_polynomial(symbol) and degree(a, symbol) == 1 and symbol not in n.free_symbols): period = Abs(n / a.diff(symbol)) elif isinstance(f, Piecewise): pass # not handling Piecewise yet as the return type is not favorable elif period is None: from sympy.solvers.decompogen import compogen, decompogen g_s = decompogen(f, symbol) num_of_gs = len(g_s) if num_of_gs > 1: for index, g in enumerate(reversed(g_s)): start_index = num_of_gs - 1 - index g = compogen(g_s[start_index:], symbol) if g not in (orig_f, f): # Fix for issue 12620 period = periodicity(g, symbol) if period is not None: break if period is not None: if check: return _check(orig_f, period) return period return None
def _print_Mul(self, expr): prec = precedence(expr) # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. args = expr.args if args[0] is S.One or any( isinstance(arg, Number) for arg in args[1:]): factors = [self.parenthesize(a, prec, strict=False) for a in args] return '*'.join(factors) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [ ] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance( item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec, strict=False) for x in a] b_str = [self.parenthesize(x, prec, strict=False) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
def eval(cls, *_args, **kwargs): """.""" if not _args: return if not len(_args) == 1: raise ValueError('Expecting one argument') expr = _args[0] d_atoms = kwargs.pop('d_atoms', {}) mapping = kwargs.pop('mapping', None) if isinstance(expr, Add): args = [ cls.eval(a, d_atoms=d_atoms, mapping=mapping) for a in expr.args ] return Add(*args) elif isinstance(expr, Mul): coeffs = [a for a in expr.args if isinstance(a, _coeffs_registery)] stests = [ a for a in expr.args if not (a in coeffs) and a.atoms(ScalarTestFunction) ] vtests = [ a for a in expr.args if not (a in coeffs) and a.atoms(VectorTestFunction) ] vectors = [ a for a in expr.args if (not (a in coeffs) and not (a in stests) and not (a in vtests)) ] a = S.One if coeffs: a = Mul(*coeffs) b = S.One if vectors: args = [cls(i, evaluate=False) for i in vectors] b = Mul(*args) sb = S.One if stests: args = [ cls.eval(i, d_atoms=d_atoms, mapping=mapping) for i in stests ] sb = Mul(*args) vb = S.One if vtests: args = [ cls.eval(i, d_atoms=d_atoms, mapping=mapping) for i in vtests ] vb = Mul(*args) return Mul(a, b, sb, vb) elif isinstance(expr, _coeffs_registery): return expr elif isinstance(expr, Pow): b = expr.base e = expr.exp return Pow(cls.eval(b), e) elif isinstance(expr, (Matrix, ImmutableDenseMatrix)): n_rows, n_cols = expr.shape lines = [] for i_row in range(0, n_rows): line = [] for i_col in range(0, n_cols): line.append( cls.eval(expr[i_row, i_col], d_atoms=d_atoms, mapping=mapping)) lines.append(line) return Matrix(lines) elif isinstance(expr, DomainExpression): # TODO to be removed target = expr.target expr = expr.expr return cls.eval(expr, d_atoms=d_atoms, mapping=mapping) elif isinstance(expr, BilinearForm): trials = list(expr.variables[0]) tests = list(expr.variables[1]) # ... # TODO improve terminal_expr = TerminalExpr(expr)[0] # ... # ... variables = list(terminal_expr.atoms(ScalarTestFunction)) variables += list(terminal_expr.atoms(IndexedTestTrial)) d_atoms = {} for a in variables: new = _split_test_function(a) d_atoms[a] = new # ... # ... logical = False if not (mapping is None): logical = True terminal_expr = LogicalExpr(mapping, terminal_expr.expr) det_M = DetJacobian(mapping) det = SymbolicDeterminant(mapping) terminal_expr = terminal_expr.subs(det_M, det) terminal_expr = expand(terminal_expr) # ... # ... expr = cls.eval(terminal_expr, d_atoms=d_atoms, mapping=mapping) # ... # ... trials = [ a for a in variables if ((isinstance(a, ScalarTestFunction) and a in trials) or ( isinstance(a, IndexedTestTrial) and a.base in trials)) ] tests = [ a for a in variables if ((isinstance(a, ScalarTestFunction) and a in tests) or ( isinstance(a, IndexedTestTrial) and a.base in tests)) ] # ... expr = _replace_atomic_expr(expr, trials, tests, d_atoms, logical=logical) return expr if expr.atoms(ScalarTestFunction) or expr.atoms(IndexedTestTrial): return _tensorize_atomic_expr(expr, d_atoms) return cls(expr, evaluate=False)
def test_Pow_Expr_args(): x = Symbol('x') bases = [Basic(), Poly(x, x), FiniteSet(x)] for base in bases: with warns_deprecated_sympy(): Pow(base, S.One)
def powsimp(expr, deep=False, combine='all', force=False, measure=count_ops): """ reduces expression by combining powers with similar bases and exponents. Notes ===== If deep is True then powsimp() will also simplify arguments of functions. By default deep is set to False. If force is True then bases will be combined without checking for assumptions, e.g. sqrt(x)*sqrt(y) -> sqrt(x*y) which is not true if x and y are both negative. You can make powsimp() only combine bases or only combine exponents by changing combine='base' or combine='exp'. By default, combine='all', which does both. combine='base' will only combine:: a a a 2x x x * y => (x*y) as well as things like 2 => 4 and combine='exp' will only combine :: a b (a + b) x * x => x combine='exp' will strictly only combine exponents in the way that used to be automatic. Also use deep=True if you need the old behavior. When combine='all', 'exp' is evaluated first. Consider the first example below for when there could be an ambiguity relating to this. This is done so things like the second example can be completely combined. If you want 'base' combined first, do something like powsimp(powsimp(expr, combine='base'), combine='exp'). Examples ======== >>> from sympy import powsimp, exp, log, symbols >>> from sympy.abc import x, y, z, n >>> powsimp(x**y*x**z*y**z, combine='all') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='exp') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='base', force=True) x**y*(x*y)**z >>> powsimp(x**z*x**y*n**z*n**y, combine='all', force=True) (n*x)**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='exp') n**(y + z)*x**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='base', force=True) (n*x)**y*(n*x)**z >>> x, y = symbols('x y', positive=True) >>> powsimp(log(exp(x)*exp(y))) log(exp(x)*exp(y)) >>> powsimp(log(exp(x)*exp(y)), deep=True) x + y Radicals with Mul bases will be combined if combine='exp' >>> from sympy import sqrt, Mul >>> x, y = symbols('x y') Two radicals are automatically joined through Mul: >>> a=sqrt(x*sqrt(y)) >>> a*a**3 == a**4 True But if an integer power of that radical has been autoexpanded then Mul does not join the resulting factors: >>> a**4 # auto expands to a Mul, no longer a Pow x**2*y >>> _*a # so Mul doesn't combine them x**2*y*sqrt(x*sqrt(y)) >>> powsimp(_) # but powsimp will (x*sqrt(y))**(5/2) >>> powsimp(x*y*a) # but won't when doing so would violate assumptions x*y*sqrt(x*sqrt(y)) """ from sympy.matrices.expressions.matexpr import MatrixSymbol def recurse(arg, **kwargs): _deep = kwargs.get('deep', deep) _combine = kwargs.get('combine', combine) _force = kwargs.get('force', force) _measure = kwargs.get('measure', measure) return powsimp(arg, _deep, _combine, _force, _measure) expr = sympify(expr) if (not isinstance(expr, Basic) or isinstance(expr, MatrixSymbol) or (expr.is_Atom or expr in (exp_polar(0), exp_polar(1)))): return expr if deep or expr.is_Add or expr.is_Mul and _y not in expr.args: expr = expr.func(*[recurse(w) for w in expr.args]) if expr.is_Pow: return recurse(expr * _y, deep=False) / _y if not expr.is_Mul: return expr # handle the Mul if combine in ('exp', 'all'): # Collect base/exp data, while maintaining order in the # non-commutative parts of the product c_powers = defaultdict(list) nc_part = [] newexpr = [] coeff = S.One for term in expr.args: if term.is_Rational: coeff *= term continue if term.is_Pow: term = _denest_pow(term) if term.is_commutative: b, e = term.as_base_exp() if deep: b, e = [recurse(i) for i in [b, e]] if b.is_Pow or isinstance(b, exp): # don't let smthg like sqrt(x**a) split into x**a, 1/2 # or else it will be joined as x**(a/2) later b, e = b**e, S.One c_powers[b].append(e) else: # This is the logic that combines exponents for equal, # but non-commutative bases: A**x*A**y == A**(x+y). if nc_part: b1, e1 = nc_part[-1].as_base_exp() b2, e2 = term.as_base_exp() if (b1 == b2 and e1.is_commutative and e2.is_commutative): nc_part[-1] = Pow(b1, Add(e1, e2)) continue nc_part.append(term) # add up exponents of common bases for b, e in ordered(iter(c_powers.items())): # allow 2**x/4 -> 2**(x - 2); don't do this when b and e are # Numbers since autoevaluation will undo it, e.g. # 2**(1/3)/4 -> 2**(1/3 - 2) -> 2**(1/3)/4 if (b and b.is_Rational and not all(ei.is_Number for ei in e) and \ coeff is not S.One and b not in (S.One, S.NegativeOne)): m = multiplicity(abs(b), abs(coeff)) if m: e.append(m) coeff /= b**m c_powers[b] = Add(*e) if coeff is not S.One: if coeff in c_powers: c_powers[coeff] += S.One else: c_powers[coeff] = S.One # convert to plain dictionary c_powers = dict(c_powers) # check for base and inverted base pairs be = list(c_powers.items()) skip = set() # skip if we already saw them for b, e in be: if b in skip: continue bpos = b.is_positive or b.is_polar if bpos: binv = 1 / b if b != binv and binv in c_powers: if b.as_numer_denom()[0] is S.One: c_powers.pop(b) c_powers[binv] -= e else: skip.add(binv) e = c_powers.pop(binv) c_powers[b] -= e # check for base and negated base pairs be = list(c_powers.items()) _n = S.NegativeOne for i, (b, e) in enumerate(be): if ((-b).is_Symbol or b.is_Add) and -b in c_powers: if (b.is_positive in (0, 1) or e.is_integer): c_powers[-b] += c_powers.pop(b) if _n in c_powers: c_powers[_n] += e else: c_powers[_n] = e # filter c_powers and convert to a list c_powers = [(b, e) for b, e in c_powers.items() if e] # ============================================================== # check for Mul bases of Rational powers that can be combined with # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) -> # (x*sqrt(x*y))**(3/2) # ---------------- helper functions def ratq(x): '''Return Rational part of x's exponent as it appears in the bkey. ''' return bkey(x)[0][1] def bkey(b, e=None): '''Return (b**s, c.q), c.p where e -> c*s. If e is not given then it will be taken by using as_base_exp() on the input b. e.g. x**3/2 -> (x, 2), 3 x**y -> (x**y, 1), 1 x**(2*y/3) -> (x**y, 3), 2 exp(x/2) -> (exp(a), 2), 1 ''' if e is not None: # coming from c_powers or from below if e.is_Integer: return (b, S.One), e elif e.is_Rational: return (b, Integer(e.q)), Integer(e.p) else: c, m = e.as_coeff_Mul(rational=True) if c is not S.One: if m.is_integer: return (b, Integer(c.q)), m * Integer(c.p) return (b**m, Integer(c.q)), Integer(c.p) else: return (b**e, S.One), S.One else: return bkey(*b.as_base_exp()) def update(b): '''Decide what to do with base, b. If its exponent is now an integer multiple of the Rational denominator, then remove it and put the factors of its base in the common_b dictionary or update the existing bases if necessary. If it has been zeroed out, simply remove the base. ''' newe, r = divmod(common_b[b], b[1]) if not r: common_b.pop(b) if newe: for m in Mul.make_args(b[0]**newe): b, e = bkey(m) if b not in common_b: common_b[b] = 0 common_b[b] += e if b[1] != 1: bases.append(b) # ---------------- end of helper functions # assemble a dictionary of the factors having a Rational power common_b = {} done = [] bases = [] for b, e in c_powers: b, e = bkey(b, e) if b in common_b: common_b[b] = common_b[b] + e else: common_b[b] = e if b[1] != 1 and b[0].is_Mul: bases.append(b) bases.sort(key=default_sort_key) # this makes tie-breaking canonical bases.sort(key=measure, reverse=True) # handle longest first for base in bases: if base not in common_b: # it may have been removed already continue b, exponent = base last = False # True when no factor of base is a radical qlcm = 1 # the lcm of the radical denominators while True: bstart = b qstart = qlcm bb = [] # list of factors ee = [] # (factor's expo. and it's current value in common_b) for bi in Mul.make_args(b): bib, bie = bkey(bi) if bib not in common_b or common_b[bib] < bie: ee = bb = [] # failed break ee.append([bie, common_b[bib]]) bb.append(bib) if ee: # find the number of integral extractions possible # e.g. [(1, 2), (2, 2)] -> min(2/1, 2/2) -> 1 min1 = ee[0][1] // ee[0][0] for i in range(1, len(ee)): rat = ee[i][1] // ee[i][0] if rat < 1: break min1 = min(min1, rat) else: # update base factor counts # e.g. if ee = [(2, 5), (3, 6)] then min1 = 2 # and the new base counts will be 5-2*2 and 6-2*3 for i in range(len(bb)): common_b[bb[i]] -= min1 * ee[i][0] update(bb[i]) # update the count of the base # e.g. x**2*y*sqrt(x*sqrt(y)) the count of x*sqrt(y) # will increase by 4 to give bkey (x*sqrt(y), 2, 5) common_b[base] += min1 * qstart * exponent if (last # no more radicals in base or len(common_b) == 1 # nothing left to join with or all(k[1] == 1 for k in common_b) # no rad's in common_b ): break # see what we can exponentiate base by to remove any radicals # so we know what to search for # e.g. if base were x**(1/2)*y**(1/3) then we should # exponentiate by 6 and look for powers of x and y in the ratio # of 2 to 3 qlcm = lcm([ratq(bi) for bi in Mul.make_args(bstart)]) if qlcm == 1: break # we are done b = bstart**qlcm qlcm *= qstart if all(ratq(bi) == 1 for bi in Mul.make_args(b)): last = True # we are going to be done after this next pass # this base no longer can find anything to join with and # since it was longer than any other we are done with it b, q = base done.append((b, common_b.pop(base) * Rational(1, q))) # update c_powers and get ready to continue with powsimp c_powers = done # there may be terms still in common_b that were bases that were # identified as needing processing, so remove those, too for (b, q), e in common_b.items(): if (b.is_Pow or isinstance(b, exp)) and \ q is not S.One and not b.exp.is_Rational: b, be = b.as_base_exp() b = b**(be / q) else: b = root(b, q) c_powers.append((b, e)) check = len(c_powers) c_powers = dict(c_powers) assert len(c_powers) == check # there should have been no duplicates # ============================================================== # rebuild the expression newexpr = expr.func(*(newexpr + [Pow(b, e) for b, e in c_powers.items()])) if combine == 'exp': return expr.func(newexpr, expr.func(*nc_part)) else: return recurse(expr.func(*nc_part), combine='base') * \ recurse(newexpr, combine='base') elif combine == 'base': # Build c_powers and nc_part. These must both be lists not # dicts because exp's are not combined. c_powers = [] nc_part = [] for term in expr.args: if term.is_commutative: c_powers.append(list(term.as_base_exp())) else: nc_part.append(term) # Pull out numerical coefficients from exponent if assumptions allow # e.g., 2**(2*x) => 4**x for i in range(len(c_powers)): b, e = c_powers[i] if not (all(x.is_nonnegative for x in b.as_numer_denom()) or e.is_integer or force or b.is_polar): continue exp_c, exp_t = e.as_coeff_Mul(rational=True) if exp_c is not S.One and exp_t is not S.One: c_powers[i] = [Pow(b, exp_c), exp_t] # Combine bases whenever they have the same exponent and # assumptions allow # first gather the potential bases under the common exponent c_exp = defaultdict(list) for b, e in c_powers: if deep: e = recurse(e) c_exp[e].append(b) del c_powers # Merge back in the results of the above to form a new product c_powers = defaultdict(list) for e in c_exp: bases = c_exp[e] # calculate the new base for e if len(bases) == 1: new_base = bases[0] elif e.is_integer or force: new_base = expr.func(*bases) else: # see which ones can be joined unk = [] nonneg = [] neg = [] for bi in bases: if bi.is_negative: neg.append(bi) elif bi.is_nonnegative: nonneg.append(bi) elif bi.is_polar: nonneg.append( bi) # polar can be treated like non-negative else: unk.append(bi) if len(unk) == 1 and not neg or len(neg) == 1 and not unk: # a single neg or a single unk can join the rest nonneg.extend(unk + neg) unk = neg = [] elif neg: # their negative signs cancel in groups of 2*q if we know # that e = p/q else we have to treat them as unknown israt = False if e.is_Rational: israt = True else: p, d = e.as_numer_denom() if p.is_integer and d.is_integer: israt = True if israt: neg = [-w for w in neg] unk.extend([S.NegativeOne] * len(neg)) else: unk.extend(neg) neg = [] del israt # these shouldn't be joined for b in unk: c_powers[b].append(e) # here is a new joined base new_base = expr.func(*(nonneg + neg)) # if there are positive parts they will just get separated # again unless some change is made def _terms(e): # return the number of terms of this expression # when multiplied out -- assuming no joining of terms if e.is_Add: return sum([_terms(ai) for ai in e.args]) if e.is_Mul: return prod([_terms(mi) for mi in e.args]) return 1 xnew_base = expand_mul(new_base, deep=False) if len(Add.make_args(xnew_base)) < _terms(new_base): new_base = factor_terms(xnew_base) c_powers[new_base].append(e) # break out the powers from c_powers now c_part = [Pow(b, ei) for b, e in c_powers.items() for ei in e] # we're done return expr.func(*(c_part + nc_part)) else: raise ValueError("combine must be one of ('all', 'exp', 'base').")
def is_deriv_k(fa, fd, DE): """ Checks if Df/f is the derivative of an element of k(t). a in k(t) is the derivative of an element of k(t) if there exists b in k(t) such that a = Db. Either returns (ans, u), such that Df/f == Du, or None, which means that Df/f is not the derivative of an element of k(t). ans is a list of tuples such that Add(*[i*j for i, j in ans]) == u. This is useful for seeing exactly which elements of k(t) produce u. This function uses the structure theorem approach, which says that for any f in K, Df/f is the derivative of a element of K if and only if there are ri in QQ such that:: --- --- Dt \ r * Dt + \ r * i Df / i i / i --- = --. --- --- t f i in L i in E i K/C(x) K/C(x) Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of hyperexponential monomials of K over C(x)). If K is an elementary extension over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the transcendence degree of K over C(x). Furthermore, because Const_D(K) == Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) and L_K/C(x) are disjoint. The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed recursively using this same function. Therefore, it is required to pass them as indices to D (or T). E_args are the arguments of the hyperexponentials indexed by E_K (i.e., if i is in E_K, then T[i] == exp(E_args[i])). This is needed to compute the final answer u such that Df/f == Du. log(f) will be the same as u up to a additive constant. This is because they will both behave the same as monomials. For example, both log(x) and log(2*x) == log(x) + log(2) satisfy Dt == 1/x, because log(2) is constant. Therefore, the term const is returned. const is such that log(const) + f == u. This is calculated by dividing the arguments of one logarithm from the other. Therefore, it is necessary to pass the arguments of the logarithmic terms in L_args. To handle the case where we are given Df/f, not f, use is_deriv_k_in_field(). """ # Compute Df/f dfa, dfd = fd * (fd * derivation(fa, DE) - fa * derivation(fd, DE)), fd**2 * fa dfa, dfd = dfa.cancel(dfd, include=True) # Our assumption here is that each monomial is recursively transcendental if len(DE.L_K) + len(DE.E_K) != len(DE.D) - 1: if [i for i in DE.cases if i == 'tan'] or \ set([i for i in DE.cases if i == 'primitive']) - set(DE.L_K): raise NotImplementedError( "Real version of the structure " "theorems with hypertangent support is not yet implemented.") # TODO: What should really be done in this case? raise NotImplementedError("Nonelementary extensions not supported " "in the structure theorems.") E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.E_K] L_part = [DE.D[i].as_expr() for i in DE.L_K] lhs = Matrix([E_part + L_part]) rhs = Matrix([dfa.as_expr() / dfd.as_expr()]) A, u = constant_system(lhs, rhs, DE) if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: # If the elements of u are not all constant # Note: See comment in constant_system # Also note: derivation(basic=True) calls cancel() return None else: if not all(i.is_Rational for i in u): raise NotImplementedError("Cannot work with non-rational " "coefficients in this case.") else: terms = DE.E_args + [DE.T[i] for i in DE.L_K] ans = list(zip(terms, u)) result = Add(*[Mul(i, j) for i, j in ans]) argterms = [DE.T[i] for i in DE.E_K] + DE.L_args l = [] ld = [] for i, j in zip(argterms, u): # We need to get around things like sqrt(x**2) != x # and also sqrt(x**2 + 2*x + 1) != x + 1 # Issue 10798: i need not be a polynomial i, d = i.as_numer_denom() icoeff, iterms = sqf_list(i) l.append( Mul(*([Pow(icoeff, j)] + [Pow(b, e * j) for b, e in iterms]))) dcoeff, dterms = sqf_list(d) ld.append( Mul(*([Pow(dcoeff, j)] + [Pow(b, e * j) for b, e in dterms]))) const = cancel(fa.as_expr() / fd.as_expr() / Mul(*l) * Mul(*ld)) return (ans, result, const)
def _denest_pow(eq): """ Denest powers. This is a helper function for powdenest that performs the actual transformation. """ from sympy.simplify.simplify import logcombine b, e = eq.as_base_exp() if b.is_Pow or isinstance(b.func, exp) and e != 1: new = b._eval_power(e) if new is not None: eq = new b, e = new.as_base_exp() # denest exp with log terms in exponent if b is S.Exp1 and e.is_Mul: logs = [] other = [] for ei in e.args: if any(isinstance(ai, log) for ai in Add.make_args(ei)): logs.append(ei) else: other.append(ei) logs = logcombine(Mul(*logs)) return Pow(exp(logs), Mul(*other)) _, be = b.as_base_exp() if be is S.One and not (b.is_Mul or b.is_Rational and b.q != 1 or b.is_positive): return eq # denest eq which is either pos**e or Pow**e or Mul**e or # Mul(b1**e1, b2**e2) # handle polar numbers specially polars, nonpolars = [], [] for bb in Mul.make_args(b): if bb.is_polar: polars.append(bb.as_base_exp()) else: nonpolars.append(bb) if len(polars) == 1 and not polars[0][0].is_Mul: return Pow(polars[0][0], polars[0][1] * e) * powdenest( Mul(*nonpolars)**e) elif polars: return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \ *powdenest(Mul(*nonpolars)**e) if b.is_Integer: # use log to see if there is a power here logb = expand_log(log(b)) if logb.is_Mul: c, logb = logb.args e *= c base = logb.args[0] return Pow(base, e) # if b is not a Mul or any factor is an atom then there is nothing to do if not b.is_Mul or any(s.is_Atom for s in Mul.make_args(b)): return eq # let log handle the case of the base of the argument being a Mul, e.g. # sqrt(x**(2*i)*y**(6*i)) -> x**i*y**(3**i) if x and y are positive; we # will take the log, expand it, and then factor out the common powers that # now appear as coefficient. We do this manually since terms_gcd pulls out # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2; # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but # we want 3*x. Neither work with noncommutatives. def nc_gcd(aa, bb): a, b = [i.as_coeff_Mul() for i in [aa, bb]] c = gcd(a[0], b[0]).as_numer_denom()[0] g = Mul(*(a[1].args_cnc(cset=True)[0] & b[1].args_cnc(cset=True)[0])) return _keep_coeff(c, g) glogb = expand_log(log(b)) if glogb.is_Add: args = glogb.args g = reduce(nc_gcd, args) if g != 1: cg, rg = g.as_coeff_Mul() glogb = _keep_coeff(cg, rg * Add(*[a / g for a in args])) # now put the log back together again if isinstance(glogb, log) or not glogb.is_Mul: if glogb.args[0].is_Pow or isinstance(glogb.args[0], exp): glogb = _denest_pow(glogb.args[0]) if (abs(glogb.exp) < 1) == True: return Pow(glogb.base, glogb.exp * e) return eq # the log(b) was a Mul so join any adds with logcombine add = [] other = [] for a in glogb.args: if a.is_Add: add.append(a) else: other.append(a) return Pow(exp(logcombine(Mul(*add))), e * Mul(*other))
def _invert_real(f, g_ys, symbol): """ Helper function for invert_real """ if not f.has(symbol): raise ValueError("Inverse of constant function doesn't exist") if f is symbol: return (f, g_ys) n = Dummy('n') if hasattr(f, 'inverse') and not isinstance(f, TrigonometricFunction): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): return _invert_real(f.args[0], Union(g_ys, imageset(Lambda(n, -n), g_ys)), symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g != S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g != S.One: return _invert_real(h, imageset(Lambda(n, n/g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: res = imageset(Lambda(n, Pow(n, 1/expo)), g_ys) if expo.is_rational: numer, denom = expo.as_numer_denom() if numer == S.One or numer == - S.One: return _invert_real(base, res, symbol) else: if numer % 2 == 0: n = Dummy('n') neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) else: return _invert_real(base, res, symbol) else: if not base.is_positive: raise ValueError("x**w where w is irrational is not" "defined for negative x") return _invert_real(base, res, symbol) if not base_has_sym: return _invert_real(expo, imageset(Lambda(n, log(n)/log(base)), g_ys), symbol) if isinstance(f, tan) or isinstance(f, cot): n = Dummy('n') if isinstance(g_ys, FiniteSet): tan_cot_invs = Union(*[imageset(Lambda(n, n*pi + f.inverse()(g_y)), S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], tan_cot_invs, symbol) return (f, g_ys)
def test_sympy_parser(): x = Symbol('x') inputs = { '2*x': 2 * x, '3.00': Float(3), '22/7': Rational(22, 7), '2+3j': 2 + 3 * I, 'exp(x)': exp(x), 'x!': factorial(x), 'x!!': factorial2(x), '(x + 1)! - 1': factorial(x + 1) - 1, '3.[3]': Rational(10, 3), '.0[3]': Rational(1, 30), '3.2[3]': Rational(97, 30), '1.3[12]': Rational(433, 330), '1 + 3.[3]': Rational(13, 3), '1 + .0[3]': Rational(31, 30), '1 + 3.2[3]': Rational(127, 30), '.[0011]': Rational(1, 909), '0.1[00102] + 1': Rational(366697, 333330), '1.[0191]': Rational(10190, 9999), '10!': 3628800, '-(2)': -Integer(2), '[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)], 'Symbol("x").free_symbols': x.free_symbols, "S('S(3).n(n=3)')": 3.00, 'factorint(12, visual=True)': Mul(Pow(2, 2, evaluate=False), Pow(3, 1, evaluate=False), evaluate=False), 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'), 'Q.even(x)': Q.even(x), } for text, result in inputs.items(): assert parse_expr(text) == result raises(TypeError, lambda: parse_expr('x', standard_transformations)) raises(TypeError, lambda: parse_expr('x', transformations=lambda x, y: 1)) raises(TypeError, lambda: parse_expr('x', transformations=(lambda x, y: 1, ))) raises(TypeError, lambda: parse_expr('x', transformations=((), ))) raises(TypeError, lambda: parse_expr('x', {}, [], [])) raises(TypeError, lambda: parse_expr('x', [], [], {})) raises(TypeError, lambda: parse_expr('x', [], [], {}))
def __pow__(self, other): from sympy.functions.elementary.miscellaneous import real_root if isinstance(other, Expr): if other is S.Infinity: if self.min.is_nonnegative: if self.max < 1: return S.Zero if self.min > 1: return S.Infinity return AccumBounds(0, oo) elif self.max.is_negative: if self.min > -1: return S.Zero if self.max < -1: return FiniteSet(-oo, oo) return AccumBounds(-oo, oo) else: if self.min > -1: if self.max < 1: return S.Zero return AccumBounds(0, oo) return AccumBounds(-oo, oo) if other is S.NegativeInfinity: return (1 / self)**oo if other.is_real and other.is_number: if other.is_zero: return S.One if other.is_Integer: if self.min.is_positive: return AccumBounds( Min(self.min**other, self.max**other), Max(self.min**other, self.max**other)) elif self.max.is_negative: return AccumBounds( Min(self.max**other, self.min**other), Max(self.max**other, self.min**other)) if other % 2 == 0: if other.is_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(self.min**other, oo) return AccumBounds(0, oo) return AccumBounds( S.Zero, Max(self.min**other, self.max**other)) else: if other.is_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(-oo, self.min**other) return AccumBounds(-oo, oo) return AccumBounds(self.min**other, self.max**other) num, den = other.as_numer_denom() if num == S(1): if den % 2 == 0: if S.Zero in self: if self.min.is_negative: return AccumBounds(0, real_root(self.max, den)) return AccumBounds(real_root(self.min, den), real_root(self.max, den)) num_pow = self**num return num_pow**(1 / den) return Pow(self, other, evaluate=False) return NotImplemented
def _denest(b, e): if not isinstance(b, (Pow, exp)): return b.is_positive, Pow(b, e, evaluate=False) return _denest(b.base, b.exp * e)