I am trying to calculate a velocity tensor from a time dependent rotationmatrix RE(t) (Namely the earth rotation at latitude 48.3°). This is achieved by determining the skew symmetric matrix SE(t) = dRE(t)/dt * RE.T. I am obtaining incorrect results when utilizing a float instead of a Sympy expression, as shown in the following example:
from IPython.display import display
import sympy as sy
sy.init_printing()  # LaTeX like pretty printing for IPython
def mk_rotmatrix(alpha, coord_ax="x"):
    """ Rotation matrix around coordinate axis """
    ca, sa = sy.cos(alpha), sy.sin(alpha)
    if coord_ax == "x":
        return sy.Matrix([[1,  0,   0],
                          [0, ca, -sa],
                          [0, sa, +ca]])
    elif coord_ax == 'y':
        return sy.Matrix([[+ca, 0, sa],
                          [0,   1,  0],
                          [-sa, 0, ca]])
    elif coord_ax == 'z':
        return sy.Matrix([[ca, -sa, 0],
                          [sa, +ca, 0],
                          [0,    0, 1]])
    else:
        raise ValueError("Parameter coord_ax='" + coord_ax +
                         "' is not in ['x', 'y', 'z']!")
t, lat = sy.symbols("t, lat", real=True)  # time and latitude
omE = 7.292115e-5  # rad/s -- earth rotation rate (15.04107 °/h)
lat_sy = 48.232*sy.pi/180  # latitude in rad
lat_fl = float(lat_sy)  # latitude as float
print("\nlat_sy - lat_fl = {}".format((lat_sy - lat_fl).evalf()))
# earth rotation matrix at latitiude 48.232°:
RE = (mk_rotmatrix(omE*t, "z") * mk_rotmatrix(lat - sy.pi/2, "y"))
# substitute latitude with sympy and float value:
RE_sy, RE_fl = RE.subs(lat, lat_sy), RE.subs(lat, lat_fl)
# Angular velocity in world coordinates as skew symmetric matrix:
SE_sy = sy.simplify(RE_sy.diff(t) * RE_sy.T)
SE_fl = sy.simplify(RE_fl.diff(t) * RE_fl.T)
print("\nAngular velocity with Sympy latitude ({}):".format(lat_sy))
display(SE_sy)  # correct result
print("\nAngular velocity with float latitude ({}):".format(lat_fl))
display(SE_fl)  # incorrect result
The result is:

For the float latitude the result is totally wrong in spite of the difference of only -3e-17 to the Sympy value. It is not clear to me, why this happens. Numerically, this calculation does not seem to be problematic.
My question is, how to work around such deficits. Should I avoid mixing Sympy and float/Numpy data types? They are quite difficult to detect for more complex settings.
PS: The Sympy version is 0.7.6.
 
                        
TL; DR
It is a bug. If you don't believe it, try this:
Two years ago, the default value for the parameter
tolinRealField.__init__was changed fromNonetoFalsein commit polys: Disabled automatic reduction to zero in RR and CC.Later,
tolwas reverted back toNoneto fix a simplification issue, in commit Changed tol on Complex and Real field to None.It seems the developers didn't expect this reversion would bring some other issue.
If you modify
tol=NoneatRealField.__init__inrealfield.py, totol=False, you will get the correct result forSE_fl.The change of
tolcan explain why you've got a wrong result, but I don't thint it is the root of the issue.IMHO, there is a deficiency in the polynomial factorization in SymPy. I'll illustrate this deficiency.
For convenience, let us do some preparation work.
Add the followings to your example.
We don't need to study the whole matrices. Let us focus on one element, element at row 1 and column 2. It has already shown the result is incorrect.
When we call
simplify, in this case, it's almost equivalent to a combination ofTR6andfactor.Now, we know wrong results would be produced during the invocation of
factor().Actually,
factoris just a wrapper, the major work is done by_symbolic_factor_list.Let us take a look at
_symbolic_factor_list. The key part is:We use the above
my_symbolic_factor_listto simulate this procedure.By design, the constant polynomial should execute
except PolificationFailed as exc:suite, while the other polynomials should executeelse:suite.expr_sy, which is a number afterexpand(), and1are both constant polynomials, thusPolificationFaileds were thrown.poly_flis-7.292115e-5 * sin(7.292115e-5*t) ** 0, namely,-7.292115e-5, a constant polynomial, whereasexpr_flis not. They were supposed to be the same polynomial, just different representation. Now they are not.This is the deficiency I mentioned.
Where is the missing
1.35525271560688e-20*sin(7.292115e-5*t)**2?Let us recall:
tolwas reverted back toNone, which means automatic reduction to zero inRRis enabled again.1.35525271560688e-20was reduced to zero. Thus,poly_flbecame a constant polynomial.If
tolisFalse, this won't happen.Now, we can explain why you've got
-2785579325.0. In theelse:suite,Poly.factor_listis called.According to docs:
poly_flis supposed to be a non constant polynomial, but it is just a number. Thus, SymPy was tring to use a rational number to approximatepoly_fl. The numerator is kept, while the denominator is discarded.I don't think we should blame mixing Sympy and float/Numpy data types. This problem is not caused by those pitfalls SymPy mentioned.
Even a very simple factorization can produce a counterintuitive result.
So it is a bug. Just let the developers fix it.