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

Commit

Permalink
Rename subquotient back to submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
kwankyu committed Jun 24, 2022
1 parent 1ca0d64 commit 1baa006
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 49 deletions.
35 changes: 18 additions & 17 deletions src/sage/modules/free_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -1394,11 +1394,12 @@ def _eq(self, other):
return False
if self.base_ring() != other.base_ring():
return False

from sage.modules.quotient_module import QuotientModule_free_ambient
lq = isinstance(self, QuotientModule_free_ambient)
rq = isinstance(other, QuotientModule_free_ambient)
if lq or rq:
# if the relations agree we continue with the covers.
# if the relations agree we continue with the covers
if lq:
lx = self.relations()
self = self.cover()
Expand All @@ -1411,11 +1412,10 @@ def _eq(self, other):
rx = other.zero_submodule()
if lx != rx:
return False
# NOTE: This method is overwritten for free modules.
# Subsequently, we know we are not an ambient free module!

# self and other are not ambient.
# but they are contained in the same ambient space
# This method is overridden for free modules in FreeModule_generic.
# Hence we know self and other are not ambient, but they are contained
# in the same ambient space
return self.is_submodule(other) and other.is_submodule(self)

def is_submodule(self, other):
Expand All @@ -1426,7 +1426,7 @@ def is_submodule(self, other):
Submodule testing over general rings is not guaranteed to work in
all cases. However, it will raise an error when it is unable to
determine containment::
determine containment.
The zero module can always be tested::
Expand Down Expand Up @@ -1468,7 +1468,7 @@ def is_submodule(self, other):

from sage.modules.quotient_module import QuotientModule_free_ambient
if isinstance(other, QuotientModule_free_ambient):
#if the relations agree we continue with the covers.
# if the relations agree we continue with the covers
if isinstance(self, QuotientModule_free_ambient):
if other.relations() != self.relations():
return False
Expand All @@ -1491,20 +1491,17 @@ def is_submodule(self, other):
raise NotImplementedError("could not determine if %s is a "
"subring of %s" % (R, S))
if not self.gens():
# We are the zero module
# self is the zero module
return True
if not other.gens():
# The other is the zero module
# other is the zero module
return False
if self.ambient_module().is_submodule(other):
return True
if self.degree() == 1:
# Simple for degree 1: just check if scalar mmultiple
return all(any(h[0].divides(g[0]) for h in other.gens()) for g in self.gens())

raise NotImplementedError("could not determine containment")

_submodule_class = LazyImport("sage.modules.submodule", "Subquotient_free_ambient")
_submodule_class = LazyImport("sage.modules.submodule", "Submodule_free_ambient")

def span(self, gens, base_ring=None, check=True, already_echelonized=False):
r"""
Expand All @@ -1518,10 +1515,13 @@ def span(self, gens, base_ring=None, check=True, already_echelonized=False):
INPUT:
- ``gens`` -- a list of vectors
- ``base_ring`` -- (optional) a ring
- ``check`` -- boolean (default: ``True``): whether or not to
coerce entries of gens into base field
- ``already_echelonized`` -- boolean (default: ``False``):
- ``already_echelonized`` -- boolean (default: ``False``);
set this if you know the gens are already in echelon form
EXAMPLES::
Expand Down Expand Up @@ -1638,6 +1638,7 @@ def submodule(self, gens, check=True, already_echelonized=False):
INPUT:
- ``gens`` -- a list of free module elements or a free module
- ``check`` -- (default: ``True``) whether or not to verify
that the gens are in ``self``
Expand Down Expand Up @@ -1715,6 +1716,7 @@ def quotient_module(self, sub, check=True):
- ``sub`` -- a submodule of ``self`` or something that can
be turned into one via ``self.submodule(sub)``
- ``check`` -- (default: ``True``) whether or not to check that
``sub`` is a submodule
Expand Down Expand Up @@ -3434,7 +3436,6 @@ def _mul_(self, other, switch_sides=False):
B = other * B if switch_sides else B * other
return self.span(B.rows())

# Subclasses should override this method when appropriate
def relations(self):
"""
Return the module of relations of ``self``.
Expand Down Expand Up @@ -5236,7 +5237,7 @@ def _coerce_map_from_(self, M):
sage: V = QQ^2
sage: V.coerce_map_from(M)
"""
from sage.modules.submodule import Subquotient_free_ambient
from sage.modules.submodule import Submodule_free_ambient
from sage.modules.quotient_module import FreeModule_ambient_field_quotient

if isinstance(M, FreeModule_ambient_field_quotient):
Expand All @@ -5249,7 +5250,7 @@ def _coerce_map_from_(self, M):
# complexity of this is quadratic in space and time,
# since it constructs a matrix.
return True
elif isinstance(M, Subquotient_free_ambient):
elif isinstance(M, Submodule_free_ambient):
if (self.base_ring().has_coerce_map_from(M.base_ring()) and
self.rank() == M.degree()):
return True
Expand Down
49 changes: 25 additions & 24 deletions src/sage/modules/quotient_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@

class QuotientModule_free_ambient(Module_free_ambient):
"""
Quotients of ambient free modules over a domain by a submodule.
Quotients of ambient free modules by a submodule.
INPUT:
- ``domain`` -- an ambient free module
- ``sub`` -- a submodule of ``domain``
- ``module`` -- an ambient free module
- ``sub`` -- a submodule of ``module``
EXAMPLES::
Expand All @@ -52,9 +53,9 @@ class QuotientModule_free_ambient(Module_free_ambient):
[x - y z]
[ y*z x*z]
"""
def __init__(self, domain, sub):
def __init__(self, module, sub):
"""
Create this quotient module of ``module`` by a submodule ``sub``.
Create this quotient module of ``module`` by a submodule ``sub``.
TESTS::
Expand All @@ -64,23 +65,23 @@ def __init__(self, domain, sub):
sage: Q = M.quotient_module(N)
sage: TestSuite(Q).run(skip=['_test_elements', '_test_pickling', '_test_zero'])
"""
base_ring = domain.base_ring()
degree = domain.degree()
sparse = domain.is_sparse()
base_ring = module.base_ring()
degree = module.degree()
sparse = module.is_sparse()
# We store these in order to retain the information of how this was constructed
self._domain = domain
self._module = module
self._sub = sub
self.__hash = hash((self._domain, self._sub))
self.__hash = hash((self._module, self._sub))

# We then convert the data into maps from free modules
if isinstance(domain, QuotientModule_free_ambient):
self._free_cover = domain.cover()
if isinstance(module, QuotientModule_free_ambient):
self._free_cover = module.cover()
C = self._free_cover.element_class
v = [C(self._free_cover, x.list(), coerce=False, copy=False) for x in sub.gens()]
w = [C(self._free_cover, x.list(), coerce=False, copy=False) for x in domain.free_relations().gens()]
w = [C(self._free_cover, x.list(), coerce=False, copy=False) for x in module.free_relations().gens()]
self._relations = self._free_cover.submodule(v + w, check=False)
else: # Otherwise domain should be a free module
self._free_cover = domain
else: # Otherwise module should be a free module
self._free_cover = module
self._relations = sub

Module_free_ambient.__init__(self, base_ring, degree=degree, sparse=sparse)
Expand Down Expand Up @@ -131,7 +132,7 @@ def gens(self):
sage: Q.gens()
((1, 0), (0, 1))
"""
return tuple([self(list(g)) for g in self._domain.gens()])
return tuple([self(list(g)) for g in self._module.gens()])

def gen(self, i=0):
"""
Expand All @@ -146,7 +147,7 @@ def gen(self, i=0):
sage: Q.gen(0)
(1, 0)
"""
if i < 0 or i >= self._domain.degree():
if i < 0 or i >= self._module.degree():
raise ValueError('generator %s not defined' % i)
return self.gens()[i]

Expand All @@ -173,9 +174,9 @@ def _coerce_map_from_(self, M):
if isinstance(M, FreeModule_ambient):
return (self.base_ring().has_coerce_map_from(M.base_ring()) and
self.degree() == M.degree())
from sage.modules.submodule import Subquotient_free_ambient
if isinstance(M, Subquotient_free_ambient):
return self._domain.has_coerce_map_from(self.ambient_module())
from sage.modules.submodule import Submodule_free_ambient
if isinstance(M, Submodule_free_ambient):
return self._module.has_coerce_map_from(self.ambient_module())
if (isinstance(M, QuotientModule_free_ambient)
and M.free_cover() == self.free_cover()):
try:
Expand Down Expand Up @@ -211,7 +212,7 @@ def cover(self):
sage: Q.cover() is M
True
"""
return self._domain
return self._module

V = cover

Expand Down Expand Up @@ -261,8 +262,8 @@ def free_cover(self):

def free_relations(self):
r"""
Given this quotient space `Q = V/W`, return the submodule
that generates all relations of `Q`.
Given this quotient space `Q = V/W`, return the submodule that
generates all relations of `Q`.
When `V` is a free module, then this returns `W`. Otherwise this
returns the union of `W` lifted to the cover of `V` and the relations
Expand All @@ -274,7 +275,7 @@ def free_relations(self):
sage: M = S**2
sage: N = M.submodule([vector([x - y, z]), vector([y*z, x*z])])
sage: Q = M / N
sage: NQ = Q.submodule([Q([1,x])])
sage: NQ = Q.submodule([Q([1, x])])
sage: QNQ = Q / NQ
sage: QNQ.free_relations()
Submodule of Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring in x, y, z over Rational Field
Expand Down
27 changes: 19 additions & 8 deletions src/sage/modules/submodule.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
r"""
Submodules of free modules
Submodules of free modules and quotients of free modules
Free modules and submodules of a free module (of finite rank) over a principal
ideal domain have well-defined notion of rank, and they are implemented in
Expand Down Expand Up @@ -39,16 +39,26 @@
FreeModule_ambient_domain)
from .quotient_module import QuotientModule_free_ambient

class Subquotient_free_ambient(Module_free_ambient):

class Submodule_free_ambient(Module_free_ambient):
"""
Base class of subquotients of ambient free modules over an integral domain.
Base class of submodules of ambient modules.
The ambient module is either a free module or a quotient of a free module
by a submodule.
Note that if the ambient module is a quotient module, submodules
of the quotient module are called subquotients.
INPUT:
- ``ambient`` -- an ambient free module
- ``ambient`` -- an ambient module
- ``gens`` -- vectors of the ambient free module generating this submodule
- ``check`` -- boolean; if ``True``, vectors in ``gens`` are checked whether
they belong to the ambient free module
- ``already_echelonized`` -- ignored; for compatibility with other submodules
EXAMPLES::
Expand Down Expand Up @@ -135,8 +145,8 @@ def _repr_(self):
"""
if isinstance(self._ambient, QuotientModule_free_ambient):
return ("Subquotient of %s\n" % self.ambient_module().free_cover() +
"Generated by the rows of the matrix:\n%s" % self.matrix() +
"\nWith relations matrix:\n%s" % self._ambient.free_relations().matrix())
"Generated by the rows of the matrix:\n%s\n" % self.matrix() +
"With relations matrix:\n%s" % self._ambient.free_relations().matrix())
return ("Submodule of %s\n" % self.ambient_module() +
"Generated by the rows of the matrix:\n%s" % self.matrix())

Expand Down Expand Up @@ -164,8 +174,9 @@ def matrix(self):

def relations(self):
r"""
Return the submodule defining the relations of ``self`` as a
subquotient (considering the ambient module as a quotient module).
Return the relations module of the ambient module.
If the ambient module is free, then the relations module is trivial.
EXAMPLES::
Expand Down

0 comments on commit 1baa006

Please sign in to comment.