Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch '21413_ring_extensions' into general-extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
roed314 committed Sep 12, 2019
2 parents 71668c6 + 22d7f4d commit dfef02d
Show file tree
Hide file tree
Showing 9 changed files with 404 additions and 222 deletions.
378 changes: 251 additions & 127 deletions src/sage/rings/algebra_from_morphism.py

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions src/sage/rings/algebra_from_morphism_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ def RingExtension(ring, base=None, defining_morphism=None):
coerces to K1 (be careful at the direction) and the defining morphisms
agree. For example::
sage: K1 = GF(3^4); L1 = GF(3^8); E1 = L1/K1
sage: K2 = GF(3^2); L2 = GF(3^16); E2 = L2/K2
sage: K1 = GF(3^4); L1 = GF(3^8); E1 = RingExtension(L1,K1)
sage: K2 = GF(3^2); L2 = GF(3^16); E2 = RingExtension(L2,K2)
sage: E2.has_coerce_map_from(E1)
True
Expand All @@ -164,9 +164,9 @@ def RingExtension(ring, base=None, defining_morphism=None):
DEFINING MORPHISM:
When creating the extension E = L/K, we have not specified the defining
morphism. In that case, the coercion map from the base to the ring (if
it exists) is used by default::
When creating the extension ``E = L/K``, we have not specified the defining
morphism. In that case, the coercion map from the base to the ring (if it
exists) is used by default::
sage: E.defining_morphism()
Ring morphism:
Expand Down Expand Up @@ -237,7 +237,7 @@ def RingExtension(ring, base=None, defining_morphism=None):
sage: aE = ExtFrob(a)
sage: aE + c
4*z4^3 + 4*z4^2 + 2
sage: a^5 + c
sage: a + c^5
4*z4^3 + 4*z4^2 + 2
Expand Down Expand Up @@ -277,3 +277,10 @@ def RingExtension(ring, base=None, defining_morphism=None):
else:
raise ValueError("No coercion map from %s to %s" % (codomain,ring))
return AlgebraFromMorphism(defining_morphism, coerce)


def TowerExtensions(*rings):
tower = rings[-1]
for i in range(len(rings)-2, -1, -1):
tower = RingExtension(rings[i], tower)
return tower
2 changes: 2 additions & 0 deletions src/sage/rings/algebra_from_morphism_element.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ from sage.structure.element cimport Element
cdef class AlgebraFMElement(CommutativeAlgebraElement):
cdef Element _element

cdef class RingExtensionWithBasisElement(AlgebraFMElement):
pass
82 changes: 70 additions & 12 deletions src/sage/rings/algebra_from_morphism_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,22 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
- Xavier Caruso (2016)
"""
def __init__(self, parent, element, *args, **kwds):
def __init__(self, parent, x, *args, **kwds):
from sage.rings.algebra_from_morphism import AlgebraFromMorphism
if not isinstance(parent, AlgebraFromMorphism):
raise TypeError("%s is not an instance of AlgebraFromMorphism" % parent)
if isinstance(x, AlgebraFMElement):
x = x._backend()
try:
parentx = x.parent()
if parent.base().has_coerce_map_from(parentx):
x = parent.base().coerce_map_from(parentx)(x)
x = parent.defining_morphism()(x)
except AttributeError:
pass
Element.__init__(self, parent)
ring = parent._backend()
self._element = ring(element, *args, **kwds)
self._element = ring(x, *args, **kwds)

def _repr_(self):
r"""
Expand All @@ -30,7 +39,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = L.gen()
sage: E(x)._repr_()
Expand All @@ -52,7 +61,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = L.gen()
sage: E(x)._latex_()
Expand All @@ -72,7 +81,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = E.random_element()
sage: y = E.random_element()
Expand All @@ -90,7 +99,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = E.random_element()
sage: y = E.random_element()
Expand All @@ -105,7 +114,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = E.random_element()
sage: y = E.random_element()
Expand All @@ -125,7 +134,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = E.gen()
sage: x.additive_order()
Expand All @@ -141,7 +150,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: E = RingExtension(L,K)
sage: x = E.gen()
sage: x.multiplicative_order()
Expand All @@ -157,7 +166,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
EXAMPLES::
sage: A.<x> = PolynomialRing(QQ)
sage: E = A/QQ
sage: E = RingExtension(A,QQ)
sage: E(4).is_unit()
True
sage: E(x).is_unit()
Expand All @@ -173,7 +182,7 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
EXAMPLES::
sage: A.<x> = PolynomialRing(QQ)
sage: E = A/QQ
sage: E = RingExtension(A,QQ)
sage: E(0).is_nilpotent()
True
sage: E(x).is_nilpotent()
Expand All @@ -189,10 +198,59 @@ cdef class AlgebraFMElement(CommutativeAlgebraElement):
EXAMPLES::
sage: A.<x> = PolynomialRing(QQ)
sage: E = A/QQ
sage: E = RingExtension(A,QQ)
sage: E(x^2+1).is_prime()
True
sage: E(x^2-1).is_prime()
False
"""
return self._element.is_prime()


cdef class RingExtensionWithBasisElement(AlgebraFMElement):
def _repr_(self):
parent = self._parent
names = parent._names
_, _, j = parent.vector_space()
coeffs = j(self)
s = ""
for i in range(len(names)):
if coeffs[i].is_zero(): continue
c = coeffs[i]
sign = 1
if (-c)._is_atomic():
c = -c
sign = -sign
if s == "":
if sign == -1: s = "-"
else:
s += " + " if sign == 1 else " - "
ss = ""
if c != 1:
if c._is_atomic():
ss += "%s" % c
else:
ss += "(%s)" % c
if names[i] != "": ss += "*"
ss += names[i]
if ss == "": ss += "1"
s += ss
if s == "": return "0"
return s

def matrix(self):
from sage.matrix.matrix_space import MatrixSpace
parent = self._parent
_, _, j = parent.vector_space()
x = self._backend()
M = [ j(x*b) for b in parent._basis ]
return MatrixSpace(parent._base, len(parent._basis))(M)

def trace(self):
return self.matrix().trace()

def norm(self):
return self.matrix().determinant()

def charpoly(self, var='x'):
return self.matrix().charpoly(var)
2 changes: 1 addition & 1 deletion src/sage/rings/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@
del absolute_import

# Extensions
from sage.rings.algebra_from_morphism_constructor import RingExtension
from sage.rings.algebra_from_morphism_constructor import RingExtension, TowerExtensions
21 changes: 21 additions & 0 deletions src/sage/rings/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,24 @@ def _coerce_impl(self, x):
if x.parent() == self:
return morphism.RingHomomorphism_from_quotient(self, x._phi())
raise TypeError


class AlgebraFromMorphismHomset(RingHomset_generic):
def __call__(self, *args, **kwargs):
from sage.rings.morphism import AlgebraFromMorphismHomomorphism
return AlgebraFromMorphismHomomorphism(self, *args, **kwargs)

def _coerce_impl(self, x):
from sage.rings.morphism import AlgebraFromMorphismHomomorphism
from sage.rings.algebra_from_morphism import AlgebraFromMorphism
if isinstance(x, AlgebraFromMorphismHomomorphism):
x = x._backend()
domain = self.domain()
if isinstance(domain, AlgebraFromMorphism):
domain = domain._backend()
codomain = self.codomain()
if isinstance(codomain, AlgebraFromMorphism):
codomain = codomain._backend()
if domain is x.domain() and codomain is x.codomain():
return AlgebraFromMorphismHomomorphism(self, x)
raise TypeError
2 changes: 0 additions & 2 deletions src/sage/rings/morphism.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism):
cdef class RingHomomorphism_coercion(RingHomomorphism):
pass

cdef class AlgebraToRing(RingHomomorphism):
cpdef Element _call_(self, x)

cdef class AlgebraFromMorphismHomomorphism(RingHomomorphism):
cdef _backend_morphism
Expand Down
101 changes: 46 additions & 55 deletions src/sage/rings/morphism.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2097,68 +2097,33 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism):

from sage.rings.algebra_from_morphism import AlgebraFromMorphism

cdef class AlgebraToRing(RingHomomorphism):
cdef class AlgebraFromMorphismHomomorphism(RingHomomorphism):
r"""
Coercion map between an extension and its ring
It acts as the identity, only modifies the parent
EXAMPLES::
Homomorphisms between extensions
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
EXAMPLES:
sage: coerce_map = L.coerce_map_from(E)
sage: coerce_map
Ring Coercion morphism:
From: Finite Field in z4 of size 5^4 viewed as an algebra over Finite Field in z2 of size 5^2
To: Finite Field in z4 of size 5^4
sage: type(coerce_map)
<type 'sage.rings.morphism.AlgebraToRing'>
sage: F = GF(5^2)
sage: K = GF(5^4)
sage: L = GF(5^8)
sage: E1 = RingExtension(K,F)
sage: E2 = RingExtension(L,K)
sage: x = E.random_element()
sage: x == coerce_map(x)
True
"""
cpdef Element _call_(self, x):
r"""
TESTS::
sage: K = GF(5^2)
sage: L = GF(5^4)
sage: E = L/K
sage: coerce_map = L.coerce_map_from(E)
sage: x = coerce_map(E.gen()); x
z4
sage: x.parent() is L
True
sage: E = RingExtension(L, K, K.frobenius_endomorphism())
sage: coerce_map = L.coerce_map_from(E)
sage: x = coerce_map(E.gen()); x
z4
sage: x.parent() is L
True
"""
return x._backend()


cdef class AlgebraFromMorphismHomomorphism(RingHomomorphism):
def __init__(self, parent, backend_morphism):
def __init__(self, parent, backend):
RingHomomorphism.__init__(self, parent)
backend_domain = self.domain()
if isinstance(backend_domain, AlgebraFromMorphism):
backend_domain = backend_domain._backend()
backend_codomain = self.codomain()
if isinstance(backend_codomain, AlgebraFromMorphism):
backend_codomain = backend_codomain._backend()
if backend_morphism.domain() is not backend_domain:
backend = backend_morphism(backend)
if backend.domain() is not backend_domain:
raise TypeError("the domain of the backend morphism is not correct")
if backend_morphism.codomain() is not backend_codomain:
if backend.codomain() is not backend_codomain:
raise TypeError("the codomain of the backend morphism is not correct")
self._backend_morphism = backend_morphism
self._backend_morphism = backend
# We should probably allow for more general constructions but
# self._backend_morphism = backend_domain.Hom(backend_codomain)(*args, **kwargs)
# does not work currently
Expand All @@ -2171,13 +2136,8 @@ cdef class AlgebraFromMorphismHomomorphism(RingHomomorphism):
y = self._codomain(y)
return y

def _backend(self, forget=None):
backend = self._backend_morphism
if forget == "domain" and not isinstance(self.domain(), AlgebraFromMorphism):
return self.__class__(backend.domain().Hom(self._codomain), backend)
if forget == "codomain" and not isinstance(self.codomain(), AlgebraFromMorphism):
return self.__class__(self._domain.Hom(backend.codomain()), backend)
return backend
def _backend(self):
return self._backend_morphism

cdef _update_slots(self, dict _slots):
self._backend_morphism = _slots['_backend_morphism']
Expand All @@ -2188,3 +2148,34 @@ cdef class AlgebraFromMorphismHomomorphism(RingHomomorphism):
slots['_backend_morphism'] = self._backend_morphism
return slots



def _backend_morphism(f):
from sage.categories.map import FormalCompositeMap
if not isinstance(f.domain(), AlgebraFromMorphism) and not isinstance(f.codomain(), AlgebraFromMorphism):
return f
elif isinstance(f, AlgebraFromMorphismHomomorphism):
return f._backend()
elif isinstance(f, FormalCompositeMap):
return _backend_morphism(f.then()) * _backend_morphism(f.first())
else:
raise NotImplementedError

def backend_morphism(f, forget="all"):
try:
g = _backend_morphism(f)
if forget is None and (isinstance(f.domain(), AlgebraFromMorphism) or isinstance(f.codomain(), AlgebraFromMorphism)):
g = AlgebraFromMorphismHomomorphism(f.domain().Hom(f.codomain()), g)
if forget == "domain" and isinstance(f.codomain(), AlgebraFromMorphism):
g = AlgebraFromMorphismHomomorphism(g.domain().Hom(f.codomain()), g)
if forget == "codomain" and isinstance(f.domain(), AlgebraFromMorphism):
g = AlgebraFromMorphismHomomorphism(f.domain().Hom(g.codomain()), g)
except NotImplementedError:
g = f
if (forget == "all" or forget == "domain") and isinstance(f.domain(), AlgebraFromMorphism):
ring = f.domain()._backend()
g = g * AlgebraFromMorphismHomomorphism(ring.Hom(f.domain()), ring.Hom(ring).identity())
if (forget == "all" or forget == "codomain") and isinstance(f.codomain(), AlgebraFromMorphism):
ring = f.codomain()._backend()
g = AlgebraFromMorphismHomomorphism(f.codomain().Hom(ring), ring.Hom(ring).identity()) * g
return g

0 comments on commit dfef02d

Please sign in to comment.