Repository: sympy/sympy
Pull request: Fix powsimp issues #9183, #10095, and KeyError
- Fixed powsimp raising ValueError when base is float and Pow is argument of Mul. Since multiplicity expects integer or rational but powsimp doesn't checks it, it raises ValueError: fixes #9183
- Fixed Pow.as_numer_denom() returning nan when either numerator or denominator of base is 1 and exp is infinite. Since 1**oo is NaN, numerator or denominator becomes NaN: fixes #10095
- Fixed powsimp raising KeyError in common_b[b] = common_b[b] + e, when one base is Float and another is equal Rational(Integer). This seems to be caused by #11707.

~**Thing(s) to consider:** Should we automatically evaluate k**oo to zero where k is in (-1, 1), i.e., `(1/(2*E))**oo`?~

Problem statement:
simplify throws unexpected ValueError
The following error was unexpected for me and I could not find anything about it in the docs so I thought I'd report it. Hope it helps.

kind regards,
Jesse

this works fine:

> > > a=sympy.sympify('0.12**d+43') - sympy.sympify('0.12*d+43')
> > > a.simplify()
> > > 0.12**d - 0.12*d

however, the reverse throws an exception:

> > > a=sympy.sympify('0.12_d+43') - sympy.sympify('0.12__d+43')
> > > a
> > > -0.12__d + 0.12_d
> > > a.simplify()
> > > Traceback (most recent call last):
> > >   File "<interactive input>", line 1, in <module>
> > >   File "C:\Python34\lib\site-packages\sympy\core\expr.py", line 2922, in simplify
> > >     return simplify(self, ratio, measure)
> > >   File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 3684, in simplify
> > >     expr = Mul(_powsimp(expr).as_content_primitive())
> > >   File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2549, in powsimp
> > >     expr = expr.func(_[recurse(w) for w in expr.args])
> > >   File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2549, in <listcomp>
> > >     expr = expr.func(*[recurse(w) for w in expr.args])
> > >   File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2540, in recurse
> > >     return powsimp(arg, _deep, _combine, _force, _measure)
> > >   File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2597, in powsimp
> > >     m = multiplicity(abs(b), abs(coeff))
> > >   File "C:\Python34\lib\site-packages\sympy\ntheory\factor_.py", line 230, in multiplicity
> > >     raise ValueError('expecting ints or fractions, got %s and %s' % (p, n))
> > > ValueError: expecting ints or fractions, got 0.120000000000000 and 1


simplify((1/(2*E))**oo) returns `nan`
```
>>> (1/(2*E))**oo
(1/(2*E))**oo
>>> simplify((1/(2*E))**oo)
nan
>>> powsimp((1/(2*E))**oo)
(1/(2*E))**oo
```

Hints from issue discussion:
sorry, I'm new to github. I don't see the asterisks in my above code anymore (why?), but I really did type in 0.12 asterisk d and 0.12 asterisk asterisk d 

Please read more about [markdown](https://guides.github.com/features/mastering-markdown/).

Enclosing the text in triple backticks ("annotate as code") should do the trick.

Works:

```
>>> a=sympy.sympify('0.12**d+43') - sympy.sympify('0.12*d+43')
>>> a.simplify()
0.12**d - 0.12*d
```

Fails:

```
>>> a=sympy.sympify('0.12*d+43') - sympy.sympify('0.12**d+43')
>>> a
-0.12**d + 0.12*d
>>> a.simplify()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "C:\Python34\lib\site-packages\sympy\core\expr.py", line 2922, in simplify
    return simplify(self, ratio, measure)
  File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 3684, in simplify
    expr = Mul(*powsimp(expr).as_content_primitive())
  File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2549, in powsimp
    expr = expr.func(*[recurse(w) for w in expr.args])
  File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2549, in <listcomp>
    expr = expr.func(*[recurse(w) for w in expr.args])
  File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2540, in recurse
    return powsimp(arg, _deep, _combine, _force, _measure)
  File "C:\Python34\lib\site-packages\sympy\simplify\simplify.py", line 2597, in powsimp
    m = multiplicity(abs(b), abs(coeff))
  File "C:\Python34\lib\site-packages\sympy\ntheory\factor_.py", line 230, in multiplicity
    raise ValueError('expecting ints or fractions, got %s and %s' % (p, n))
ValueError: expecting ints or fractions, got 0.120000000000000 and 1
```

I am having a related issue I believe, however I am not sure this is supposed to be supported yet or not, or if I am doing something wrong. I deeply appreciate any input on this. If I try to integrate without symbols (using values for the interval) the computation is performed.

``` python

X1 = Normal('X1',50, 28.3)
X2 = Normal('X2',50, 28.3)
x1 = Symbol('x1')
x2 = Symbol('x2')
f = density(X1)(x1)*density(X2)(x2)

s = Symbol('s')
Q = Symbol('Q')

integrate(f, (x1, s+Q-50, +oo), (x2, Q, +oo))
```

The traceback:

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/sympy/utilities/decorator.py", line 35, in threaded_func
    return func(expr, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 1232, in integrate
    risch=risch, manual=manual)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 487, in doit
    conds=conds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 760, in _eval_integral
    return result + i.doit(risch=False)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 487, in doit
    conds=conds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 876, in _eval_integral
    h = meijerint_indefinite(g, x)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/meijerint.py", line 1596, in meijerint_indefinite
    res = _meijerint_indefinite_1(f.subs(x, x + a), x)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/meijerint.py", line 1611, in _meijerint_indefinite_1
    gs = _rewrite1(f, x)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/meijerint.py", line 1548, in _rewrite1
    g = _rewrite_single(g, x, recursive)
  File "/usr/local/lib/python2.7/site-packages/sympy/core/cache.py", line 93, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sympy/core/compatibility.py", line 872, in wrapper
    result = user_function(*args, **kwds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/meijerint.py", line 1503, in _rewrite_single
    simplify=False, needeval=True)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 353, in mellin_transform
    return MellinTransform(f, x, s).doit(**hints)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 129, in doit
    for x in fn.args]
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 118, in doit
    self.function_variable, self.transform_variable, **hints)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 295, in _compute_transform
    return _mellin_transform(f, x, s, **hints)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 196, in wrapper
    res = func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/transforms.py", line 220, in _mellin_transform
    F = integrator(x**(s - 1) * f, x)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/meijerint.py", line 1497, in my_integrator
    res = _my_unpolarify(hyperexpand(res, rewrite='nonrepsmall'))
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/hyperexpand.py", line 2482, in hyperexpand
    return f.replace(hyper, do_replace).replace(meijerg, do_meijer)
  File "/usr/local/lib/python2.7/site-packages/sympy/core/basic.py", line 1351, in replace
    rv = bottom_up(self, rec_replace, atoms=True)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 4079, in bottom_up
    for a in rv.args])
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 4082, in bottom_up
    rv = F(rv)
  File "/usr/local/lib/python2.7/site-packages/sympy/core/basic.py", line 1336, in rec_replace
    new = _value(expr, result)
  File "/usr/local/lib/python2.7/site-packages/sympy/core/basic.py", line 1280, in <lambda>
    _value = lambda expr, result: value(*expr.args)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/hyperexpand.py", line 2479, in do_meijer
    allow_hyper, rewrite=rewrite)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/hyperexpand.py", line 2378, in _meijergexpand
    slater2 = powdenest(slater2.subs(t, 1/z0), polar=True)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 2443, in powdenest
    return unpolarify(powdenest(unpolarify(eq, exponents_only=True)), rep)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 2445, in powdenest
    new = powsimp(sympify(eq))
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 2550, in powsimp
    expr = expr.func(*[recurse(w) for w in expr.args])
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 2541, in recurse
    return powsimp(arg, _deep, _combine, _force, _measure)
  File "/usr/local/lib/python2.7/site-packages/sympy/simplify/simplify.py", line 2601, in powsimp
    m = multiplicity(abs(b), abs(coeff))
  File "/usr/local/lib/python2.7/site-packages/sympy/ntheory/factor_.py", line 231, in multiplicity
    raise ValueError('expecting ints or fractions, got %s and %s' % (p, n))
ValueError: expecting ints or fractions, got 1.56076365043889 and 2
```

As the integrand is a product, the integral can be computed by multiplying two independent integrals. (There is only limited support for multidimensional integrals.)

```
integrate(density(X1)(x1), (x1, s + Q - 50, oo))*integrate(density(X2)(x2), (x2, Q, oo))
```

Thanks for the reply jksuom. The thing is that they are not independent (I realise now that in the example they are, I was following a buggy article), but what I need to do is actually:

`integrate(f, (x1, s+Q-x2, +oo), (x2, Q, +oo))`

So the inner integral depends on the outer. This actually gives a different error:

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/sympy/utilities/decorator.py", line 35, in threaded_func
    return func(expr, *args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 1232, in integrate
    risch=risch, manual=manual)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 487, in doit
    conds=conds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/integrals.py", line 849, in _eval_integral
    h, i = risch_integrate(g, x, separate_integral=True, conds=conds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/risch.py", line 1678, in risch_integrate
    ans, i, b = integrate_hyperexponential(fa, fd, DE, conds=conds)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/risch.py", line 1408, in integrate_hyperexponential
    g1, h, r = hermite_reduce(a, d, DE)
  File "/usr/local/lib/python2.7/site-packages/sympy/integrals/risch.py", line 997, in hermite_reduce
    q, r = a.div(d)
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/polytools.py", line 1529, in div
    dom, per, F, G = f._unify(g)
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/polytools.py", line 358, in _unify
    dom, lev = f.rep.dom.unify(g.rep.dom, gens), len(gens) - 1
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/domains/domain.py", line 250, in unify
    return K0.unify_with_symbols(K1, symbols)
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/domains/domain.py", line 230, in unify_with_symbols
    return K0.unify(K1)
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/domains/domain.py", line 274, in unify
    domain = domain.get_ring()
  File "/usr/local/lib/python2.7/site-packages/sympy/polys/domains/realfield.py", line 106, in get_ring
    raise DomainError('there is no ring associated with %s' % self)
sympy.polys.polyerrors.DomainError: there is no ring associated with RR
```

Should I start a discussion in the googlegroups forum?

The cause of this DomainError is 28.3. Python will automatically transform it to a floating point number and some integrators in SymPy cannot deal with floats. The error does not appear if the rational number `S(283)/10` is used instead. Unfortunately, this does not help to compute the integral. It appears currently too hard for SymPy.

I see what you mean. I tried to use an integer instead, and I've been waiting for the result for half an hour (I am guessing it will throw an error sooner or later, or I'll just have to kill it). 
For this specific case, I was trying to build an expression (which has that integral) that will be derived wrt s and Q iteratively. I know it is a rather complex task. In order to solve it manually we use a Taylor series approximation. Can I do this with sympy?

I just got the same `sympy.polys.polyerrors.DomainError: there is no ring associated with RR` error when trying the following

``` py
from sympy import symbols, integrate, exp, nsimplify
a, b, c, d, f, g, z = symbols('a, b, c, d, f, g, z', real=True)
src = a*exp((1/2)*b**(-2)*(-c + d)**2 - (-(1/2)*f + (1/2)*z)/g)
int_src = integrate(src, (z, 0, 1)) 
```

Although rewriting to 

``` py
src = exp((1/2)*b**(-2)*(-c + d)**2 - (-(1/2)*f + (1/2)*z)/g)
```

did not throw the error. Also

``` py
from sympy import nsimplify
src = nsimplify(src)
```

made it work (as suggested by @jksuom).

> some integrators in SymPy cannot deal with floats

Is there any plans to make this happen? I guess this very bug could be the cause of major frustrations for many users (at least it did for me).

The basic issue here appears to be in `powsimp()`:

```python
>>> sympy.sympify('0.1*d-0.1**d').powsimp()
ValueError                                Traceback (most recent call last)
   ...
ValueError: expecting ints or fractions, got 0.100000000000000 and 1
```

This is really frustrating as there is no clear path on how to prevent this when simplifying complex expressions.
This works,

```
>>> limit((1/(2*E))**x, x, oo)
0
```

@asmeurer was the automatic simplification of `1/(2*E)**oo`  is not done. Is that so because that makes the `core` slow? Or is that a bug?

```
>>> from sympy import *
>>> (1/(2*E))**oo
(exp(-1)/2)**oo
>>> simplify((exp(-1)/2)**oo)
nan
```

So, I don't think that it is a bug.. Perhaps you should calculate the limit instead.

Commit message: Fix powsimp raising KeyError when base has Float

Fixed powsimp raising KeyError in common_b[b] = common_b[b] + e, when
one base has Float and another has its Rational(Integer) counterpart.
This seems to be caused by sympy/sympy#11707.

Patch to review:
diff --git a/sympy/core/power.py b/sympy/core/power.py
index 82bc545f3307..2c31134dc460 100644
--- a/sympy/core/power.py
+++ b/sympy/core/power.py
@@ -1174,6 +1174,11 @@ def as_numer_denom(self):
         if neg_exp:
             n, d = d, n
             exp = -exp
+        if exp.is_infinite:
+            if n is S.One and d is not S.One:
+                return n, self.func(d, exp)
+            if n is not S.One and d is S.One:
+                return self.func(n, exp), d
         return self.func(n, exp), self.func(d, exp)
 
     def matches(self, expr, repl_dict={}, old=False):
diff --git a/sympy/simplify/powsimp.py b/sympy/simplify/powsimp.py
index 3cf646ca4dd7..8367dca7eb8b 100644
--- a/sympy/simplify/powsimp.py
+++ b/sympy/simplify/powsimp.py
@@ -163,9 +163,9 @@ def recurse(arg, **kwargs):
             # 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_Number and not all(ei.is_Number for ei in e) and \
-                    coeff is not S.One and
-                    b not in (S.One, S.NegativeOne)):
+            if (b and b.is_Number 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)
@@ -276,7 +276,7 @@ def update(b):
         bases = []
         for b, e in c_powers:
             b, e = bkey(b, e)
-            if b in common_b.keys():
+            if b in common_b:
                 common_b[b] = common_b[b] + e
             else:
                 common_b[b] = e
diff --git a/sympy/simplify/tests/test_powsimp.py b/sympy/simplify/tests/test_powsimp.py
index 8c80867ddfb6..6a41c23637bf 100644
--- a/sympy/simplify/tests/test_powsimp.py
+++ b/sympy/simplify/tests/test_powsimp.py
@@ -1,7 +1,7 @@
 from sympy import (
     symbols, powsimp, symbols, MatrixSymbol, sqrt, pi, Mul, gamma, Function,
     S, I, exp, simplify, sin, E, log, hyper, Symbol, Dummy, powdenest, root,
-    Rational)
+    Rational, oo)
 
 from sympy.abc import x, y, z, t, a, b, c, d, e, f, g, h, i, k
 
@@ -98,6 +98,16 @@ def test_powsimp():
     # issue 8836
     assert str( powsimp(exp(I*pi/3)*root(-1,3)) ) == '(-1)**(2/3)'
 
+    # issue 9183
+    assert powsimp(-0.1**x) == -0.1**x
+
+    # issue 10095
+    assert powsimp((1/(2*E))**oo) == (exp(-1)/2)**oo
+
+    # PR 13131
+    eq = sin(2*x)**2*sin(2.0*x)**2
+    assert powsimp(eq) == eq
+
 
 def test_powsimp_negated_base():
     assert powsimp((-x + y)/sqrt(x - y)) == -sqrt(x - y)


Code review comments:
diff_hunk: @@ -163,9 +163,9 @@ def recurse(arg, **kwargs):
             # 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_Number and not all(ei.is_Number for ei in e) and \
-                    coeff is not S.One and
-                    b not in (S.One, S.NegativeOne)):
+            if (b and b.is_Number and b.is_rational and not all(
path: sympy/simplify/powsimp.py
text: @user1:
If you need an actual rational number you should use is_Rational or isinstance(b, Rational). is_rational will also be True for things like `Symbol('x', rational=True)`.