Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeModuleAutomorphism: Add more invariants #37826

Merged
merged 3 commits into from
May 2, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
118 changes: 106 additions & 12 deletions src/sage/tensor/modules/free_module_automorphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
# https://www.gnu.org/licenses/
# *****************************************************************************

from sage.misc.lazy_attribute import lazy_attribute
from sage.structure.element import MultiplicativeGroupElement
from sage.tensor.modules.free_module_tensor import FreeModuleTensor

Expand Down Expand Up @@ -1055,6 +1056,55 @@ def matrix(self, basis1=None, basis2=None):
raise NotImplementedError("basis1 != basis2 not implemented yet")
return self._matrices[(basis1, basis2)]

def _some_matrix(self):
r"""
Return the matrix of ``self`` w.r.t. some basis.

EXAMPLES::

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a._some_matrix()
[1 1]
[0 2]
"""
self.matrix() # forces the update of the matrix in the module's default
# basis, to make sure that the dictionary self._matrices
# is not empty
return next(iter(self._matrices.values()))

@lazy_attribute
def characteristic_polynomial(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't var appear in the argument list?

Suggested change
def characteristic_polynomial(self):
def characteristic_polynomial(self, var):

r"""
Return the characteristic polynomial of ``self``.

:meth:`characteristic_polynomial` and :meth:`charpoly` are the same method.

INPUT:

- ``var`` -- variable
mkoeppe marked this conversation as resolved.
Show resolved Hide resolved

EXAMPLES::

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a.matrix(e)
[1 1]
[0 2]
sage: a.characteristic_polynomial()
x^2 - 3*x + 2
sage: a.charpoly()
x^2 - 3*x + 2
sage: a.charpoly('T')
T^2 - 3*T + 2
"""
return self._some_matrix().characteristic_polynomial

charpoly = characteristic_polynomial

@lazy_attribute
def det(self):
r"""
Return the determinant of ``self``.
Expand Down Expand Up @@ -1085,13 +1135,62 @@ def det(self):
1

"""
self.matrix() # forces the update of the matrix in the module's default
# basis, to make sure that the dictionary self._matrices
# is not empty
return next(iter(self._matrices.values())).det() # pick a random value in the
# dictionary self._matrices
# and compute the determinant
return self._some_matrix().det

determinant = det

@lazy_attribute
def fcp(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as for characteristic_polynomial:

Suggested change
def fcp(self):
def fcp(self, var):

r"""
Return the factorization of the characteristic polynomial of ``self``.

INPUT:

- ``var`` -- variable
mkoeppe marked this conversation as resolved.
Show resolved Hide resolved

EXAMPLES::

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a.matrix(e)
[1 1]
[0 2]
sage: a.fcp() # needs sage.libs.pari
(x - 2) * (x - 1)
sage: a.fcp('T') # needs sage.libs.pari
(T - 2) * (T - 1)
"""
return self._some_matrix().fcp

@lazy_attribute
def minimal_polynomial(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't var appear in the argument list?

Suggested change
def minimal_polynomial(self):
def minimal_polynomial(self, var):

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because this is the implementation of the lazy attribute. When it is invoked, it returns the method of the matrix.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see. This is unfortunate regarding the documentation as shown in the reference manual (https://deploy-preview-37826--sagemath.netlify.app/html/en/reference/tensor_free_modules/sage/tensor/modules/free_module_automorphism#sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism.minimal_polynomial) : the method minimal_polynomial appears as if it takes no argument.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is unfortunate...

r"""
Return the minimal polynomial of ``self``.

:meth:`minimal_polynomial` and :meth:`minpoly` are the same method.

INPUT:

- ``var`` -- string (default: ``'x'``); a variable name

EXAMPLES::

sage: M = FiniteRankFreeModule(GF(7), 3, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[0,1,2], [-1,0,3], [2,4,1]], name='a')
sage: a.minpoly() # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial() # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial('T') # needs sage.libs.pari
T^3 + 6*T^2 + 6*T + 1
"""
return self._some_matrix().minimal_polynomial

minpoly = minimal_polynomial

@lazy_attribute
def trace(self):
r"""
Return the trace of ``self``.
Expand All @@ -1118,9 +1217,4 @@ def trace(self):
2

"""
self.matrix() # forces the update of the matrix in the module's default
# basis, to make sure that the dictionary self._matrices
# is not empty
return next(iter(self._matrices.values())).trace() # pick a random value in the
# dictionary self._matrices
# and compute the trace
return self._some_matrix().trace