How to simplify sqrt expressions in sympy - python

I'm using sympy v1.0 in a Jupyter Notebook. I'm having trouble getting expression to simplify how I'd like. Here's a toy example; it does the same thing my more complicated expressions do...
import sympy
sympy.init_printing(use_latex='mathjax')
x, y = sympy.symbols("x, y", real=True, positive=True)
sympy.simplify(sqrt(2*x/y))
gives me...
But I would prefer...
How can I get sympy to group things in this way? Ive tried some of the other simplify functions, but they all give me the same result. Or am I missing something else?

Use "symbol trickery" for numbers that you want to behave like symbols and "vanilla symbols" when you don't want simplifications (as #asmeurer pointed out):
>>> _2,x,y = list(map(Symbol,'2xy'))
>>> sqrt(_2*x/y)
sqrt(2*x/y)

sympy really wants to simplify by pulling terms out of sqrt, which makes sense. I think you have to do what you want manually, i.e., get the simplification you want without the sqrt call, and then fudge it using Symbol with a LaTex \sqrt wrap. For example:
from sympy import *
init_printing(use_latex='mathjax')
# Wanted to show this will work for slightly more complex expressions,
# but at the end it should still simplify to 2x/y
x, y = symbols("x, y", real=True, positive=True)
z = simplify((2*2*3*x)/(1*2*3*y))
Symbol("\sqrt{" + latex(z) + "}", real=True, positive=True) # Wrap the simplified fraction in \sqrt{}
This really isn't ideal, but I looked through the docs for about an hour, and just couldn't find support for what you want directly. The sympy library is more about actual symbolic manipulation, less about printing, so I can hardly blame them.

Related

Sympy bug? Even with `evaluate=False` equations are automatically processed

Consider the following sympy code:
from sympy import Add
from sympy.abc import x
t1 = 2+2*x
t2 = x
myeq = sp.UnevaluatedExpr(Add(sp.UnevaluatedExpr(t1), sp.UnevaluatedExpr(t2), evaluate=False))
# BUG! Will print: x + 2*x + 2
# Yet it should print: 2+2*x+x
print(myeq)
This code snippet was adapted from this answer. There the terms are simpler, so Add preserved the order. But how can I make Add preserve the order in this case as well?
(Remark: If we change the terms to t1=x and t2=x**2 my approach with using the sp.UnevaluatedExpr works, but the original answer that did not have those terms does not. Alas, for my specific case, not even using sp.UnevaluatedExpr works.)
This is not a bug...
... but more a missing feature. All of it being documented.
Here is what SymPy means by unevaluated.
By unevaluated it is meant that the value inside of it will not
interact with the expressions outside of it to give simplified
outputs.
In your example, the terms 2*x and x were not simplified, as is expected.
Order of input
What you are seeing is SymPy not preserving the order in which you input your terms. This is documented under the expression tree section.
The arguments of the commutative operations Add and Mul are stored in
an arbitrary (but consistent!) order, which is independent of the
order inputted.
This should not be a problem since Add and Mul are commutative.
Although, if for some reason you want to preserve the order of input due to non-commutativity of multiplication, you can do so.
In SymPy, you can create noncommutative Symbols using Symbol('A',
commutative=False), and the order of multiplication for
noncommutative Symbols is kept the same as the input)
As for now, there does not seem to be non-commutative addition.

Python Sympy module NoConvergence: convergence to root failed; try n < 15 or maxsteps > 50

I encountered a problem when I using Sympy to solve problems
Here is my code:
from math import pi, hypot
from sympy import solve, solveset, sqrt, Symbol
one_x=-0.08
one_y=1.28
second_x=0
second_y=0
second_r=7
one_r=7.3
slopes=-16.0000000000 (maybe more trailing 0s)
intercepts=0.0
x=Symbol('x')
solveset(sqrt((x-second_x)**2+(slope*x+intercept-second_y)**2)+second_r-one_r-sqrt((x-one_x)**2+(slope*x+intercept-one_y)**2),x)
That's only part of my code but it raises a lot of errors
but instead, I replaced all of the variables with its value like
x=Symbol('x')
solveset(sqrt((x)**2+((-16)*x)**2)+7-7.3-sqrt((x+0.08)**2+((-16)*x-1.28)**2),x)
It works nicely and i can get an output {-0.0493567429232771}
I think It's because of the type of slopes(-16 compared with -16.000000), I really wanna know why an equation with float number cannot be calculated, and how I can fix it (cause I need it to be more precise so I cannot just ignore the number after the dot )
Thanks so much!
SymPy + algebraic equation + floating point numbers => trouble. Floating point math does not work like normal math, and SymPy is designed for the latter. Small things like 16 (integer) versus 16.0 (float) make a lot of difference in solving equations with SymPy: ideally, you would have no floating point numbers there, creating exact rational numbers instead, like this.
from sympy import S
one_x = S('-0.08')
However, you have floating point data and are looking for a floating point solution. This makes SymPy the wrong tool for the job. SymPy is for doing math with symbols, not for crunching floating point numbers. The correct solution is to use an appropriate solve from SciPy, such as brentq. It takes a bracketing interval as an input (where the function has different signs at both ends). For example:
from scipy.optimize import brentq
eq = lambda x: np.sqrt((x-second_x)**2 + (slope*x+intercept-second_y)**2) + second_r - one_r - np.sqrt((x-one_x)**2 + (slope*x + intercept - one_y)**2)
brentq(eq, -10, 10) # returns -0.049356742923277075
If you stick with SymPy, that means your equation is going outsourced to mpmath library, which is much more limited in the numerical root finding and optimization. To get a solution to converge with its methods, you'll need a really good starting point: apparently, one_x/2 is such a point.
from sympy import sqrt, Symbol, nsolve
# ... as in your code
nsolve(sqrt((x-second_x)**2+(slope*x+intercept-second_y)**2)+second_r-one_r-sqrt((x-one_x)**2+(slope*x+intercept-one_y)**2), one_x/2)
returns -0.0493567429232771.
By using sympy.solveset, which is intended for symbolic solution, you deprive yourself not only of SciPy's powerful numeric solvers, but also of an opportunity to set a good starting value for the numeric search which sympy.nsolve provides. Hence the lack of convergence in this numerically tricky problem. By the way, this is what makes it numerically tricky: the function is nearly constant most of the time, with one rapid change.

Solving a complicated multivariable function with Python

I have a very complicated function of two variables, let's call them x and y. I want to create a Python program where the user can input two values, a and b, where a is the value of that complicated function of x and y, and b = math.atan(y/x). This program should then output the values of x and y.
I am clueless as to where to start. I have tried to make the function into that of just one variable, then generate many random values for x and pick the closest one, but I have learnt that this is horribly inefficient and produces a result which is only accurate to about 2 significant figures, which is pretty horrible. Is there a better way to do this? Many thanks!
(P.S. I did not reveal the function here due to copyright issues. For the sake of example, you can consider the function
a = 4*math.atan(math.sqrt(math.tan(x)*math.tan(y)/math.tan(x+y)))
where y = x * math.tan(b).)
Edit: After using the approach of the sympy library, it appears as though the program ignores my second equation (the complicated one). I suspect it is too complicated for sympy to handle. Thus, I am asking for another approach which does not utilise sympy.
You could use sympy and import the trigonometric functions from sympy.
from sympy.core.symbol import symbols
from sympy.solvers.solveset import nonlinsolve
from sympy import sqrt, tan, atan
y = symbols('y', real=True)
a,b = 4,5 # user-given values
eq2 = a - 4*atan(sqrt(tan(y/tan(b))*tan(y)/tan((y/tan(b))+y)))
S = nonlinsolve( [eq2], [y] )
print(S)
It'll return you a series of conditions ( ConditionSet object ) for possible adequate results.
If that wasn't clear enough, you can read the docs for nonlinsolve.

Is it possible to find the value of x in python? i.e asking python to solve an equation such as 2x + 23 - 7x when x is not a pre-defined variable

What I want is a program that can determine the value of x from an equation when x is not yet defined i.e. not a python variable.
Just an example below, not the real thing.
sol = eval("input please type the equation: ")
#i.e sol = 32x - 40
print(sol)
I am not aware of any built in way to do that but Sympy library is built exactly for this stuff. Solvers module in Sympy can be used to solve linear equations. (Here) is a link to its docs.
An explicit example using sympy
import sympy
from sympy.abc import x
print sympy.solve(32*x-40,"x")
print sympy.solve(2*x+23-7*x,"x")
Gives as output:
[5/4]
[23/5]
Note that there is the separate question of parsing user input. That is, how do we take the string "32x-40" and turn it into the expression 32*x-40. This can be a non-trivial task depending on the complexity of the equations you are looking to model. If you are insterested in that, I would look into pyparsing.
You can just use sympy. Then you can do it in the print command. It looks like this.
import sympy
from sympy.abc import x
print sympy.solve(nub1*x+nub2-nub3*x,"Whatever you want here.")

ValueError: Math domain error (for a 2nd grade equation function)

I've tried to solve the problem myself but i cant. Its a function in order to solve 2nd grade equations when y=0 like 'ax2+bx+c=0'. when i execute it it says me there is math domain error. if u can help me it will be nice thx.
a=raw_input('put a number for variable a:')
b=raw_input('put a number for variable b:')
c=raw_input('put a number for variable c:')
a=float(a)
b=float(b)
c=float(c)`
import math
x=(-b+math.sqrt((b**2)-4*a*c))/2*a
print x`
x=(-b-math.sqrt((b**2)-4*a*c))/2*a`
print x
PD:im starting with python so im quite a disaster sorry.
The issue here is that the standard math library in python cannot handle complex variables. The sqrt you've got up there reflects this.
If you want to handle a function that could have complex variables (such as the one above) I would suggest using the cmath library, which has a replacement cmath.sqrt function.
You could change your above code to the following:
from cmath import sqrt
a = raw_input('put a number for variable a:')
b = raw_input('put a number for variable b:')
c = raw_input('put a number for variable c:')
a = float(a)
b = float(b)
c = float(c)`
x = (-b + sqrt((b**2) - 4 * a * c)) / 2 * a
print x`
x = (-b - sqrt((b**2) - 4 * a * c)) / 2 * a`
print x
and it should fix your problem (I also made some edits to make the code look a little more pythonic (read: pep8 compliant))
First, it's worth noting that in "2nd grade math", that equation doesn't have a solution with the values you (presumably) entered.* When you get to high school math and learn about imaginary numbers, you learn that all quadratic equations actually do have solutions, it's just that sometimes the solutions are complex numbers. And then, when you get to university, you learn that whether or not the equations have solutions depends on the domain; the function to real numbers and the function to complex numbers are different functions. So, from either a 2nd-grade perspective or a university perspective, Python is doing the right thing by raising a "math domain error".
* Actually, do you even learn about quadratic equations before middle school? That seems a bit early…
The math docs explain:
These functions cannot be used with complex numbers; use the functions of the same name from the cmath module if you require support for complex numbers. The distinction between functions which support complex numbers and those which don’t is made since most users do not want to learn quite as much mathematics as required to understand complex numbers. Receiving an exception instead of a complex result allows earlier detection of the unexpected complex number used as a parameter, so that the programmer can determine how and why it was generated in the first place.
But there's another reason for this: math was specifically designed to be thin wrappers around the standard C library math functions. It's part of the intended goal that you can take code written for another language that uses C's <math.h>, C++'s <cmath>, or similar functions in Perl, PHP, etc. and have it work the same way with the math module in Python.
So, if you want the complex roots, all you have to do is import cmath and use cmath.sqrt instead of math.sqrt.
As a side note: In general, the operators and other builtins are more "friendly" than the functions from these modules. However, until 3.0, the ** operator breaks this rule, so ** .5 will just raise ValueError: negative number cannot be raised to a fractional power. If you upgrade to 3.x, it will work as desired. (This change is exactly like the one with integer division giving a floating-point result, but there's no __future__ statement to enable it in 2.6-2.7 because it was deemed to be less of a visible and important change.)

Categories

Resources