What is the easiest way to turn an algebraic number (i.e. an element of QQbar
) into a symbolic expression involving radicals? I know that this is only possible if the degree of the minimal polynomial does not exceed 4, but for those cases I'd have hoped to find an easy solution, but haven't found one yet.
Example of where this would be useful:
sage: M = Matrix([[1,2],[3,4]])
sage: M.parent()
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
Simply applying gram_schmidt
over ZZ
will fail:
sage: M.gram_schmidt(True)[0]
TypeError: QR decomposition unable to compute square roots in Rational Field
Changing to the symbolic ring won't help either:
sage: M.change_ring(SR).gram_schmidt(True)[0]
NotImplementedError: Gram-Scmidt orthogonalization not implemented for matrices
over inexact rings, except for RDF and CDF
Changing to the algebraic numbers lets me compute the matrix, but reading the result is kind of hard.
sage: N = M.change_ring(QQbar).gram_schmidt(True)[0]
sage: N
[ 0.4472135954999580? 0.8944271909999159?]
[ 0.8944271909999159? -0.4472135954999580?]
But all the numbers in there are actually simple square roots, as the minimal polynomials will show.
sage: N.apply_map(lambda x: x.minpoly())
[x^2 - 1/5 x^2 - 4/5]
[x^2 - 4/5 x^2 - 1/5]
So I wrote my own function to convert real algebraic numbers of degree two to symbolic expressions.
sage: def AA2SR(x):
....: x = AA(x)
....: p = x.minpoly()
....: if p.degree() < 2:
....: return SR(QQ(x))
....: if p.degree() > 2:
....: raise TypeError("Cannot handle degrees > 2")
....: c, b, a = p.coeffs()
....: y = (-b+sqrt(b*b-4*a*c))/(2*a)
....: if x == AA(y):
....: return y
....: y = (-b-sqrt(b*b-4*a*c))/(2*a)
....: assert x == AA(y)
....: return y
....:
sage: M.change_ring(QQbar).gram_schmidt(True)[0].apply_map(AA2SR)
[ sqrt(1/5) 2*sqrt(1/5)]
[2*sqrt(1/5) -sqrt(1/5)]
But pasting that code into every sage session where I might need it feels rather ugly. I would have hoped that there is some easier way to achieve what I'm doing here. Is there?