Quotients of modules with basis¶
- class sage.modules.with_basis.subquotient.QuotientModuleWithBasis(submodule, category, *args, **opts)[source]¶
Bases:
CombinatorialFreeModuleA class for quotients of a module with basis by a submodule.
INPUT:
submodule– a submodule ofselfcategory– a category (default:ModulesWithBasis(submodule.base_ring()))
submoduleshould be a free submodule admitting a basis in unitriangular echelon form. Typicallysubmoduleis aSubmoduleWithBasisas returned byModules.WithBasis.ParentMethods.submodule().The
liftmethod should have a method.cokernel_basis_indicesthat computes the indexing set of a subset \(B\) of the basis ofselfthat spans some supplementary ofsubmoduleinself(typically the non characteristic columns of the aforementioned echelon form).submoduleshould further implement asubmodule.reduce(x)method that returns the unique element in the span of \(B\) which is equivalent to \(x\) modulosubmodule.This is meant to be constructed via
Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module()This differs from
sage.rings.quotient_ring.QuotientRingin the following ways:submoduleneeds not be an ideal. If it is, the transportation of the ring structure is taken care of by theSubquotientscategories.Thanks to
.cokernel_basis_indices, we know the indices of a basis of the quotient, and elements are represented directly in the free module spanned by those indices rather than by wrapping elements of the ambient space.
There is room for sharing more code between those two implementations and generalizing them. See Issue #18204.
See also
Modules.WithBasis.ParentMethods.submodule()Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module()sage.rings.quotient_ring.QuotientRing
- ambient()[source]¶
Return the ambient space of
self.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])) sage: Y.ambient() is X True
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.quotient_module((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)])) >>> Y.ambient() is X True
- lift(x)[source]¶
Lift
xto the ambient space ofself.INPUT:
x– an element ofself
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.lift(y[2]) x[2]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.quotient_module((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)])); y = Y.basis() >>> Y.lift(y[Integer(2)]) x[2]
- retract(x)[source]¶
Retract an element of the ambient space by projecting it back to
self.INPUT:
x– an element of the ambient space ofself
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.print_options(prefix='y') sage: Y.retract(x[0]) y[2] sage: Y.retract(x[1]) y[2] sage: Y.retract(x[2]) y[2]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.quotient_module((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)])); y = Y.basis() >>> Y.print_options(prefix='y') >>> Y.retract(x[Integer(0)]) y[2] >>> Y.retract(x[Integer(1)]) y[2] >>> Y.retract(x[Integer(2)]) y[2]
- class sage.modules.with_basis.subquotient.SubmoduleWithBasis(basis, support_order, ambient, unitriangular, category, *args, **opts)[source]¶
Bases:
CombinatorialFreeModuleA base class for submodules of a ModuleWithBasis spanned by a (possibly infinite) basis in echelon form.
INPUT:
basis– a family of elements in echelon form in somemodule with basis\(V\), or data that can be converted into such a familysupport_order– an ordering of the support ofbasisexpressed inambientgiven as a listunitriangular– if the lift morphism is unitriangularambient– the ambient space \(V\)category– a category
Further arguments are passed down to
CombinatorialFreeModule.This is meant to be constructed via
Modules.WithBasis.ParentMethods.submodule().See also
Modules.WithBasis.ParentMethods.submodule()
- ambient()[source]¶
Return the ambient space of
self.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2])) sage: Y.ambient() is X True
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3))); x = X.basis() >>> Y = X.submodule((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)])) >>> Y.ambient() is X True
- intersection(other)[source]¶
Return the intersection of
selfandother.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(4)); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: G = X.submodule([x[0]-x[2]]) sage: H = X.submodule([x[0]-x[1], x[2]]) sage: FG = F & G; FG Free module generated by {0} over Rational Field sage: [FG.lift(b) for b in FG.basis()] [B[0] - B[2]] sage: FH = F & H; FH Free module generated by {0} over Rational Field sage: [FH.lift(b) for b in FH.basis()] [B[0] - B[1]] sage: GH = G & H; GH Free module generated by {} over Rational Field sage: [GH.lift(b) for b in GH.basis()] [] sage: F.intersection(X) is F True
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(4))); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(2)]]) >>> H = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(2)]]) >>> FG = F & G; FG Free module generated by {0} over Rational Field >>> [FG.lift(b) for b in FG.basis()] [B[0] - B[2]] >>> FH = F & H; FH Free module generated by {0} over Rational Field >>> [FH.lift(b) for b in FH.basis()] [B[0] - B[1]] >>> GH = G & H; GH Free module generated by {} over Rational Field >>> [GH.lift(b) for b in GH.basis()] [] >>> F.intersection(X) is F True
- is_equal_subspace(other)[source]¶
Return whether
selfis an equal submodule toother.Note
This is the mathematical notion of equality (as sets that are isomorphic as vector spaces), which is weaker than the \(==\) which takes into account things like the support order.
INPUT:
other– another submodule of the same ambient module or the ambient module itself
EXAMPLES:
sage: R.<z> = LaurentPolynomialRing(QQ) sage: X = CombinatorialFreeModule(R, range(4)); x = X.basis() sage: F = X.submodule([x[0]-x[1], z*x[1]-z*x[2], z^2*x[2]-z^2*x[3]]) sage: G = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: H = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]], support_order=(3,2,1,0)) sage: F.is_equal_subspace(F) True sage: F == G False sage: F.is_equal_subspace(G) True sage: F.is_equal_subspace(H) True sage: G == H # different support orders False sage: G.is_equal_subspace(H) True
>>> from sage.all import * >>> R = LaurentPolynomialRing(QQ, names=('z',)); (z,) = R._first_ngens(1) >>> X = CombinatorialFreeModule(R, range(Integer(4))); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], z*x[Integer(1)]-z*x[Integer(2)], z**Integer(2)*x[Integer(2)]-z**Integer(2)*x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> H = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]], support_order=(Integer(3),Integer(2),Integer(1),Integer(0))) >>> F.is_equal_subspace(F) True >>> F == G False >>> F.is_equal_subspace(G) True >>> F.is_equal_subspace(H) True >>> G == H # different support orders False >>> G.is_equal_subspace(H) True
sage: X = CombinatorialFreeModule(QQ, ZZ); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[3]]) sage: G = X.submodule([x[0]-x[1], x[2]]) sage: H = X.submodule([x[0]+x[1], x[1]+3*x[2]]) sage: Hp = X.submodule([x[0]+x[1], x[1]+3*x[2]], prefix='Hp') sage: F.is_equal_subspace(X) False sage: F.is_equal_subspace(G) False sage: G.is_equal_subspace(H) False sage: H == Hp False sage: H.is_equal_subspace(Hp) True
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, ZZ); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(2)]]) >>> H = X.submodule([x[Integer(0)]+x[Integer(1)], x[Integer(1)]+Integer(3)*x[Integer(2)]]) >>> Hp = X.submodule([x[Integer(0)]+x[Integer(1)], x[Integer(1)]+Integer(3)*x[Integer(2)]], prefix='Hp') >>> F.is_equal_subspace(X) False >>> F.is_equal_subspace(G) False >>> G.is_equal_subspace(H) False >>> H == Hp False >>> H.is_equal_subspace(Hp) True
- is_submodule(other)[source]¶
Return whether
selfis a submodule ofother.INPUT:
other– another submodule of the same ambient module or the ambient module itself
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(4)); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: G = X.submodule([x[0]-x[2]]) sage: H = X.submodule([x[0]-x[1], x[2]]) sage: F.is_submodule(X) True sage: G.is_submodule(F) True sage: H.is_submodule(F) False sage: H.is_submodule(G) False
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(4))); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(2)]]) >>> H = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(2)]]) >>> F.is_submodule(X) True >>> G.is_submodule(F) True >>> H.is_submodule(F) False >>> H.is_submodule(G) False
Infinite dimensional examples:
sage: X = CombinatorialFreeModule(QQ, ZZ); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: G = X.submodule([x[0]-x[2]]) sage: H = X.submodule([x[0]-x[1]]) sage: F.is_submodule(X) True sage: G.is_submodule(F) True sage: H.is_submodule(F) True sage: H.is_submodule(G) False
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, ZZ); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(2)]]) >>> H = X.submodule([x[Integer(0)]-x[Integer(1)]]) >>> F.is_submodule(X) True >>> G.is_submodule(F) True >>> H.is_submodule(F) True >>> H.is_submodule(G) False
Different ambient spaces:
sage: X = CombinatorialFreeModule(QQ, range(4)); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: Y = CombinatorialFreeModule(QQ, range(6)); y = Y.basis() sage: G = Y.submodule([y[0]-y[1], y[1]-y[2], y[2]-y[3]]) sage: F.is_submodule(G) False
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(4))); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> Y = CombinatorialFreeModule(QQ, range(Integer(6))); y = Y.basis() >>> G = Y.submodule([y[Integer(0)]-y[Integer(1)], y[Integer(1)]-y[Integer(2)], y[Integer(2)]-y[Integer(3)]]) >>> F.is_submodule(G) False
- lift()[source]¶
The lift (embedding) map from
selfto the ambient space.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() sage: Y.lift Generic morphism: From: Free module generated by {0, 1} over Rational Field To: Free module generated by {0, 1, 2} over Rational Field sage: [ Y.lift(u) for u in y ] [x[0] - x[1], x[1] - x[2]] sage: (y[0] + y[1]).lift() x[0] - x[2]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.submodule((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)]), already_echelonized=True); y = Y.basis() >>> Y.lift Generic morphism: From: Free module generated by {0, 1} over Rational Field To: Free module generated by {0, 1, 2} over Rational Field >>> [ Y.lift(u) for u in y ] [x[0] - x[1], x[1] - x[2]] >>> (y[Integer(0)] + y[Integer(1)]).lift() x[0] - x[2]
- reduce()[source]¶
The reduce map.
This map reduces elements of the ambient space modulo this submodule.
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) sage: Y.reduce Generic endomorphism of Free module generated by {0, 1, 2} over Rational Field sage: Y.reduce(x[1]) x[2] sage: Y.reduce(2*x[0] + x[1]) 3*x[2]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.submodule((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)]), already_echelonized=True) >>> Y.reduce Generic endomorphism of Free module generated by {0, 1, 2} over Rational Field >>> Y.reduce(x[Integer(1)]) x[2] >>> Y.reduce(Integer(2)*x[Integer(0)] + x[Integer(1)]) 3*x[2]
- retract()[source]¶
The retract map from the ambient space.
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix='x'); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) sage: Y.print_options(prefix='y') sage: Y.retract Generic morphism: From: Free module generated by {0, 1, 2} over Rational Field To: Free module generated by {0, 1} over Rational Field sage: Y.retract(x[0] - x[2]) y[0] + y[1]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(3)), prefix='x'); x = X.basis() >>> Y = X.submodule((x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)]), already_echelonized=True) >>> Y.print_options(prefix='y') >>> Y.retract Generic morphism: From: Free module generated by {0, 1, 2} over Rational Field To: Free module generated by {0, 1} over Rational Field >>> Y.retract(x[Integer(0)] - x[Integer(2)]) y[0] + y[1]
- subspace(gens, *args, **opts)[source]¶
The submodule of the ambient space spanned by a finite set of generators
gens(as a submodule).INPUT:
gens– list or family of elements ofself
For additional optional arguments, see
ModulesWithBasis.ParentMethods.submodule().EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(4), prefix='X'); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]], prefix='F'); f = F.basis() sage: U = F.submodule([f[0] + 2*f[1] - 5*f[2], f[1] + 2*f[2]]); U Free module generated by {0, 1} over Rational Field sage: [U.lift(u) for u in U.basis()] [F[0] - 9*F[2], F[1] + 2*F[2]] sage: V = F.subspace([f[0] + 2*f[1] - 5*f[2], f[1] + 2*f[2]]); V Free module generated by {0, 1} over Rational Field sage: [V.lift(u) for u in V.basis()] [X[0] - 9*X[2] + 8*X[3], X[1] + 2*X[2] - 3*X[3]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(4)), prefix='X'); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]], prefix='F'); f = F.basis() >>> U = F.submodule([f[Integer(0)] + Integer(2)*f[Integer(1)] - Integer(5)*f[Integer(2)], f[Integer(1)] + Integer(2)*f[Integer(2)]]); U Free module generated by {0, 1} over Rational Field >>> [U.lift(u) for u in U.basis()] [F[0] - 9*F[2], F[1] + 2*F[2]] >>> V = F.subspace([f[Integer(0)] + Integer(2)*f[Integer(1)] - Integer(5)*f[Integer(2)], f[Integer(1)] + Integer(2)*f[Integer(2)]]); V Free module generated by {0, 1} over Rational Field >>> [V.lift(u) for u in V.basis()] [X[0] - 9*X[2] + 8*X[3], X[1] + 2*X[2] - 3*X[3]]
- subspace_sum(other)[source]¶
Return the sum of
selfandother.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(4)); x = X.basis() sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) sage: G = X.submodule([x[0]-x[2]]) sage: H = X.submodule([x[0]-x[1], x[2]]) sage: FG = F + G; FG Free module generated by {0, 1, 2} over Rational Field sage: [FG.lift(b) for b in FG.basis()] [B[0] - B[3], B[1] - B[3], B[2] - B[3]] sage: FH = F + H; FH Free module generated by {0, 1, 2, 3} over Rational Field sage: [FH.lift(b) for b in FH.basis()] [B[0], B[1], B[2], B[3]] sage: GH = G + H; GH Free module generated by {0, 1, 2} over Rational Field sage: [GH.lift(b) for b in GH.basis()] [B[0], B[1], B[2]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, range(Integer(4))); x = X.basis() >>> F = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(1)]-x[Integer(2)], x[Integer(2)]-x[Integer(3)]]) >>> G = X.submodule([x[Integer(0)]-x[Integer(2)]]) >>> H = X.submodule([x[Integer(0)]-x[Integer(1)], x[Integer(2)]]) >>> FG = F + G; FG Free module generated by {0, 1, 2} over Rational Field >>> [FG.lift(b) for b in FG.basis()] [B[0] - B[3], B[1] - B[3], B[2] - B[3]] >>> FH = F + H; FH Free module generated by {0, 1, 2, 3} over Rational Field >>> [FH.lift(b) for b in FH.basis()] [B[0], B[1], B[2], B[3]] >>> GH = G + H; GH Free module generated by {0, 1, 2} over Rational Field >>> [GH.lift(b) for b in GH.basis()] [B[0], B[1], B[2]]