1 | initial version |
Regarding your second question, the problem is that Sage breaks (by lack of choice) an important Python rule: two objects that are equal must have the same hash (the hash
function maps a (hashable) Python object into an int
). Python sets use hash to avoid repetitions: if two objects have different hash, they take two different "slots" in the set, if they have the same hash, then Python asks if they are equal to decide whether they have to take two different "slots" in the set. Hashing is a way to avoid long equality tests.
The problem is that Sage considers as equal some objects of different nature (type) for which it is very hard to construct an efficient transversally-consistent hash function.
Note that positive integers are their own hashes. So, if Sage was consistent, every algebraic numbers that is actually a positive integer should have itself (as a Python int) as a hash. Unfortunately, some integers can be roots of polynomials of high degree, and we do not want Sage to check whether the number is an integer when computing the hash, precisely because the hash function is a shortcut that aims to be fast.
Here is an illustration:
sage: a = QQbar(2).sqrt()^2
sage: a
2.000000000000000?
sage: hash(a)
8966545466098104078
sage: a.is_integer()
True
sage: a
2
sage: hash(a)
8966545466098104078
sage: b = 2
sage: hash(b)
2
sage: a == b
True
sage: hash(a) == hash(b)
False
Note the timings:
sage: a = QQbar(2).sqrt()^2
sage: %time hash(a)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 681 µs
8966545466098104078
sage: %time a.is_integer()
CPU times: user 16 ms, sys: 8 ms, total: 24 ms
Wall time: 19.4 ms
True
In particular:
sage: set([2,QQbar(2)])
{2, 2}
sage: set([2]) == set([QQbar(2)])
False
Of course, a trivial hash
function (sending every object to 0) would be consistent, but useless since then Python will have to do a lot of equality testing.
What are the options ?
Now, regarding your first question, a matrix defined over QQ
always has complex eigenvalues, because the field of complex numbers is algebaically closed. So, i guess, looking at your attempts, that you are trying to know whether there are non-rational eigenvalues.
What you can do is to transform the rational roots into algebraic roots:
sage: set([QQbar(x) for x in a]) == set(b)
True
A second option is not to discard multiplicities when you compute the rational roots. You only have rational eigenvalues if, and only if, the sum of the multiplicities of the rational roots is equal to the dimension:
sage: A.charpoly().roots(ring=QQ)
[(3, 1), (0, 1), (-4, 1)]
sage: sum(r[1] for r in A.charpoly().roots(ring=QQ)) == A.dimensions()[0]
True