Quotients of modules with basis#

class sage.modules.with_basis.subquotient.QuotientModuleWithBasis(submodule, category)#

Bases: CombinatorialFreeModule

A class for quotients of a module with basis by a submodule.

INPUT:

  • submodule – a submodule of self

  • category – a category (default: ModulesWithBasis(submodule.base_ring()))

submodule should be a free submodule admitting a basis in unitriangular echelon form. Typically submodule is a SubmoduleWithBasis as returned by Modules.WithBasis.ParentMethods.submodule().

The lift method should have a method .cokernel_basis_indices that computes the indexing set of a subset \(B\) of the basis of self that spans some supplementary of submodule in self (typically the non characteristic columns of the aforementioned echelon form). submodule should further implement a submodule.reduce(x) method that returns the unique element in the span of \(B\) which is equivalent to \(x\) modulo submodule.

This is meant to be constructed via Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module()

This differs from sage.rings.quotient_ring.QuotientRing in the following ways:

  • submodule needs not be an ideal. If it is, the transportation of the ring structure is taken care of by the Subquotients categories.

  • 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 github issue #18204.

See also

  • Modules.WithBasis.ParentMethods.submodule()

  • Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module()

  • SubmoduleWithBasis

  • sage.rings.quotient_ring.QuotientRing

ambient()#

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
lift(x)#

Lift x to the ambient space of self.

INPUT:

  • x – an element 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]));         y = Y.basis()
sage: Y.lift(y[2])
x[2]
retract(x)#

Retract an element of the ambient space by projecting it back to self.

INPUT:

  • x – an element of 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]));         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]
class sage.modules.with_basis.subquotient.SubmoduleWithBasis(basis, support_order, ambient, unitriangular, category, *args, **opts)#

Bases: CombinatorialFreeModule

A 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 some module with basis \(V\), or data that can be converted into such a family

  • support_order – an ordering of the support of basis expressed in ambient given as a list

  • unitriangular – if the lift morphism is unitriangular

  • ambient – 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

ambient()#

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
intersection(other)#

Return the intersection of self and other.

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
is_equal_subspace(other)#

Return whether self is an equal submodule to other.

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
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
is_submodule(other)#

Return whether self is a submodule of other.

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

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
lift()#

The lift (embedding) map from self to 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]
reduce()#

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]
retract()#

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]
subspace(gens, *args, **opts)#

The submodule of the ambient space spanned by a finite set of generators gens (as a submodule).

INPUT:

  • gens – a list or family of elements of self

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]]
subspace_sum(other)#

Return the sum of self and other.

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]]