Chop Polynomial Coefficients Close to Zero

147 views
Skip to first unread message

Scott

unread,
Oct 4, 2010, 8:40:43 PM10/4/10
to sympy
Hello. I some very large polynomials. Some coefficients are very
small (E-16) and I'd like to get rid of these terms. I found a
previous method with a solution posted here:
<http://groups.google.com/group/sympy/browse_thread/thread/
e244e9d9431f3acd/add6f883e7419b27?lnk=gst&q=close+to
+zero#add6f883e7419b27>
def chop(expr, tol=1e-6):
return Add(term for term in expr.as_Add() if term.as_coeff_terms()
[0] >= tol)

However, when I try this method, it doesn't seem to work. I have the
latest sympy (0.6.7). The error demonstrated below is the same as the
one I get using that chop function. I'm running this on Windows, but
could try it on Linux of it would make a difference (though ultimately
I need a method that works on both).

>>> type(x+y)
<class 'sympy.core.add.Add'>
>>> (x+y).as_Add()
Traceback (most recent call last):
File "(stdin)", line 1, in <module>
AttributeError: 'Add' object has no attribute 'as_Add'

According to the documents though, this should exist:
<http://docs.sympy.org/modules/core.html#module-sympy.core.sets>

I also tried just changing 'expr.as_Add()' to 'expr' since I'm giving
it an 'Add' object already, but then I got another error saying that
the object is not iterable.

Does anyone have any other ideas of how I can chop off the terms with
very small coefficients?

Thanks,
Scott

Ondrej Certik

unread,
Oct 4, 2010, 8:48:05 PM10/4/10
to sy...@googlegroups.com
On Mon, Oct 4, 2010 at 5:40 PM, Scott <spect...@gmail.com> wrote:
> Hello.  I some very large polynomials.  Some coefficients are very
> small (E-16) and I'd like to get rid of these terms.  I found a
> previous method with a solution posted here:
> <http://groups.google.com/group/sympy/browse_thread/thread/
> e244e9d9431f3acd/add6f883e7419b27?lnk=gst&q=close+to
> +zero#add6f883e7419b27>
> def chop(expr, tol=1e-6):
>    return Add(term for term in expr.as_Add() if term.as_coeff_terms()
> [0] >= tol)
>
> However, when I try this method, it doesn't seem to work.  I have the
> latest sympy (0.6.7).  The error demonstrated below is the same as the
> one I get using that chop function.  I'm running this on Windows, but
> could try it on Linux of it would make a difference (though ultimately
> I need a method that works on both).
>
>>>> type(x+y)
> <class 'sympy.core.add.Add'>
>>>> (x+y).as_Add()
> Traceback (most recent call last):
>  File "(stdin)", line 1, in <module>
> AttributeError: 'Add' object has no attribute 'as_Add'

Since you have a large polynomial, you can do something like this:

def chop(expr, tol=1e-6):
if isinstance(expr, Add)
return Add(term for term in expr.args if
term.as_coeff_terms()[0] >= tol)
else:
raise NotImplementedError()


Ondrej

Scott

unread,
Oct 5, 2010, 12:46:26 PM10/5/10
to sympy
On Oct 4, 5:48 pm, Ondrej Certik <ond...@certik.cz> wrote:
This seems to almost work. If I set it to:
print [term for term in expr.args if term.as_coeff_terms()[0] >= tol]

Then I can see that the correct terms are printed into a list.
However, when I use the following:
return Add(term for term in expr.args if term.as_coeff_terms()[0] >=
tol)

I get an error:
sympy.core.sympify.SympifyError: SympifyError: <generator object at
0x01911E68> is NOT a valid SymPy expression

The output from the print command I showed above is the following
list:
[0.166666666666667*x1*x2*y2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*y1*x4**2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*x1*x4*y1/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*y4*x3**2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*x3*x4*y4/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*y2*x1**2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*x2*x3*y3/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3),
0.166666666666667*y3*x2**2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3)]

So I'm thinking that it matters that a term is not a simple
polynomial, the first term is:
0.166666666666667*x1*x2*y2/(0.5*x1*y2 + 0.5*x2*y3 + 0.5*x3*y4 +
0.5*x4*y1 - 0.5*x1*y4 - 0.5*x2*y1 - 0.5*x3*y2 - 0.5*x4*y3)
(Note that term.as_coeff_terms()[0] == 0.166666666666667 which is
correct)

Thanks for the help!
Scott

smichr

unread,
Oct 6, 2010, 2:55:12 AM10/6/10
to sympy
On Oct 5, 9:46 pm, Scott <spectre...@gmail.com> wrote:
> On Oct 4, 5:48 pm, Ondrej Certik <ond...@certik.cz> wrote:
>
> > >    return Add(term for term in expr.as_Add() if term.as_coeff_terms()

Add wants items, not a generator:

return Add(*[term for term in expr.as_Add() if
term.as_coeff_terms()[0] >= tol])

To summarize:

use Add(a,b,c) or Add(*[a,b,c]) or Add(*[x for x in iter]) but not
Add(x for x in iter)

Vinzent Steinberg

unread,
Oct 6, 2010, 8:17:49 AM10/6/10
to sympy
On 6 Okt., 08:55, smichr <smi...@gmail.com> wrote:
> Add wants items, not a generator:
>
>     return Add(*[term for term in expr.as_Add() if
> term.as_coeff_terms()[0] >= tol])
>
> To summarize:
>
>     use Add(a,b,c) or Add(*[a,b,c]) or Add(*[x for x in iter]) but not
> Add(x for x in iter)

I think this should be fixed for the sake of a cleaner syntax, even if
Add(*[...]) was still faster. Expr() should accept generators.

Vinzent

Scott

unread,
Oct 7, 2010, 11:35:58 AM10/7/10
to sympy
Excellent, this solves the problem and works as expected. Thank you
very much!

-Scott

Aaron S. Meurer

unread,
Oct 7, 2010, 12:09:42 PM10/7/10
to sy...@googlegroups.com


Is there any reason why Add couldn't be just as fast for an iterator, i.e., suck out all the terms before flattening them?

I agree that it should work either way, though. Actually, I don't see why Add([…]) doesn't work either.

Aaron Meurer

smichr

unread,
Oct 7, 2010, 12:23:58 PM10/7/10
to sympy
>
> Is there any reason why Add couldn't be just as fast for an iterator, i.e., suck out all the terms before flattening them?
>
> I agree that it should work either way, though.  Actually, I don't see why Add([…]) doesn't work either.  

There is a lot less code to test and maintain if have one way to
provide the input. Add wants items and you can give them as Add(a, b)
or Add(*[a, b]) or Add(*list(generator)) -- you let the user maintain
their own code/preferences. If you want to allow Add(a, b) or Add([a,
b]) or Add(generator) then your overhead at the beginning of the
routine gets bloated. And that slows things down.
Reply all
Reply to author
Forward
0 new messages