Collecting rationals with sympy collect_const - sympy

Sympy (ver. 1.1.1) documentation of collect_const says that using the Numbers=False option, "no Float or Rational will be collected". This makes you think that rationals are normally collected by collect_const, but they don't seem to be:
>>> from sympy import *
>>> x, y, z = symbols('x y z')
>>> collect_const(2*x - 2*y - 2*z, 2)
2*(x - y - z)
>>> collect_const(x/2 - y/2 - z/2, 1/2)
x/2 - y/2 - z/2
Am I missing something?
Thank in advance.

I think is a little bug. The argument Numbers doesn't seem to work well with the arithmetic operator "/". From your example:
>>> from sympy import *
>>> x, y, z = symbols('x y z')
>>> collect_const(x/2 - y/2 - z/2, 1/2, Numbers=False)
x/2 - y/2 - z/2
>>> collect_const(x/2 - y/2 - z/2, 1/2, Numbers=True)
x/2 - y/2 - z/2
It doesn't seem to affect the expression. However, if we change "/2" for ".5*" the result is quite different:
>>> collect_const(.5*x - .5*y - .5*z, 1/2, Numbers=False)
.5*x - .5*y - .5*z
>>> collect_const(.5*x - .5*y - .5*z, 1/2, Numbers=True)
.5*(x - y - z)
Anyway, I've created an Issue on Github.

Related

Sympy can't solve inequality with radicals

I need to solve this inequality:
enter image description here
import sympy as sp
from sympy.abc import x,n
epsilon = 0.01
a = 2/3
xn = (n**3 + n**2)**(1/3) - (n**3 - n**2)**(1/3)
i tried to solve it like this:
ans = sp.solve_univariate_inequality(sp.Abs(xn-a) < epsilon,n,relational=False)
but received:
NotImplementedError: The inequality, Abs((x3 -
x2)0.333333333333333 - (x3 + x**2)**0.333333333333333 + 2/3) <
0.01, cannot be solved using solve_univariate_inequality.
And tried so, but it didn't work
ans = sp.solve_poly_inequality(sp.Poly(xn-2/3-0.01, n, domain='ZZ'), '==')
but received:
sympy.polys.polyerrors.PolynomialError: (n3 +
n2)**0.333333333333333 contains an element of the set of generators.
Same:
ans = sp.solveset(sp.Abs(xn-2/3) < 0.01, n)
ConditionSet(n, Abs((n3 - n2)0.333333333333333 - (n3 +
n**2)**0.333333333333333 + 0.666666666666667) < 0.01, Complexes)
How can this inequality be solved?
from sympy import *
from sympy.abc import x,n
a = S(2) / 3
epsilon = 0.01
xn = (n**3 + n**2)**(S(1)/3) - (n**3 - n**2)**(S(1)/3)
ineq = Abs(xn-a) < epsilon
Let's verify where ineq is satisfied with plot_implicit. Note that the left hand side of the inequality is valid only for n>=1.
plot_implicit(ineq, (n, 0, 5), adaptive=False)
So, the inequality is satisfied for values of n greater than 3.something.
We can use a numerical approach to find the root of this equation: Abs(xn-a) - epsilon.
from scipy.optimize import bisect
func = lambdify([n], Abs(xn-a) - epsilon)
bisect(func, 1, 5)
# out: 3.5833149415284424

Sympy cannot compute integrate(sec(x+1)**2, x)

I find it strange that sympy cannot evaluate integrate(sec(x+1)**2, x) when it can evaluate integrate(sec(x)**2, x). I've restricted the domain of x just in case and I still can't evaluate the integral of `sec(x+1)**2.
x, y, z = symbols('x, y, z', real=True, positive=True)
Why does sympy struggle with this?
This is arguably a bug in SymPy but you can work around by rewriting sec:
>>> integrate(sec(x+1)**2, x)
Integral(sec(x + 1)**2, x)
>>> _.rewrite(cos) # sin or tan works too
Integral(cos(x + 1)**(-2), x)
>>> _.doit()
-2*tan(x/2 + 1/2)/(tan(x/2 + 1/2)**2 - 1)
>>> simplify(_)
tan(x + 1)

How to make sympy simplify a radical expression equaling zero

The three (real) roots of the polynomial x^3 - 3x + 1 sum up to 0. But sympy does not seem to be able to simplify this sum of roots:
>>> from sympy import *
>>> from sympy.abc import x
>>> rr = real_roots(x**3 -3*x + 1)
>>> sum(rr)
CRootOf(x**3 - 3*x + 1, 0) + CRootOf(x**3 - 3*x + 1, 1) + CRootOf(x**3 - 3*x + 1, 2)
The functions simplify and radsimp cannot simplify this expression. The minimal polynomial, however, is computed correctly:
>>> minimal_polymial(sum(rr))
_x
From this we can conclude that the sum is 0. Is there a direct way of making sympy simplify this sum of roots?
The following function computes the rational number equal to an algebraic term if possible:
import sympy as sp
# try to simplify an algebraic term to a rational number
def try_simplify_to_rational(expr):
try:
float(expr) # does the expression evaluate to a real number?
minPoly = sp.poly(sp.minimal_polynomial(expr))
print('minimal polynomial:', minPoly)
if len(minPoly.monoms()) == 1: # minPoly == x
return 0
if minPoly.degree() == 1: # minPoly == a*x + b
a,b = minPoly.coeffs()
return sp.Rational(-b, a)
except TypeError:
pass # expression does not evaluate to a real number
except sp.polys.polyerrors.NotAlgebraic:
pass # expression does not evaluate to an algebraic number
except Exception as exc:
print("unexpected exception:", str(exc))
print('simplification to rational number not successful')
return expr # simplification not successful
See the working example:
x = sp.symbols('x')
rr = sp.real_roots(x**3 - 3*x + 1)
# sum of roots equals (-1)*coefficient of x^2, here 0
print(sp.simplify(sum(rr)))
print(try_simplify_to_rational(sum(rr))) # -> 0
A more elaborate function computing also simple radical expressions is proposed in sympy issue #19726.

rotating coordinate systems sympy

I'm a complete beginner with sympy, so it may be I'm overlooking something basic. I would like to rotate my coordinate system so I can build a hyperbola in standard position and then transform it to the arbitrary case. First I set up my equation:
> x, y, a, b, theta = symbols('x y a b theta')
> f = Eq(x ** 2/a ** 2 - y ** 2/b ** 2, 1)
> f1 = f.subs({a: 5, b: 10})
> f1
> x**2/25 - y**2/100 == 1
Next I want to rotate it, which I try to do by using a sub:
> f1.subs({x: x*cos(theta) - y*sin(theta), y: x*sin(theta) + y*cos(theta)})
> -(x*sin(theta) + y*cos(theta))**2/100 + (x*cos(theta) - (x*sin(theta) + y*cos(theta))*sin(theta))**2/25 == 1
But that doesn't work because apparently the substitution for x is made before the one for y, and the value of x substituted in is already updated. There must be some way to do this substitution, right?
Or is there a better tool than sympy to do this in? Once I get my hyperbolas I will want to find points of intersection between different ones.
Thanks for any suggestions.
One simple solution is to use temporary symbols :
x_temp, y_temp = symbols('x_temp y_temp')
f1.subs({x: x_temp*cos(theta) - y_temp*sin(theta), y: x_temp*sin(theta) + y_temp*cos(theta)}).subs({x_temp: x, y_temp: y})
> -(x*sin(theta) + y*cos(theta))**2/100 + (x*cos(theta) - y*sin(theta))**2/25 == 1
I think sympy can do what you want. There is a polysys modules in sympy.solvers :
"""
Solve a system of polynomial equations.
Examples
========
>>> from sympy import solve_poly_system
>>> from sympy.abc import x, y
>>> solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y)
[(0, 0), (2, -sqrt(2)), (2, sqrt(2))]
"""
You can set simultaneous=True in the .subs( ) method to force SymPy to replace all variables at once (practically, SymPy internally creates temporary variables, proceeds with the substitution, then restores the old variables).
In [13]: f1.subs({x: x*cos(theta) - y*sin(theta),
y: x*sin(theta) + y*cos(theta)}, simultaneous=True)
Out[13]:
2 2
(x⋅sin(θ) + y⋅cos(θ)) (x⋅cos(θ) - y⋅sin(θ))
- ────────────────────── + ────────────────────── = 1
100 25
Otherwise use .xreplace( ... ) instead of .subs( ... )
In [11]: f1.xreplace({x: x*cos(theta) - y*sin(theta),
y: x*sin(theta) + y*cos(theta)})
Out[11]:
2 2
(x⋅sin(θ) + y⋅cos(θ)) (x⋅cos(θ) - y⋅sin(θ))
- ────────────────────── + ────────────────────── = 1
100 25

How to group integrals in sympy?

Suppose an expression contains nested integrals, for example:
I'd like to "group" (not sure if this is the right word) the integrals in the front of the expression, if possible. The result in this case would be
I am working with equations that require me to change the order of integration, and I think this form would be more useful.
Is there an existing function in sympy that would do this?
I think this is what you want:
In [1]: from sympy import *
In [2]: from sympy.abc import x, y
In [3]: a, b = Function('a'), Function('b')
In [4]: Integral(a(x)*b(y), y, x)
Out[4]:
⌠ ⌠
⎮ ⎮ a(x)⋅b(y) dy dx
⌡ ⌡
Update: Because code in comment is awful
In [14]: Integral(a(x)*b(y), y, x).doit()
Out[14]:
⎛⌠ ⎞ ⌠
⎜⎮ a(x) dx⎟⋅⎮ b(y) dy
⎝⌡ ⎠ ⌡