Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
from __future__ import print_function, division
from collections import defaultdict from functools import cmp_to_key import operator
from .sympify import sympify from .basic import Basic from .singleton import S from .operations import AssocOp from .cache import cacheit from .logic import fuzzy_not, _fuzzy_group from .compatibility import reduce, range from .expr import Expr
# internal marker to indicate: # "there are still non-commutative objects -- don't forget to process them"
class NC_Marker: is_Order = False is_Mul = False is_Number = False is_Poly = False
is_commutative = False
# Key for sorting commutative args in canonical order _args_sortkey = cmp_to_key(Basic.compare) def _mulsort(args): # in-place sorting of args
def _unevaluated_Mul(*args): """Return a well-formed unevaluated Mul: Numbers are collected and put in slot 0, any arguments that are Muls will be flattened, and args are sorted. Use this when args have changed but you still want to return an unevaluated Mul.
Examples ========
>>> from sympy.core.mul import _unevaluated_Mul as uMul >>> from sympy import S, sqrt, Mul >>> from sympy.abc import x >>> a = uMul(*[S(3.0), x, S(2)]) >>> a.args[0] 6.00000000000000 >>> a.args[1] x
Two unevaluated Muls with the same arguments will always compare as equal during testing:
>>> m = uMul(sqrt(2), sqrt(3)) >>> m == uMul(sqrt(3), sqrt(2)) True >>> u = Mul(sqrt(3), sqrt(2), evaluate=False) >>> m == uMul(u) True >>> m == Mul(*m.args) False
""" c, nc = a.args_cnc() args.extend(c) if nc: ncargs.append(Mul._from_args(nc)) else: newargs.insert(0, co) newargs.append(Mul._from_args(ncargs))
class Mul(Expr, AssocOp):
__slots__ = []
is_Mul = True
@classmethod def flatten(cls, seq): """Return commutative, noncommutative and order arguments by combining related terms.
Notes ===== * In an expression like ``a*b*c``, python process this through sympy as ``Mul(Mul(a, b), c)``. This can have undesirable consequences.
- Sometimes terms are not combined as one would like: {c.f. https://github.com/sympy/sympy/issues/4596}
>>> from sympy import Mul, sqrt >>> from sympy.abc import x, y, z >>> 2*(x + 1) # this is the 2-arg Mul behavior 2*x + 2 >>> y*(x + 1)*2 2*y*(x + 1) >>> 2*(x + 1)*y # 2-arg result will be obtained first y*(2*x + 2) >>> Mul(2, x + 1, y) # all 3 args simultaneously processed 2*y*(x + 1) >>> 2*((x + 1)*y) # parentheses can control this behavior 2*y*(x + 1)
Powers with compound bases may not find a single base to combine with unless all arguments are processed at once. Post-processing may be necessary in such cases. {c.f. https://github.com/sympy/sympy/issues/5728}
>>> a = sqrt(x*sqrt(y)) >>> a**3 (x*sqrt(y))**(3/2) >>> Mul(a,a,a) (x*sqrt(y))**(3/2) >>> a*a*a x*sqrt(y)*sqrt(x*sqrt(y)) >>> _.subs(a.base, z).subs(z, a.base) (x*sqrt(y))**(3/2)
- If more than two terms are being multiplied then all the previous terms will be re-processed for each new argument. So if each of ``a``, ``b`` and ``c`` were :class:`Mul` expression, then ``a*b*c`` (or building up the product with ``*=``) will process all the arguments of ``a`` and ``b`` twice: once when ``a*b`` is computed and again when ``c`` is multiplied.
Using ``Mul(a, b, c)`` will process all arguments once.
* The results of Mul are cached according to arguments, so flatten will only be called once for ``Mul(a, b, c)``. If you can structure a calculation so the arguments are most likely to be repeats then this can save time in computing the answer. For example, say you had a Mul, M, that you wished to divide by ``d[i]`` and multiply by ``n[i]`` and you suspect there are many repeats in ``n``. It would be better to compute ``M*n[i]/d[i]`` rather than ``M/d[i]*n[i]`` since every time n[i] is a repeat, the product, ``M*n[i]`` will be returned without flattening -- the cached value will be returned. If you divide by the ``d[i]`` first (and those are more unique than the ``n[i]``) then that will create a new Mul, ``M/d[i]`` the args of which will be traversed again when it is multiplied by ``n[i]``.
{c.f. https://github.com/sympy/sympy/issues/5706}
This consideration is moot if the cache is turned off.
NB -- The validity of the above notes depends on the implementation details of Mul and flatten which may change at any time. Therefore, you should only consider them when your code is highly performance sensitive.
Removal of 1 from the sequence is already handled by AssocOp.__new__. """
# leave the Mul as a Mul rv = [b], [], None else:
# apply associativity, separate commutative part of seq
# e.g. 3 * ...
# e.g. (x,n) for x
# e.g. (3, y) for ... * 3 * ...
# e.g. (3, 1/2) for ... * 3 * ...
# --- PART 1 --- # # "collect powers and coeff": # # o coeff # o c_powers # o num_exp # o neg1e # o pnum_rat # # NOTE: this is optimized for all-objects-are-commutative case # O(x)
# Mul([...])
else: # NCMul can have commutative parts as well for q in o.args: if q.is_commutative: seq.append(q) else: nc_seq.append(q)
# append non-commutative marker, so we don't forget to # process scheduled non-commutative objects seq.append(NC_Marker)
continue
# 3 # we know for sure the result will be nan # we know for sure the result will be nan return [S.NaN], [], None
coeff = o.__mul__(coeff) continue
# 0 * zoo = NaN return [S.NaN], [], None # zoo * zoo = zoo return [S.ComplexInfinity], [], None
# e # o = b
# y # 3
# get all the factors with numeric base so they can be # combined below, but don't combine negatives unless # the exponent is an integer seq.append(Pow(b, e)) continue continue
# NON-COMMUTATIVE # TODO: Make non-commutative exponents not combine automatically else: if o is not NC_Marker: nc_seq.append(o)
# process nc_seq (if any) while nc_seq: o = nc_seq.pop(0) if not nc_part: nc_part.append(o) continue
# b c b+c # try to combine last terms: a * a -> a o1 = nc_part.pop() b1, e1 = o1.as_base_exp() b2, e2 = o.as_base_exp() new_exp = e1 + e2 # Only allow powers to combine if the new exponent is # not an Add. This allow things like a**2*b**3 == a**5 # if a.is_commutative == False, but prohibits # a**x*a**y and x**a*x**b from combining (x,y commute). if b1 == b2 and (not new_exp.is_Add): o12 = b1 ** new_exp
# now o12 could be a commutative object if o12.is_commutative: seq.append(o12) continue else: nc_seq.insert(0, o12)
else: nc_part.append(o1) nc_part.append(o)
# We do want a combined exponent if it would not be an Add, such as # y 2y 3y # x * x -> x # We determine if two exponents have the same term by using # as_coeff_Mul. # # Unfortunately, this isn't smart enough to consider combining into # exponents that might already be adds, so things like: # z - y y # x * x will be left alone. This is because checking every possible # combination can slow things down.
# gather exponents of common bases... co[1], []).append(co[0])
# in c_powers
# and in num_exp
# --- PART 2 --- # # o process collected powers (x**0 -> 1; x**1 -> x; otherwise Pow) # o combine collected powers (2**x * 3**x -> 6**x) # with numeric base
# ................................ # now we have: # - coeff: # - c_powers: (b, e) # - num_exp: (2, e) # - pnum_rat: {(1/3, [1/3, 2/3, 1/4])}
# 0 1 # x -> 1 x -> x
# this should only need to run twice; if it fails because # it needs to be run more times, perhaps this should be # changed to a "while True" loop -- the only reason it # isn't such now is to allow a less-than-perfect result to # be obtained rather than raising an error or entering an # infinite loop coeff *= b continue # check to make sure that the base doesn't change # after exponentiation; to allow for unevaluated # Pow, we only do so if b is not already a Pow # there might have been a change, but unless the base # matches some other base, there is nothing to do b for b, e in new_c_powers)) != len(new_c_powers): # start over again c_part = [] c_powers = _gather(new_c_powers) else:
# x x x # 2 * 3 -> 6 # e.g. x:6 for ... * 2 * 3 * ...
# b, e -> e' = sum(e), b # {(1/5, [1/3]), (1/2, [1/12, 1/4]} -> {(1/3, [1/5, 1/2])} # process them, reducing exponents to values less than 1 # and updating coeff if necessary else adding them to # num_rat for further processing
# extract gcd of bases in num_rat # 2**(1/3)*6**(1/4) -> 2**(1/3+1/4)*3**(1/4) bj, ej = num_rat[j] g = bi.gcd(bj) if g is not S.One: # 4**r1*6**r2 -> 2**(r1+r2) * 2**r1 * 3**r2 # this might have a gcd with something else e = ei + ej if e.q == 1: coeff *= Pow(g, e) else: if e.p > e.q: e_i, ep = divmod(e.p, e.q) # change e in place coeff *= Pow(g, e_i) e = Rational(ep, e.q) grow.append((g, e)) # update the jth item num_rat[j] = (bj/g, ej) # update bi that we are checking with bi = bi/g if bi is S.One: break else: # changes like sqrt(12) -> 2*sqrt(3) else:
# combine bases of the new powers
# handle -1 and I # treat I as (-1)**(1/2) and compute -1's total exponent # if the integer part is odd, extract -1 # if it's a multiple of 1/2 extract I # see if there is any positive base this power of # -1 can join pnew[e] = -b break else: # keep it separate; we've already evaluated it as # much as possible so evaluate=False
# add all the pnew powers
# oo, -oo continue coeff_sign *= -1 continue
# zoo # zoo might be # infinite_real + bounded_im # bounded_real + infinite_im # infinite_real + infinite_im # and non-zero real or imaginary will not change that status. c.is_real is not None)] c.is_real is not None)]
# 0 # we know for sure the result will be 0 except the multiplicand # is infinity return [S.NaN], [], order_symbols
# check for straggling Numbers that were produced else:
# order commutative part canonically
# current code expects coeff to be always in slot-0
# we are done c_part[1].is_Add): # 2*(1+a) -> 2 + 2 * a
def _eval_power(b, e):
# don't break up NC terms: (A*B)**3 != A**3*B**3, it is A*B*A*B*A*B
Pow(Mul._from_args(nc), e, evaluate=False)
return p
@classmethod def class_key(cls):
def _eval_evalf(self, prec): else: else:
@cacheit def as_two_terms(self): """Return head and tail of self.
This is the most efficient way to get the head and tail of an expression.
- if you want only the head, use self.args[0]; - if you want to process the arguments of the tail then use self.as_coef_mul() which gives the head and a tuple containing the arguments of the tail when treated as a Mul. - if you want the coefficient when self is treated as an Add then use self.as_coeff_add()[0]
>>> from sympy.abc import x, y >>> (3*x*y).as_two_terms() (3, x*y) """
return S.One, self
else:
@cacheit def as_coefficients_dict(self): """Return a dictionary mapping terms to their coefficient. Since the dictionary is a defaultdict, inquiries about terms which were not present will return a coefficient of 0. The dictionary is considered to have a single term.
Examples ========
>>> from sympy.abc import a, x >>> (3*a*x).as_coefficients_dict() {a*x: 3} >>> _[a] 0 """
d = defaultdict(int) args = self.args
if len(args) == 1 or not args[0].is_Number: d[self] = S.One else: d[self._new_rawargs(*args[1:])] = args[0]
return d
@cacheit def as_coeff_mul(self, *deps, **kwargs): else: elif args[0].is_negative: return S.NegativeOne, (-args[0],) + args[1:]
def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """
else: elif coeff.is_negative: return S.NegativeOne, self._new_rawargs(*((-coeff,) + args))
def as_real_imag(self, deep=True, **hints): # search for complex conjugate pairs: coeffr.append(Abs(x)**2) del other[i] break else: else: else: other.append(a) # all other pairs make a real factor; they will be # put into reco below else: else: else:
@staticmethod def _expandsums(sums): """ Helper function for _eval_expand_mul.
sums must be a list of instances of Basic. """
def _eval_expand_mul(self, **hints):
# Handle things like 1/(x*(x + 1)), which are automatically converted # to 1/x*1/(x + 1) for i in (n, d)]
else: else: sums.append(Basic(factor)) # Wrapper
else: t = t._eval_expand_mul() else: return plain
@cacheit def _eval_derivative(self, s):
def _eval_difference_delta(self, n, step): from sympy.series.limitseq import difference_delta as dd arg0 = self.args[0] rest = Mul(*self.args[1:]) return (arg0.subs(n, n + step) * dd(rest, n, step) + dd(arg0, n, step) * rest)
def _matches_simple(self, expr, repl_dict): # handle (w*3).matches('x*5') -> {w: x*5/3}
def matches(self, expr, repl_dict={}, old=False): elif self.is_commutative is not expr.is_commutative: return None c1, nc1 = self.args_cnc() c2, nc2 = expr.args_cnc() repl_dict = repl_dict.copy() if c1: if not c2: c2 = [1] a = self.func(*c1) if isinstance(a, AssocOp): repl_dict = a._matches_commutative(self.func(*c2), repl_dict, old) else: repl_dict = a.matches(self.func(*c2), repl_dict) if repl_dict: a = self.func(*nc1) if isinstance(a, self.func): repl_dict = a._matches(self.func(*nc2), repl_dict) else: repl_dict = a.matches(self.func(*nc2), repl_dict) return repl_dict or None
def _matches(self, expr, repl_dict={}): # weed out negative one prefixes# from sympy import Wild sign = 1 a, b = self.as_two_terms() if a is S.NegativeOne: if b.is_Mul: sign = -sign else: # the remainder, b, is not a Mul anymore return b.matches(-expr, repl_dict) expr = sympify(expr) if expr.is_Mul and expr.args[0] is S.NegativeOne: expr = -expr sign = -sign
if not expr.is_Mul: # expr can only match if it matches b and a matches +/- 1 if len(self.args) == 2: # quickly test for equality if b == expr: return a.matches(Rational(sign), repl_dict) # do more expensive match dd = b.matches(expr, repl_dict) if dd is None: return None dd = a.matches(Rational(sign), dd) return dd return None
d = repl_dict.copy()
# weed out identical terms pp = list(self.args) ee = list(expr.args) for p in self.args: if p in expr.args: ee.remove(p) pp.remove(p)
# only one symbol left in pattern -> match the remaining expression if len(pp) == 1 and isinstance(pp[0], Wild): if len(ee) == 1: d[pp[0]] = sign * ee[0] else: d[pp[0]] = sign * expr.func(*ee) return d
if len(ee) != len(pp): return None
for p, e in zip(pp, ee): d = p.xreplace(d).matches(e, d) if d is None: return None return d
@staticmethod def _combine_inverse(lhs, rhs): """ Returns lhs/rhs, but treats arguments like symbols, so things like oo/oo return 1, instead of a nan. """
# if both objects are added to 0 they will share the same "normalization" # and are more likely to compare the same. Since Add(foo, 0) will not allow # the 0 to pass, we use __add__ directly. return l.__add__(0) == r.evalf().__add__(0) return S.One a = list(lhs.args) b = [1] for x in rhs.args: if x in a: a.remove(x) elif -x in a: a.remove(-x) b.append(-1) else: b.append(x) return lhs.func(*a)/rhs.func(*b)
def as_powers_dict(self):
def as_numer_denom(self): # don't use _from_args to rebuild the numerators and denominators # as the order is not guaranteed to be the same once they have # been separated from each other
def as_base_exp(self): nc += 1
def _eval_is_polynomial(self, syms):
def _eval_is_rational_function(self, syms): return all(term._eval_is_rational_function(syms) for term in self.args)
def _eval_is_algebraic_expr(self, syms): return all(term._eval_is_algebraic_expr(syms) for term in self.args)
a.is_finite for a in self.args) a.is_commutative for a in self.args) (a.is_complex for a in self.args), quick_exit=True)
def _eval_is_infinite(self): return S.NaN.is_infinite return True
def _eval_is_rational(self):
def _eval_is_algebraic(self):
def _eval_is_zero(self): return # 0*oo is nan and nan.is_zero is None else:
def _eval_is_integer(self):
elif d is S(2): return n.is_even
def _eval_is_polar(self): all(arg.is_polar or arg.is_positive for arg in self.args)
def _eval_is_real(self):
def _eval_real_imag(self, real):
return True else:
def _eval_is_imaginary(self): return False
def _eval_is_hermitian(self):
def _eval_herm_antiherm(self, real):
if one_nc: return one_nc = True
return True return else:
def _eval_is_antihermitian(self): return False
def _eval_is_irrational(self):
def _eval_is_positive(self): """Return True if self is positive, False if not, and None if it cannot be determined.
This algorithm is non-recursive and works by keeping track of the sign which changes when a negative or nonpositive is encountered. Whether a nonpositive or nonnegative is seen is also tracked since the presence of these makes it impossible to return True, but possible to return False if the end result is nonpositive. e.g.
pos * neg * nonpositive -> pos or zero -> None is returned pos * neg * nonnegative -> neg or zero -> False is returned """
def _eval_pos_neg(self, sign): return False sign = -sign saw_NON = True if saw_NOT: return saw_NOT = True else:
def _eval_is_negative(self):
def _eval_is_odd(self):
return None r = False
# !integer -> !odd
def _eval_is_even(self):
def _eval_is_prime(self): """ If product is a positive integer, multiplication will never result in a prime number. """ """ If input is a number that is not completely simplified. e.g. Mul(sqrt(3), sqrt(3), evaluate=False) So we manually evaluate it and return whether that is prime or not. """ # Note: `doit()` was not used due to test failing (Infinite Recursion)
""" Here we count the number of arguments that have a minimum value greater than two. If there are more than one of such a symbol then the result is not prime. Else, the result cannot be determined. """ number_of_args = 0 # count of symbols with minimum value greater than one for arg in self.args: if (arg-1).is_positive: number_of_args += 1
if number_of_args > 1: return False
def _eval_subs(self, old, new):
# try keep replacement literal so -2*x doesn't replace 4*x if self.args[0].is_Number: if self.args[0] < 0: return self._subs(-old, -new) return None
# if I and -1 are in a Mul, they get both end up with # a -1 base (see issue 6421); all we want here are the # true Pow or exp separated into base and exponent
"""break up powers of eq when treated as a Mul: b**(Rational*e) -> b**e, Rational commutatives come back as a dictionary {b**e: Rational} noncommutatives come back as a list [(b**e, Rational)] """
else: nc.append([b, e])
""" Put rational back with exponent; in general this is not ok, but since we took it from the exponent for analysis, it's ok to put it back. """
(b, e) = base_exp(b) return Pow(b, e*co)
"""if b divides a in an extractive way (like 1/4 divides 1/2 but not vice versa, and 2/5 does not divide 1/3) then return the integer number of times it divides, else return 0. """ if not b.q % a.q or not a.q % b.q: return int(a/b) return 0
# give Muls in the denominator a chance to be changed (see issue 5651) # rv will be the default return value return self2._subs(old, new) rv = self2
# Now continue with regular substitution.
# handle the leading coefficient and use it to decide if anything # should even be started; we always know where to find the Rational # so it's a quick test
# if coeffs are the same there will be no updating to do # below after breakup() step; so skip (and keep co_xmul=None) if co_old != co_self: co_xmul = co_self.extract_multiplicatively(co_old) return rv
# break self and old into factors
# update the coefficients if we had an extraction # e.g. if co_self were 2*(3/35*x)**2 and co_old = 3/5 # then co_self in c is replaced by (3/5)**2 and co_residual # is 2*(1/7)**2
mult = S(multiplicity(abs(co_old), co_self)) c.pop(co_self) if co_old in c: c[co_old] += mult else: c[co_old] = mult co_residual = co_self/co_old**mult else:
# do quick tests to see if we can't succeed
# more non-commutative terms ok = False # more commutative terms ok = False # unmatched non-commutative bases ok = False # unmatched commutative terms elif any(sign(c[b]) != sign(old_c[b]) for b in old_c): # differences in sign ok = False
if not old_c: cdid = None else: rat = [] for (b, old_e) in old_c.items(): c_e = c[b] rat.append(ndiv(c_e, old_e)) if not rat[-1]: return rv cdid = min(rat)
if not old_nc: ncdid = None for i in range(len(nc)): nc[i] = rejoin(*nc[i]) else: ncdid = 0 # number of nc replacements we did take = len(old_nc) # how much to look at each time limit = cdid or S.Infinity # max number that we can take failed = [] # failed terms will need subs if other terms pass i = 0 while limit and i + take <= len(nc): hit = False
# the bases must be equivalent in succession, and # the powers must be extractively compatible on the # first and last factor but equal inbetween.
rat = [] for j in range(take): if nc[i + j][0] != old_nc[j][0]: break elif j == 0: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif j == take - 1: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif nc[i + j][1] != old_nc[j][1]: break else: rat.append(1) j += 1 else: ndo = min(rat) if ndo: if take == 1: if cdid: ndo = min(cdid, ndo) nc[i] = Pow(new, ndo)*rejoin(nc[i][0], nc[i][1] - ndo*old_nc[0][1]) else: ndo = 1
# the left residual
l = rejoin(nc[i][0], nc[i][1] - ndo* old_nc[0][1])
# eliminate all middle terms
mid = new
# the right residual (which may be the same as the middle if take == 2)
ir = i + take - 1 r = (nc[ir][0], nc[ir][1] - ndo* old_nc[-1][1]) if r[1]: if i + take < len(nc): nc[i:i + take] = [l*mid, r] else: r = rejoin(*r) nc[i:i + take] = [l*mid*r] else:
# there was nothing left on the right
nc[i:i + take] = [l*mid]
limit -= ndo ncdid += ndo hit = True if not hit:
# do the subs on this failing factor
failed.append(i) i += 1 else:
if not ncdid: return rv
# although we didn't fail, certain nc terms may have # failed so we rebuild them after attempting a partial # subs on them
failed.extend(range(i, len(nc))) for i in failed: nc[i] = rejoin(*nc[i]).subs(old, new)
# rebuild the expression
if cdid is None: do = ncdid elif ncdid is None: do = cdid else: do = min(ncdid, cdid)
margs = [] for b in c: if b in old_c:
# calculate the new exponent
e = c[b] - old_c[b]*do margs.append(rejoin(b, e)) else: margs.append(rejoin(b.subs(old, new), c[b])) if cdid and not ncdid:
# in case we are replacing commutative with non-commutative, # we want the new term to come at the front just like the # rest of this routine
margs = [Pow(new, cdid)] + margs return co_residual*self2.func(*margs)*self2.func(*nc)
def _eval_nseries(self, x, n, logx): res += Order(x**n, x)
def _eval_as_leading_term(self, x):
def _eval_conjugate(self):
def _eval_transpose(self): return self.func(*[t.transpose() for t in self.args[::-1]])
def _eval_adjoint(self): return self.func(*[t.adjoint() for t in self.args[::-1]])
def _sage_(self): s = 1 for x in self.args: s *= x._sage_() return s
def as_content_primitive(self, radical=False, clear=True): """Return the tuple (R, self/R) where R is the positive Rational extracted from self.
Examples ========
>>> from sympy import sqrt >>> (-3*sqrt(2)*(2 - 2*sqrt(2))).as_content_primitive() (6, -sqrt(2)*(-sqrt(2) + 1))
See docstring of Expr.as_content_primitive for more examples. """
# don't use self._from_args here to reconstruct args # since there may be identical args now that should be combined # e.g. (2+2*x)*(3+3*x) should be (6, (1 + x)**2) not (6, (1+x)*(1+x))
def as_ordered_factors(self, order=None): """Transform an expression into an ordered list of factors.
Examples ========
>>> from sympy import sin, cos >>> from sympy.abc import x, y
>>> (2*x*y*sin(x)*cos(x)).as_ordered_factors() [2, x, y, sin(x), cos(x)]
"""
@property def _sorted_args(self): return tuple(self.as_ordered_factors())
def prod(a, start=1): """Return product of elements of a. Start with int 1 so if only ints are included then an int result is returned.
Examples ========
>>> from sympy import prod, S >>> prod(range(3)) 0 >>> type(_) is int True >>> prod([S(2), 3]) 6 >>> _.is_Integer True
You can start the product at something other than 1:
>>> prod([1, 2], 3) 6
"""
def _keep_coeff(coeff, factors, clear=True, sign=False): """Return ``coeff*factors`` unevaluated if necessary.
If ``clear`` is False, do not keep the coefficient as a factor if it can be distributed on a single factor such that one or more terms will still have integer coefficients.
If ``sign`` is True, allow a coefficient of -1 to remain factored out.
Examples ========
>>> from sympy.core.mul import _keep_coeff >>> from sympy.abc import x, y >>> from sympy import S
>>> _keep_coeff(S.Half, x + 2) (x + 2)/2 >>> _keep_coeff(S.Half, x + 2, clear=False) x/2 + 1 >>> _keep_coeff(S.Half, (x + 2)*y, clear=False) y*(x + 2)/2 >>> _keep_coeff(S(-1), x + y) -x - y >>> _keep_coeff(S(-1), x + y, sign=True) -(x + y) """
if factors.is_Number: factors, coeff = coeff, factors else: return coeff*factors else: else:
def expand_2arg(e): return _unevaluated_Add(*[c*ri for ri in r.args])
from .numbers import Rational from .power import Pow from .add import Add, _addsort, _unevaluated_Add |