Curve translation in Python does not reach expected value - python

Suppose I have two curves, f(x) and g(x), and I want to evaluate if g(x) is a translation of f(x).
I used Sympy Curve to do the job with the function translate. However, I need help to reach the correct result. Consider the two functions:
f(x) = -x^2 and g(x) = -(x+5)^2 + 8
Notice that g is vertically translated by 8 and horizontally translated by 5. Why at is not equal to b in the following Python code?
from sympy import expand, Symbol, Curve, oo
x = Symbol('x')
f = -x**2
g = -(x+5)**2+8
a = Curve((x, f), (x, -oo, oo))
at = a.translate(5,8)
b = Curve((x, g), (x, -oo, oo))
a, at, b, at == b
>>> (Curve((x, -x**2), (x, -10, 10)),
Curve((x + 5, 8 - x**2), (x, -10, 10)),
Curve((x, 8 - (x + 5)**2), (x, -10, 10)),
False)
How could I make this analysis work using this or any other method?

Curve is probably not the right way to do this. If you have univariate functions for which you want to know a x and y translation will make them equal, you could use something like the following:
>>> dx,dy = Symbols('dx dy')
>>> eq = Eq(f.subs(x,x-dx)+dy)
>>> solve_undetermined_coeffs(eq,g),(dx,dy),x)
[(-5, 8)]
If there are no values of dx and dy that will solve the equality, then an empty list will be returned.

Thanks to #smichr for the reference about solve_undetermined_coeffs. Here you can find a full answer to my initial problem in Python 3.8.10 and Sympy 1.11.1.
from sympy import symbols, Eq, solve_undetermined_coeffs
x, dx, dy = symbols('x dx dy')
f = -x**2
g = -(x+5)**2+8
eq = Eq(f.subs(x,x-dx)+dy,g)
solve_undetermined_coeffs(eq,[dx,dy],x)

Related

Solving ill-posed non-linear equations numerically in python/SymPy

I'm trying to get a solution by running the code below.
Python just "hangs" and won't find a numeric solution. I can use an app on my phone (Desmos) to graph the functions and find a numeric solution easily, 0.024. Does python have limitations when solving for 2 decimal places?
import sympy
x = sympy.symbols('x')
e_1 = x**-0.5
e_2 = -2*sympy.log(0.0001*3.7**-1*0.05**-1+2.51*350000**-1*x**-0.5, 10)
sol = sympy.solve(e_2 - e_1, x, 0.024)
num = float(sol[0])
print(num)
Usually, nsolve is the SymPy tool used to numerically solve an equation (or a system of equations). However, I wasn't able to use: it kept raising errors. The problem is that your function is defined on a very small region, and the zero is very close to the boundary:
So, in this case we can try numerical root finding techniques. Again, some tools might fail, but after a few tries I've found that bisect works fine:
from sympy import *
from scipy.optimize import root, brentq, bisect
x = symbols('x')
# you didn't provide the diameter, so I've computed it based on your expected solution
d = 1.56843878182221
e_1 = x**-0.5
e_2 = -2 * log(0.00013 * 7-1*d-1+2.51350000**-1*x**-0.5, 10)
# convert the symbolic expression to a numerical function
ff = lambdify(x, e_1 - e_2)
root, output = bisect(ff, 0.023, 0.025, full_output=True)
print(root)
# 0.024000000001862646
print(output)
# converged: True
# flag: 'converged'
# function_calls: 32
# iterations: 30
# root: 0.024000000001862646
The fixed point method is a great one to use for situations like this. Or at least the principles of transforming the equation into a compatible form can benefit standard solvers by providing a less ill-behaved form of the function.
You have an ill-defined equation in the form y - g(y) where y = 1/sqrt(x). So let's get the inverse of g (call it G) so we can solve G(y) - G(g(y)) = G(y) - y instead.
>>> g = e_2.subs(1/x**.5, y)
>>> d = Dummy()
>>> G = solve(g - d, y)[0].subs(d, y)
>>> nsolve(G - y, 6)
6.45497224367903
>>> solve(1/x**.5 - _, dict=True)
{x: 0.024}
The process of rearranging an equation f(x) into form x - g(x) could probably use a built-in method in SymPy, but it's not too hard to do this by replacing each x with a dummy variable, solving for it, and then replacing the dummy symbols with x again. Different g will be more favorable for finding different roots as can be seen in the example below where the purple dashed line is good for finding the root near 1 while the solid blue is better near the smaller root.
Here is a possibility for a "fixed point form" function:
def fixedpoint_Eqs(eq, x=None):
"""rearrange to give eq in form x = g(x)"""
f = eq.free_symbols
fp = []
if x is None:
assert len(f) == 1, 'must specify x in this case'
x = list(f)[0]
Xeq = eq.replace(lambda _:_ == x, lambda _:Dummy())
X = Xeq.free_symbols - f
reps = {xi: x for xi in X}
for xi in X:
try:
g = solve(Xeq, xi, dict=True)
if len(g) != 1:
raise NotImplementedError
fp.append(Eq(x, g[0][xi].xreplace(reps)))
except NotImplementedError:
pass
return fp
>>> fixedpoint_Eqs(x+exp(x)+1/x-5)
Eq(x, -1/(x + exp(x) - 5))
Eq(x, -exp(x) + 5 - 1/x)
Eq(x, log(-x + 5 - 1/x))

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())

Getting the derivative of a function as a function with sympy (for later evaluation and substitution)

I want to work with generic functions as long as possible, and only substitute functions at the end.
I'd like to define a function as the derivative of another one, define a generic expression with the function and its derivative, and substitute the function at the end.
Right now my attempts is as follows, but I get the error 'Derivative' object is not callable:
from sympy import Function
x, y, z = symbols('x y z')
f = Function('f')
df = f(x).diff(x) # <<< I'd like this to be a function of dummy variable x
expr = f(x) * df(z) + df(y) + df(0) # df is unfortunately not callable
# At the end, substitute with example function
expr.replace(f, Lambda(X, cos(X))) # should return: -cos(x)*sin(z) - sin(y) - sin(0)
I think I got it to work with integrals as follows:
I= Lambda( x, integrate( f(y), (y, 0, x))) but that won't work for derivatives.
If that helps, I'm fine restricting myself to functions of a single variable for now.
As a bonus, I'd like to get this to work with any combination (products, derivatives, integrals) of the original function.
It's pretty disappointing that f.diff(x) doesn't work, as you say. Maybe someone will create support it sometime in the future. In the mean time, there are 2 ways to go about it: either substitute x for your y, z, ... OR lambdify df.
I think the first option will work more consistently in the long run (for example, if you decide to extend to multivariate calculus). But the expr in second option is far more natural.
Using substitution:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = f(x).diff(x)
expr = f(x) * df.subs(x, z) + df.subs(x, y) + df.subs(x, 0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Lambdifying df:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = lambda t: f(t).diff(t) if isinstance(t, Symbol) else f(X).diff(X).subs(X, t)
expr = f(x) * df(z) + df(y) + df(0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Both give the desired output.

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.

Numerical and analytical equation solving in python or matlab

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.

Categories