Numpy to solve multi-variable algebraic function - python

Let's assume we know the following:
a = 1
b = 4
c = 7
d = 2
e = 2
f = 9
With these six variables, we can solve for X, Y, and Z as follows:
X = (b - a) / (d + e)
Y = 2 * np.sin(X/2) * ((c / X) + f)
Z = 2 * np.sin(X/2) * ((a / X) + d)
print(X)
print(Y)
print(Z)
0.75
13.42999273315508
2.4418168605736503
Now, let's flip things around and assume that we're given the values of X, Y, and Z, as well as d, e, and f.
How would we solve for the values of a, b, and c? My algebra is shaky. Is this something that Numpy can handle?
Thanks!

Numpy, no. (Or rather, not as easily, or accurately.)
Sympy, yes.
Declare a, b and c as symbols.
Create expressions that should equal to zero (by moving the left hand side of the equation to the right hand side and changing the sign).
Use sympy.sin instead of math.sin or np.sin.
Use sympy.solve to get the solution of the system.
import sympy
from sympy.abc import a, b, c
X = 0.75
Y = 13.42999273315508
Z = 2.4418168605736503
d = 2
e = 2
f = 9
e1 = (b - a) / (d + e) - X
e2 = 2 * sympy.sin(X/2) * ((c / X) + f) - Y
e3 = 2 * sympy.sin(X/2) * ((a / X) + d) - Z
sympy.solve([e1, e2, e3])
# => {a: 1.00000000000000, b: 4.00000000000000, c: 7.00000000000000}

Solving equations with unknown variables can be done in Sympy.
from sympy import symbols, solve, Eq, sin
a, b, c, d, e, f, X, Y, Z = symbols("a b c d e f X Y Z")
eqns = [
Eq(X, (b - a) / (d + e)),
Eq(Y, 2 * sin(X / 2) * ((c / X) + f)),
Eq(Z, 2 * sin(X / 2) * ((a / X) + d)),
]
assignments = {a: 1, b: 4, c: 7, d: 2, e: 2, f: 9}
print(solve([eq.subs(assignments) for eq in eqns], [X, Y, Z]))
Output:
[(3/4, 110*sin(3/8)/3, 20*sin(3/8)/3)]
To solve for a, b, c just replace X, Y, Z in solve and add their values in the assignments dict.

Related

How can I resolve this binomial equation by coding?

I'm having a problem finding out how to discover the write function to solve this problem:
Write a function that will take as an input two numbers (l,m) and return as a tuple the coefficients (a,b,c) for the quadratic equation a x^2 + b x + c found from expanding (x + l) * (x + m).
def func(l,m):
a = 1
equation = (a * (x ** 2)) + (b * x) + c
coef = [a,b,c]
eq2 = (x + m) * (x + l)
coef1 = m + l
coef2 = m * l
if coef1 == coef[1] and coef2 == coef[2]:
return coef
func(2,2)
Just to make it clear:
Your problem states:
return as a tuple the coefficients (a,b,c) for the quadratic equation
a x^2 + b x + c found from expanding (x + l) * (x + m).
Let's find the equation by expanding:
(x + l) * (x + m) =
= x^2 + l*x + m*x + l*m =
= x^2 + (l+m)*x + l*m
Now, by coefficients comparison with a x^2 + b x + c, we get that:
a = 1
b = l + m
c = l * m
So your function can basically return (1, l + m, l * m) directly...
Now that we have your code, I can tell you you're not using Python functions right. You can't create an unknown variable as you can do in math (here you called x)
There are modules who allow such operation with different syntax such as SymPy.
If you don't want to use it and you want to solve it "by-hand" maybe for a school project you'll need to compute a, b and conly from l and m with formulas.
As mentionned Tomerikoo
a = 1
b = l + m
c = l * m

point-plane distance in SymPy

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.

Simplify solution for Symbolic solver for system of equations in Python (with symbolic output)

I have the following system of equations :
-2yz = a
-2xy = b
-x^2 + y^2 - z^2 = c
How can I simplify the solution for these equations using SymPy? x, y, z are unknowns. I have the following script:
from sympy import *
x, y, z = var('x y z')
a, b, c = var('a b c')
E1 = -2 * y * z - a
E2 = -2 * x * y - b
E3 = -x**2 + y ** 2 - z ** 2 - c
sols = solve([E1, E2, E3], [x, y, z])
The simplifies solution is not really palatable. Any idea?
You might consider running cse over your solutions. I will let you see what the replacments are, but here is the result:
>>> r, e = cse(flatten(sols))
>>> reshape(e, (3,)) # restore tuples of 3 solutions
[
(x1*x9, -x11*x13, x9),
(-x1*x13, x11*x9, -x13),
(-x16, x12*x17, -x15),
(x16, x17*x8, x15)]

sympy: How to solve this system of transcendental equations?

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

Can it be that `sympy` is much, much slower than Mathematica?

I'm reproducing Mathematica results using Sympy, and I'm new to the latter, so I might be doing things wrong. However, I noticed that some stuff that took a minute at max using Mathematica is just taking forever (read: did not finish after I started it an hour ago) in sympy. That applies both to Simplify(), and solve(). Am I doing something wrong, or is that really the case?
I'll attach my solve() case:
import sympy as sp
from sympy import init_printing
init_printing()
p, r, c, p, y, Lambda = sp.symbols('p r c p y Lambda')
F = sp.Symbol('F')
eta1 = lambda p: 1/(1-sp.exp(-Lambda) * sp.exp(-Lambda)*(sp.exp(Lambda) - 1 - Lambda))
eta2 = lambda p: 1/(1-sp.exp(-Lambda)) * sp.exp(-Lambda)/(1-F) * (sp.exp(Lambda*(1- F)) - 1 - Lambda*(1-F))
eta = lambda p: 1 - eta1(p) + eta2(p)
etaOfR = sp.limit(eta(p), F, 1)
S = lambda p: eta(p)*y/p*(p-c)
SOfR = etaOfR*y/r*(r-c)
sp.solve(S(p)-SOfR, F)
The corresponding Mathematica code:
ClearAll[r, p, lambda, a, A, c, eta, f, y, constant1, constant2, eta, \
etaOfR]
constant1[lambda_] := Exp[-lambda]/(1 - Exp[-lambda]);
constant2[lambda_] := constant1[lambda]*(Exp[lambda] - 1 - lambda);
eta[lambda_, f_] :=
1 - constant2[lambda] +
constant1[lambda]*(Exp[lambda*(1 - f)] - 1 - lambda*(1 - f)) ;
etaOfR[lambda_] := Limit[eta[lambda, f], f -> 1];
expression1[lambda_, f_] :=
y/p (p - c) eta[lambda, f] == y/r (r - c) etaOfR[lambda];
Solve[expression1[lambda, f], f] // FullSimplify
Output:
{{f -> (-(1 + lambda) p r +
c (lambda p + r) + (c -
p) r ProductLog[-E^(((-c lambda p + (c (-1 + lambda) +
p) r)/((c - p) r)))])/(lambda (c - p) r)}}
The correct way to do it is:
from sympy import *
init_printing()
p, r, c, p, y, lam, f = symbols('p r c p y lambda f')
constant1 = exp(-lam) / (1 - exp(-lam))
constant2 = constant1 * (exp(lam) - 1 - lam)
eta = 1 - constant2 + constant1 * (exp(lam * (1-f)) - 1 - lam * (1 - f))
etaOfR = limit(eta, f, 1)
expression1 = Eq(y / p * (p - c) * eta,
y / r * (r - c) * etaOfR)
solve(expression1, f)
You can also check the notebook here:
http://nbviewer.ipython.org/gist/jankoslavic/0ad7d5c2731d425dabb3
The results is equal to the one from Mathematica (see last line) and Sympy performance is comparable.

Categories