Modules With Basis#

AUTHORS:

  • Nicolas M. Thiery (2008-2014): initial revision, axiomatization

  • Jason Bandlow and Florent Hivert (2010): Triangular Morphisms

  • Christian Stump (2010): github issue #9648 module_morphism’s to a wider class of codomains

class sage.categories.modules_with_basis.ModulesWithBasis(base_category)#

Bases: CategoryWithAxiom_over_base_ring

The category of modules with a distinguished basis.

The elements are represented by expanding them in the distinguished basis. The morphisms are not required to respect the distinguished basis.

EXAMPLES:

sage: ModulesWithBasis(ZZ)
Category of modules with basis over Integer Ring
sage: ModulesWithBasis(ZZ).super_categories()
[Category of modules over Integer Ring]

If the base ring is actually a field, this constructs instead the category of vector spaces with basis:

sage: ModulesWithBasis(QQ)
Category of vector spaces with basis over Rational Field

sage: ModulesWithBasis(QQ).super_categories()
[Category of modules with basis over Rational Field,
 Category of vector spaces over Rational Field]

Let \(X\) and \(Y\) be two modules with basis. We can build \(Hom(X,Y)\):

sage: X = CombinatorialFreeModule(QQ, [1,2]); X.__custom_name = "X"             # optional - sage.modules
sage: Y = CombinatorialFreeModule(QQ, [3,4]); Y.__custom_name = "Y"             # optional - sage.modules
sage: H = Hom(X, Y); H                                                          # optional - sage.modules
Set of Morphisms from X to Y
 in Category of finite dimensional vector spaces with basis over Rational Field

The simplest morphism is the zero map:

sage: H.zero()     # todo: move this test into module once we have an example   # optional - sage.modules
Generic morphism:
  From: X
  To:   Y

which we can apply to elements of \(X\):

sage: x = X.monomial(1) + 3 * X.monomial(2)                                     # optional - sage.modules
sage: H.zero()(x)                                                               # optional - sage.modules
0

EXAMPLES:

We now construct a more interesting morphism by extending a function by linearity:

sage: phi = H(on_basis=lambda i: Y.monomial(i + 2)); phi                        # optional - sage.modules
Generic morphism:
  From: X
  To:   Y
sage: phi(x)                                                                    # optional - sage.modules
B[3] + 3*B[4]

We can retrieve the function acting on indices of the basis:

sage: f = phi.on_basis()                                                        # optional - sage.modules
sage: f(1), f(2)                                                                # optional - sage.modules
(B[3], B[4])

\(Hom(X,Y)\) has a natural module structure (except for the zero, the operations are not yet implemented though). However since the dimension is not necessarily finite, it is not a module with basis; but see FiniteDimensionalModulesWithBasis and GradedModulesWithBasis:

sage: H in ModulesWithBasis(QQ), H in Modules(QQ)                               # optional - sage.modules
(False, True)

Some more playing around with categories and higher order homsets:

sage: H.category()                                                              # optional - sage.modules
Category of homsets of modules with basis over Rational Field
sage: Hom(H, H).category()                                                      # optional - sage.modules
Category of endsets of homsets of modules with basis over Rational Field

Todo

End(X) is an algebra.

Note

This category currently requires an implementation of an element method support. Once github issue #18066 is merged, an implementation of an items method will be required.

class CartesianProducts(category, *args)#

Bases: CartesianProductsCategory

The category of modules with basis constructed by Cartesian products of modules with basis.

class ParentMethods#

Bases: object

extra_super_categories()#

EXAMPLES:

sage: ModulesWithBasis(QQ).CartesianProducts().extra_super_categories()
[Category of vector spaces with basis over Rational Field]
sage: ModulesWithBasis(QQ).CartesianProducts().super_categories()
[Category of Cartesian products of modules with basis over Rational Field,
 Category of vector spaces with basis over Rational Field,
 Category of Cartesian products of vector spaces over Rational Field]
class DualObjects(category, *args)#

Bases: DualObjectsCategory

extra_super_categories()#

EXAMPLES:

sage: ModulesWithBasis(ZZ).DualObjects().extra_super_categories()
[Category of modules over Integer Ring]
sage: ModulesWithBasis(QQ).DualObjects().super_categories()
[Category of duals of vector spaces over Rational Field,
 Category of duals of modules with basis over Rational Field]
class ElementMethods#

Bases: object

coefficient(m)#

Return the coefficient of m in self and raise an error if m is not in the basis indexing set.

INPUT:

  • m – a basis index of the parent of self

OUTPUT:

The B[m]-coordinate of self with respect to the basis B. Here, B denotes the given basis of the parent of self.

EXAMPLES:

sage: s = CombinatorialFreeModule(QQ, Partitions())                     # optional - sage.combinat sage.modules
sage: z = s([4]) - 2*s([2,1]) + s([1,1,1]) + s([1])                     # optional - sage.combinat sage.modules
sage: z.coefficient([4])                                                # optional - sage.combinat sage.modules
1
sage: z.coefficient([2,1])                                              # optional - sage.combinat sage.modules
-2
sage: z.coefficient(Partition([2,1]))                                   # optional - sage.combinat sage.modules
-2
sage: z.coefficient([1,2])                                              # optional - sage.combinat sage.modules
Traceback (most recent call last):
...
AssertionError: [1, 2] should be an element of Partitions
sage: z.coefficient(Composition([2,1]))                                 # optional - sage.combinat sage.modules
Traceback (most recent call last):
...
AssertionError: [2, 1] should be an element of Partitions

Test that coefficient also works for those parents that do not have an element_class:

sage: H = pAdicWeightSpace(3)                                           # optional - sage.modules sage.rings.padics
sage: F = CombinatorialFreeModule(QQ, H)                                # optional - sage.modules sage.rings.padics
sage: hasattr(H, "element_class")                                       # optional - sage.modules sage.rings.padics
False
sage: h = H.an_element()                                                # optional - sage.modules sage.rings.padics
sage: (2*F.monomial(h)).coefficient(h)                                  # optional - sage.modules sage.rings.padics
2
coefficients(sort=True)#

Return a list of the (non-zero) coefficients appearing on the basis elements in self (in an arbitrary order).

INPUT:

  • sort – (default: True) to sort the coefficients based upon the default ordering of the indexing set

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] - 3*B['c']                                             # optional - sage.modules
sage: f.coefficients()                                                  # optional - sage.modules
[1, -3]
sage: f = B['c'] - 3*B['a']                                             # optional - sage.modules
sage: f.coefficients()                                                  # optional - sage.modules
[-3, 1]
sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])                       # optional - sage.combinat sage.modules
sage: z.coefficients()                                                  # optional - sage.combinat sage.modules
[1, 1, 1, 1]
is_zero()#

Return True if and only if self == 0.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] - 3*B['c']                                             # optional - sage.modules
sage: f.is_zero()                                                       # optional - sage.modules
False
sage: F.zero().is_zero()                                                # optional - sage.modules
True
sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: s([2,1]).is_zero()                                                # optional - sage.combinat sage.modules
False
sage: s(0).is_zero()                                                    # optional - sage.combinat sage.modules
True
sage: (s([2,1]) - s([2,1])).is_zero()                                   # optional - sage.combinat sage.modules
True
leading_coefficient(*args, **kwds)#

Return the leading coefficient of self.

This is the coefficient of the term whose corresponding basis element is maximal. Note that this may not be the term which actually appears first when self is printed.

If the default term ordering is not what is desired, a comparison key, key(x,y), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.leading_coefficient()                                           # optional - sage.modules
1
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.leading_coefficient(key=key)                                    # optional - sage.modules
3

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.leading_coefficient()                                           # optional - sage.combinat sage.modules
-5
leading_item(*args, **kwds)#

Return the pair (k, c) where

\[c \cdot (\mbox{the basis element indexed by } k)\]

is the leading term of self.

Here ‘leading term’ means that the corresponding basis element is maximal. Note that this may not be the term which actually appears first when self is printed.

If the default term ordering is not what is desired, a comparison function, key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)           # optional - sage.modules
sage: x.leading_item()                                                  # optional - sage.modules
(3, 4)
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.leading_item(key=key)                                           # optional - sage.modules
(1, 3)

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.leading_item()                                                  # optional - sage.combinat sage.modules
([3], -5)
leading_monomial(*args, **kwds)#

Return the leading monomial of self.

This is the monomial whose corresponding basis element is maximal. Note that this may not be the term which actually appears first when self is printed.

If the default term ordering is not what is desired, a comparison key, key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.leading_monomial()                                              # optional - sage.modules
B[3]
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.leading_monomial(key=key)                                       # optional - sage.modules
B[1]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.leading_monomial()                                              # optional - sage.combinat sage.modules
s[3]
leading_support(*args, **kwds)#

Return the maximal element of the support of self.

Note that this may not be the term which actually appears first when self is printed.

If the default ordering of the basis elements is not what is desired, a comparison key, key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3])                        # optional - sage.modules
sage: X.rename("X"); x = X.basis()                                      # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)           # optional - sage.modules
sage: x.leading_support()                                               # optional - sage.modules
3
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.leading_support(key=key)                                        # optional - sage.modules
1

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.leading_support()                                               # optional - sage.combinat sage.modules
[3]
leading_term(*args, **kwds)#

Return the leading term of self.

This is the term whose corresponding basis element is maximal. Note that this may not be the term which actually appears first when self is printed.

If the default term ordering is not what is desired, a comparison key, key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.leading_term()                                                  # optional - sage.modules
B[3]
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.leading_term(key=key)                                           # optional - sage.modules
3*B[1]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.leading_term()                                                  # optional - sage.combinat sage.modules
-5*s[3]
length()#

Return the number of basis elements whose coefficients in self are nonzero.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] - 3*B['c']                                             # optional - sage.modules
sage: f.length()                                                        # optional - sage.modules
2
sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])                       # optional - sage.combinat sage.modules
sage: z.length()                                                        # optional - sage.combinat sage.modules
4
map_coefficients(f)#

Mapping a function on coefficients.

INPUT:

  • f – an endofunction on the coefficient ring of the free module

Return a new element of self.parent() obtained by applying the function f to all of the coefficients of self.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] - 3*B['c']                                             # optional - sage.modules
sage: f.map_coefficients(lambda x: x + 5)                               # optional - sage.modules
6*B['a'] + 2*B['c']

Killed coefficients are handled properly:

sage: f.map_coefficients(lambda x: 0)                                   # optional - sage.modules
0
sage: list(f.map_coefficients(lambda x: 0))                             # optional - sage.modules
[]
sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: a = s([2,1]) + 2*s([3,2])                                         # optional - sage.combinat sage.modules
sage: a.map_coefficients(lambda x: x * 2)                               # optional - sage.combinat sage.modules
2*s[2, 1] + 4*s[3, 2]
map_item(f)#

Mapping a function on items.

INPUT:

  • f – a function mapping pairs (index, coeff) to other such pairs

Return a new element of self.parent() obtained by applying the function \(f\) to all items (index, coeff) of self.

EXAMPLES:

sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1])                       # optional - sage.modules
sage: x = B.an_element(); x                                             # optional - sage.modules
2*B[-1] + 2*B[0] + 3*B[1]
sage: x.map_item(lambda i, c: (-i, 2*c))                                # optional - sage.modules
6*B[-1] + 4*B[0] + 4*B[1]

f needs not be injective:

sage: x.map_item(lambda i, c: (1, 2*c))                                 # optional - sage.modules
14*B[1]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = lambda m, c: (m.conjugate(), 2 * c)                           # optional - sage.combinat sage.modules
sage: a = s([2,1]) + s([1,1,1])                                         # optional - sage.combinat sage.modules
sage: a.map_item(f)                                                     # optional - sage.combinat sage.modules
2*s[2, 1] + 2*s[3]
map_support(f)#

Mapping a function on the support.

INPUT:

  • f – an endofunction on the indices of the free module

Return a new element of self.parent() obtained by applying the function f to all of the objects indexing the basis elements.

EXAMPLES:

sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1])                       # optional - sage.modules
sage: x = B.an_element(); x                                             # optional - sage.modules
2*B[-1] + 2*B[0] + 3*B[1]
sage: x.map_support(lambda i: -i)                                       # optional - sage.modules
3*B[-1] + 2*B[0] + 2*B[1]

f needs not be injective:

sage: x.map_support(lambda i: 1)                                        # optional - sage.modules
7*B[1]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: a = s([2,1]) + 2*s([3,2])                                         # optional - sage.combinat sage.modules
sage: a.map_support(lambda x: x.conjugate())                            # optional - sage.combinat sage.modules
s[2, 1] + 2*s[2, 2, 1]
map_support_skip_none(f)#

Mapping a function on the support.

INPUT:

  • f – an endofunction on the indices of the free module

Returns a new element of self.parent() obtained by applying the function \(f\) to all of the objects indexing the basis elements.

EXAMPLES:

sage: B = CombinatorialFreeModule(ZZ, [-1, 0, 1])                       # optional - sage.modules
sage: x = B.an_element(); x                                             # optional - sage.modules
2*B[-1] + 2*B[0] + 3*B[1]
sage: x.map_support_skip_none(lambda i: -i if i else None)              # optional - sage.modules
3*B[-1] + 2*B[1]

f needs not be injective:

sage: x.map_support_skip_none(lambda i: 1 if i else None)               # optional - sage.modules
5*B[1]
monomial_coefficients(copy=True)#

Return a dictionary whose keys are indices of basis elements in the support of self and whose values are the corresponding coefficients.

INPUT:

  • copy – (default: True) if self is internally represented by a dictionary d, then make a copy of d; if False, then this can cause undesired behavior by mutating d

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] + 3*B['c']                                             # optional - sage.modules
sage: d = f.monomial_coefficients()                                     # optional - sage.modules
sage: d['a']                                                            # optional - sage.modules
1
sage: d['c']                                                            # optional - sage.modules
3
monomials()#

Return a list of the monomials of self (in an arbitrary order).

The monomials of an element \(a\) are defined to be the basis elements whose corresponding coefficients of \(a\) are non-zero.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] + 2*B['c']                                             # optional - sage.modules
sage: f.monomials()                                                     # optional - sage.modules
[B['a'], B['c']]

sage: (F.zero()).monomials()                                            # optional - sage.modules
[]
support()#

Return an iterable of the objects indexing the basis of self.parent() whose corresponding coefficients of self are non-zero.

This method returns these objects in an arbitrary order.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] - 3*B['c']                                             # optional - sage.modules
sage: sorted(f.support())                                               # optional - sage.modules
['a', 'c']
sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])                       # optional - sage.combinat sage.modules
sage: sorted(z.support())                                               # optional - sage.combinat sage.modules
[[1], [1, 1, 1], [2, 1], [4]]
support_of_term()#

Return the support of self, where self is a monomial (possibly with coefficient).

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1,2,3,4]); X.rename("X")         # optional - sage.modules
sage: X.monomial(2).support_of_term()                                   # optional - sage.modules
2
sage: X.term(3, 2).support_of_term()                                    # optional - sage.modules
3

An exception is raised if self has more than one term:

sage: (X.monomial(2) + X.monomial(3)).support_of_term()                 # optional - sage.modules
Traceback (most recent call last):
...
ValueError: B[2] + B[3] is not a single term
tensor(*elements)#

Return the tensor product of its arguments, as an element of the tensor product of the parents of those elements.

EXAMPLES:

sage: C = AlgebrasWithBasis(QQ)
sage: A = C.example()                                                   # optional - sage.combinat sage.modules
sage: a, b, c = A.algebra_generators()                                  # optional - sage.combinat sage.modules
sage: a.tensor(b, c)                                                    # optional - sage.combinat sage.modules
B[word: a] # B[word: b] # B[word: c]

FIXME: is this a policy that we want to enforce on all parents?

terms()#

Return a list of the (non-zero) terms of self (in an arbitrary order).

See also

monomials()

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])                    # optional - sage.modules
sage: B = F.basis()                                                     # optional - sage.modules
sage: f = B['a'] + 2*B['c']                                             # optional - sage.modules
sage: f.terms()                                                         # optional - sage.modules
[B['a'], 2*B['c']]
trailing_coefficient(*args, **kwds)#

Return the trailing coefficient of self.

This is the coefficient of the monomial whose corresponding basis element is minimal. Note that this may not be the term which actually appears last when self is printed.

If the default term ordering is not what is desired, a comparison key key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.trailing_coefficient()                                          # optional - sage.modules
3
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.trailing_coefficient(key=key)                                   # optional - sage.modules
1

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.trailing_coefficient()                                          # optional - sage.combinat sage.modules
2
trailing_item(*args, **kwds)#

Return the pair (c, k) where c*self.parent().monomial(k) is the trailing term of self.

This is the monomial whose corresponding basis element is minimal. Note that this may not be the term which actually appears last when self is printed.

If the default term ordering is not what is desired, a comparison key key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.trailing_item()                                                 # optional - sage.modules
(1, 3)
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.trailing_item(key=key)                                          # optional - sage.modules
(3, 1)

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.trailing_item()                                                 # optional - sage.combinat sage.modules
([1], 2)
trailing_monomial(*args, **kwds)#

Return the trailing monomial of self.

This is the monomial whose corresponding basis element is minimal. Note that this may not be the term which actually appears last when self is printed.

If the default term ordering is not what is desired, a comparison key key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.trailing_monomial()                                             # optional - sage.modules
B[1]
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.trailing_monomial(key=key)                                      # optional - sage.modules
B[3]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.trailing_monomial()                                             # optional - sage.combinat sage.modules
s[1]
trailing_support(*args, **kwds)#

Return the minimal element of the support of self. Note that this may not be the term which actually appears last when self is printed.

If the default ordering of the basis elements is not what is desired, a comparison key, key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)           # optional - sage.modules
sage: x.trailing_support()                                              # optional - sage.modules
1

sage: def key(x): return -x                                             # optional - sage.modules
sage: x.trailing_support(key=key)                                       # optional - sage.modules
3

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.trailing_support()                                              # optional - sage.combinat sage.modules
[1]
trailing_term(*args, **kwds)#

Return the trailing term of self.

This is the term whose corresponding basis element is minimal. Note that this may not be the term which actually appears last when self is printed.

If the default term ordering is not what is desired, a comparison key key(x), can be provided.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)             # optional - sage.modules
sage: x.trailing_term()                                                 # optional - sage.modules
3*B[1]
sage: def key(x): return -x                                             # optional - sage.modules
sage: x.trailing_term(key=key)                                          # optional - sage.modules
B[3]

sage: s = SymmetricFunctions(QQ).schur()                                # optional - sage.combinat sage.modules
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]                                    # optional - sage.combinat sage.modules
sage: f.trailing_term()                                                 # optional - sage.combinat sage.modules
2*s[1]
Filtered#

alias of FilteredModulesWithBasis

FiniteDimensional#

alias of FiniteDimensionalModulesWithBasis

Graded#

alias of GradedModulesWithBasis

class Homsets(category, *args)#

Bases: HomsetsCategory

class ParentMethods#

Bases: object

class MorphismMethods#

Bases: object

on_basis()#

Return the action of this morphism on basis elements.

OUTPUT:

  • a function from the indices of the basis of the domain to the codomain

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1,2,3]);   X.rename("X")         # optional - sage.modules
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y")         # optional - sage.modules
sage: H = Hom(X, Y)                                                     # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules

sage: f = H(lambda x: Y.zero()).on_basis()                              # optional - sage.modules
sage: f(2)                                                              # optional - sage.modules
0

sage: f = lambda i: Y.monomial(i) + 2*Y.monomial(i+1)                   # optional - sage.modules
sage: g = H(on_basis=f).on_basis()                                      # optional - sage.modules
sage: g(2)                                                              # optional - sage.modules
B[2] + 2*B[3]
sage: g == f                                                            # optional - sage.modules
True
class ParentMethods#

Bases: object

basis()#

Return the basis of self.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])                  # optional - sage.modules
sage: F.basis()                                                         # optional - sage.modules
Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']}
sage: QS3 = SymmetricGroupAlgebra(QQ, 3)                                # optional - sage.group sage.modules
sage: list(QS3.basis())                                                 # optional - sage.group sage.modules
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
cardinality()#

Return the cardinality of self.

EXAMPLES:

sage: S = SymmetricGroupAlgebra(QQ, 4)                                  # optional - sage.groups sage.modules
sage: S.cardinality()                                                   # optional - sage.groups sage.modules
+Infinity
sage: S = SymmetricGroupAlgebra(GF(2), 4)  # not tested -- MRO bug trac #15475      # optional - sage.groups sage.rings.finite_rings sage.modules
sage: S.cardinality()                      # not tested -- MRO bug trac #15475      # optional - sage.groups sage.rings.finite_rings sage.modules
16777216
sage: S.cardinality().factor()             # not tested -- MRO bug trac #15475      # optional - sage.groups sage.rings.finite_rings sage.modules
2^24

sage: E.<x,y> = ExteriorAlgebra(QQ)                                     # optional - sage.combinat sage.modules
sage: E.cardinality()                                                   # optional - sage.combinat sage.modules
+Infinity
sage: E.<x,y> = ExteriorAlgebra(GF(3))                                  # optional - sage.combinat sage.rings.finite_rings sage.modules
sage: E.cardinality()                                                   # optional - sage.combinat sage.rings.finite_rings sage.modules
81

sage: s = SymmetricFunctions(GF(2)).s()                                 # optional - sage.combinat sage.rings.finite_rings sage.modules
sage: s.cardinality()                                                   # optional - sage.combinat sage.rings.finite_rings sage.modules
+Infinity
dimension()#

Return the dimension of self.

EXAMPLES:

sage: A.<x,y> = algebras.DifferentialWeyl(QQ)                           # optional - sage.combinat sage.modules
sage: A.dimension()                                                     # optional - sage.combinat sage.modules
+Infinity
echelon_form(elements, row_reduced=False, order=None)#

Return a basis in echelon form of the subspace spanned by a finite set of elements.

INPUT:

  • elements – a list or finite iterable of elements of self

  • row_reduced – (default: False) whether to compute the basis for the row reduced echelon form

  • order – (optional) either something that can be converted into a tuple or a key function

OUTPUT:

A list of elements of self whose expressions as vectors form a matrix in echelon form. If base_ring is specified, then the calculation is achieved in this base ring.

EXAMPLES:

sage: R.<x,y> = QQ[]
sage: C = CombinatorialFreeModule(R, ZZ, prefix='z')                    # optional - sage.modules
sage: z = C.basis()                                                     # optional - sage.modules
sage: C.echelon_form([z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]])       # optional - sage.modules
[z[0] - z[2], z[1] - z[2]]
is_finite()#

Return whether self is finite.

This is true if and only if self.basis().keys() and self.base_ring() are both finite.

EXAMPLES:

sage: GroupAlgebra(SymmetricGroup(2), IntegerModRing(10)).is_finite()   # optional - sage.groups sage.modules
True
sage: GroupAlgebra(SymmetricGroup(2)).is_finite()                       # optional - sage.groups sage.modules
False
sage: GroupAlgebra(AbelianGroup(1), IntegerModRing(10)).is_finite()     # optional - sage.groups sage.modules
False
module_morphism(on_basis=None, matrix=None, function=None, diagonal=None, triangular=None, unitriangular=False, **keywords)#

Construct a module morphism from self to codomain.

Let self be a module \(X\) with a basis indexed by \(I\). This constructs a morphism \(f: X \to Y\) by linearity from a map \(I \to Y\) which is to be its restriction to the basis \((x_i)_{i \in I}\) of \(X\). Some variants are possible too.

INPUT:

  • self – a parent \(X\) in ModulesWithBasis(R) with basis \(x=(x_i)_{i\in I}\).

Exactly one of the four following options must be specified in order to define the morphism:

  • on_basis – a function \(f\) from \(I\) to \(Y\)

  • diagonal – a function \(d\) from \(I\) to \(R\)

  • function – a function \(f\) from \(X\) to \(Y\)

  • matrix – a matrix of size \(\dim Y \times \dim X\) (if the keyword side is set to 'left') or \(\dim Y \times \dim X\) (if this keyword is 'right')

Further options include:

  • codomain – the codomain \(Y\) of the morphism (default: f.codomain() if it’s defined; otherwise it must be specified)

  • category – a category or None (default: None)

  • zero – the zero of the codomain (default: codomain.zero()); can be used (with care) to define affine maps. Only meaningful with on_basis.

  • position – a non-negative integer specifying which positional argument is used as the input of the function \(f\) (default: 0); this is currently only used with on_basis.

  • triangular – (default: None) "upper" or "lower" or None:

    • "upper" - if the leading_support() of the image of the basis vector \(x_i\) is \(i\), or

    • "lower" - if the trailing_support() of the image of the basis vector \(x_i\) is \(i\).

  • unitriangular – (default: False) a boolean. Only meaningful for a triangular morphism. As a shorthand, one may use unitriangular="lower" for triangular="lower", unitriangular=True.

  • side – “left” or “right” (default: “left”) Only meaningful for a morphism built from a matrix.

EXAMPLES:

With the on_basis option, this returns a function \(g\) obtained by extending \(f\) by linearity on the position-th positional argument. For example, for position == 1 and a ternary function \(f\), one has:

\[g\left( a,\ \sum_i \lambda_i x_i,\ c \right) = \sum_i \lambda_i f(a, i, c).\]
sage: X = CombinatorialFreeModule(QQ, [1,2,3]);   X.rename("X")         # optional - sage.modules
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y")         # optional - sage.modules
sage: def f(i):
....:     return Y.monomial(i) + 2*Y.monomial(i+1)
sage: phi = X.module_morphism(f, codomain=Y)                            # optional - sage.modules
sage: x = X.basis(); y = Y.basis()                                      # optional - sage.modules
sage: phi(x[1] + x[3])                                                  # optional - sage.modules
B[1] + 2*B[2] + B[3] + 2*B[4]

sage: phi                                                               # optional - sage.modules
Generic morphism:
From: X
To:   Y

By default, the category is the first of Modules(R).WithBasis().FiniteDimensional(), Modules(R).WithBasis(), Modules(R), and CommutativeAdditiveMonoids() that contains both the domain and the codomain:

sage: phi.category_for()                                                # optional - sage.modules
Category of finite dimensional vector spaces with basis
 over Rational Field

With the zero argument, one can define affine morphisms:

sage: def f(i):
....:     return Y.monomial(i) + 2*Y.monomial(i+1)
sage: phi = X.module_morphism(f, codomain=Y, zero=10*y[1])              # optional - sage.modules
sage: phi(x[1] + x[3])                                                  # optional - sage.modules
11*B[1] + 2*B[2] + B[3] + 2*B[4]

In this special case, the default category is Sets():

sage: phi.category_for()                                                # optional - sage.modules
Category of sets

One can construct morphisms with the base ring as codomain:

sage: X = CombinatorialFreeModule(ZZ, [1, -1])                          # optional - sage.modules
sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=ZZ)        # optional - sage.modules
sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1))                       # optional - sage.modules
-1
sage: phi.category_for()                                                # optional - sage.modules
Category of commutative additive semigroups
sage: phi.category_for()  # todo: not implemented (ZZ is currently not in Modules(ZZ))  # optional - sage.modules
Category of modules over Integer Ring

Or more generally any ring admitting a coercion map from the base ring:

sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=RR)        # optional - sage.modules
sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1))                       # optional - sage.modules
-1.00000000000000
sage: phi.category_for()                                                # optional - sage.modules
Category of commutative additive semigroups
sage: phi.category_for()  # todo: not implemented (RR is currently not in Modules(ZZ))  # optional - sage.modules
Category of modules over Integer Ring

sage: phi = X.module_morphism(on_basis=lambda i: i, codomain=Zmod(4))   # optional - sage.modules
sage: phi(2 * X.monomial(1) + 3 * X.monomial(-1))                       # optional - sage.modules
3

sage: phi = Y.module_morphism(on_basis=lambda i: i, codomain=Zmod(4))   # optional - sage.modules
Traceback (most recent call last):
...
ValueError: codomain(=Ring of integers modulo 4) should be a module
over the base ring of the domain(=Y)

On can also define module morphisms between free modules over different base rings; here we implement the natural map from \(X = \RR^2\) to \(Y = \CC\):

sage: X = CombinatorialFreeModule(RR, ['x', 'y'])                       # optional - sage.modules
sage: Y = CombinatorialFreeModule(CC, ['z'])                            # optional - sage.modules
sage: x = X.monomial('x')                                               # optional - sage.modules
sage: y = X.monomial('y')                                               # optional - sage.modules
sage: z = Y.monomial('z')                                               # optional - sage.modules
sage: def on_basis(a):                                                  # optional - sage.modules
....:     if a == 'x':
....:         return CC(1) * z
....:     elif a == 'y':
....:         return CC(I) * z
sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y)            # optional - sage.modules
sage: v = 3 * x + 2 * y; v                                              # optional - sage.modules
3.00000000000000*B['x'] + 2.00000000000000*B['y']
sage: phi(v)                                                            # optional - sage.modules
(3.00000000000000+2.00000000000000*I)*B['z']
sage: phi.category_for()                                                # optional - sage.modules
Category of commutative additive semigroups
sage: phi.category_for()  # todo: not implemented (CC is currently not in Modules(RR)!)  # optional - sage.modules
Category of vector spaces over Real Field with 53 bits of precision

sage: Y = CombinatorialFreeModule(CC['q'], ['z'])                       # optional - sage.modules
sage: z = Y.monomial('z')                                               # optional - sage.modules
sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y)            # optional - sage.modules
sage: phi(v)                                                            # optional - sage.modules
(3.00000000000000+2.00000000000000*I)*B['z']

Of course, there should be a coercion between the respective base rings of the domain and the codomain for this to be meaningful:

sage: Y = CombinatorialFreeModule(QQ, ['z'])                            # optional - sage.modules
sage: phi = X.module_morphism(on_basis=on_basis, codomain=Y)            # optional - sage.modules
Traceback (most recent call last):
...
ValueError: codomain(=Free module generated by {'z'} over Rational Field)
should be a module over the base ring of the domain(=Free module
generated by {'x', 'y'} over Real Field with 53 bits of precision)

sage: Y = CombinatorialFreeModule(RR['q'], ['z'])                       # optional - sage.modules
sage: phi = Y.module_morphism(on_basis=on_basis, codomain=X)            # optional - sage.modules
Traceback (most recent call last):
...
ValueError: codomain(=Free module generated by {'x', 'y'}
over Real Field with 53 bits of precision) should be a module over
the base ring of the domain(=Free module generated by {'z'} over
Univariate Polynomial Ring in q over Real Field with 53 bits of precision)

With the diagonal=d argument, this constructs the module morphism \(g\) such that

\[`g(x_i) = d(i) y_i`.\]

This assumes that the respective bases \(x\) and \(y\) of \(X\) and \(Y\) have the same index set \(I\):

sage: X = CombinatorialFreeModule(ZZ, [1, 2, 3]); X.rename("X")         # optional - sage.modules
sage: from sage.arith.misc import factorial                             # optional - sage.modules
sage: phi = X.module_morphism(diagonal=factorial, codomain=X)           # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: phi(x[1]), phi(x[2]), phi(x[3])                                   # optional - sage.modules
(B[1], 2*B[2], 6*B[3])

See also: sage.modules.with_basis.morphism.DiagonalModuleMorphism.

With the matrix=m argument, this constructs the module morphism whose matrix in the distinguished basis of \(X\) and \(Y\) is \(m\):

sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X")           # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: Y = CombinatorialFreeModule(ZZ, [3,4]); Y.rename("Y")             # optional - sage.modules
sage: y = Y.basis()                                                     # optional - sage.modules
sage: m = matrix([[0,1,2], [3,5,0]])                                    # optional - sage.modules
sage: phi = X.module_morphism(matrix=m, codomain=Y)                     # optional - sage.modules
sage: phi(x[1])                                                         # optional - sage.modules
3*B[4]
sage: phi(x[2])                                                         # optional - sage.modules
B[3] + 5*B[4]

See also: sage.modules.with_basis.morphism.ModuleMorphismFromMatrix.

With triangular="upper", the constructed module morphism is assumed to be upper triangular; that is its matrix in the distinguished basis of \(X\) and \(Y\) would be upper triangular with invertible elements on its diagonal. This is used to compute preimages and to invert the morphism:

sage: I = list(range(1, 200))
sage: X = CombinatorialFreeModule(QQ, I); X.rename("X"); x = X.basis()  # optional - sage.modules
sage: Y = CombinatorialFreeModule(QQ, I); Y.rename("Y"); y = Y.basis()  # optional - sage.modules
sage: f = Y.sum_of_monomials * divisors                                 # optional - sage.modules
sage: phi = X.module_morphism(f, triangular="upper", codomain=Y)        # optional - sage.modules
sage: phi(x[2])                                                         # optional - sage.modules
B[1] + B[2]
sage: phi(x[6])                                                         # optional - sage.modules
B[1] + B[2] + B[3] + B[6]
sage: phi(x[30])                                                        # optional - sage.modules
B[1] + B[2] + B[3] + B[5] + B[6] + B[10] + B[15] + B[30]
sage: phi.preimage(y[2])                                                # optional - sage.modules
-B[1] + B[2]
sage: phi.preimage(y[6])                                                # optional - sage.modules
B[1] - B[2] - B[3] + B[6]
sage: phi.preimage(y[30])                                               # optional - sage.modules
-B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30]
sage: (phi^-1)(y[30])                                                   # optional - sage.modules
-B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30]

Since github issue #8678, one can also define a triangular morphism from a function:

sage: X = CombinatorialFreeModule(QQ, [0,1,2,3,4]); x = X.basis()       # optional - sage.modules
sage: from sage.modules.with_basis.morphism import TriangularModuleMorphismFromFunction  # optional - sage.modules
sage: def f(x): return x + X.term(0, sum(x.coefficients()))             # optional - sage.modules
sage: phi = X.module_morphism(function=f, codomain=X,                   # optional - sage.modules
....:                         triangular="upper")
sage: phi(x[2] + 3*x[4])                                                # optional - sage.modules
4*B[0] + B[2] + 3*B[4]
sage: phi.preimage(_)                                                   # optional - sage.modules
B[2] + 3*B[4]

For details and further optional arguments, see sage.modules.with_basis.morphism.TriangularModuleMorphism.

Warning

As a temporary measure, until multivariate morphisms are implemented, the constructed morphism is in Hom(codomain, domain, category). This is only correct for unary functions.

Todo

  • Should codomain be self by default in the diagonal, triangular, and matrix cases?

  • Support for diagonal morphisms between modules not sharing the same index set

monomial(i)#

Return the basis element indexed by i.

INPUT:

  • i – an element of the index set

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])                  # optional - sage.modules
sage: F.monomial('a')                                                   # optional - sage.modules
B['a']

F.monomial is in fact (almost) a map:

sage: F.monomial                                                        # optional - sage.modules
Term map from {'a', 'b', 'c'}
 to Free module generated by {'a', 'b', 'c'} over Rational Field
monomial_or_zero_if_none(i)#

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])                  # optional - sage.modules
sage: F.monomial_or_zero_if_none('a')                                   # optional - sage.modules
B['a']
sage: F.monomial_or_zero_if_none(None)                                  # optional - sage.modules
0
quotient_module(submodule, check=True, already_echelonized=False, category=None)#

Construct the quotient module self / submodule.

INPUT:

Warning

At this point, this only supports quotients by free submodules admitting a basis in unitriangular echelon form. In this case, the quotient is also a free module, with a basis consisting of the retract of a subset of the basis of self.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x")             # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: Y = X.quotient_module([x[0] - x[1], x[1] - x[2]],                 # optional - sage.modules
....:                       already_echelonized=True)
sage: Y.print_options(prefix='y'); Y                                    # optional - sage.modules
Free module generated by {2} over Rational Field
sage: y = Y.basis()                                                     # optional - sage.modules
sage: y[2]                                                              # optional - sage.modules
y[2]
sage: y[2].lift()                                                       # optional - sage.modules
x[2]
sage: Y.retract(x[0] + 2*x[1])                                          # optional - sage.modules
3*y[2]

sage: R.<a,b> = QQ[]
sage: C = CombinatorialFreeModule(R, range(3), prefix='x')              # optional - sage.modules
sage: x = C.basis()                                                     # optional - sage.modules
sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]                # optional - sage.modules
sage: Y = C.quotient_module(gens)                                       # optional - sage.modules
random_element(n=2)#

Return a ‘random’ element of self.

INPUT:

  • n – integer (default: 2); number of summands

ALGORITHM:

Return a sum of n terms, each of which is formed by multiplying a random element of the base ring by a random element of the group.

EXAMPLES:

sage: x = DihedralGroup(6).algebra(QQ).random_element()                 # optional - sage.groups sage.modules
sage: x.parent() is DihedralGroup(6).algebra(QQ)                        # optional - sage.groups sage.modules
True

Note, this result can depend on the PRNG state in libgap in a way that depends on which packages are loaded, so we must re-seed GAP to ensure a consistent result for this example:

sage: libgap.set_seed(0)                                                # optional - sage.libs.gap
0
sage: m = SU(2, 13).algebra(QQ).random_element(1)                       # optional - sage.groups sage.modules
sage: m.parent() is SU(2, 13).algebra(QQ)                               # optional - sage.groups sage.modules
True
sage: p = CombinatorialFreeModule(ZZ, Partitions(4)).random_element()   # optional - sage.combinat sage.modules
sage: p.parent() is CombinatorialFreeModule(ZZ, Partitions(4))          # optional - sage.combinat sage.modules
True
submodule(gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts)#

The submodule spanned by a finite set of elements.

INPUT:

  • gens – a list or family of elements of self

  • check – (default: True) whether to verify that the

    elements of gens are in self

  • already_echelonized – (default: False) whether

    the elements of gens are already in (not necessarily reduced) echelon form

  • unitriangular – (default: False) whether the lift morphism is unitriangular

  • support_order – (optional) either something that can be converted into a tuple or a key function

  • category – (optional) the category of the submodule

If already_echelonized is False, then the generators are put in reduced echelon form using echelonize(), and reindexed by \(0,1,...\).

Warning

At this point, this method only works for finite dimensional submodules and if matrices can be echelonized over the base ring.

If in addition unitriangular is True, then the generators are made such that the coefficients of the pivots are 1, so that lifting map is unitriangular.

The basis of the submodule uses the same index set as the generators, and the lifting map sends \(y_i\) to \(gens[i]\).

See also

EXAMPLES:

We construct a submodule of the free \(\QQ\)-module generated by \(x_0, x_1, x_2\). The submodule is spanned by \(y_0 = x_0 - x_1\) and \(y_1 - x_1 - x_2\), and its basis elements are indexed by \(0\) and \(1\):

sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x")             # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: gens = [x[0] - x[1], x[1] - x[2]]; gens                           # optional - sage.modules
[x[0] - x[1], x[1] - x[2]]
sage: Y = X.submodule(gens, already_echelonized=True)                   # optional - sage.modules
sage: Y.print_options(prefix='y'); Y                                    # optional - sage.modules
Free module generated by {0, 1} over Rational Field
sage: y = Y.basis()                                                     # optional - sage.modules
sage: y[1]                                                              # optional - sage.modules
y[1]
sage: y[1].lift()                                                       # optional - sage.modules
x[1] - x[2]
sage: Y.retract(x[0] - x[2])                                            # optional - sage.modules
y[0] + y[1]
sage: Y.retract(x[0])                                                   # optional - sage.modules
Traceback (most recent call last):
...
ValueError: x[0] is not in the image

By using a family to specify a basis of the submodule, we obtain a submodule whose index set coincides with the index set of the family:

sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x")             # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: gens = Family({1: x[0] - x[1], 3: x[1] - x[2]}); gens             # optional - sage.modules
Finite family {1: x[0] - x[1], 3: x[1] - x[2]}
sage: Y = X.submodule(gens, already_echelonized=True)                   # optional - sage.modules
sage: Y.print_options(prefix='y'); Y                                    # optional - sage.modules
Free module generated by {1, 3} over Rational Field
sage: y = Y.basis()                                                     # optional - sage.modules
sage: y[1]                                                              # optional - sage.modules
y[1]
sage: y[1].lift()                                                       # optional - sage.modules
x[0] - x[1]
sage: y[3].lift()                                                       # optional - sage.modules
x[1] - x[2]
sage: Y.retract(x[0] - x[2])                                            # optional - sage.modules
y[1] + y[3]
sage: Y.retract(x[0])                                                   # optional - sage.modules
Traceback (most recent call last):
...
ValueError: x[0] is not in the image

It is not necessary that the generators of the submodule form a basis (an explicit basis will be computed):

sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x")             # optional - sage.modules
sage: x = X.basis()                                                     # optional - sage.modules
sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]; gens          # optional - sage.modules
[x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]
sage: Y = X.submodule(gens, already_echelonized=False)                  # optional - sage.modules
sage: Y.print_options(prefix='y')                                       # optional - sage.modules
sage: Y                                                                 # optional - sage.modules
Free module generated by {0, 1} over Rational Field
sage: [b.lift() for b in Y.basis()]                                     # optional - sage.modules
[x[0] - x[2], x[1] - x[2]]

We now implement by hand the center of the algebra of the symmetric group \(S_3\):

sage: S3 = SymmetricGroup(3)                                            # optional - sage.groups sage.modules
sage: S3A = S3.algebra(QQ)                                              # optional - sage.groups sage.modules
sage: basis = S3A.annihilator_basis(S3A.algebra_generators(),           # optional - sage.groups sage.modules
....:                               S3A.bracket)
sage: basis                                                             # optional - sage.groups sage.modules
((), (1,2,3) + (1,3,2), (2,3) + (1,2) + (1,3))
sage: center = S3A.submodule(basis,                                     # optional - sage.groups sage.modules
....:     category=AlgebrasWithBasis(QQ).Subobjects(),
....:     already_echelonized=True)
sage: center                                                            # optional - sage.groups sage.modules
Free module generated by {0, 1, 2} over Rational Field
sage: center in Algebras                                                # optional - sage.groups sage.modules
True
sage: center.print_options(prefix='c')                                  # optional - sage.groups sage.modules
sage: c = center.basis()                                                # optional - sage.groups sage.modules
sage: c[1].lift()                                                       # optional - sage.groups sage.modules
(1,2,3) + (1,3,2)
sage: c[0]^2                                                            # optional - sage.groups sage.modules
c[0]
sage: e = 1/6 * (c[0]+c[1]+c[2])                                        # optional - sage.groups sage.modules
sage: e.is_idempotent()                                                 # optional - sage.groups sage.modules
True

Of course, this center is best constructed using:

sage: center = S3A.center()                                             # optional - sage.groups sage.modules

We can also automatically construct a basis such that the lift morphism is (lower) unitriangular:

sage: R.<a,b> = QQ[]
sage: C = CombinatorialFreeModule(R, range(3), prefix='x')              # optional - sage.modules
sage: x = C.basis()                                                     # optional - sage.modules
sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]                # optional - sage.modules
sage: Y = C.submodule(gens, unitriangular=True)                         # optional - sage.modules
sage: Y.lift.matrix()                                                   # optional - sage.modules
[ 1  0]
[ 0  1]
[-1 -1]

We now construct a (finite-dimensional) submodule of an infinite dimensional free module:

sage: C = CombinatorialFreeModule(QQ, ZZ, prefix='z')                   # optional - sage.modules
sage: z = C.basis()                                                     # optional - sage.modules
sage: gens = [z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]]                # optional - sage.modules
sage: Y = C.submodule(gens)                                             # optional - sage.modules
sage: [Y.lift(b) for b in Y.basis()]                                    # optional - sage.modules
[z[0] - z[2], z[1] - z[2]]
sum_of_monomials()#

Return the sum of the basis elements with indices in indices.

INPUT:

  • indices – an list (or iterable) of indices of basis elements

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])                  # optional - sage.modules
sage: F.sum_of_monomials(['a', 'b'])                                    # optional - sage.modules
B['a'] + B['b']

sage: F.sum_of_monomials(['a', 'b', 'a'])                               # optional - sage.modules
2*B['a'] + B['b']

F.sum_of_monomials is in fact (almost) a map:

sage: F.sum_of_monomials                                                # optional - sage.modules
A map to Free module generated by {'a', 'b', 'c'} over Rational Field
sum_of_terms(terms)#

Construct a sum of terms of self.

INPUT:

  • terms – a list (or iterable) of pairs (index, coeff)

OUTPUT:

Sum of coeff * B[index] over all (index, coeff) in terms, where B is the basis of self.

EXAMPLES:

sage: m = matrix([[0,1], [1,1]])                                        # optional - sage.modules
sage: J.<a,b,c> = JordanAlgebra(m)                                      # optional - sage.combinat sage.modules
sage: J.sum_of_terms([(0, 2), (2, -3)])                                 # optional - sage.combinat sage.modules
2 + (0, -3)
tensor(*parents, **kwargs)#

Return the tensor product of the parents.

EXAMPLES:

sage: C = AlgebrasWithBasis(QQ)
sage: A = C.example(); A.rename("A")                                    # optional - sage.combinat sage.modules
sage: A.tensor(A, A)                                                    # optional - sage.combinat sage.modules
A # A # A
sage: A.rename(None)                                                    # optional - sage.combinat sage.modules
term(index, coeff=None)#

Construct a term in self.

INPUT:

  • index – the index of a basis element

  • coeff – an element of the coefficient ring (default: one)

OUTPUT:

coeff * B[index], where B is the basis of self.

EXAMPLES:

sage: m = matrix([[0,1], [1,1]])                                        # optional - sage.modules
sage: J.<a,b,c> = JordanAlgebra(m)                                      # optional - sage.combinat sage.modules
sage: J.term(1, -2)                                                     # optional - sage.combinat sage.modules
0 + (-2, 0)

Design: should this do coercion on the coefficient ring?

Super#

alias of SuperModulesWithBasis

class TensorProducts(category, *args)#

Bases: TensorProductsCategory

The category of modules with basis constructed by tensor product of modules with basis.

class ElementMethods#

Bases: object

Implements operations on elements of tensor products of modules with basis.

apply_multilinear_morphism(f, codomain=None)#

Return the result of applying the morphism induced by f to self.

INPUT:

  • f – a multilinear morphism from the component modules of the parent tensor product to any module

  • codomain – the codomain of f (optional)

By the universal property of the tensor product, f induces a linear morphism from \(self.parent()\) to the target module. Returns the result of applying that morphism to self.

The codomain is used for optimizations purposes only. If it’s not provided, it’s recovered by calling f on the zero input.

EXAMPLES:

We start with simple (admittedly not so interesting) examples, with two modules \(A\) and \(B\):

sage: A = CombinatorialFreeModule(ZZ, [1,2], prefix="A")            # optional - sage.modules
sage: A.rename("A")                                                 # optional - sage.modules
sage: B = CombinatorialFreeModule(ZZ, [3,4], prefix="B")            # optional - sage.modules
sage: B.rename("B")                                                 # optional - sage.modules

and \(f\) the bilinear morphism \((a,b) \mapsto b \otimes a\) from \(A \times B\) to \(B \otimes A\):

sage: def f(a,b):
....:     return tensor([b,a])

Now, calling applying \(f\) on \(a \otimes b\) returns the same as \(f(a,b)\):

sage: a = A.monomial(1) + 2 * A.monomial(2); a                      # optional - sage.modules
A[1] + 2*A[2]
sage: b = B.monomial(3) - 2 * B.monomial(4); b                      # optional - sage.modules
B[3] - 2*B[4]
sage: f(a, b)                                                       # optional - sage.modules
B[3] # A[1] + 2*B[3] # A[2] - 2*B[4] # A[1] - 4*B[4] # A[2]
sage: tensor([a, b]).apply_multilinear_morphism(f)                  # optional - sage.modules
B[3] # A[1] + 2*B[3] # A[2] - 2*B[4] # A[1] - 4*B[4] # A[2]

\(f\) may be a bilinear morphism to any module over the base ring of \(A\) and \(B\). Here the codomain is \(\ZZ\):

sage: def f(a, b):
....:     return sum(a.coefficients(), 0) * sum(b.coefficients(), 0)
sage: f(a, b)                                                       # optional - sage.modules
-3
sage: tensor([a, b]).apply_multilinear_morphism(f)                  # optional - sage.modules
-3

Mind the \(0\) in the sums above; otherwise \(f\) would not return \(0\) in \(\ZZ\):

sage: def f(a,b):
....:     return sum(a.coefficients()) * sum(b.coefficients())
sage: type(f(A.zero(), B.zero()))                                   # optional - sage.modules
<... 'int'>

Which would be wrong and break this method:

sage: tensor([a, b]).apply_multilinear_morphism(f)                  # optional - sage.modules
Traceback (most recent call last):
...
AttributeError: 'int' object has no attribute 'parent'

Here we consider an example where the codomain is a module with basis with a different base ring:

   sage: C = CombinatorialFreeModule(QQ, [(1,3),(2,4)], prefix="C")    # optional - sage.modules
   sage: C.rename("C")                                                 # optional - sage.modules
   sage: def f(a, b):
   ....:     return C.sum_of_terms([((1,3), QQ(a[1]*b[3])),
   ....:                            ((2,4), QQ(a[2]*b[4]))])
   sage: f(a,b)                                                        # optional - sage.modules
   C[(1, 3)] - 4*C[(2, 4)]
   sage: tensor([a, b]).apply_multilinear_morphism(f)                  # optional - sage.modules
   C[(1, 3)] - 4*C[(2, 4)]

We conclude with a real life application, where we
check that the antipode of the Hopf algebra of
Symmetric functions on the Schur basis satisfies its
defining formula::

   sage: Sym = SymmetricFunctions(QQ)                                  # optional - sage.combinat sage.modules
   sage: s = Sym.schur()                                               # optional - sage.combinat sage.modules
   sage: def f(a, b): return a * b.antipode()                          # optional - sage.combinat sage.modules
   sage: x = 4 * s.an_element(); x                                     # optional - sage.combinat sage.modules
   8*s[] + 8*s[1] + 12*s[2]
   sage: x.coproduct().apply_multilinear_morphism(f)                   # optional - sage.combinat sage.modules
   8*s[]
   sage: x.coproduct().apply_multilinear_morphism(f) == x.counit()     # optional - sage.combinat sage.modules
   True

We recover the constant term of \(x\), as desired.

Todo

Extract a method to linearize a multilinear morphism, and delegate the work there.

class ParentMethods#

Bases: object

Implements operations on tensor products of modules with basis.

extra_super_categories()#

EXAMPLES:

sage: ModulesWithBasis(QQ).TensorProducts().extra_super_categories()
[Category of vector spaces with basis over Rational Field]
sage: ModulesWithBasis(QQ).TensorProducts().super_categories()
[Category of tensor products of modules with basis over Rational Field,
 Category of vector spaces with basis over Rational Field,
 Category of tensor products of vector spaces over Rational Field]
is_abelian()#

Return whether this category is abelian.

This is the case if and only if the base ring is a field.

EXAMPLES:

sage: ModulesWithBasis(QQ).is_abelian()
True
sage: ModulesWithBasis(ZZ).is_abelian()
False