My favorites | Sign in
Logo
                
New issue | Search
for
| Advanced search | Search tips
Issue 896: inconsistency and wrong result with simplifying exponentation
7 people starred this issue and may be notified of changes. Back to list
Status:  Fixed
Owner:  pearu.peterson
Closed:  Nov 18
Cc:  mattpap
Type-Defect
Priority-High
WrongResult
Milestone-Release0.6.6


Sign in to add a comment
 
Reported by pearu.peterson, Jun 22, 2008

First, from

>>> simplify((a**2)**(1+a))
a**(2 + 2*a)

follows that the result of

>>> simplify((a**2)**(a))
(a**2)**a

should be `a**(2*a)`.

However, (a**2)**a==a**(2*a) does not hold in general.
Take for example a==-1/2, then there is contradiction 2==-2.

Hence also the result of the first simplification is
wrong.
Comment 1 by ondrej.certik, Jun 22, 2008
Thanks for the spot. So it should only work for a>0, right?
Labels: -Priority-Medium Priority-High WrongResult
Comment 2 by pearu.peterson, Jun 22, 2008
The question is whether
 (expr ** n) ** a
where n is integer, should simplify to
 expr ** (n * a)
. 

This transformation is valid if a is integer (both positive and negative).
However, it is late now and I don't see why it should hold also for
positive rational numbers in general.
Comment 3 by tetaberta, Jul 13, 2008
The expression
(expr ** n) ** a
where n is integer should not simplify for general rational a, because
for example
((-1) ** 3) ** (1/3) = (-1)**(1/3)
has one real root (-1), but the principal value is given by 
In [34]: ((-1)**Rational(1,3)).evalf()
Out[34]: 0.5 + 0.866025403784439*ⅈ
therefore ((-1)**3)**(1/3) != -1

This expression can be simplified to expr**(a*b) if:
 - expr is positive; a, b are real
 - a, b are integer

it simplifies to abs(expr)**(a*b) if:
 - expr is real, a is even

Are there some other possible simplifications?
Comment 4 by ondrej.certik, Jul 13, 2008
Maybe there are, but let's just implement those two simplifications for the start.
Thanks for looking into that.
Comment 5 by fredrik.johansson, Aug 25, 2008
Very simple counterexamples with square roots:

>>> sqrt(1/x)
x**(-1/2)
>>> 1/sqrt(x)
x**(-1/2)
>>> sqrt(1/(-1))
I
>>> 1/sqrt(-1)
-I

>>> sqrt(x*y)
x**(1/2)*y**(1/2)
>>> sqrt(x)*sqrt(y)
x**(1/2)*y**(1/2)
>>> sqrt((-1)*(-2))
2**(1/2)
>>> sqrt(-1)*sqrt(-2)
-2**(1/2)
Comment 6 by ondrej.certik, Aug 25, 2008
Could anyone please try to fix it? I think this should be fixed soon.
Labels: Milestone-Release0.6.3
Comment 7 by tetaberta, Aug 26, 2008
I tried it some time ago and it caused a lot of test failures
Attached is patch with basic simplification rules.
I found quite general formula for simplification:
assume x is complex, a,b are real
then (x**a)**b == x**(a*b) if and only if
modpi(b * modpi(a * arg(x))) == modpi(a * b * arg(x))
where modpi(x) = ((x + pi) mod pi) - pi
Comment 8 by tetaberta, Aug 26, 2008
i forgot the patch
exponentiation.patch
2.9 KB   Download
Comment 9 by ondrej.certik, Aug 26, 2008
Thanks a lot, if I find time I'll look into that.
Comment 10 by tetaberta, Aug 26, 2008
I fixed some failing tests. I was mainly because tested identities hold
only for real variables, but tests were written for generic symbols.
There are still many failures in series tests. Each fixed test is
in separate patch. 
spherical.patch
885 bytes   Download
test_complexes.patch
805 bytes   Download
test_numbers.patch
624 bytes   Download
test_polynomial.patch
1.1 KB   Download
test_powsimp.patch
1.0 KB   Download
test_together2.patch
740 bytes   Download
Comment 11 by ondrej.certik, Aug 26, 2008
Thanks!

Don't worry about the series tests, we are refactoring them in the  issue 1029 .

Comment 12 by tetaberta, Aug 26, 2008
Here are two other fixes. In both of them, the problem
was, that the summation index has to be explicitly
set as integer eg

In [10]: n = Symbol('n')
In [11]: Sum((-1)**n / n, (n, 1, oo)).evalf()

fails, but
 
In [12]: n = Symbol('n', integer=True)
In [13]: Sum((-1)**n / n, (n, 1, oo)).evalf()
Out[13]: -0.693147180559945

probably the assumption should be made inside sum (issue 1047)
test_evalf.patch
742 bytes   Download
test_sums_products.patch
812 bytes   Download
Comment 13 by ondrej.certik, Aug 26, 2008
Thanks Štěpán. I just polished the series patches, sent for a review. If you want to
get these things fixed faster, please review them in the sympy-patches mailinglist.

I'll then look at this what can be done with it.

Btw, I noticed you can also use git, I've setup:

http://git.sympy.org/

but unfortunately it cannot yet be pulled over the web interface, so stay tuned. :)
Comment 14 by ondrej.certik, Aug 27, 2008
I could look at this after I finish my thesis, hopefully < 1 week.
Comment 15 by tetaberta, Aug 27, 2008
Here is one more patch. The problem is similar
to summation. The correct assumptions have to
be set before calling nseries.

Now there is only one strange failing test_heurisch_symbolic_coeffs():
It fails in the full test suite
...
sympy/integrals/tests/test_integrals.py[28] ...........................f
sympy/integrals/tests/test_risch.py[18] ..........F...ssss
sympy/integrals/tests/test_trigonometry.py[2] ..
...

but works if run separately

py.test sympy/integrals/tests/test_risch.py
...
sympy/integrals/tests/test_risch.py[18] ..............ssss

attached is also a corrected exponentiation.patch
the original contained trailing whitespaces.

BTW good luck with your thesis and dont hurry with this, thesis
is more important. I printed mine on monday.

test_nseries.patch
1.5 KB   Download
exponentiation.patch
2.9 KB   Download
Comment 16 by ondrej.certik, Aug 27, 2008
Do you think you could please create a repo at freehg.sympy.org (for example) or
github and push your patches in? I'll pull it and look if I can fix it easily.
Comment 17 by tetaberta, Aug 27, 2008
I created a repo at
http://freehg.sympy.org/u/tetaberta/sympy/
Comment 18 by ondrej.certik, Aug 27, 2008
Thanks. Here are couple more patches to make nseries work:

diff --git a/sympy/series/tests/test_nseries.py b/sympy/series/tests/test_nseries.py
--- a/sympy/series/tests/test_nseries.py
+++ b/sympy/series/tests/test_nseries.py
@@ -121,7 +121,7 @@ def testseries2():
     assert (1/(1+1/x**2)).nseries(x,0,6) == x**2-x**4+O(x**6, x)
 
 def test_bug2(): ### 1/log(0) * log(0) problem
-    w = Symbol("w")
+    w = Symbol("w", real=True, positive=True)
     e =
(w**(-1)+w**(-log(3)*log(2)**(-1)))**(-1)*(3*w**(-log(3)*log(2)**(-1))+2*w**(-1))
     e = e.expand()
     #should be 3, but is 2
@@ -164,7 +164,7 @@ def test_genexp_x():
 
 # more complicated example
 def test_genexp_x2():
-    x = Symbol("x")
+    x = Symbol("x", real=True, positive=True)
     p = Rational(3,2)
     e = (2/x+3/x**p)/(1/x+1/x**p)
     assert e.nseries(x,0,3) == 3 - sqrt(x) + x + O(sqrt(x)**3)
@@ -221,7 +221,7 @@ def test_issue159():
     assert a.nseries(x,0,6) == 1 - x/2 - x**4/720 + x**2/12 + O(x**5)
 
 def test_issue105():
-    x = Symbol("x")
+    x = Symbol("x", real=True, positive=True)
     f = sin(x**3)**Rational(1,3)
     assert f.nseries(x,0,17) == x - x**7/18 - x**13/3240 + O(x**17)
 


But I don't have time for the rest now. But surely it can be fixed, there are just
couple more failures.
Comment 19 by tetaberta, Aug 27, 2008
I've put your patch into my repository. Is the real=True necessary?
If it is positive, it must be real, doesnt it? Now all tests pass or xfail
except the test_risch
Comment 20 by ondrej.certik, Aug 27, 2008
> Is the real=True necessary?

Maybe not, didn't have time to play with it.


> Now all tests pass or xfail except the test_risch. 

Excellent.

Cc: mattpap
Comment 21 by kirill.smelkov, Aug 28, 2008
Ondrej, Stepan, what's the state of this?

Please ping me when it is ok to pull from your repo, ok?

Thanks beforehand.
Comment 22 by ondrej.certik, Aug 28, 2008
I don't have time for this now, but the state imho is that most of the tests pass,
but not all yet. Also the patches should be probably merged/polished etc. But it's on
a good way.
Comment 23 by kirill.smelkov, Aug 28, 2008
Thanks for the update, looking forward!
Comment 24 by tetaberta, Sep 07, 2008
I think some of the patches to tests above could be merged
and imported to sympy already, because they test the right behavior
and they shouldn't introduce any bugs. I'll look into that...
Comment 25 by tetaberta, Sep 24, 2008
I sent a patch for most of the tests to sympy-patches, however, new problems
appeared. With the exponentiation.patch applied some test in the galgebra
module fails

_______________________________________________________________ entrypoint:
test_noneuclidian _______________________________________________________________

    def test_noneuclidian():
        global s,c,Binv,M,S,C,alpha
        #set_main(sys.modules[__name__])
        metric = '0 # #,'+ \
                 '# 0 #,'+ \
                 '# # 1,'
        MV.setup('X Y e',metric,debug=0)
        MV.set_str_format(1)
        L = X^Y^e
        B = L*e
        Bsq = (B*B)()
        BeBr =B*e*B.rev()
        make_symbols('s c Binv M S C alpha')
        Bhat = Binv*B # Normalize translation generator
        R = c+s*Bhat # Rotor R = exp(alpha*Bhat/2)
        Z = R*X*R.rev()
        Z.expand()
        Z.collect([Binv,s,c,XdotY])
        W = Z|Y
        W.expand()
        W.collect([s*Binv])
        M = 1/Bsq
        W.subs(Binv**2,M)
        W.simplify()
        Bmag = sympy.sqrt(XdotY**2-2*XdotY*Xdote*Ydote)
        W.collect([Binv*c*s,XdotY])
        W.subs(2*XdotY**2-4*XdotY*Xdote*Ydote,2/(Binv**2))
        W.subs(2*c*s,S)
        W.subs(c**2,(C+1)/2)
        W.subs(s**2,(C-1)/2)
        W.simplify()
        W.subs(1/Binv,Bmag)
    
        W = W().expand()
        #print '(R*X*R.rev()).Y =',W
        Wd = collect(W,[C,S],exact=True,evaluate=False)
        #print 'Wd =',Wd
        Wd_1 = Wd[ONE]
        Wd_C = Wd[C]
        Wd_S = Wd[S]
        #print '|B| =',Bmag
        Wd_1 = Wd_1.subs(Bmag,1/Binv)
        Wd_C = Wd_C.subs(Bmag,1/Binv)
        Wd_S = Wd_S.subs(Bmag,1/Binv)
        #print 'Wd[ONE] =',Wd_1
        #print 'Wd[C] =',Wd_C
        #print 'Wd[S] =',Wd_S
        lhs = Wd_1+Wd_C*C
        rhs = -Wd_S*S
        lhs = lhs**2
        rhs = rhs**2
        W = (lhs-rhs).expand()
        W = (W.subs(1/Binv**2,Bmag**2)).expand()
        #print 'W =',W
        W = (W.subs(S**2,C**2-1)).expand()
        W = collect(W,[C**2,C],evaluate=False)
        #print 'W =',W
        a = W[C**2]
E       b = W[abs(C)]
>       KeyError: abs(C)

[/home/rouckas/prgm/sympy-896/sympy/galgebra/tests/test_GA.py:96]

W = {1: -2*(X.Y)*(X.e)*(Y.e) + (X.Y)**2 + (X.e)**2*(Y.e)**2, C**2: (X.e)**2*(Y.e)**2,
(C**2)**(1/2): 2*(X.Y)*(X.e)*(Y.e) - 2*(X.e)**2*(Y.e)**2}

Because C is defined as complex, the expression (C**2)**(1/2) cannot be simplified
to abs(C). Maybe C could be defined real, but I'm not sure about meaning of this
variable.

Comment 26 by tetaberta, Sep 25, 2008
If we let the C to be complex, it could be fixed with this patch.
The only remaining problem is the heurisch test:
_____________________________________________________________________________________________________________________________________________________________
_________________________________________________________ entrypoint:
test_heurisch_symbolic_coeffs _________________________________________________________

    def test_heurisch_symbolic_coeffs():
        assert heurisch(1/(x+y), x)         == log(x+y)
        assert heurisch(1/(x+sqrt(2)), x)   == log(x+sqrt(2))
        assert heurisch(1/(x**2+y), x)      == I*y**(-S.Half)*log(x + (-y)**S.Half)/2 - \
E                                              I*y**(-S.Half)*log(x - (-y)**S.Half)/2
>                                              AssertionError: (inconsistently failed
then succeeded)

[/home/rouckas/prgm/sympy-896/sympy/integrals/tests/test_risch.py:109]

galgebra.patch
863 bytes   Download
Comment 27 by ondrej.certik, Sep 25, 2008
Thanks for the work. So which patches are ready for review?
Comment 28 by tetaberta, Sep 25, 2008
I have one patch that implements the exponentiation and other one that fixes the
tests. Is it OK to submit patches that break tests if applied separately or should I
merge them? There still remains the problem with the failing heurisch test. I think
that it is quite important but I have no idea how to fix it. The functionality itself
isn't broken, it works in sympy or if the test is run separately using py.test. It
fails only if the full test suite is executed.
Comment 29 by ondrej.certik, Sep 25, 2008
It's better if the patches don't break stuff (so that hg/git bisect works nice), and
it's also good if each patch is semantically just one change. But sometimes one needs
to make compromises.

So post what you have, we'll look at it.
Comment 30 by tetaberta, Sep 25, 2008
Ok, I'll post it in ~two hours, now I have to go to some presentation as I'm
attending some conference in Hungary.
Comment 31 by tetaberta, Sep 25, 2008
Here is what I have:
The spherical.patch could be aplied without problems.
exponantiation.patch introduces 3 failing tests. Two of them (except risch) are fixed
in tests.patch.
spherical.patch
885 bytes   Download
exponentiation.patch
2.8 KB   Download
tests.patch
2.1 KB   Download
Comment 32 by tetaberta, Sep 25, 2008
I did some experiments to see what causes the risch test to fail, but the results
don't make sense to me. 
py.test sympy/core/ sympy/integrals/tests/test_risch.py OK
py.test sympy/concrete/  sympy/integrals/tests/test_risch.py OK, but
py.test sympy/concrete/ sympy/core/ sympy/integrals/tests/test_risch.py FAIL

py.test sympy/functions/ sympy/geometry/ sympy/integrals/tests/test_risch.py OK
py.test sympy/galgebra/ sympy/integrals/tests/test_risch.py OK, but
py.test sympy/functions/ sympy/galgebra/ sympy/geometry/
sympy/integrals/tests/test_risch.py FAIL

I guess it could be problem of memory management or caching?
I noticed, that similar error appeared in issue 597 
Comment 33 by tetaberta, Sep 25, 2008
I think, that in order to solve this problem with exponentiation, we could XFAIL the
risch test and start a new issue for it. What do you think about it? 
Comment 34 by Vinzent.Steinberg, Sep 27, 2008
Did you try it without caching?

If it's only one failing test, I'm +1 for XFAIL.
Status: Started
Comment 35 by tetaberta, Sep 29, 2008
It fails also with caching disabled
SYMPY_USE_CACHE=no py.test sympy/
...
sympy/integrals/tests/test_risch.py[18] ..........F...ssss
...
Comment 36 by tetaberta, Oct 12, 2008
The inconsistency in simplifying expressions of the form (x**y)**z is now
imho removed. What remains to be fixed is this:

>>> sqrt(x*y)
x**(1/2)*y**(1/2)
>>> sqrt(x)*sqrt(y)
x**(1/2)*y**(1/2)
>>> sqrt((-1)*(-2))
2**(1/2)
>>> sqrt(-1)*sqrt(-2)
-2**(1/2)

Comment 37 by ondrej.certik, Oct 17, 2008
(No comment was entered for this change.)
Labels: -Milestone-Release0.6.3 Milestone-Release0.6.4
Comment 38 by ondrej.certik, Feb 08, 2009
(No comment was entered for this change.)
Labels: -Milestone-Release0.6.4 Milestone-Release0.6.5
Comment 39 by ondrej.certik, Jul 13, 2009
(No comment was entered for this change.)
Labels: Milestone-Release0.6.6
Comment 40 by Ronan.L...@gmail.com, Nov 18, 2009
The last problems seem to have been fixed at some point.

In [1]: sqrt(x*y)
Out[1]: 
  ⎽⎽⎽⎽⎽
╲╱ x⋅y 

In [2]: sqrt(x)*sqrt(y)
Out[2]: 
  ⎽⎽⎽   ⎽⎽⎽
╲╱ x ⋅╲╱ y 

In [3]: a,b = symbols('ab', positive=True)

In [4]: sqrt(a*b)
Out[4]: 
  ⎽⎽⎽   ⎽⎽⎽
╲╱ a ⋅╲╱ b 

In [5]: sqrt(-1*-2)
Out[5]: 
  ⎽⎽⎽
╲╱ 2 

In [6]: sqrt(-1)*sqrt(-2)
Out[6]: 
   ⎽⎽⎽
-╲╱ 2 

Status: Fixed
Sign in to add a comment

Hosted by Google Code