I don't think that in this case there would be a performance penality, the
computation of the eigenvalues itself is not affected. Regardless, I think
that in general, a high level convenience method should be optimized for
reliability, not for performance. In fact, removing the optimization we
could avoid the universe computation in eigenvalues = Sequence(res), which
might be just as expensive.
Of course, if I know that the eigenvalues will be rational, it would be
good to be able to tell the method that. I am a bit unsure how difficult
that would be. I am guessing that the default ring cannot be the base
ring, because that would break existing code, right?
Apart from that, I just found another snippet of the documentation, which
says:
The eigenvalues are elements of ``QQbar``, so they really represent
exact roots of polynomials, not just approximations.
Here is what I would like to change:
diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx
index 63102fb380b..0b3d2040e80 100644
--- a/src/sage/matrix/matrix2.pyx
+++ b/src/sage/matrix/matrix2.pyx
@@ -7297,7 +7297,7 @@ cdef class Matrix(Matrix1):
res = []
for f, e in self.charpoly().change_ring(K).factor():
if f.degree() == 1:
- res.extend([-f.constant_coefficient()]*e)
+ res.extend([A(-f.constant_coefficient())]*e)
else:
for r, ee in f.change_ring(A).roots():
res.extend([r]*(e*ee))
On Wednesday, 3 December 2025 at 18:47:23 UTC+1 Nils Bruin wrote:
> Your example hides a lesser consistency: the list of eigenvalues for a
> matrix over QQ does seem to lie either in Q (if all the eigenvalues lie in
> QQ) or in QQbar. Putting them in QQbar in all cases is of course the
> general thing to do, but if you know your matrix has rational eigenvalues
> and you just want to work with them (take their numerator and denominator
> perhaps? reduce them mod p?) it could be quite annoying to find them in
> QQbar. Arithmetic in QQbar is also going to be horribly slow in comparison.
>
> I can see why, with such an expensive general parent, there might be an
> argument to put the arguments in a smaller parent when possible (for all of
> them). There is a practical argument to be made here for why one might want
> to deviate from the purity of "parent of return value determined by parent
> of input".
>
> The documentation is formulated in a confusing way: It can be read as if
> for matrices over QQ, only *separate* roots are returned: no multiplicity
> information. I haven't tested this, but I'm pretty sure that's not what is
> intended.
>
> The documentation also doesn't reflect the "parent optimization". I think
> that's your main question. As described above, I think there's some
> practical nuance to that...
>
> In actuality, due to the problem "eigenvalues in what field"? I'd probably
> steer away from routines like "eigenvalues" in my own code, because I
> wouldn't dare to trust the choice that's made. I probably instead would
> just ask for the characteristic poly and determine its roots where I want
> (that's almost never QQbar unless it's in an interactive situation), and
> then work with that.
>
>
> On Wednesday, 3 December 2025 at 01:52:39 UTC-8 [email protected] wrote:
>
>> Do we really want that the parent of the result depends on the *value* of
>> its input here, rather than on the parent of the input?
>>
>> Actually, strictly speaking the documentation promises something else:
>>
>> Return a sequence of the eigenvalues of a matrix, with
>> multiplicity. If the eigenvalues are roots of polynomials in
>> ``QQ``,
>> then ``QQbar`` elements are returned that represent each separate
>> root.
>>
>> Do I misunderstand this, or *is* the behaviour a bug? (If so, it is easy
>> to fix.)
>>
>> I am guessing that harmonizing the hash of QQbar with the hash of QQ is
>> expensive. Also, I don't think it would be the correct fix.
>>
>> Martin
>> On Tuesday, 2 December 2025 at 23:20:30 UTC+1 Martin R wrote:
>>
>>> sage: OZ = lambda P: (ones_matrix(P.cardinality()) - P.lequal_matrix())
>>> sage: set(min(OZ(P).eigenvalues()) for n in range(1, 7) for P in
>>> posets(n))
>>> {-1, -1, 0}
>>> sage: [type(x) for x in _]
>>> [<class 'sage.rings.rational.Rational'>,
>>> <class 'sage.rings.rational.Rational'>,
>>> <class 'sage.rings.qqbar.AlgebraicNumber'>]
>>>
>>>
--
You received this message because you are subscribed to the Google Groups
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/sage-devel/6f4f4480-6628-4aa4-945d-6c4894c1649cn%40googlegroups.com.