I'm trying to solve a system of transcendental equations using sympy:
from sympy import *
A, Z, phi, d, a, tau, t, R, u, v = symbols('A Z phi d a tau t R u v', real=True)
system = [
Eq(A, sqrt(R**2*cos(u)**2 + 2*R*d*cos(a)*cos(u) + d**2 + 2*d*(v*sin(tau) - (R*sin(u) + t)*cos(tau))*sin(a) + (v*sin(tau) - (R*sin(u) + t)*cos(tau))**2)),
Eq(Z, v*cos(tau) + (R*sin(u) + t)*sin(tau)),
Eq(phi, (R*sin(a)*cos(u) - (v*sin(tau) - (R*sin(u) + t)*cos(tau))*cos(a))/A),
]
or in euclidian coordinates:
system = [
Eq(A, sqrt(d**2 + 2*d*x*cos(a) + 2*d*(z*sin(tau) - (t + y)*cos(tau))*sin(a) + x**2 + (z*sin(tau) - (t + y)*cos(tau))**2)),
Eq(Z, z*cos(tau) + (t + y)*sin(tau)),
Eq(phi, (x*sin(a) - (z*sin(tau) - (t + y)*cos(tau))*cos(a))/A),
Eq(R**2, x**2+y**2),
]
Essentially this is an intersection of a circle (radius A) with a skewed (angle τ) cylinder (radius R) rotating (angle a) around an eccentric axis (d). I'm interested in the function φ(A, Z) as I need to evaluate it for several hundred combinations of A and Z for a few combinations of the other parameters (R, A, d, t, τ).
Here is what I tried:
Directly using solve(system, [u, v, phi]): Needs too much time to complete.
Reducing it to one equation using first and then using solveset().
Inserting numbers for all parameters (example: R, A, d, t, tao = 25, 150, 125, 2, 5/180*pi) then using any combination of the N() and solve() or solveset().
I was able to get solutions for the simplified problem of the unskewed cylinder (t, tao = 0, 0) with d = sqrt(A**2 - R**2).
How can I solve this system of equations? Failing that: How can I get numeric values for φ for a few dozen combinations of the parameters and a few hundred points (A, Z) each?
If you are interested. Here is the code leading up to the equation:
A, Z, phi, d, a, tau, t, R, u, v = symbols('A Z phi d a tau t R u v', real=True)
r10, z10, phi10 = symbols('r10 z10 phi_10', real=True)
system10 = [Eq(A, r10), Eq(Z, z10), Eq(phi, phi10)]
x9, x8, y8, z8 = symbols('x9 x8 y8 z8', real=True)
system8 = [e.subs(r10, sqrt(x9**2+y8**2)).subs(z10, z8).subs(phi10, y8/A).subs(x9, x8+d) for e in system10]
r6, phi7, phi6, z6 = symbols('r6 phi_7 phi_6 z6', real=True)
system6 = [e.subs(x8, r6*cos(phi7)).subs(y8, r6*sin(phi7)).subs(z8, z6).subs(phi7, phi6+a) for e in system8]
x6, y6 = symbols('x_6 y_6', real=True)
system6xy = [simplify(expand_trig(e).subs(cos(phi6), x6/r6).subs(sin(phi6), y6/r6)) for e in system6]
# solve([simplify(e.subs(phi6, u).subs(r6, R).subs(z6, v).subs(d, sqrt(A**2-R**2))) for e in system6], [u, v, phi]) -> phi = acos(+-R/A)
r5, phi5, x5 = symbols('r_5 phi_5 x_5', real=True)
system5 = [e.subs(x6, x5).subs(y6, r5*cos(phi5)).subs(z6, r5*sin(phi5)) for e in system6xy]
r4, phi4, x4 = symbols('r_4 phi_4 x_4', real=True)
system4 = [e.subs(phi5, phi4 + tau).subs(r5, r4).subs(x5, x4) for e in system5]
x3, y3, z3 = symbols('x_3 y_3 z_3', real=True)
system3 = [expand_trig(e).subs(cos(phi4), y3/r4).subs(sin(phi4), z3/r4).subs(r4, sqrt(y3**2+z3**2)).subs(x4, x3) for e in system4]
x2, y2, z2 = symbols('x_2 y_2 z_2', real=True)
system2 = [e.subs(x3, x2).subs(y3, y2+t).subs(z3, z2) for e in system3]
system = [simplify(e.subs(x2, R*cos(u)).subs(y2, R*sin(u)).subs(z2, v)) for e in system2]
# solve([simplify(e.subs(tau, 0).subs(t, 0).subs(d, sqrt(A**2-R**2))) for e in system], [u, v, phi]) -> phi = acos(+-R/A)
Your first two equations must be solved for u and v; the 3rd then gives the corresponding value of phi. You can easily solve the 2nd for v.
Approach:
Solve the 2nd equation for v and substitute that into the 1st to obtain a function of only u and other variables, the values of which you will define (solving this high order symbolic expression will not be effective). You can't easily solve that equation for u, but you can get a reasonable solution for sin(u) in terms of cos(u) to give two roots: sin(u) = f1(cos(u)) and f2(cos(u)). I get
(Z*sin(tau) + d*sin(a)*cos(tau) - t - sqrt(A**2 - R**2*cos(u)**2 -
2*R*d*cos(a)*cos(u) - d**2*cos(a)**2)*cos(tau))/R
and
(Z*sin(tau) + d*sin(a)*cos(tau) - t + sqrt(A**2 - R**2*cos(u)**2 -
2*R*d*cos(a)*cos(u) - d**2*cos(a)**2)*cos(tau))/R
If we let x = cos(u) we know that f1(x)**2 + x**2 - 1 = 0 (which we call z1(x) and similarly z2(x) for the other root) AND we know that x is constrained to the range of [-1, 1]. So we can bisect zi(x) for x in the range of [-1, 1] to find the value of x; u = asin(x) can be substituted into the second equation to find v; finally, u and v can be substituted into the 3rd to find phi.
e.g. for {tau: 3, R: 7, A: 7, t: 4, a: 3, Z: 3, d: 2}
I get x = sin(u) = {-.704, 0.9886} which gives v = {-1.47, -3.16} and phi = {1.52, -.093}
Of course, those values may be meaningless if the input is meaningless, but with the right values hopefully this approach might prove worthwhile.
/c
Related
I am trying to solve an equation but the solve() function is taking over 10 minutes even on a high RAM colab notebook. Are there any simplifications to the problem that I can take to speed this along? Here is the code:
x, y, x_0, y_0, x_new, y_new, t, f = symbols('x y x_0 y_0 x_new y_new t f')
D = (2 * (1 - t) * sqrt(x * y) + t * (x + y)) / (2 * (x + y) * sqrt(x * y))
D_old = D.subs([(x, x_0), (y, y_0)])
D_new = D.subs([(x, x_new), (y, y_new)])
delta_D = D_new - D_old
target = Eq(delta_D, f)
answer = solve(target, x_new)
If it is taking a long time you must be trying to solve for one of the x or y values. This will require solving a messy cubic equation in many variables. It would be better if you just substituted in the values of interest and then used nsolve to find the roots of interest. Otherwise, you can get a symbolic solution to the generic cubic g3 = solve(a*x**3 + b*x**2 + c*x + d, x) and then substitute in the corresponding expressions for the coefficients of collect(sympy.solvers.solvers.unrad(target.rewrite(Add))[0], v) where v is the variable of interest. But I won't bog this down with more details until it is clear what you really want to do.
Firstly, the task is to write the code that will count the area of the triangle on the mathematical plane. However not just it, but use in the code the function, that will count the distance between 2 points on the plane.
So, what we have: 6 points like (x1, y1, x2, y2, x3, y3) and we need to write code for the area of the triangle using a function that counts the distance between 2 points on the plane.
P.S: one point = (x1, y1)
What is the problem? IDK
Let's see my code:
def length(x1, y1, x2, y2):
z = (abs(x1 - x2) ** 2 + abs(y1 - y2) ** 2) ** (1/2)
return z
a, b, c, d, e, f = float(input()), float(input()), float(input()), float(input()), float(input()), float(input())
a = length(a, b, c, d)
b = length(a, b, e, f)
c = length(c, d, e, f)
p = a + b + c
ans = (p(p - a)(p - b)(p - c)) ** (1/2)
print(ans)
Unfortunately, I receive a mistake: "'float' object is not callable"
PLZ, help with this code and maybe u will help with input. It is actually strange 6 input() in a row.
In Python, p(p-a) isn't a multiplication: It's an attempt to call a function p with the argument p-a, which, as alexpdev pointed out in their comment, is an error because your p (of type float) isn't a function. You need to explicitly write all the * operators.
ans = (p * (p - a) * (p - b) * (p - c)) ** (1/2)
Also, you got Heron's formula wrong: You've got p = a + b + c, but you need (a + b + c) / 2.
I was trying to calculate the point-plane distance from point (x_1, y_1, z_1) to the plane ax+by+cz+d=0 in SymPy, but I found the result incorrect. The following is the code I use
from sympy import *
a, b, c, d = symbols('a b c d')
x1, y1, z1 = symbols('x_1 y_1 z_1')
p1 = Point(x1, y1, z1)
plane1 = Plane(Point(0, 0, -d/c), normal_vector=(a, b, c))
plane1.distance(p1)
The correct answer should be \frac{ax_1+by_1+cz_1+d}{\sqrt{a^2+b^2+c^2}}
But SymPy gives me \frac{ax_1+by_1+cz_1+d}{\sqrt{a^2+b^2}}.
This looks like a bug to me. Here is how sympy calculates the distance (method distance(self, o)):
self = plane1
o = p1
x, y, z = map(Dummy, 'xyz')
k = self.equation(x, y, z)
a, b, c = [k.coeff(i) for i in (x, y, z)]
d = k.xreplace({x: o.args[0], y: o.args[1], z: o.args[2]})
t = abs(d/sqrt(a**2 + b**2 + c**2))
If we inspect k and a, b, c we see that the equation's coefficients are not correct:
print(k)
print(a, b, c)
# output:
_x*a + _y*b + c*(_z + d/c)
a b 0
c is zero, which explains your result. This can be fixed by simplifying the equation:
k = simplify(self.equation(x, y, z))
in which case the distance t is as you expected it:
print(t)
# output
Abs((a*x_1 + b*y_1 + c*z_1 + d)/sqrt(a**2 + b**2 + c**2))
Update: This was fixed in the current master of SymPy. See the corresponding issue.
Source: http://datasciencelab.wordpress.com/2014/01/10/machine-learning-classics-the-perceptron/
"The general equation of a line given two points in it, (x1,y2) and (x2,y2), is A + Bx + Cy = 0 where A, B, C can be written in terms of the two points. Defining a vector V = (A, B, C), any point (x,y) belongs to the line if V'x = 0, where x = (1,x,y). Points for which the dot product is positive fall on one side of the line, negatives fall on the other."
I don't quite understand how it works. Also, this line in particular:
self.V = np.array([xB*yA-xA*yB, yB-yA, xA-xB])
Why is Bx determined by yb-ya?
For what its worth, I'm learning Linear Algebra, so I'm quite familiar with the mathematical concept (I realize it is meant to be a normal), but how it is done escapes me.
Why is B determined by yb - ya? (or rather y2 - y1 for our example)
The text assumes the line equation to be: A + B*x + C*y = 0
Let's say we have two points from that line, P1(x1, y1) and P2(x2, y2)
Using the two-points form of the line equation, you will get y - y1 = [(y2 - y1)/(x2 - x1)] * (x - x1) (based on P1and P2)
The same equation, can be developed into [(x2 -x1)*y1 + (y1 - y2)*x1] + (y2 - y1) * x + (x1 - x2) * y = 0
Looking at A + B*x + C*y = 0, you see that:
A, is [(x2 -x1)*y1 + (y1 - y2)*x1] = x2*y1 - y2*x1
B, the coefficient of x is (y2 - y1)
C, the coefficient of y is (x1 - x2)
hence the value np.array([A, B, C]) in the source code appears as np.array([xB*yA - xA*yB, yB - yA, xA - xB])
I don't really know where to start with this problem, as I haven't had much experience with this but it is required to solve this part of the project using a computer.
I have a 2nd order ODE which is:
m = 1220
k = 35600
g = 17.5
a = 450000
and b is between 1000 and 10000 with increments of 500.
x(0)= 0
x'(0)= 5
m*x''(t) + b*x'(t) + k*x(t)+a*(x(t))^3 = -m*g
I need to find the smallest b such that the solution is never positive. I know what the graph should look like, but I just don't know how to use odeint to get a solution to the differential equation.
This is the code I have so far:
from numpy import *
from matplotlib.pylab import *
from scipy.integrate import odeint
m = 1220.0
k = 35600.0
g = 17.5
a = 450000.0
x0= [0.0,5.0]
b = 1000
tmax = 10
dt = 0.01
def fun(x, t):
return (b*x[1]-k*x[0]-a*(x[0]**3)-m*g)*(1.0/m)
t_rk = arange(0,tmax,dt)
sol = odeint(fun, x0, t_rk)
plot(t_rk,sol)
show()
Which doesn't really produce much of anything.
Any thoughts? Thanks
To solve a second-order ODE using scipy.integrate.odeint, you should write it as a system of first-order ODEs:
I'll define z = [x', x], then z' = [x'', x'], and that's your system! Of course, you have to plug in your real relations:
x'' = -(b*x'(t) + k*x(t) + a*(x(t))^3 + m*g) / m
becomes:
z[0]' = -1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g)
z[1]' = z[0]
Or, just call it d(z):
def d(z, t):
return np.array((
-1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g), # this is z[0]'
z[0] # this is z[1]'
))
Now you can feed it to the odeint as such:
_, x = odeint(d, x0, t).T
(The _ is a blank placeholder for the x' variable we made)
In order to minimize b subject to the constraint that the maximum of x is always negative, you can use scipy.optimize.minimize. I'll implement it by actually maximizing the maximum of x, subject to the constraint that it remains negative, because I can't think of how to minimize a parameter without being able to invert the function.
from scipy.optimize import minimize
from scipy.integrate import odeint
m = 1220
k = 35600
g = 17.5
a = 450000
z0 = np.array([-.5, 0])
def d(z, t, m, k, g, a, b):
return np.array([-1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g), z[0]])
def func(b, z0, *args):
_, x = odeint(d, z0, t, args=args+(b,)).T
return -x.max() # minimize negative max
cons = [{'type': 'ineq', 'fun': lambda b: b - 1000, 'jac': lambda b: 1}, # b > 1000
{'type': 'ineq', 'fun': lambda b: 10000 - b, 'jac': lambda b: -1}, # b < 10000
{'type': 'ineq', 'fun': lambda b: func(b, z0, m, k, g, a)}] # func(b) > 0 means x < 0
b0 = 10000
b_min = minimize(func, b0, args=(z0, m, k, g, a), constraints=cons)
I don't think you can solve your problem as stated: your initial conditions, with x = 0 and x' > 0 imply that the solution will be positive for some values very close to the starting point. So there is no b for which the solution is never positive...
Leaving that aside, to solve a second order differential equation, you first need to rewrite it as a system of two first order differential equations. Defining y = x' we can rewrite your single equation as:
x' = y
y' = -b/m*y - k/m*x - a/m*x**3 - g
x[0] = 0, y[0] = 5
So your function should look something like this:
def fun(z, t, m, k, g, a, b):
x, y = z
return np.array([y, -(b*y + (k + a*x*x)*x) / m - g])
And you can solve and plot your equations doing:
m, k, g, a = 1220, 35600, 17.5, 450000
tmax, dt = 10, 0.01
t = np.linspace(0, tmax, num=np.round(tmax/dt)+1)
for b in xrange(1000, 10500, 500):
print 'Solving for b = {}'.format(b)
sol = odeint(fun, [0, 5], t, args=(m, k, g, a, b))[..., 0]
plt.plot(t, sol, label='b = {}'.format(b))
plt.legend()