Simplify strategies: Convince sympy that complicated term is zero - python-3.x

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).

Related

How can I do more accurate calculation ln(1+x) in verliog

I want to calculate ln(1+x)in verilog A.
I know that the code is
y = ln(1+x);
But if the x value becomes very small(ex x=3.52e-18), the y value becomes zero.
In MATLAB, I can calculate like
y=log1p(x);
and I want to calculate like that code.
How can I calculate more accurately?
The only way to add math functions that are not part of the IEEE standard are by using the C interface.
In SystemVerilog, you can add this line and not have to write any C code
import "DPI-C" function real log1p(real arg);
But in Verilog, you would have to call a VPI wrapper function that called log1p from code that you would have to write in C.
You can always write a polynomial or rational or table-driven approximation to log1p, or find a library where someone else already implemented it, of course.
But there's a cheap trick to compute log(1 + π‘₯) given π‘₯ in a pinch if you already have a function to compute log(𝑦)!
If 1 + x = 1β€”that is, if fl(1 + π‘₯) = 1β€”then just return π‘₯.
Otherwise, evaluate x*log(1 + x)/((1 + x) βˆ’ 1) (with exactly that parenthesization in the denominator).
Why does this work?
For the easy case of |π‘₯| > 1/2, this works because fl(1 + π‘₯) only loses at worst a single bit of precision from π‘₯, so the quotient π‘₯/(fl(1 + π‘₯) βˆ’ 1) essentially cancels (or exactly cancels, if π‘₯ ≀ βˆ’1/2 or π‘₯ β‰₯ 1) leaving essentially only log(fl(1 + π‘₯)) β‰ˆ log(1 + π‘₯).
For the interesting case of ulp(1)/2 < |π‘₯| ≀ 1/2, this works because our approximation factors into π‘₯β‹…πœ‡(π‘₯) where πœ‡(π‘₯) := log(1 + π‘₯)/π‘₯ is very well-conditioned near zero so that we still get a good approximation to πœ‡(π‘₯) even if we actually evaluate πœ‡(fl(1 + π‘₯) βˆ’ 1).
So while log(1 + x) alone magnifies the rounding error in 1 + x,
x*log(1 + x)/((1 + x) - 1)
gives a good approximation to log(1 + π‘₯), within a handful of ulps (provided your log function has small error).
Details:
The absolute error of fl(1 + π‘₯) βˆ’ 1 from π‘₯ is at most ulp(1)/2.
πœ‡(πœ‰) β‰₯ 1/2 for all |πœ‰| ≀ 1/2.
|πœ‡β€²(πœ‰)| ≀ 2 for all |πœ‰| ≀ 1/2.
Hence by the mean value theorem there is some πœ‰ between π‘₯ and fl(1 + π‘₯) βˆ’ 1 such that
|πœ‡(π‘₯) βˆ’ πœ‡(fl(1 + π‘₯) βˆ’ 1)| = |πœ‡β€²(πœ‰)β‹…(π‘₯ βˆ’ [fl(1 + π‘₯) βˆ’ 1])| ≀ 2β‹…|1 + π‘₯ βˆ’ fl(1 + π‘₯)| ≀ 2β‹…ulp(1)/2 = ulp(1),
so that the relative error of πœ‡(fl(1 + π‘₯) βˆ’ 1) from πœ‡(π‘₯) is |πœ‡(π‘₯) βˆ’ πœ‡(fl(1 + π‘₯) βˆ’ 1)|/|πœ‡(π‘₯)| ≀ 2β‹…ulp(1).
And πœ‡(fl(1 + π‘₯) βˆ’ 1) is what log(1 + x)/((1 + x) - 1) approximates.
(For positive inputs, |πœ‡β€²(πœ‰)| ≀ 1/2 so the bound improves to ulp(1)/2.)
The edge case where 1 + x = 1 happens if and only if |π‘₯| ≀ ulp(1)/2.
When this holds, since log(1 + π‘₯) = π‘₯ + O(π‘₯Β²) the error of series truncation (specifically, at most |π‘₯|/2 ≀ ulp(1)/4, if you look at the exact terms of the series) is no worse than a rounding error.
This case must be treated specially in order to avoid dividing by zero given by (1 + x) - 1.
(This technique appears as Theorem 4 in Goldberg's infamous note on What Every Computer Scientist Should Know about Floating-Point Arithmetic.)

How can I round numbers with unknown constants on Python

I'm having problems with a project.
I want any number that multiplies with G (or G**yyy)with less precision than 0,5e-14 to be equal to 0.
I don't know how I can round a number next to a unknown constant.
I tried:
- the function round(x1,14),didn't work, gave me "type Add doesn't define round method"
- the
Input: x0=0.025*G-4.03
x1=x0-(((func.subs(x,x0))**2)/(func.subs(x,x0+func.subs(x,x0))-func.subs(x,x0)))
print(simplify(x1)-x0)
Output: -0.025*G + 4.03 + 1.0*(3.94430452610506e-31*G**10 + 1.81753552562921e-27*G**9 - 7.10858338912758e-25*G**8 - 1.52201232709757e-22*G**7 + 4.2351647362715e-22*G**6 - 2.02610280983229e-18*G**5 + 3.53883589099269e-16*G**4 - 2.39530617562878e-14*G**3 + 6.21724893790087e-13*G**2 + 1660.85701907689*G - 266416.790310032)/(5.16987882845642e-26*G**8 - 1.73707928636136e-23*G**7 - 3.3881317890172e-21*G**6 + 9.75781955236954e-19*G**5 - 5.55111512312578e-17*G**4 + 4.66293670342566e-15*G**3 - 1.4210854715202e-13*G**2 + 6.82121026329696e-12*G + 66434.2807630764
I want any number that multiplies with G (or G**yyy)with less precision than 0,5e-14 to be equal to 0.
For example
what I have: 3.94430452610506e-31*G**10
I want this to presented as: 0

Re-writing sympy expression as cubic polynomial with defined variables and coefficients

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

Python implementation of bilinear quadrilateral interpolation

I'm trying to perform bilinear quadrilateral interpolation. So I have four nodes with known values and I want to find a value that lies in between those four nodes by interpolation, but the four nodes do not form a rectangle. 4-node sketch
I found several ways to solve this, but none of them is implemented in Python already. Does there exist somewhere an already finished python implementation? If not which of the two solutions below would you recommend? Or would you recommend another approach?
**************Different solutions*******************
Solution 1:
I found here, https://www.colorado.edu/engineering/CAS/courses.d/IFEM.d/IFEM.Ch16.d/IFEM.Ch16.pdf, that I should solve the following set of equations: set of equations with Ni being: N definition.
Finally this results in solving a set of equations of the form:
a*x+b*y+c*xy=z1
d*x+e*y+f*xy=z2
with x and y being the unknowns. This could be solved numerically using fsolve.
Solution 2:
This one is completely explained here: https://math.stackexchange.com/questions/828392/spatial-interpolation-for-irregular-grid
but it's quite complex and I think it will take me longer to code it.
Due to a lack of answers I went for the first option. You can find the code below. Recommendations to improve this code are always welcome.
import numpy as np
from scipy.optimize import fsolve
def interpolate_quatrilateral(pt1,pt2,pt3,pt4,pt):
'''Interpolates a value in a quatrilateral figure defined by 4 points.
Each point is a tuple with 3 elements, x-coo,y-coo and value.
point1 is the lower left corner, point 2 the lower right corner,
point 3 the upper right corner and point 4 the upper left corner.
args is a list of coordinates in the following order:
x1,x2,x3,x4 and x (x-coo of point to be interpolated) and y1,y2...
code based on the theory found here:
https://www.colorado.edu/engineering/CAS/courses.d/IFEM.d/IFEM.Ch16.d/IFEM.Ch16.pdf'''
coos = (pt1[0],pt2[0],pt3[0],pt4[0],pt[0],
pt1[1],pt2[1],pt3[1],pt4[1],pt[1]) #coordinates of the points merged in tuple
guess = np.array([0,0]) #The center of the quadrilateral seem like a good place to start
[eta, mu] = fsolve(func=find_local_coo_equations, x0=guess, args=coos)
densities = (pt1[2], pt2[2], pt3[2], pt4[2])
density = find_density(eta,mu,densities)
return density
def find_local_coo_equations(guess, *args):
'''This function creates the transformed coordinate equations of the quatrilateral.'''
eta = guess[0]
mu = guess[1]
eq=[0,0]#Initialize eq
eq[0] = 1 / 4 * (args[0] + args[1] + args[2] + args[3]) - args[4] + \
1 / 4 * (-args[0] - args[1] + args[2] + args[3]) * mu + \
1 / 4 * (-args[0] + args[1] + args[2] - args[3]) * eta + \
1 / 4 * (args[0] - args[1] + args[2] - args[3]) * mu * eta
eq[1] = 1 / 4 * (args[5] + args[6] + args[7] + args[8]) - args[9] + \
1 / 4 * (-args[5] - args[6] + args[7] + args[8]) * mu + \
1 / 4 * (-args[5] + args[6] + args[7] - args[8]) * eta + \
1 / 4 * (args[5] - args[6] + args[7] - args[8]) * mu * eta
return eq
def find_density(eta,mu,densities):
'''Finds the final density based on the eta and mu local coordinates calculated
earlier and the densities of the 4 points'''
N1 = 1/4*(1-eta)*(1-mu)
N2 = 1/4*(1+eta)*(1-mu)
N3 = 1/4*(1+eta)*(1+mu)
N4 = 1/4*(1-eta)*(1+mu)
density = densities[0]*N1+densities[1]*N2+densities[2]*N3+densities[3]*N4
return density
pt1= (0,0,1)
pt2= (1,0,1)
pt3= (1,1,2)
pt4= (0,1,2)
pt= (0.5,0.5)
print(interpolate_quatrilateral(pt1,pt2,pt3,pt4,pt))

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