Why does Sympy cut off polynomial terms with small coefficients?

1k views Asked by At

I am trying to convert an expression containing terms with various degrees of a symbolic variable z_s into a polynomial in python using sympy.Poly() so that I can then extract the coefficients using .coeffs().

The expression I have is a high-order polynomial with independent, symbolic variable z_s. For some reason, when I convert the expression into a polynomial using sympy.Poly(), it seems to chop off the terms with small coefficients. Below is my function, and I included the line where I redefined it as a symbolic polynomial:

f = -1.29096669270427e-61*z_s**33 + 6.24438995041203e-59*z_s**32 - 6.41125090009095e-57*z_s**31 - 8.30852813320818e-55*z_s**30 + 5.84175807723288e-53*z_s**29 + 1.88577332997761e-50*z_s**28 + 9.46504910106607e-49*z_s**27 - 2.28903644846359e-46*z_s**26 - 4.63321594171589e-44*z_s**25 - 1.78254194888339e-42*z_s**24 + 6.43406800910469e-40*z_s**23 + 1.20425521347205e-37*z_s**22 + 3.4116753522246e-36*z_s**21 - 1.92084369416715e-33*z_s**20 - 3.04107684362554e-31*z_s**19 + 2.89289551256439e-30*z_s**18 + 6.38382842182985e-27*z_s**17 + 5.46438700248253e-25*z_s**16 - 8.50501280745176e-23*z_s**15 - 1.6344595302306e-20*z_s**14 + 1.07764488797684e-18*z_s**13 + 3.47026242660686e-16*z_s**12 - 2.93966702403133e-14*z_s**11 - 5.25394006214533e-12*z_s**10 + 1.21642330162702e-9*z_s**9 - 1.16577645027166e-7*z_s**8 + 6.82117624588787e-6*z_s**7 - 0.000267513120031891*z_s**6 + 0.00723589681411793*z_s**5 - 0.134846078975788*z_s**4 + 1.69035817278476*z_s**3 - 13.5277365002646*z_s**2 + 62.3459673862853*z_s - 76.5029927727737
sympy.Poly(f,z_s)

This returns:

Poly(-2.93966702403133e-14*z_s**11 - 5.25394006214533e-12*z_s**10 + 1.21642330162702e-9*z_s**9 - 1.16577645027166e-7*z_s**8 + 6.82117624588787e-6*z_s**7 - 0.000267513120031891*z_s**6 + 0.00723589681411793*z_s**5 - 0.134846078975788*z_s**4 + 1.69035817278476*z_s**3 - 13.5277365002646*z_s**2 + 62.3459673862853*z_s - 76.5029927727737, z_s, domain='RR')

As you can see, the first several terms were taken out.

At first I thought it was cutting off my high-order terms because there was some built-in cutoff for high-order polynomials, but I could not find that to be the case in any documentation. I then discovered that the terms that are being cut off seem to be cut off because of the low coefficient value (I assume sympy or python thinks that the term is negligible because its coefficient is so close to zero). You can see in my function that the first term has a coefficient of approximately -1.3e-61. I tested this theory using a simple example of a 2-term polynomial with degree 1 that has a "small" term cut off:

h = 10e-27*z_s + 1
sympy.Poly(h,z_s)

(EDIT: The + 1 should have been within the h function, I just fixed it so it reads correctly. This does not change the output.) This returns:

Poly(1.0, z_s, domain='RR')

As you can see, the term containing the coefficient 10e-27 was dropped out of the polynomial, and only the constant (1.0) remains.

I could not find any information on this on multiple forums, or in the SymPy documentation (unless I missed it). I did, however, find that people were trying to do the exact opposite of what I was trying to do (see here, for example): they were trying to cut off terms with small coefficients, whereas I am trying to PREVENT python from cutting off those terms.

Is there a way to tell python/sympy that I do not want those small coefficients set to zero?

Or, to bypass this problem, is there another way to extract the coefficients from my original function in order without using sympy.Poly() and .coeffs()?

1

There are 1 answers

0
AudioBubble On BEST ANSWER

I don't know why sympy truncates small coefficients when constructing a polynomial over reals, but it doesn't do this over rationals. So as a workaround, you can construct a polynomial with domain='QQ', extract coefficients, and then convert back to floats.

Example using your polynomial:

import sympy
z_s = symbols('z_s')
f = -1.29096669270427e-61*z_s**33 + 6.24438995041203e-59*z_s**32 - 6.41125090009095e-57*z_s**31 - 8.30852813320818e-55*z_s**30 + 5.84175807723288e-53*z_s**29 + 1.88577332997761e-50*z_s**28 + 9.46504910106607e-49*z_s**27 - 2.28903644846359e-46*z_s**26 - 4.63321594171589e-44*z_s**25 - 1.78254194888339e-42*z_s**24 + 6.43406800910469e-40*z_s**23 + 1.20425521347205e-37*z_s**22 + 3.4116753522246e-36*z_s**21 - 1.92084369416715e-33*z_s**20 - 3.04107684362554e-31*z_s**19 + 2.89289551256439e-30*z_s**18 + 6.38382842182985e-27*z_s**17 + 5.46438700248253e-25*z_s**16 - 8.50501280745176e-23*z_s**15 - 1.6344595302306e-20*z_s**14 + 1.07764488797684e-18*z_s**13 + 3.47026242660686e-16*z_s**12 - 2.93966702403133e-14*z_s**11 - 5.25394006214533e-12*z_s**10 + 1.21642330162702e-9*z_s**9 - 1.16577645027166e-7*z_s**8 + 6.82117624588787e-6*z_s**7 - 0.000267513120031891*z_s**6 + 0.00723589681411793*z_s**5 - 0.134846078975788*z_s**4 + 1.69035817278476*z_s**3 - 13.5277365002646*z_s**2 + 62.3459673862853*z_s - 76.5029927727737
[sympy.N(c) for c in sympy.poly(f,z_s,domain='QQ').coeffs()] 

returns

[-1.29096669270427e-61, 6.24438995041203e-59, -6.41125090009095e-57, -8.30852813320818e-55, 5.84175807723288e-53, 1.88577332997761e-50, 9.46504910106607e-49, -2.28903644846359e-46, -4.63321594171589e-44, -1.78254194888339e-42, 6.43406800910469e-40, 1.20425521347205e-37, 3.41167535222460e-36, -1.92084369416715e-33, -3.04107684362554e-31, 2.89289551256439e-30, 6.38382842182985e-27, 5.46438700248253e-25, -8.50501280745176e-23, -1.63445953023060e-20, 1.07764488797684e-18, 3.47026242660686e-16, -2.93966702403133e-14, -5.25394006214533e-12, 1.21642330162702e-9, -1.16577645027166e-7, 6.82117624588787e-6, -0.000267513120031891, 0.00723589681411793, -0.134846078975788, 1.69035817278476, -13.5277365002646, 62.3459673862853, -76.5029927727737]