I made a Matlab function and I would like to convert it to Python to use with my web application.
I converted (.m file to .py file) almost everything using OMPC.
However, I can't make the solve() function to work (I am using the sympy library).
This is the Matlab line:
SBC = solve(sqrt((xa-x)^(2)+(ya-y)^(2))-sqrt((xb-x)^(2)+(yb-y)^(2))-D12==0,sqrt((xa-x)^(2)+(ya-y)^(2))-sqrt((xc-x)^(2)+(yc-y)^(2))-D13==0,[x,y]);
And this is the Python line where x and y are symbols (with x = Symbol('x') and y = Symbol('y')) :
sbc = solve(
sqrt((xa - x) ** (2) + (ya - y) ** (2))
- sqrt((xb - x) ** (2) + (yb - y) ** (2))
- D12 == 0,
sqrt((xa - x) ** (2) + (ya - y) ** (2))
- sqrt((xc - x) ** (2) + (yc - y) ** (2))
- D13 == 0,
[x, y]
)
With this Python code, I am getting False instead of a result (it works great with the Matlab code).
Am I missing something?
EDIT:
And with this, I am getting [] :
# -*- coding: utf-8 -*-
from sympy import *
def alg(xa=None, ya=None, za=None, Ta=None, xb=None, yb=None, zb=None, Tb=None, xc=None, yc=None, zc=None, Tc=None, xd=None, yd=None, zd=None, Td=None, RSSIA=None, RSSIB=None, RSSIC=None, RSSID=None, txPower=None, n=None):
n = 2
c = 3 * 10 ** 8
TOA12 = Ta - Tb
TOA13 = Ta - Tc
TOA14 = Ta - Td
D12 = TOA12 * c
D13 = TOA13 * c
D14 = TOA14 * c
x, y = symbols('x y')
eqs = [sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xb - x) ** (2) + (yb - y) ** (2)) - D12,
sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xc - x) ** (2) + (yc - y) ** (2)) - D13]
print solve(eqs, [x, y])
alg(3,1,0,21.8898790015,4,6,0,21.8898790005,10,4,0,21.88987900009,9,0.5,0,21.889879000105,23.9,23.85,23.9,23.95,24,1)
There is only one small change required in order to make it work. The reason why you receive False is that you use the == 0 in your function definition. In sympy, it is generally assumed that your functions evaluate to 0. To give an example taken from here:
If you want to solve the equations x+5y=2, -3x+6y=15 then you would do it as follows:
from sympy import *
x, y = symbols('x y')
solve([x + 5*y - 2, -3*x + 6*y - 15], [x, y])
which gives you
{x: -3, y: 1}
Note that the equations are passed in a way that they evaluate to 0.
If you run it like you did
solve([x + 5*y - 2 == 0, -3*x + 6*y - 15 == 0], [x, y])
then also False is returned.
So for your example, the following would work:
from sympy import *
x, y, xa, xb, xc, ya, yb, yc, D12, D13 = symbols('x y xa xb xc ya yb yc D12 D13')
eqs = [sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xb - x) ** (2) + (yb - y) ** (2)) - D12,
sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xc - x) ** (2) + (yc - y) ** (2)) - D13]
solve(eqs, [x, y])
Unfortunately, that does not run through on my private computer (my Python gets killed; apparently that is hard to solve) so I just tested it for a simpler version to demonstrate the principle:
eqs2 = [sqrt(xa - x) - D12,
(yc - y) ** (2) - D13]
solve(eqs2, [x, y])
which then gives you the expected output:
[(-D12**2 + xa, -sqrt(D13) + yc), (-D12**2 + xa, sqrt(D13) + yc)]
Hope you have more luck on your machine to solve these complicated functions. But this post explains why you receive the False.
EDIT
With your modified code, you can get a solution if you decrease the precision of your parameters D12 and D13. Here is the solution you then get:
[sqrt((-x + 3)**2 + (-y + 1)**2) - sqrt((-x + 4)**2 + (-y + 6)**2) - 0.3, sqrt((-x + 3)**2 + (-y + 1)**2) - sqrt((-x + 10)**2 + (-y + 4)**2) - 0.42]
[{x: 6.45543078993649, y: 3.14390310591109}, {x: 6.67962865117349, y: 2.61399193301427}]
Are these the same you receive for the Matlab simulations?
Here is the modified code; please note that I force the output to be in form of a dictionary and also print the equations (I round to two decimals but it also works with 4; you can play with that):
from sympy import *
def alg(xa=None, ya=None, za=None, Ta=None, xb=None, yb=None, zb=None, Tb=None, xc=None, yc=None, zc=None, Tc=None, xd=None, yd=None, zd=None, Td=None, RSSIA=None, RSSIB=None, RSSIC=None, RSSID=None, txPower=None, n=None):
n = 2
c = 3 * 10 ** 8
TOA12 = Ta - Tb
TOA13 = Ta - Tc
TOA14 = Ta - Td
D12 = round(TOA12 * c, 2)
D13 = round(TOA13 * c, 2)
# D14 = TOA14 * c
# x, y, D12, D13 = symbols('x y D12 D13')
x, y = symbols('x y')
eqs = [sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xb - x) ** (2) + (yb - y) ** (2)) - D12,
sqrt((xa - x) ** (2) + (ya - y) ** (2)) - sqrt((xc - x) ** (2) + (yc - y) ** (2)) - D13]
print eqs
print solve(eqs, x, y, dict=True)
alg(3,1,0,21.8898790015,4,6,0,21.8898790005,10,4,0,21.88987900009,9,0.5,0,21.889879000105,23.9,23.85,23.9,23.95,24,1)
Related
I have two point cloud and I use scipy.optimize.curve_fit to get the equations representing two surfaces:
z1 = F1(x, y) = (A1 * x ** 2) + (B1 * y ** 2) + (C1 * x * y) + (D1 * x) + (E1 * y) + F1
z2 = F2(x, y) = (A2 * x ** 2) + (B2 * y ** 2) + (C2 * x * y) + (D2 * x) + (E2 * y) + F2
And the equation of their intersection line is:
MY GOAL: Find the domain of x and y
For example: if x0 is in the domain of the intersection line, what is the range of y corresponding to x0?
I have tried some methods with sympy or scipy, but cannot get the domian.
I need algorithm, that solve systems like this:
Example 1:
5x - 6y = 0 <--- line
(10- x)**2 + (10- y)**2 = 2 <--- circle
Solution:
find y:
(10- 6/5*y)**2 + (10- y)**2 = 2
100 - 24y + 1.44y**2 + 100 - 20y + y**2 = 2
2.44y**2 - 44y + 198 = 0
D = b**2 - 4ac
D = 44*44 - 4*2.44*198 = 3.52
y[1,2] = (-b+-sqrt(D))/2a
y[1,2] = (44+-1.8761)/4.88 = 9.4008 , 8.6319
find x:
(10- x)**2 + (10- 5/6y)**2 = 2
100 - 20x + y**2 + 100 - 5/6*20y + (5/6*y)**2 = 2
1.6944x**2 - 36.6666x + 198 = 0
D = b**2 - 4ac
D = 36.6666*36.6666 - 4*1.6944*198 = 2.4747
x[1,2] = (-b+-sqrt(D))/2a
x[1,2] = (36.6666+-1.5731)/3.3888 = 11.2841 , 10.3557
my skills are not enough to write this algorithm please help
and another algorithm that solve this system.
5x - 6y = 0 <--- line
|-10 - x| + |-10 - y| = 2 <--- rhomb
as answer here i need two x and two y.
You can use sympy, Python's symbolic math library.
Solutions for fixed parameters
from sympy import symbols, Eq, solve
x, y = symbols('x y', real=True)
eq1 = Eq(5 * x - 6 * y, 0)
eq2 = Eq((10 - x) ** 2 + (10 - y) ** 2, 2)
solutions = solve([eq1, eq2], (x, y))
print(solutions)
for x, y in solutions:
print(f'{x.evalf()}, {y.evalf()}')
This leads to two solutions:
[(660/61 - 6*sqrt(22)/61, 550/61 - 5*sqrt(22)/61),
(6*sqrt(22)/61 + 660/61, 5*sqrt(22)/61 + 550/61)]
10.3583197613288, 8.63193313444070
11.2810245009662, 9.40085375080520
The other equations work very similar:
eq1 = Eq(5 * x - 6 * y, 0)
eq2 = Eq(Abs(-10 - x) + Abs(-10 - y), 2)
leading to :
[(-12, -10),
(-108/11, -90/11)]
-12.0000000000000, -10.0000000000000
-9.81818181818182, -8.18181818181818
Dealing with arbitrary parameters
For your new question, how to deal with arbitrary parameters, sympy can help to find formulas, at least when the structure of the equations is fixed:
from sympy import symbols, Eq, Abs, solve
x, y = symbols('x y', real=True)
a, b, xc, yc = symbols('a b xc yc', real=True)
r = symbols('r', real=True, positive=True)
eq1 = Eq(a * x - b * y, 0)
eq2 = Eq((xc - x) ** 2 + (yc - y) ** 2, r ** 2)
solutions = solve([eq1, eq2], (x, y))
Studying the generated solutions, some complicated expressions are repeated. Those could be substituted by auxiliary variables. Note that this step isn't necessary, but helps a lot in making sense of the solutions. Also note that substitution in sympy often only considers quite literal replacements. That's by the introduction of c below is done in two steps:
c, d = symbols('c d', real=True)
for xi, yi in solutions:
print(xi.subs(a ** 2 + b ** 2, c)
.subs(r ** 2 * a ** 2 + r ** 2 * b ** 2, c * r ** 2)
.subs(-a ** 2 * xc ** 2 + 2 * a * b * xc * yc - b ** 2 * yc ** 2 + c * r ** 2, d)
.simplify())
print(yi.subs(a ** 2 + b ** 2, c)
.subs(r ** 2 * a ** 2 + r ** 2 * b ** 2, c * r ** 2)
.subs(-a ** 2 * xc ** 2 + 2 * a * b * xc * yc - b ** 2 * yc ** 2 + c * r ** 2, d)
.simplify())
Which gives the formulas:
x1 = b*(a*yc + b*xc - sqrt(d))/c
y1 = a*(a*yc + b*xc - sqrt(d))/c
x2 = b*(a*yc + b*xc + sqrt(d))/c
y2 = a*(a*yc + b*xc + sqrt(d))/c
These formulas then can be converted to regular Python code without the need of sympy. That code will only work for an arbitrary line and circle. Some tests need to be added around, such as c == 0 (meaning the line is just a dot), and d either be zero, positive or negative.
The stand-alone code could look like:
import math
def give_solutions(a, b, xc, yc, r):
# intersection between a line a*x-b*y==0 and a circle with center (xc, yc) and radius r
c =a ** 2 + b ** 2
if c == 0:
print("degenerate line equation given")
else:
d = -a**2 * xc**2 + 2*a*b * xc*yc - b**2 * yc**2 + c * r**2
if d < 0:
print("no solutions")
elif d == 0:
print("1 solution:")
print(f" x1 = {b*(a*yc + b*xc)/c}")
print(f" y1 = {a*(a*yc + b*xc)/c}")
else: # d > 0
print("2 solutions:")
sqrt_d = math.sqrt(d)
print(f" x1 = {b*(a*yc + b*xc - sqrt_d)/c}")
print(f" y1 = {a*(a*yc + b*xc - sqrt_d)/c}")
print(f" x2 = {b*(a*yc + b*xc + sqrt_d)/c}")
print(f" y2 = {a*(a*yc + b*xc + sqrt_d)/c}")
For the rhombus, sympy doesn't seem to be able to work well with abs in the equations. However, you could use equations for the 4 sides, and test whether the obtained intersections are inside the range of the rhombus. (The four sides would be obtained by replacing abs with either + or -, giving four combinations.)
Working this out further, is far beyond the reach of a typical stackoverflow answer, especially as you seem to ask for an even more general solution.
So I am trying to write a python program to calculate 4 unknowns (x, y, z, d) given a system of 4 non-linear equations. I am using the multivariate newton method.
However, the problem I have at the moment is that when I start my program, I do not get any output. The program runs (red square is going), but nothing is outputted.
There are some holes perhaps in my program, was hoping you could give some pointers.
Many thanks.
from autograd import jacobian
import autograd.numpy as np
import numpy.linalg
import sys
tolerance = 0.0001
sys.setrecursionlimit(10000);
def functionmatrix(x0):
f1 = pow((x0[0] - 1560), 2) + pow((x0[1] - 6540), 2) + pow((x0[2] - 20140), 2) - (2.9*10**3*pow((0.07074 - x0[3]), 2))
f2 = pow((x0[0] - 18760), 2) + pow((x0[1] - 2750), 2) + pow((x0[2] - 18610), 2) - (2.9*10**3*pow((0.07220 - x0[3]), 2))
f3 = pow((x0[0] - 17610), 2) + pow((x0[1] - 14630), 2) + pow((x0[2] - 13480), 2) - (2.9*10**3*pow((0.07690 - x0[3]), 2))
f4 = pow((x0[0] - 19170), 2) + pow((x0[1] - 610), 2) + pow((x0[2] - 18390), 2) - (2.9*10**3*pow((0.07242 - x0[3]), 2))
functionmatrix = np.array([f1, f2, f3, f4]).reshape(4,1)
return functionmatrix
def jacobianmatrix(x0):
f1 = pow((x0[0] - 1560), 2) + pow((x0[1] - 6540), 2) + pow((x0[2] - 20140), 2) - (2.9*10**3*pow((0.07074 - x0[3]), 2))
f2 = pow((x0[0] - 18760), 2) + pow((x0[1] - 2750), 2) + pow((x0[2] - 18610), 2) - (2.9*10**3*pow((0.07220 - x0[3]), 2))
f3 = pow((x0[0] - 17610), 2) + pow((x0[1] - 14630), 2) + pow((x0[2] - 13480), 2) - (2.9*10**3*pow((0.07690 - x0[3]), 2))
f4 = pow((x0[0] - 19170), 2) + pow((x0[1] - 610), 2) + pow((x0[2] - 18390), 2) - (2.9*10**3*pow((0.07242 - x0[3]), 2))
jacobianmatrix = np.array([jacobian(f1), jacobian(f2), jacobian(f3), jacobian(f4)]).reshape(4,1)
inversejacobian = np.linalg.inv(jacobianmatrix)
return inversejacobian
def determinevalues():
euclideandistance = 100
iteration = 0
tolerance = 0.00000001
maxiterations = 1000
x0 = np.array([0,0,6370,0], dtype = float).reshape(4,1)
while(np.any(abs(euclideandistance) > tolerance) and iteration < maxiterations):
outputfunctionmatrix = functionmatrix(x0)
outputjacobianmatrix = jacobianmatrix(x0)
newxvalues = x0 - np.linalg.solve(outputfunctionmatrix, outputjacobianmatrix)
iteration = iteration + 1
x0 = newxvalues
euclideandistance = np.linalg.norm(newxvalues - x0)
def main():
determinevalues()
main()
I run it in my side and the determinate() function cause an error due to the recursion. But, there are also many things to work on.
First, you should used appropriated librairies, the Harvard autograd library (link), has already grad and jacobian implementation. You problem can be simply resolve with this sample (link) :
import autograd.numpy as np
import autograd
def newton(f, x0, tol=0.0001, maxiter=10000):
g = autograd.jacobian(f)
h = autograd.hessian(f)
x = x0
for _ in range(maxiter):
# ==========================
# EDITED
gx = np.squeeze(g(x))
hx = np.squeeze(h(x))
delta = np.linalg.multi_dot([np.linalg.inv(hx), gx])
# ==========================
x = x - delta
if np.linalg.norm(delta) < tol:
break
return x
def main():
def f(x):
return np.array([[(x[0] - 1560) ** 2 + (x[1] - 6540) ** 2 + (x[2] - 20140) ** 2 - (2.9 * 10 ** 3 * (0.07074 - x[3]) ** 2)],
[(x[0] - 18760) ** 2 + (x[1] - 2750) ** 2 + (x[2] - 18610) ** 2 - (2.9 * 10 ** 3 * (0.0722 - x[3]) ** 2)],
[(x[0] - 17640) ** 2 + (x[1] - 14630) ** 2 + (x[2] - 13480) ** 2 - (2.9 * 10 ** 3 * (0.0769 - x[3]) ** 2)],
[(x[0] - 19170) ** 2 + (x[1] - 610) ** 2 + (x[2] - 18390) ** 2 - (2.9 * 10 ** 3 * (0.07242 - x[3]) ** 2)]])
x0 = np.array([0., 0., 6730., 0.])
print(newton(f, x0))
if __name__ == '__main__':
main()
Since you are in matrix alegra not linear, you just need to replace autograd.grad(f) by autograd.jacobian(f). I don't know if the system will converge though! You could rebuild jacobian and hessian function if you want to do it yourself.
EDIT :
There is an error in my code, jacobian and hessian need be reshaped before the calculation and we need to use, as you already used in your previous code, np.linalg.multi_dot() function.
When i run the following code i get
TypeError: can't multiply sequence by non-int of type "Add'
Can anyone explain why I get this error?
from sympy.core.symbol import symbols
from sympy.solvers.solveset import nonlinsolve
x, y, z, r, R, a, m, n, b, k1, k2 = symbols('x,y,z,r,R,a,m,n,b,k1,k2', positive=True)
f1 = r * x * (1 - x / k1) - (a * z * x ** (n + 1)) / (x ** n + y ** n)
f2 = R * y * (1 - y / k2) - (b * z * y ** (n + 1)) / (x ** n + y ** n)
f3 = z * (a * x ** (n + 1) + b * y ** (n + 1)) / (x ** n + y ** n) - m * z
f = [f1, f2, f3]
nonlinsolve(f, [x, y, z])
The error message is not really descriptive but the full stack trace indicates where the problem was: SymPy tries to work with the expression as if it was a polynomial, and finds that impossible because the exponent n is a symbol rather than a concrete integer.
Simply put, SymPy does not have an algorithm for solving systems like that one (and I'm not sure if any CAS has).
When written in polynomial form, the system has monomials of total degree n+2. So, already for n = 1 this is utterly hopeless: a system of three cubic equations with three unknowns. SymPy can solve the case n = 0, and I wouldn't expect anything more than that.
I'm trying to plot the batman equation. A solution in sympy or matplotlib will be great (sage isn't cool because I'm using windows). The problem is that if I comment out certain parts the part of the figure appears but with all the F *= parts, I get a blank plot.
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F = 1
F *= (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F *= (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F *= (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F *= (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F *= ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F *= ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
G = 0
matplotlib.pyplot.contour(x, y, (F - G), [0])
matplotlib.pyplot.show()
What's going on here? If the graph is zero for one multiplicand, it should still be so no matter which other multiplicands I throw in there.
source of the batman equation: http://www.reddit.com/r/pics/comments/j2qjc/do_you_like_batman_do_you_like_math_my_math/
The parameter of sqrt is negative for many points, so the finally products are all NaN. You can plot every factor as following:
from __future__ import division # this is important, otherwise 1/2 will be 0
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F1 = (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F2 = (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F3 = (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F4 = (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F5 = ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F6 = ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
for f in [F1,F2,F3,F4,F5,F6]:
matplotlib.pyplot.contour(x, y, f, [0])
matplotlib.pyplot.show()
the result plot:
I know this might seem lame, but how about creating a list of x values, and then computing the value of "batman" at each of those positions, and storing in another list. You could define a function "batman" which computes the y value for each x value you pass in.
Then just plot those lists with matplotlib.
EDIT: Since you've made numpy arrays already to store the results, you could use those when computing the y values.
I'm not even sure how this equation would work, since I see divisions by zero arising in the first term (under the first square root, when abs(x) = 3), and imaginary numbers showing up in the last term (under the last square root, when {abs(x)-1}^2 > 4, ie x > 3 or x < -3).
What am I missing here? Is only the real part of the result used, and are divisions by zero ignored or approximated?
Running this, I do indeed see lots of RunTimeWarnings, and it is not unlikely matplotlib would get totally confused what numbers to work with (NaNs, Infs; trying print F at the end). Looks like it still manages when there's only a relatively low number of NaNs or Infs, which would explain that you're seeing part of the figure.
I'd think matplotlib's contour is fine, just confused by the input.