# How do I "tidy up" error terms in a matrix?

Hi - I have some calculation results in the form of a complex Gram matrix which are all supposed to be integers (or "obvious" algebraic numbers which I know about). However inevitably in the course of creating them as inner products, some "error" terms arise which are of a size of the order of 10^-16 (real and/or complex). Is there an easy way to "clean up" my matrix with some sort of threshold, so that things which differ from a user-specified list of algebraic numbers by less than a tiny amount like 10^-15, are assumed to be the relevant algebraic number? At the moment I'm having to do it by a bunch of hideous if-statement contortions but I'm sure there's a better way! Many thanks in advance for any help.

edit retag close merge delete

I've wondered similar things myself. It would be nice to have something like fnormal in Maple. Can you apply round in some way using a map command to help. For example, round(1+10.^(-16),5) gives 1.0.

thanks - as an example for future reference, I used John's suggestion below in the following form: mat.apply_map( lambda x: (d*abs(x)^2).round()/d ); where I knew that the largest denominator for the abs values was d (one has to be a little more careful with complex entries)

Sort by » oldest newest most voted

Matrices over ComplexField don't implement round(), unfortunately. But the following variant of John's answer works:

sage: mat = matrix(3, 3, [2+1e-15+i*1e-15]*9)
sage: mat.change_ring(CDF).round()
[2.0 2.0 2.0]
[2.0 2.0 2.0]
[2.0 2.0 2.0]

more

Agreed. I just wanted to point out that matrices over some rings have already a round() method. This will clean things up if the entries are integers. If the entries differ by small amounts from known algebraic numbers, that's more complicated.

sage: mat = matrix(3, 3, [2+1e-15+i*1e-15]*9)
sage: mat
[2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I]
[2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I]
[2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I 2.00000000000000 + 1.00000000000000e-15*I]
sage: mat.apply_map(lambda x: x.real().round())
[2 2 2]
[2 2 2]
[2 2 2]
sage: mat_Z = mat.apply_map(lambda x: x.real().round())
sage: mat_Z.base_ring()
Integer Ring

more

thanks John - that's certainly a thousand times neater than the mess I had before! The algebraic number thing is almost too good to be true, but maybe someone out there knows a way ... (obviously the list would have to be "restricted" in the sense that the abs vals of the entries would have to be separated by more than twice the error term or something, etc etc)