why sympy count_ops() fail on this result from integration? - sympy

I use sympy's count_opt as a way to estimate size (leaf count) of antiderivative returned by integrate.
http://docs.sympy.org/latest/modules/core.html
I found it fails on some expressions. This is using sympy 1.1.1 on
Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56)
[GCC 7.2.0] on linux
Here is an example
from sympy import *
x,n,a = symbols('x n a')
integrand = x**n*log(a*x)
anti= integrate(integrand,x)
count_ops(anti)
and now
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/anaconda/lib/python3.6/site-packages/sympy/core/function.py",
line 2473, in count_ops
if a.is_Rational:
AttributeError: 'NoneType' object has no attribute 'is_Rational'
Something about this result it does not like
>>> anti
Piecewise((None, Eq(n, -1)), (n*x*x**n*log(a)/(n**2 + 2*n + 1) +
n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(a)/(n**2 + 2*n + 1) +
x*x**n*log(x)/(n**2 + 2*n + 1) - x*x**n/(n**2 + 2*n + 1), True))
Is this a known issue? Why does it happen? Is this a bug? Should I report it? How?
The above is on linux Manjaro 17.1 XFCE

The function count_ops does not expect to see None, which sometimes appears in a Piecewise object. I'd say this is a bug. It was already reported on SymPy issue tracker.
A workaround is to pass conds='none' to integrate, which will cause it to ignore the special case n=-1 and return a single expression,
n*x*x**n*log(a)/(n**2 + 2*n + 1) + n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(a)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - x*x**n/(n**2 + 2*n + 1)
Then count_ops works correctly.
anti = integrate(integrand, x, conds='none')
count_ops(anti) # 49

Related

Sympy solve cannot find real solution when solving first and substituting later

I have a system of two equations that calculate the coordinates of two points T1(u1,v1) and T2(u2,v2), where lines starting from point A to those points are tangent with a given circle. Point A is always outside of the circle, so there should always be two solutions.
The system of equations is given as follows:
eq1 = Eq((xpos-u)**2 + (ypos-v)**2, tglensq)
eq2 = Eq((oxpos-u)**2 + (oypos-v)**2, radsq)
where xpos,ypos are coordinates of A, and oxpos, oypos are coordinates of the center of the circle. tglensq represents the length of the tangent squared, and radsq the radius of the circle squared.
The solutions need to be calculated continuously in a loop.
I want to solve the equation first for u and v, and then plugin the other values (as described here). Solving for each iteration of the loop turns out to be quite expensive, although it always produces the two solutions.
After getting the solution, in the loop I substitute the other values, like so:
u1 = first_solution[0].subs([(xpos, robot_pos[0]), (ypos, robot_pos[1]), (oxpos, obstacle_pos[0]), (oypos, obstacle_pos[1]), (tglensq, tangent_len_squared), (minkradsq, minkowski_radius_sq)])
However, sympy fails to find the real solutions, and ends up giving imaginary ones, like:
628644.458063364 - 3693.82126269719*I
I saw here a similar issue about solving first then substituting, but I am not sure how to proceed from here. Any help would be greatly appreciated :).
Does defining the location of one circle relative to the other help? Let dx,dy = Point(oxpos,oypos)-Point(xpos,ypos) so the equations are
>>> dx,dy = symbols('dx,dy') # and your other symbols
>>> eq1,eq2 = Eq((u)**2 + (v)**2, tglensq),Eq((dx-u)**2 + (dy-v)**2, radsq)
>>> sol=solve((eq1,eq2), (u,v))
>>> sol[0]
(-(-dx**2 - dy**2 + 2*dy*(-dx*sqrt(-dx**4 - 2*dx**2*dy**2 + 2*dx**2*radsq + 2*dx**2*tglensq - dy**4 + 2*dy**2*radsq + 2*dy**2*tglensq - radsq**2 + 2*radsq*tglensq - tglensq**2)/(2*(dx**2 + dy**2)) + dy*(dx**2 + dy**2 - radsq + tglensq)/(2*(dx**2 + dy**2))) + radsq - tglensq)/(2*dx), -dx*sqrt(-dx**4 - 2*dx**2*dy**2 + 2*dx**2*radsq + 2*dx**2*tglensq - dy**4 + 2*dy**2*radsq + 2*dy**2*tglensq - radsq**2 + 2*radsq*tglensq - tglensq**2)/(2*(dx**2 + dy**2)) + dy*(dx**2 + dy**2 - radsq + tglensq)/(2*(dx**2 + dy**2)))
>>> sol[1]
(-(-dx**2 - dy**2 + 2*dy*(dx*sqrt(-dx**4 - 2*dx**2*dy**2 + 2*dx**2*radsq + 2*dx**2*tglensq - dy**4 + 2*dy**2*radsq + 2*dy**2*tglensq - radsq**2 + 2*radsq*tglensq - tglensq**2)/(2*(dx**2 + dy**2)) + dy*(dx**2 + dy**2 - radsq + tglensq)/(2*(dx**2 + dy**2))) + radsq - tglensq)/(2*dx), dx*sqrt(-dx**4 - 2*dx**2*dy**2 + 2*dx**2*radsq + 2*dx**2*tglensq - dy**4 + 2*dy**2*radsq + 2*dy**2*tglensq - radsq**2 + 2*radsq*tglensq - tglensq**2)/(2*(dx**2 + dy**2)) + dy*(dx**2 + dy**2 - radsq + tglensq)/(2*(dx**2 + dy**2)))
To calculate u,v try
>>> dif = (Point(oxpos,oypos)-Point(xpos,ypos)).subs(dict(zip((xpos,ypos,oxpos,oypos),(1,2,3,4))))
>>> Tuple(*sol).subs(dict(zip((tglensq,radsq),(5,6)))).subs(dict(zip((dx,dy),dif)))
Replace 1,2,3,4,5,6 with the actual values. Does that give you two real solutions?

general expression substitution in sympy

I have two univariate functions, f(x) and g(x), and I'd like to substitute g(x) = y to rewrite f(x) as some f2(y).
Here is a simple example that works:
In [240]: x = Symbol('x')
In [241]: y = Symbol('y')
In [242]: f = abs(x)**2 + 6*abs(x) + 5
In [243]: g = abs(x)
In [244]: f.subs({g: y})
Out[244]: y**2 + 6*y + 5
But now, if I try a slightly more complex example, it fails:
In [245]: h = abs(x) + 1
In [246]: f.subs({h: y})
Out[246]: Abs(x)**2 + 6*Abs(x) + 5
Is there a general approach that works for this problem?
The expression abs(x)**2 + 6*abs(x) + 5 does not actually contain abs(x) + 1 anywhere, so there is nothing to substitute for.
One can imagine changing it to abs(x)**2 + 5*(abs(x) + 1) + abs(x), with the substitution result being abs(x)**2 + 5*y + abs(x). Or maybe changing it to abs(x)**2 + 6*(abs(x) + 1) - 1, with the result being abs(x)**2 + 6*y - 1. There are other choices too. What should the result be?
There is no general approach to this task because it's not a well-defined task to begin with.
In contrast, the substitution f.subs(abs(x), y-1) is a clear instruction to replace all occurrences of abs(x) in the expression tree with y-1. It returns 6*y + (y - 1)**2 - 1.
The substitution above of abs(x) + 1 in abs(x)**2 + 6*abs(x) + 5 is a clear instruction too: to find exact occurrences of the expression abs(x) + 1 in the syntax tree of the expression abs(x)**2 + 6*abs(x) + 5, and replace those subtrees with the syntax tree of the expression abs(x) + 1. There is a caveat about heuristics though.
Aside: in addition to subs SymPy has a method .replace which supports wildcards, but I don't expect it to help here. In my experience, it is overeager to replace:
>>> a = Wild('a')
>>> b = Wild('b')
>>> f.replace(a*(abs(x) + 1) + b, a*y + b)
5*y/(Abs(x) + 1) + 6*y*Abs(x*y)/(Abs(x) + 1)**2 + (Abs(x*y)/(Abs(x) + 1))**(2*y/(Abs(x) + 1))
Eliminate a variable
There is no "eliminate" in SymPy. One can attempt to emulate it with solve by introducing another variable, e.g.,
fn = Symbol('fn')
solve([Eq(fn, f), Eq(abs(x) + 1, y)], [fn, x])
which attempts to solve for "fn" and "x", and therefore the solution for "fn" is an expression without x. If this works
In fact, it does not work with abs(); solving for something that sits inside an absolute value is not implemented in SymPy. Here is a workaround.
fn, ax = symbols('fn ax')
solve([Eq(fn, f.subs(abs(x), ax)), Eq(ax + 1, y)], [fn, ax])
This outputs [(y*(y + 4), y - 1)] where the first term is what you want; a solution for fn.

How to handle exceptions raised from sympy integrate

I am starting to learn sympy. I tried one integration problem using sympy, and I get this exception:
File "/home/me/anaconda3/lib/python3.6/site-
packages/sympy/polys/domains/domain.py",
line 146,
in convert raise CoercionFailed("can't convert %s of type %s to %s" %
(element, type(element), self))
sympy.polys.polyerrors.CoercionFailed: can't convert (_x4*a + a)**0.5 of
type
<class 'sympy.core.power.Pow'> to RR(a,f,n,A,B)
[_A0,_A1,_A2,_A3,_A4,_A5,_A6,_A7,_A8,_A9,_A10,_A11,
_A12,_A13,_A14,_A15,_A16,_A17
...
raise ValueError("expected an expression convertible to a polynomial in %s,
got %s" % (self, expr))
ValueError: expected an expression convertible to a polynomial in
Polynomial ring in
The full message is very long. There is a good chance I am doing something wrong? as I just started learning sympy. This is the code I used
from sympy import *
import traceback
import logging
logging.basicConfig(filename='sympy_err.log')
x, A, B, f, e, c, d, a, b, n = symbols('x A B f e c d a b n', real=True)
try:
integrate((d*sin(f*x+e))**n*(a+a*sin(f*x+e))**(5/2)*(A+B*sin(f*x+e)),x)
except Exception as e:
logging.error(traceback.format_exc())
The expected antiderivative is
-((2*a^3*(2*B*(115 + 203*n + 104*n^2 + 16*n^3) + A*
(301 + 478*n + 224*n^2 + 32*n^3))*
Cos[e + f*x]*Hypergeometric2F1[1/2, -n, 3/2, 1 - Sin[e + f*x]]*
(d*Sin[e + f*x])^n)/
Sin[e + f*x]^n/(f*(3 + 2*n)*(5 + 2*n)*(7 + 2*n)*
Sqrt[a + a*Sin[e + f*x]])) -
(2*a^3*(2*B*(35 + 23*n + 4*n^2) + A*(77 + 50*n + 8*n^2))*
Cos[e + f*x]*
(d*Sin[e + f*x])^(1 + n))/(d*f*(3 + 2*n)*(5 + 2*n)*(7 + 2*n)*
Sqrt[a + a*Sin[e + f*x]]) -
(2*a^2*(2*B*(5 + n) + A*(7 + 2*n))*Cos[e + f*x]*
(d*Sin[e + f*x])^(1 + n)*
Sqrt[a + a*Sin[e + f*x]])/(d*f*(5 + 2*n)*
(7 + 2*n)) - (2*a*B*Cos[e + f*x]*(d*Sin[e + f*x])^(1 + n)*
(a + a*Sin[e + f*x])^(3/2))/(d*f*(7 + 2*n))
My question is: Is the way I am catching exceptions from sympy above OK? Since I do not know what exceptions will be raied. And is this something to be expected if sympy unable to solve an integral, to throw an exception?
I am using Linux, just installed latest Anaconda 64bit on Linux.
code>conda list sympy
# packages in environment at /home/me/anaconda3:
#
sympy 1.0 py36_0
The exception you're seeing should be considered a bug in SymPy.
But note that the 5/2 in the expression is being evaluated to a floating point number by Python, which makes SymPy have a harder time with it. It is usually a good idea to use rational powers in SymPy instead of floating point ones. So the right version would be integrate((d*sin(f*x+e))**n*(a+a*sin(f*x+e))**Rational(5, 2)*(A+B*sin(f*x+e)),x). However, SymPy currently hangs on this integral (don't bother letting it finish; it won't find the answer).
So the short of it is: the exception you're seeing is a bug, and SymPy can't compute the integral currently anyway.

Solving ODE equation with assumptions with SymPy

I'm solving an ODE equation:
from sympy import *
E5 = Function('E5')
t = Symbol('t')
ode = Eq(Derivative(E5(t), t),
-3*E5(t)/(-10*sqrt(6) + 30)
+ sqrt(6)*E5(t)/(-10*sqrt(6) + 30)
- 67*sqrt(2)*exp(-sqrt(3)*t/10)/(200*(-sqrt(6) + 3))
+ sqrt(3)*exp(-sqrt(3)*t/10)/(10*(-sqrt(6) + 3))
+ 47*sqrt(2)*exp(-sqrt(2)*t/10)/(200*(-sqrt(6) + 3)))
dsolve(ode)
and it works (after waiting few minutes), but fails once I replace Function('E5') with Function('E5', real=True) or Symbol('t') with Symbol('t', real=True). Namely dsolve(ode) raises TypeError("eq should be an instance of Equality"). This is because dsolve(ode, simplify=False) returns False instead of an Equation. And the latter I don't know why. Is it impossible to use dsolve with assumptions? I need them because they let me symplify expressions and otherwise my expressions get too complicated and take too long to calculate.
Do you have any ideas why this could be happening?

Simplify algebraic equation in CAS

I want to be able to simplify the ellipse equation:
sqrt((x + c)^2 + y^2) + sqrt((x - c)^2 + y^2) = 2a
into its canonical form:
x^2/a^2 + y^2/(a^2 - c^2) = 1
using CAS. I actually want to know how to do that in sympy, but any other CAS will do.
If it is not possible to do that in one call, then may be by transforming the original equation using operations like "get square of the both sides; move non-radicals (e.g. by enumerating them manually) to the right side; get square of the both sides again; simplify"
unrad will do most of the heavy lifting for you in SymPy:
>>> l # your original expression with the 2a subtracted from the lhs
-2*a + sqrt(y**2 + (-c + x)**2) + sqrt(y**2 + (c + x)**2)
>>> unrad(_)
(-a**4 + a**2*c**2 + a**2*x**2 + a**2*y**2 - c**2*x**2, [], [])
>>> neg_i, dep = _[0].as_independent(x,y)
>>> xpart, ypart = [dep.coeff(i**2) for i in (x,y)]
>>> Eq(-x**2*cancel(xpart/neg_i)-y**2*cancel(ypart/neg_i), neg_i/neg_i)
y**2/(a**2 - c**2) + x**2/a**2 == 1
Subtract the doubled second sqrt from both sides.
Multiply respective sides of the new equation and the original one.
Reduce LHS applying (m+n)(m-n) = m^2 - n^2.
You'll get (if i did it right): -4xc = 4a(a - sqrt(something))
Then: -xc/a = a - sqrt(something)
and: sqrt(something) = a + xc/a
Square both sides and see what happens.
I did it wrong. Should be: 4xc = 4a(a - sqrt(something))
so sqrt(something) = a - xc/a.