Re-writing sympy expression as cubic polynomial with defined variables and coefficients - python-3.x

Given an expression in sympy, how do I re-write the expression as a polynomial defined as [1]:
D11*(omega**2/k**2)**3 + D22*(omega**2/k**2)**2 + D33*(omega**2/k**2) + D44 = 0
Note that this is different from the similar question asked here (Rewrite equation as polynomial).
Let
x=(omega**2/k**2)
then
D11*x**3 + D22*x**2 + D33*x + D44 = 0
I would like to find D11, D22, D33, and D44, given that x=omega**2/k**2
Normally, the collect function (http://docs.sympy.org/latest/tutorial/simplification.html) would collect similar terms, but in this situation, it does not seem to work well.
Here is a simple example that helps to explain what I am trying to accomplish. The output should be in the form D11*(omega**2/k**2)**3 + D22*(omega**2/k**2)**2 + D33*(omega**2/k**2) + D44 = 0
from sympy import symbols, collect
from IPython.display import display
omega = symbols('omega')
k = symbols('k')
a = symbols('a')
b = symbols('b')
c = symbols('c')
D11 = a*b*c
D22 = c+b
D33 = a+c*b + b
D44 = a+b
x = omega**2/k**2
expr = (D11*x**3 + D22*x**2 + D33*x + D44)
expr0 = expr.expand()
expr1 = collect(expr0, x)
display(expr1)
The output is:
a*b*c*omega**6/k**6 + a + b + omega**2*(a + b*c + b)/k**2 + omega**4*(b + c)/k**4
Although numerically correct, I would like the polynomial in the form [1] given above, and once it is in the form, I would like to extract the D11, D22, D33, and D44 coefficients.
Using evaluate=False in the collect function gets me closer to the goal, since the output now becomes:
{omega**2/k**2: a + b*c + b, omega**4/k**4: b + c, omega**6/k**6: a*b*c, 1: a + b}

Starting with your expr1,
expr1 = a*b*c*omega**6/k**6 + a + b + omega**2*(a + b*c + b)/k**2 + omega**4*(b + c)/k**4
it seems the easiest way to get the coefficients is to turn x into a symbol, at least temporarily:
Poly(expr1.subs(x, Symbol('x')), Symbol('x')).all_coeffs()
returns [a*b*c, b + c, a + b*c + b, a + b] (the coefficients are listed starting with the highest degree).
I would probably have x = Symbol('x') there to begin with, and only use expr.subs(x, omega**2/k**2) when needed.
SymPy's internal order of terms in a sum cannot be changed. To "rearrange" a SymPy expression means to print it in a more human-friendly form. This is largely a string manipulation problem, as we are no longer producing a SymPy object.
str(Poly(expr1.subs(x, Symbol('x')), Symbol('x'))).replace('x', '(' + str(x) + ')')
returns Poly(a*b*c*(omega**2/k**2)**3 + (b + c)*(omega**2/k**2)**2 + (a + b*c + b)*(omega**2/k**2) + a + b, (omega**2/k**2), domain='ZZ[a,b,c]')
Adding .split(',')[0].replace('Poly(', '') to the above removes the meta-data of a polynomial, leaving a*b*c*(omega**2/k**2)**3 + (b + c)*(omega**2/k**2)**2 + (a + b*c + b)*(omega**2/k**2) + a + b

Related

Solve for x using python

I came across a problem. One string is taken as input say
input_string = "12345 + x = x * 5 + (1+x)* x + (1+18/100)"
And get output of x using python. I am not able to figure out logic for this.
Here is a complete SymPy example for your input:
from sympy import Symbol, solve, Eq
from sympy.parsing.sympy_parser import parse_expr
input_string = "12345 + x = x * 5 + (1+x)* x + (1+18/100)"
x = Symbol('x', real=True)
lhs = parse_expr(input_string.split('=')[0], local_dict={'x':x})
rhs = parse_expr(input_string.split('=')[1], local_dict={'x':x})
print(lhs, "=", rhs)
sol = solve(Eq(lhs, rhs), x)
print(sol)
print([s.evalf() for s in sol])
This outputs:
x + 12345 = x*(x + 1) + 5*x + 59/50
[-5/2 + 9*sqrt(15247)/10, -9*sqrt(15247)/10 - 5/2]
[108.630868798908, -113.630868798908]
Note that solve() gives a list of solutions. And that SymPy normally does not evaluate fractions and square roots, as it prefers solutions without loss of precision. evalf() evaluates a float value for these expressions.
Well, that example shows a quadratic equation which may have no solutions, one solution, or two solutions. You would have to rearrange the terms symbolically to come to
input_string = "x**2 + 5*x - 12345 + (118/100)"
But that means you need to implement rules for multiplication, addition, subtraction and potentially division. At least for Python there is a library called SymPy which can parse such strings and provide an expression that you can evaluate and even solve.

Distance to a straight line in standard form

For a 3D straight line expressed in the standard form
a1*x + b1*y + c1*z + d1 = 0
a2*x + b2*y + c2*z + d2 = 0
and a given point x0,y0,z0
what is the distance from the point to the straight line?
Distance from point P0 to parametric line L(t) = Base + t * Dir is
Dist = Length(CrossProduct(Dir, P0 - Base)) / Length(Dir)
To find direction vector:
Dir = CrossProduct((a1,b1,c1), (a2,b2,c2))
To get some arbitrary base point, solve equation system with 2 equations and three unknowns (find arbitrary solution):
a1*x + b1*y + c1*z + d1 = 0
a2*x + b2*y + c2*z + d2 = 0
Check minors consisting of a and b, a and c, b and c coefficients. When minor is non-zero, corresponding variable might be taken as free one. For example, if a1 * b2 - b1 * a2 <> 0, choose variable z as free - make it zero or another value and solve system for two unknowns x and y.
(I omitted extra cases of parallel or coinciding planes)

Simplify strategies: Convince sympy that complicated term is zero

What are good strategies/heuristics to convince sympy that a complicated term including trigonometric functions is 0?
For example, let's consider the following term:
-2*a**2*b*(a**2 + b**2 + c**2)**(-12.0)*(a**2*(a**2 + b**2 + c**2)**9.0 + b**2*(a**2 + b**2 + c**2)**9.0 + c**2*(a**2 + b**2 + c**2)**9.0 - (a**2 + b**2 + c**2)**10.0)*sin(0.5*sqrt(a**2 + b**2 + c**2))**2
Wolfram alpha agrees with me that it should be zero.
I tried sympy.simplify as well as sympy.trigsimp, but not sure what to try next.
I'm using python 3.6.3 and sympy 1.1.1.
No special effort is needed; just avoid floating point numbers, representing them by integers or rationals. Floating point numbers are an obstacle to symbolic math because floating point arithmetics doesn't work like regular arithmetics. (The Python 2 habit of making everything a float so that division works right really needs to be unlearned to use SymPy effectively.)
e = -2*a**2*b*(a**2 + b**2 + c**2)**(-12)*(a**2*(a**2 + b**2 + c**2)**9 + b**2*(a**2 + b**2 + c**2)**9 + c**2*(a**2 + b**2 + c**2)**9 - (a**2 + b**2 + c**2)**10)*sin(sqrt(a**2 + b**2 + c**2)/2)**2
e.simplify()
returns 0.
Besides changing 12.0 to 12, etc I also got changed 0.5*sqrt(a**2 + b**2 + c**2) to sqrt(a**2 + b**2 + c**2)/2. Other options here include replacing 0.5 by
Rational(1, 2), or
Rational('0.5'), or
S.Half (SymPy's built-in 1/2 object)
S(1)/2 (S turns 1 into SymPy integer, which makes the division by 2 go by SymPy rules instead of Python rules).

Arithmetic Mean with exponent of small numbers

Due to rounding error, cannot get mean of three numbers:
a=-1.11e4
b=-1.12e4
c=-1.13e4
Mean=1/3 *[exp(a)+exp(b)+exp(c)]
How to get the results in a log value?
You're trying to find log((exp(a) + exp(b) + exp(c)) / 3), but a, b, and c are so low that the result of exp underflows to 0. You can fix this by adjusting the values so exp doesn't underflow.
Let d = max(a, b, c). Then we have the following equality:
M = log((exp(a) + exp(b) + exp(c)) / 3)
= log(exp(d) * (exp(a-d) + exp(b-d) + exp(c-d)) / 3)
= log(exp(d)) + log((exp(a-d) + exp(b-d) + exp(c-d)) / 3)
= d + log((exp(a-d) + exp(b-d) + exp(c-d)) / 3)
So we can calculate the result as d + log((exp(a-d) + exp(b-d) + exp(c-d)) / 3). Since d is equal to one of a, b, or c, one of the exp arguments is 0, and the rest are at most 0. Thus, one of the exp outputs is 1, and the rest are at most 1. We don't have to worry about overflow or underflow; while an underflow might still occur in one or more exp calls, it won't be a problem any more, since the log argument won't be 0.

How to set up quadratic equation for a ray/sphere intersection?

I'm researching the math for a ray tracer, but I'm not following a transition that is made in just about every article I've read on the subject. This is what I have:
Formula for a sphere:
(X - Cx)^2 + (Y - Cy)^2 + (Z - Cz)^2 - R^2 = 0
Where R is the radius, C is the center, and X, Y, Z are all the points in the sphere.
Formula for a line:
X + DxT, Y + DyT, Z + DzT
where D is a normalized direction vector for the line and X, Y, Z are all the points on the line, and T is a parameter for some point on the line.
By substituting the components of the line into the sphere equation, we get:
(X + DxT - Cx)^2 + (Y + DyT - Cy)^2 + (Z + DzT - Cz)^2 - R^2 = 0
I follow everything up to that point (at least I think I do), but then every tutorial I've read makes a jump from that to a quadratic equation without explaining it (this is copied from one of the sites, so the terms are a little different from my example):
A = Xd^2 + Yd^2 + Zd^2
B = 2 * (Xd * (X0 - Xc) + Yd * (Y0 - Yc) + Zd * (Z0 - Zc))
C = (X0 - Xc)^2 + (Y0 - Yc)^2 + (Z0 - Zc)^2 - Sr^2
I get how to then solve for T using the quadratic formula, but I don't understand how they get to the quadratic equation from the above formulas. I'm assuming that's just some piece of common math knowledge that I've long since forgotten, but googling for "How to set up a quadratic equation" hasn't really yielded anything either.
I'd really like to understand how to get to this step before moving on, as I don't like writing code I don't fully grasp.
Here's a detailed walkthrough of each step; hopefully this will make things crystal clear. The equation for a three-dimensional sphere is:
(x-a)^2 + (y-b)^2 + (z-c)^2 = r^2
with <a, b, c> being the center of the sphere and r its radius. The point <x, y, z> is on the sphere if it satisfies this equation.
The parametric equations for a ray are:
X = xo + xd*t
Y = yo + yd*t
Z = zo + zd*t
where <xo, yo, zo> is the origin of the ray, and <xd,yd,yd> is camera ray's direction.
To find the intersection, we want to see what points on the ray are the same as points on the sphere. So we substitute the ray equation into the sphere equation:
(xo + xd*t - a)^2 + (yo + yd*t - b)^2 + (zo + zd*t - c)^2 = r^2
which expands to:
(xd^2 + yd^2 + zd^2) * t^2 +
[2[xd * (xo - a) + yd * (yo - b) + zd *(zo - c)]] * t +
[(xo - a)^2 + (yo - b)^2 + (zo - c^)2 - r^2] * 1
= 0
Notice that this is a quadratic equation in the form At^2 + Bt + C = 0, with:
A = (xd^2 + yd^2 + zd^2)
B = [2[xd * (xo - a) + yd * (yo - b) + zd *(zo - c)]]
C = [(xo - a)^2 + (yo - b)^2 + (zo - c^)2 - r^2]
We can apply the general quadratic formula for an unknown variable, which is:
t = [-B +- sqrt(B^2 - 4AC)] / 2A
The B^2 - 4AC portion is called the "discriminant". Depending on the value of the discriminant, we will get zero, one, or two solutions to this equation:
If it is less than zero, the solution is an imaginary number, and the ray and sphere do not intersect in the real plane.
If it is equal to zero, then the ray intersects the sphere at exactly 1 point (it is exactly tangent to the sphere).
If it is greater than zero, then the ray intersects the sphere at exactly 2 points.
If the discriminant indicates that there's no solution, then you're done! The ray doesn't intersect the sphere. If the discriminant indicates at least one solution, you can solve for t to determine the intersection point. The two solutions are:
t_1 = [-B + sqrt(B^2 - 4AC)] / 2A
t_2 = [-B - sqrt(B^2 - 4AC)] / 2A
The smaller solution is the point at which the ray first hits the sphere.
From here:
(X + DxT - Cx)^2 + (Y + DyT - Cy)^2 + (Z + DzT - Cz)^2 - R^2 = 0
Expand the three squared terms, so you have a long expression:
X^2 + Dx^2T^2 + Cx^2 + 2XDxT - 2XCx - 2DxTCx + ...... = 0
(This is due to using the formula (x+y+z)^2 = x^2 + y^2 + z^2 + 2xy + 2xz + 2yz)
Then group so you have factors of T^2, T, and 1:
(....)T^2 + (....)T + .... = 0
These factors are the A,B,C given above. This is a quadratic equation for T, and can be solved using the quadratic formula.

Resources