Program to find shortest distance from f(x) to origin - python

In Python (3.8) I try make a script that takes a function f(x) as input, e.g;
f(x) = 1/x
If we define the define y = f(x), as a line on the euclidean space, we can calculate the distance d() from the origin (0,0) for each point (x,f(x)) on the line as;
d(x,y) = sqrt(x^2+(f(x))^2)
My goal is to find the x such that the above distance is minimised. This can be done by solving
2x+2f(x)*f'(x) = 0
I will be grateful for help. Thanks.

Example in sympy (not expert on sympy);
from sympy import *
from sympy.solvers import solve
x, y, z = symbols('x y z')
g = 1/x
h = 2*x + (2*g) * (diff(g,x))
solve(h,x)
This will return [-1, 1, -I, I] so -1 and 1 should be real answers;
distance = x**2 + g**2
distance.subs(x,1)
distance.subs(x,-1)
I did not sqrt() in distance, but I hope you get an idea how this could be solved in sympy . This is 1 way, there are package to approximate the derivative, and find roots, which should also work.

Related

How to use sympy to find the relationship between X and Y

I am new to sympy. My ultimate goal is to plot y with respect to x.
Y is the known formula of k, m, ω
and x = ω*(m/k)**0.5 is also known.
I want to know how can I plot a function of both of them.
I am not sure which direction I should proceed from. I have tried simplification, and in the handwritten calculation, M/K of the numerator and denominator should be eliminated, but I have used sympy to only achieve the same variables in the top and bottom, which makes me at a loss. I hope that you can give me a solution.
This is an implicit definition of y and x in terms of parameters omega, k and m. Since omega and x are directly proportional, I would recommend solving for omega in terms of x and then replacing omega in y with that solution. That will give you y as a function of x which you can then plot. Here is a toy example:
>>> from sympy.abc import x, w, k
>>> yi = w
>>> xi = w*k
>>> yx = yi.subs(w. solve(x - xi, w)[0]); yx
x/k
>>> plot(yx.subs(k, 1), ylim=(-1,3))

How to create the equivalent of Excel Solver valueof function?

I have the following equation: x/0,2 * (0,2+1)+y/0,1*(0,1+1) = 26.34
The initial values of X and Y are set as 4.085 and 0.17 respectively.
I need to find the values of X and Y which satisfy the equation and have the lowest common deviation from initially set values. In other words, sum of |4.085 - x| and |0.17 - y| is minimized.
With Excel Solver Valueof Function this easy to find:
we insert x and y as variables to be changed to reach 26 in the formula result
Here is my python code (I am trying to use sympy for that)
x,y = symbols('x y')
eqn = solve([Eq(x/0.2*(0.2+1)+y/0.1*(0.1+1),26)],x,y)
print(eqn)
I am getting however strange result {x: 4.33333333333333 - 1.83333333333333*y}
Can anyone help me solve this equation?
The answer you are obtaining is not strange, it is just the answer to what you ask. You have an equation on two variables x and y, the solution to this problem is in general not unique (sometimes infinite). Now, you can either add an extra condition (inequality for example) or change the numeric Domain in which solutions are possible (like in Diophantine equations). You can do either of them in Sympy, in the following example I find the solution on x to your problem in the Real domain, using solveset:
from sympy import symbols, Eq, solveset
x,y = symbols('x y')
eqn = solveset(Eq(1.2 * x / 0.2 + 1.1 * y / 0.1, 26), x, Reals)
print(eqn)
Output:
Intersection(FiniteSet(4.33333333333333 - 1.83333333333333*y), Reals)
As you can see the solution on x is a finite set, that is the intersection between a straight line on y and the Reals. Any particular solution can be found by direct evaluation of y.
This is equivalent to say x = 4.33333333333333 - 1.83333333333333 * y if you evaluate this equation in the guess value y = 0.17, you obtain x = 4.0216 (close to your x = 4.085 guess value).
Edit:
After analyzing the new information added to your question, I think I have finally understood it: your problem is a constrained optimization. Now, I don't use Excel frequently, but it would be my bet that under the hood this optimization is carried out there using Lagrange multipliers. In your particular case, the target function represents the deviation of the solution (x, y) from the point (4.085, 0.17). For convenience, I have chosen this function to be the Euclidean distance between them (absolute values as you suggested can be problematic due to discontinuity of the derivatives). The constraint function is simply the equation you provided. To solve this problem with Sympy, one could use something like this:
import sympy as sp
# Define symbols and functions
x, y, lamb = sp.symbols('x, y, lamb', real=True)
func = sp.sqrt((x - 4.085) ** 2 + (y - 0.17) ** 2) # Target function
const = 1.2 * x / 0.2 + 1.1 * y / 0.1 - 26 # Constraint function
# Define Lagrangian
lagrang = func - lamb * const
# Compute gradient of Lagrangian
grad_lagrang = [sp.diff(lagrang, var) for var in [x, y, lamb]]
# Solve the resulting system of equations
spoints = sp.solve(grad_lagrang, [x, y, lamb], dict=True)
# Print stationary points
print(spoints)
Output:
[{x: 4.07047770700637, lamb: -0.0798086884467563, y: 0.143375796178345}]
Since in our case only one stationary point was found, this is the optimal solution (although this is only a necessary condition). The value of the lamb multiplier can be ditched, so x, y = 4.070, 0.1434. Hope this helps.

python : intersection geometrical objects in 3D space

Definition of the problem
I am trying to calculate the points of intersection of geometrical objects, such as two planes and a sphere, in python.
Let's consider for example these three objects:
This system gives two solutions:
I would like to know if there is a python library that can help develop a solver to calculate these intersections. I am looking for something working as Wolfram alpha, where we can input three equations and it returns all the possible solutions when there's finite number of solutions for simplicity.
What I tried
I tried with SymPy, but it returns []:
from sympy.solvers import solve
from sympy import Symbol
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
solve(z, x, x**2 + y**2 + z**2 -1)
I then tried with scipy:
from scipy.optimize import fsolve
def f(x):
y = np.zeros(3)
y[2] = x[2]
y[0] = x[0]
y[1] = x[0] ** 2 + x[1] ** 2+ x[2] ** 2 - 1
return y
x0 = np.array([10, 10, 10])
solution = fsolve(f, x0)
print(solution[0],solution[1],solution[2])
but it only returns one of the two solutions:
6.79746218330325e-28 1.0000000000000002 -2.3528179942097343e-35
I also tried with gekko, and stil it only returns one possible solution (which depends on the initial guess):
from gekko import GEKKO
m = GEKKO()
x = m.Var(value = 1)
y = m.Var(value = 1)
z = m.Var(value = 1)
m.Equation(x == 0)
m.Equation(z == 0)
m.Equation(x**2 + y**2+z**2 ==1)
m.solve()
fsolve from scipy, and all other functions that I personally know of that will accept any form of input function, will return one value.
One workaround if you have an idea where the other solution is would be to give an x0 value that is closer to the second solution with a second call to fsolve (see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fsolve.html).
If you alternatively know what range you want to try and find solutions in, the easiest way is to make an array that you then check to see where the value changes sign (this would be doing it from scratch)
I found the solution with sympy. Apparently it's one of the only (if not only) libraries that allow finding analytical solutions, and returns more than just one solution. Also, we don't need to pass guesses as initial variables. In my question, there was an error in the example I posted with sympy. This is how I solved the system:
from sympy.solvers import solve
import sympy as sp
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
sp.solve([z , x, (x**2 + y**2 + z**2) - 1], x,y,z)
Result: [0,-1,0], [0,1,0]

how to solve first-order linear differential equations analytically and numerically with sympy?

How can simple linear differential equations like this one be solved in sympy?
y' + p(t)y = q(t)
I'm looking to solve it in two ways: symbolically (analytically) if possible, if sympy can derive the integrating factor, etc., and also a way to do it numerically so that the two can be compared. how can this be done in sympy? is sympy.mpmath.odefun the right place to look?
Here and here are some examples.
As for your problem, you can write your equation like:
y' + p(t)y - q(t) = 0
and then use dsolve().
import sympy
t = sympy.Symbol('t')
y = sympy.Function('y')(t)
p = sympy.Function('p')(t)
q = sympy.Function('q')(t)
y_ = sympy.Derivative(y, t)
# y' + p(t)y - q(t)
sol = sympy.dsolve(y_ + p*y - q, y)
print(sol)
Solution as function
(Note : This is a quick solution i came up with by reading the documentation. I am not experienced with sympy. There might be much better ways to do the following.)
Suppose you want to solve y' = y.
from sympy import *
t = symbols('t')
y = Function('y')(t)
y_ = Derivative(y, t)
sol = dsolve(y_ - y, y)
We did the same as previously. Now, to use the second part of the sol, we use .args[1]. Then we create a function f(t_) and substitute the t value using subs().
def f(t_):
return sol.args[1].subs([(t, t_)])
print(sol)
print(f(0))

sympy lambdify RuntimeWarning: invalid value encountered in double_scalars

I am using sympy and numpy to solve the following the problem:
Given a point (x0, y0) and a curve y=a*x**2+b*x+c, compute the minimal distances of (x0, y0) to (x,y).
from sympy.core.symbol import symbols
from sympy.solvers.solvers import solve
from sympy.utilities.lambdify import lambdify
x, y = symbols('x y')
a,b,c, x0, y0 = symbols('a b c x0 y0')
y = a*x**2 + b*x + c
dist2 = (x-x0)**2 + (y-y0)**2
sol = solve(dist2.diff(x), x)
dist2_diff_solve = lambdify( (x0,y0,a,b,c), solve(dist2.diff(x),x), modules='numpy')
Until now, every thing is fine. I can even get some results:
dist2_diff_solve(1, 1, 1, 1, 1)
[0.31718264650678707, (-0.9085913232533936-0.8665105933073626j),
(-0.9085913232533936+0.8665105933073626j)]
However, with another group of parameters, I have problems:
dist2_diff_solve(664515.9375, 3998106.0, 0.053674994761459802, -71340.561832823907, 23709057427.266102)
*** ValueError: negative number cannot be raised to a fractional power
I think this is a bug from lambdify, as I can do the following:
sol[0].evalf(subs={x0:664515.9375, y0:3998106.0, a:0.053674994761459802, b:-71340.561832823907, c:23709057427.266102})
664515.759983973 + .0e-19*I
I need lambdify because I need to compute a large number (~100K) of computation (vectorize) at one time. Can any one confirm this is a bug from lambdify? Any comments / suggestions are welcome.
I found one related question: negative pow in python
and solved this problem simply by adding +0j to a, that is:
dist2_diff_solve(664515.9375+0j, 3998106.0, 0.053674994761459802, -71340.561832823907, 23709057427.266102)
[(664515.7418921513+3.552713678800501e-15j), (664600.9266076663+5.329070518200751e-15j), (664564.8069210749-1.4210854715202004e-14j)]

Categories

Resources