Numerical and analytical equation solving in python or matlab - python

Let's suppose that I have two transcendental functions f(x, y) = 0 and g(a, b) = 0.
a and b depend on y, so if I could solve the first equation analytically for y, y = f(x), I could have the second function depending only on x and thus solving it numerically.
I prefer to use python, but if matlab is able to handle this is ok for me.
Is there a way to solve analytically trascendent functions for a variable with python/matlab? Taylor is fine too, as long as I can choose the order of approximation.

I tried running this through Sympy like so:
import sympy
j, k, m, x, y = sympy.symbols("j k m x y")
eq = sympy.Eq(k * sympy.tan(y) + j * sympy.tan(sympy.asin(sympy.sin(y) / x)), m)
eq.simplify()
which turned your equation into
Eq(m, j*sin(y)/(x*sqrt(1 - sin(y)**2/x**2)) + k*tan(y))
which, after a bit more poking, gives us
k * tan(y) + j * sin(y) / sqrt(x**2 - sin(y)**2) == m
We can find an expression for x(y) like
sympy.solve(eq, x)
which returns
[-sqrt(j**2*sin(y)**2/(k*tan(y) - m)**2 + sin(y)**2),
sqrt(j**2*sin(y)**2/(k*tan(y) - m)**2 + sin(y)**2)]
but an analytic solution for y(x) fails.

Related

Sympy trouble with simplifying partial derivatives

I do the following to generate an expression in Sympy:
Create some matrix Q_{ij} which holds some functions \eta, \mu, \nu, of x and y.
Sum over indices and take some partial derivatives.
Substitute some simple expressions for \eta, \mu, and \nu (say \sin(x)*\cos(y)).
Try to simplify the expression so that it explicitly calculates the partial derivatives of the simple expressions.
When I do this, it gives me the following error:
NotImplementedError: Improve MV Derivative support in collect
The specific code that I used is:
from sympy import *
# Set up system and generate functions
x, y, z = symbols('x y z')
i, j, k, m, p = symbols('i j k m p')
xi = Matrix([x, y, z])
lims = range(0, 3)
eta = Function('eta', real=True)(x, y)
mu = Function('mu', real=True)(x, y)
nu = Function('nu', real=True)(x, y)
Q = Matrix([[2/sqrt(3)*eta, nu, 0],
[nu, -1/sqrt(3)*eta + mu, 0],
[0, 0, -1/sqrt(3)*eta - mu]])
# Create complicated expression of partial derivatives
Phi_L1 = -sum(Eijk(3, p + 1, i + 1)
*diff(diff(diff(Q[k, l], xi[j]), xi[j]), xi[p])
*diff(Q[k, l], xi[i])
for i in lims
for j in lims
for k in lims
for l in lims
for p in lims
)
Phi_L1 = simplify(Phi_L1)
# Choose example functions and try to evaluate expression explicitly
eta1 = sin(x)*cos(y)
mu1 = sinh(x)*cosh(y)
nu1 = x**2*y**2
expr1 = Phi_L1.subs(eta, eta1).subs(mu, mu1).subs(nu, nu1)
simplify(expr1)
I couldn't find a simpler example that gives the same error. For example, the following works as intended:
f = Function('f', real=True)(x, y)
expr = diff(diff(f, x), y)
simplify(expr.subs(f, sinh(x)*cosh(y)))
'collect' and 'simplify' have known problems with higher order partial derivatives https://github.com/sympy/sympy/issues/9068 outlines the issue
The example shown is
import sympy as sp
x, y = sp.symbols("x y")
f, g = sp.symbols("f g", cls=sp.Function, args=(x,y))
f, g = f(), g()
expr1 = g.diff(x, 2) + f.diff(x, 2) + 5*f.diff(x, 2) + 2*f.diff(x) + 9*f.diff(x)
expr2 = g.diff(x, 2) + f.diff(x, 2) + 5*f.diff(x, 2) + 2*f.diff(x) + 9*f.diff(x) + g.diff(x).diff(y) + f.diff(x).diff(y)
which works correctly and show the expected output for both expr1 and expo2
sp.collect(expr1, f) works wonderfully but sp.collect(expr2, f) fails with the known error as the implementation is not finished...
This does not address the error (which is apparently a bug), but one work around for the case of explicitly taking derivatives of simple functions is to just use the doit() function. In this case, that would look like (following the code posted in the question):
simplify(expr1.doit())

How to get answers from solving system of equations in numerical form?

So I am using sympy which gives me exact answers for system of equations but I would like to get the answers in numerical form and print them as that (for example 5931,023832). How can I do it?
My code is here:
import sympy as sp
x, y = sp.symbols('x, y')
eq1 = sp.Eq((x - 5000)**2 + (y - 5000)**2, 2000**2)
eq2 = sp.Eq(((x-2500)/2000)**2 + ((y - 5000)/1000)**2, 1)
answer = sp.solve((eq1, eq2), (x, y))
print(answer[0], answer[1])
Evaluation via the evalf (or n) method will do this for you:
>>> [tuple([i.n(3) for i in j]) for j in answer]
[(3.23e+3, 4.07e+3), (3.23e+3, 5.93e+3), (8.44e+3, 5.0e+3 - 2.8e+3*I),
(8.44e+3, 5.0e+3 + 2.8e+3*I)]
The default is 15 digits of significance, but I chose 3 to make the results more compact.

Python; Solving equation equal to zero

How I can equate an equation to zero then solve it (the purpose is to eliminate the denominator).
y=(x**2-2)/3*x
In Matlab this works:
solution= solve(y==0,x)
but not in python.
from sympy import *
x, y = symbols('x y')
y=(x**2-2)/3*x
# set the expression, y, equal to 0 and solve
result = solve(Eq(y, 0))
print(result)
Another solution:
from sympy import *
x, y = symbols('x y')
equation = Eq(y, (x**2-2)/3*x)
# Use sympy.subs() method
result = solve(equation.subs(y, 0))
print(result)
Edit (even simpler):
from sympy import *
x, y = symbols('x y')
y=(x**2-2)/3*x
# solve the expression y (by default set equal to 0)
result = solve(y)
print(result)
If you want only to eliminate the denominator, then you can split it into numerator and denominator. If the equation is already appear as a fraction and you want the numerator then
>>> y=(x**2-2)/(3*x); y # note parentheses around denom, is that what you meant?
(x**2 - 2)/(3*x)
>>> numer(_)
x**2 - 2
But if the equation appears as a sum then you can put it over a denominator and perhaps factor to identify numerator factors that must be zero in order to solve the equation:
>>> y + x/(x**2+2)
x/(x**2 + 2) + (x**2 - 2)/(3*x)
>>> n, d = _.as_numer_denom(); (n, d)
(3*x**2 + (x**2 - 2)*(x**2 + 2), 3*x*(x**2 + 2))
>>> factor(n)
(x - 1)*(x + 1)*(x**2 + 4)
>>> solve(_)
[-1, 1, -2*I, 2*I]
You don't have to factor the numerator before attempting to solve, however. But I sometimes find it useful when working with a specific equation.
If you have an example of an equation that is solved quickly elsewhere but not in SymPy, please post it.

Having trouble with using sympy subs command when trying to solve a function at an x value of 0

I have a function [ -4*x/sqrt(1 - (1 - 2*x^2)^2) + 2/sqrt(1 - x^2) ] that I need to evaluate at x=0. However, whenever you graph this function, for some interval of y there are many y-values at x=0. This leads me to think that the (subs) command can only return one y-value. Any help or elaboration on this? Thank you!
Here's my code if it might help:
x = symbols('x')
f = 2*asin(x) # f(x) function
g = acos(1-2*x**2) # g(x) function
eq = diff(f-g) # evaluating the derivative of f(x) - g(x)
eq.subs(x, 0) # substituting 0 for x in the derivative of f(x) - g(x)
After I run the code, it returns NaN, which I assume is because substituting in 0 for x returns not a single number, but a range of numbers.
Here is the graph of the function to be evaluated at x=0:
You should always give SymPy as many assumptions as possible. For example, it can't pull an x**2 out of a sqrt because it thinks x is complex.
A factorization an then a simplification solves the problem. SymPy can't do L'Hopital on eq = A + B since it does not know that both A and B converge. So you have to guide it a little by bringing the fractions together and then simplifying:
from sympy import *
x = symbols('x', real=True)
f = 2*asin(x) # f(x) function
g = acos(1-2*x**2) # g(x) function
eq = diff(f-g) # evaluating the derivative of f(x) - g(x)
eq = simplify(factor(eq))
print(eq)
print(limit(eq, x, 0, "+"))
print(limit(eq, x, 0, "-"))
Outputs:
(-2*x + 2*Abs(x))/(sqrt(1 - x**2)*Abs(x))
0
4
simplify, factor and expand do wonders.

Why doesn't sympy simplify the Fourier Transform of a derivative?

We know that the Fourier Transform of a derivative is
where k is the fourier variable. Explanation here
My question is, why doesn't sympy use this knowledge? For example:
from sympy import Function, symbols, fourier_transform, Derivative
f = Function('f')
x, k= symbols('x, k')
G = fourier_transform(Derivative(f(x), x, x) + f(x), x, k)
print(G)
This prints
FourierTransform(f(x), x, k) + FourierTransform(Derivative(f(x), x, x), x, k)
But I expected it to print (up to some factors of 2 pi i)
FourierTransform(f(x), x, k) + k**2 FourierTransform(f(x), x, k)
Is there a way to tell sympy it's save to make this simplification because I expect f(x) -> 0 as x goes to infinity?
If not, what would be the cleanest way to make the substitution?
The simple reason Sympy doesn't do this is that it's not implemented yet. As a workaround for now, you can manually replace the FourierTransform of the derivative with a multiplication:
from sympy import Wild, FourierTransform, Derivative
a, b, c = symbols('a b c', cls=Wild)
G.replace(
FourierTransform(Derivative(a, b, b), b, c),
c**2 * FourierTransform(a, b, c)
)
As far as I know, Sympy doesn't offer a pattern that matches an arbitrary number of arguments, so you can't have a single pattern that matches Derivative(f(x), x), Derivative(f(x), x, x), Derivative(f(x), x, x, x), and so on. You could get around that by using the function-function form of replace(), but if you know what order of derivative you're dealing with, it's probably simpler to just put in that many bs explicitly, as I did in the example.

Categories