Testing if the entries of a matrix of rational vectors are actually integers

I moved from Python to SageMath because it allows me to deal with natural operations in mathematics without having to reinvent the wheel through typing obvious classes and methods. I also suppose the built-in classes and methods do things in more efficient ways that I could do myself.

However, sometimes I find hard to find the right function or class for what I want to do.

I have created several matrices using 'matrix' which may have rational or integer numbers (so I use QQ to define them). I want to check which matrices actually have all entries as integers. I know how to do this by looping through all entries of each matrix and calling 'is_integer', but is there an existing method in 'matrix' doing this for me? I could not find one.

edit retag close merge delete

Sort by » oldest newest most voted

If you know that you are dealing with 5x4 matrices, for example:

sage: A = random_matrix(QQ, 5, 4)
sage: A in MatrixSpace(ZZ, 5, 4)
False


Or if you don't know the size:

sage: A in MatrixSpace(ZZ, A.nrows(), A.ncols())
False


This seems to be a little faster than all(x in ZZ for x in A.list()), especially as the matrices get large.

sage: %timeit all(a in ZZ for a in random_matrix(QQ, 200, 200).list())
100 loops, best of 3: 15.5 ms per loop
sage: %timeit random_matrix(QQ, 200, 200) in MatrixSpace(ZZ, 200, 200)
100 loops, best of 3: 3.32 ms per loop


Revised timings to also compare the denominator method (on a different computer, so all of the timings are different):

sage: %timeit all(a in ZZ for a in random_matrix(QQ, 200, 200).list())
100 loops, best of 3: 16.2 ms per loop
sage: %timeit random_matrix(QQ, 200, 200) in MatrixSpace(ZZ, 200, 200)
100 loops, best of 3: 3.44 ms per loop
sage: %timeit random_matrix(QQ, 200, 200).denominator() == 1
100 loops, best of 3: 3.77 ms per loop

more

From your last comparison it seems to me that all(a in ZZ for a in random_matrix(QQ, 200, 200).list()) is the fastest as it takes less ms. Am I missing something?

( 2019-06-20 10:20:00 -0500 )edit

That one takes 16.2 ms per loop, and the others are about 3.5 ms per loop, so the others are faster.

( 2019-06-20 13:12:43 -0500 )edit

@john_Palimieri all clear, thanks. I got confused by the line "This seems to be a little faster than[...]".

( 2019-06-23 08:21:58 -0500 )edit

Try this example:

sage: set_random_seed(100); # to be able to reproduce this example
sage: A = random_matrix(QQ, 5, 4, num_bound=20, den_bound=4); A
[    0    -1  19/3  -1/4]
[ -1/2     8     1  -5/2]
[ -7/2    -9    -5   3/2]
[-11/4  -1/4    -8 -15/4]
[   -9  14/3     8   4/3]
sage: all(map(lambda x: x.is_integer(),A.list()))
False


Hope that helps.

Edit. I have found the denominator method, which yields the lowest common denominator of the matrix elements. So, all entries are integers if and only if such denominator is 1. As a continuation of the above example, we have:

sage: A.denominator()==1
False

more

Simpler:

sage: A.change_ring(ZZ)

( 2019-06-18 06:24:25 -0500 )edit

@FrédéricC If I do that and the matrix has denominators it will give an error 'matrix has denominators so can't change to ZZ.'

( 2019-06-18 06:29:39 -0500 )edit

@Juanjo Yes, of course that works, but I was interested in seeing if there was a method of the class matrix to deal with this, just as there is for the class Rational (or its parent, wherever is_rational is). Anyway, it is neat, so I vote up. If nobody replies in a few days I will accept the answer.

( 2019-06-18 07:39:31 -0500 )edit
1

A little simpler: all(x in ZZ for x in A.list()).

( 2019-06-18 09:59:08 -0500 )edit