# Modules With Basis¶

AUTHORS: - Nicolas M. Thiery (2008-2010): initial revision - Jason Bandlow & Florent Hivert (2010): Triangular Morphisms - Christian Stump (2010): #9648: module_morphism’s to a wider class of codomains

class sage.categories.modules_with_basis.DiagonalModuleMorphism(diagonal, domain, codomain=None, category=None)

A class for diagonal module morphisms.

Todo:

• implement an optimized _call_ function
• generalize to a mapcoeffs
• generalize to a mapterms
class sage.categories.modules_with_basis.ModuleMorphismByLinearity(domain, on_basis=None, position=0, zero=None, codomain=None, category=None)

A class for module morphisms obtained by extending a function by linearity

on_basis()

Returns the action of this morphism on basis elements, as per ModulesWithBasis.HomCategory.ElementMethods.on_basis().

OUTPUT:

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

EXAMPLES:

sage: X = CombinatorialFreeModule(ZZ, [-2, -1, 1, 2])
sage: Y = CombinatorialFreeModule(ZZ, [1, 2])
sage: phi_on_basis = Y.monomial * abs
sage: phi = sage.categories.modules_with_basis.ModuleMorphismByLinearity(X, on_basis = phi_on_basis, codomain = Y)
sage: x = X.basis()
sage: phi.on_basis()(-2)
B[2]
sage: phi.on_basis() == phi_on_basis
True

class sage.categories.modules_with_basis.ModulesWithBasis(base, name=None)

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 is a subcategory of the category of abstract vector fields:

sage: ModulesWithBasis(RationalField()).super_categories()
[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"
sage: Y = CombinatorialFreeModule(QQ, [3,4]); Y.__custom_name = "Y"
sage: H = Hom(X, Y); H
Set of Morphisms from X to Y in Category of modules 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
Generic morphism:
From: X
To:   Y


which we can apply to elements of X:

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


TESTS:

sage: f = H.zero().on_basis()
sage: f(1)
0
sage: f(2)
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
Generic morphism:
From: X
To:   Y
sage: phi(x)
B[3] + 3*B[4]


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

sage: f = phi.on_basis()
sage: f(1), f(2)
(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)
(False, True)


Some more playing around with categories and higher order homsets:

sage: H.category()
Category of hom sets in Category of modules with basis over Rational Field
sage: Hom(H, H).category()
Category of hom sets in Category of modules over Rational Field


# TODO: End(X) is an algebra

TESTS:

sage: TestSuite(ModulesWithBasis(ZZ)).run()

class CartesianProducts(category, *args)

The category of modules with basis constructed by cartesian products of modules with basis

ParentMethods

alias of CartesianProducts.ParentMethods

extra_super_categories()

EXAMPLES:

sage: ModulesWithBasis(QQ).CartesianProducts().extra_super_categories()
[Category of modules with basis over Rational Field]
sage: ModulesWithBasis(QQ).CartesianProducts().super_categories()
[Category of modules with basis over Rational Field, Category of Cartesian products of sets]

class ModulesWithBasis.DualObjects(category, *args)

TESTS:

sage: from sage.categories.covariant_functorial_construction import CovariantConstructionCategory
sage: class FooBars(CovariantConstructionCategory):
...       _functor_category = "FooBars"
sage: Category.FooBars = lambda self: FooBars.category_of(self)
sage: C = FooBars(ModulesWithBasis(ZZ))
sage: C
Category of foo bars of modules with basis over Integer Ring
sage: C.base_category()
Category of modules with basis over Integer Ring
sage: latex(C)
\mathbf{FooBars}(\mathbf{ModulesWithBasis}_{\Bold{Z}})
sage: import __main__; __main__.FooBars = FooBars # Fake FooBars being defined in a python module
sage: TestSuite(C).run()

extra_super_categories()

EXAMPLES:

sage: ModulesWithBasis(ZZ).DualObjects().extra_super_categories()
[Category of modules over Integer Ring]
sage: ModulesWithBasis(QQ).DualObjects().extra_super_categories()
[Category of vector spaces over Rational Field]

class ModulesWithBasis.ElementMethods

Returns 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 function, cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X")
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
1
sage: def cmp(x,y): return y-x
3

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
-5


Returns the pair (k, c) where c * (the basis elt. indexed by k) is the leading term of self.

‘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, cmp(x,y), can be provided. This should return a negative value if $$x < y$$, $$0$$ if $$x == y$$ and a positive value if $$x > y$$.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)
(3, 4)
sage: def cmp(x,y): return y-x
(1, 3)

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
([3], -5)


Returns 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 function, cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
B[3]
sage: def cmp(x,y): return y-x
B[1]

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
s[3]


Returns 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 function, cmp(x,y), can be provided. This should return a negative value if $$x < y$$, $$0$$ if $$x == y$$ and a positive value if $$x > y$$.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)
3
sage: def cmp(x,y): return y-x
1

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
[3]


Returns 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 function, cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
B[3]
sage: def cmp(x,y): return y-x
3*B[1]

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
-5*s[3]

map_coefficients(f)

Mapping a function on coefficients

INPUT:

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

Returns 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'])
sage: B = F.basis()
sage: f = B['a'] - 3*B['c']
sage: f.map_coefficients(lambda x: x+5)
6*B['a'] + 2*B['c']


Killed coefficients are handled properly:

sage: f.map_coefficients(lambda x: 0)
0
sage: list(f.map_coefficients(lambda x: 0))
[]

sage: s = SymmetricFunctions(QQ).schur()
sage: a = s([2,1])+2*s([3,2])
sage: a.map_coefficients(lambda x: x*2)
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

Returns 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])
sage: x = B.an_element(); x
2*B[-1] + 2*B[0] + 3*B[1]
sage: x.map_item(lambda i, c: (-i, 2*c))
6*B[-1] + 4*B[0] + 4*B[1]


f needs not be injective:

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

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


The following methods are deprecated:

sage: a.map_term(f)
See http://trac.sagemath.org/8890 for details.
2*s[2, 1] + 2*s[3]
sage: a.map_mc(f)
See http://trac.sagemath.org/8890 for details.
2*s[2, 1] + 2*s[3]

map_mc(*args, **kwds)

Deprecated: Use map_item() instead. See trac ticket #8890 for details.

map_support(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])
sage: x = B.an_element(); x
2*B[-1] + 2*B[0] + 3*B[1]
sage: x.map_support(lambda i: -i)
3*B[-1] + 2*B[0] + 2*B[1]


f needs not be injective:

sage: x.map_support(lambda i: 1)
7*B[1]

sage: s = SymmetricFunctions(QQ).schur()
sage: a = s([2,1])+2*s([3,2])
sage: a.map_support(lambda x: x.conjugate())
s[2, 1] + 2*s[2, 2, 1]


TESTS:

sage: B.zero()      # This actually failed at some point!!! See #8890
0

map_term(*args, **kwds)

Deprecated: Use map_item() instead. See trac ticket #8890 for details.

support_of_term()

INPUT:

• self - a monomial, possibly with coefficient

Returns the support of self.

EXAMPLES:

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


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

sage: (X.monomial(2) + X.monomial(3)).support_of_term()
Traceback (most recent call last):
...
ValueError: B[2] + B[3] is not a single term

tensor(*elements)

Returns 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()
sage: (a,b,c) = A.algebra_generators()
sage: a.tensor(b, c)
B[word: a] # B[word: b] # B[word: c]


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

trailing_coefficient(cmp=None)

Returns 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 function cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
sage: x.trailing_coefficient()
3
sage: def cmp(x,y): return y-x
sage: x.trailing_coefficient(cmp=cmp)
1

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
sage: f.trailing_coefficient()
2

trailing_item(cmp=None)

Returns 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 function cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
sage: x.trailing_item()
(1, 3)
sage: def cmp(x,y): return y-x
sage: x.trailing_item(cmp=cmp)
(3, 1)

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
sage: f.trailing_item()
([1], 2)

trailing_monomial(cmp=None)

Returns 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 function cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
sage: x.trailing_monomial()
B[1]
sage: def cmp(x,y): return y-x
sage: x.trailing_monomial(cmp=cmp)
B[3]

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
sage: f.trailing_monomial()
s[1]

trailing_support(cmp=None)

Returns 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 function, cmp(x,y), can be provided. This should return a negative value if $$x < y$$, $$0$$ if $$x == y$$ and a positive value if $$x > y$$.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + 4*X.monomial(3)
sage: x.trailing_support()
1
sage: def cmp(x,y): return y-x
sage: x.trailing_support(cmp=cmp)
3

sage: s = SymmetricFunctions(QQ).schur()
sage: f = 2*s[1] + 3*s[2,1] - 5*s[3]
sage: f.trailing_support()
[1]

trailing_term(cmp=None)

Returns 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 function cmp(x,y), can be provided. This should return a negative value if x < y, 0 if x == y and a positive value if x > y.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: x = 3*X.monomial(1) + 2*X.monomial(2) + X.monomial(3)
sage: x.trailing_term()
3*B[1]
sage: def cmp(x,y): return y-x
sage: x.trailing_term(cmp=cmp)
B[3]

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

class ModulesWithBasis.HomCategory(category, name=None)

The category of homomorphisms sets Hom(X,Y) for X, Y modules with basis

ElementMethods

alias of HomCategory.ElementMethods

ParentMethods

alias of HomCategory.ParentMethods

class ModulesWithBasis.ParentMethods
basis()

Returns the basis of self.

EXAMPLES:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
sage: F.basis()
Finite family {'a': B['a'], 'c': B['c'], 'b': B['b']}

sage: QS3 = SymmetricGroupAlgebra(QQ,3)
sage: list(QS3.basis())
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

module_morphism(on_basis=None, diagonal=None, triangular=None, **keywords)

Constructs morphisms by linearity

Constructs morphisms $$f: X \mapsto Y$$ by linearity on a basis $$(x_i)_{i \in I}$$ of $$X$$.

INPUT:

• self – a parent $$X$$ in ModulesWithBasis(R), with basis $$x$$ indexed by $$I$$

• codomain – the codomain $$Y$$ of $$f$$: defaults to f.codomain() if the later is defined

• zero – the zero of the codomain; defaults to codomain.zero() Can be used (with care) to define affine maps

• position – a non negative integer; defaults to 0

• on_basis – a function $$f$$ which accepts elements of $$I$$ as position-th argument and returns elements of $$Y$$

• diagonal – a function $$d$$ from $$I$$ to $$R$$

• triangular – “upper” or “lower” or None
• “upper”: if the $$leading_support()$$ of the image of $$F(i)$$ is $$i$$, or
• “lower”: if the $$trailing_support()$$ of the image of $$F(i)$$ is $$i$$.
• category – a category. By default, this is ModulesWithBasis(R) if $$Y$$ is in this category, and otherwise this lets $$\hom(X,Y)$$ decide

Exactly one of on_basis and diagonal options should be specified.

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(a,\ \sum_i \lambda_i x_i,\ c) = \sum_i \lambda_i f(a, i, c)$

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1,2,3]);   X.rename("X")
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y")
sage: phi = X.module_morphism(lambda i: Y.monomial(i) + 2*Y.monomial(i+1), codomain = Y)
sage: phi
Generic morphism:
From: X
To:   Y
sage: phi.category_for()
Category of modules with basis over Rational Field
sage: x = X.basis(); y = Y.basis()
sage: phi(x[1] + x[3])
B[1] + 2*B[2] + B[3] + 2*B[4]


With the zero argument, one can define affine morphisms:

sage: phi = X.module_morphism(lambda i: Y.monomial(i) + 2*Y.monomial(i+1), codomain = Y, zero = 10*y[1])
sage: phi(x[1] + x[3])
11*B[1] + 2*B[2] + B[3] + 2*B[4]
sage: phi.category_for()
Category of sets


One can construct morphisms with the base ring as codomain:

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


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

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

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

sage: phi = Y.module_morphism(on_basis= lambda i: i, codomain=Zmod(4) )
Traceback (most recent call last):
...
AssertionError: codomain should be a module over base_ring


On can also define module morphism betweem 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'])
sage: Y = CombinatorialFreeModule(CC,['z'])
sage: x = X.monomial('x')
sage: y = X.monomial('y')
sage: z = Y.monomial('z')
sage: def on_basis( a ):
...       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 )
sage: v = 3 * x + 2 * y; v
3.00000000000000*B['x'] + 2.00000000000000*B['y']
sage: phi(v)
(3.00000000000000+2.00000000000000*I)*B['z']
sage: phi.category_for()
sage: phi.category_for() # todo: not implemented (CC is currently not in Modules(RR)!)
Category of vector spaces over Real Field with 53 bits of precision

sage: Y = CombinatorialFreeModule(CC['q'],['z'])
sage: z = Y.monomial('z')
sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y )
sage: phi(v)
(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'])
sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y )
Traceback (most recent call last):
...
AssertionError: codomain should be a module over base_ring

sage: Y = CombinatorialFreeModule(RR['q'],['z'])
sage: phi = Y.module_morphism( on_basis=on_basis, codomain=X )
Traceback (most recent call last):
...
AssertionError: codomain should be a module over base_ring


With the diagonal argument, this returns 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$$.

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 inverting the morphism:

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


For details and further optional arguments, see sage.categories.modules_with_basis.TriangularModuleMorphism.

Caveat: the returned element is in Hom(codomain, domain, category). This is only correct for unary functions.

Todo: should codomain be self by default in the diagonal and triangular cases?

tensor(*parents)

Returns the tensor product of the parents

EXAMPLES:

sage: C = AlgebrasWithBasis(QQ)
sage: A = C.example(); A.rename("A")
sage: A.tensor(A,A)
A # A # A
sage: A.rename(None)

class ModulesWithBasis.TensorProducts(category, *args)

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

ElementMethods

alias of TensorProducts.ElementMethods

ParentMethods

alias of TensorProducts.ParentMethods

extra_super_categories()

EXAMPLES:

sage: ModulesWithBasis(QQ).TensorProducts().extra_super_categories()
[Category of modules with basis over Rational Field]
sage: ModulesWithBasis(QQ).TensorProducts().super_categories()
[Category of modules with basis over Rational Field]

ModulesWithBasis.is_abelian()

Returns 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

ModulesWithBasis.super_categories()

EXAMPLES:

sage: ModulesWithBasis(QQ).super_categories()
[Category of vector spaces over Rational Field]
sage: ModulesWithBasis(ZZ).super_categories()
[Category of modules over Integer Ring]

class sage.categories.modules_with_basis.PointwiseInverseFunction(f)

A class for point wise inverse functions

EXAMPLES:

sage: from sage.categories.modules_with_basis import PointwiseInverseFunction
sage: f = PointwiseInverseFunction(factorial)
sage: f(0), f(1), f(2), f(3)
(1, 1, 1/2, 1/6)

pointwise_inverse()

TESTS:

sage: from sage.categories.modules_with_basis import PointwiseInverseFunction
sage: g = PointwiseInverseFunction(operator.mul)
sage: g.pointwise_inverse() is operator.mul
True

class sage.categories.modules_with_basis.TriangularModuleMorphism(on_basis, domain, triangular='upper', unitriangular=False, codomain=None, category=None, cmp=None, inverse=None, inverse_on_support=None, invertible=None)

A class for triangular module morphisms; that is module morphisms from $$X$$ to $$Y$$ whose matrix in the distinguished basis of $$X$$ and $$Y$$ would be upper triangular with invertible elements on its diagonal.

INPUT:

• domain - a module with basis $$F$$

• codomain - a module with basis $$G$$ (defaults to $$F$$)

• on_basis - a function from the index set of the basis of $$F$$ to the elements of $$G$$ which describes the morphism

• unitriangular - boolean (default: False)

• triangular - “upper” or “lower” (default: “upper”)
• “upper”: if the $$leading_support()$$ of the image of $$F(i)$$ is $$i$$, or
• “lower”: if the $$trailing_support()$$ of the image of $$F(i)$$ is $$i$$.
• cmp - an optional comparison function on the index set $$J$$ of the basis of the codomain.

• invertible - should be set to True if self is invertible. Automatically set to True if the domain and codomain share the same indexing set

• inverse_on_support - compute the inverse on the support if the codomain and domain have different index sets. see assumptions below

Assumptions:

• $$F$$ and $$G$$ have the same base ring $$R$$
• let $$I$$ and $$J$$ be the respective index sets of the basis of $$F$$ and $$G$$. Either $$I = J$$ or inverse_on_support is a function $$r : J\mapsto I$$ with the following property: for any $$j\in J$$, $$r(j)$$ should return an $$i\in I$$ such that the leading term of on_basis(i) is $$j$$ if there exists such a $$i$$ or None if not.

OUTPUT:

The triangular module morphism from $$F$$ to $$G$$ which maps $$f_\lambda$$ to $$on_basis(\lambda)$$ and is extended by linearity.

EXAMPLES:

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

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename("X"); x = X.basis()
sage: def ut(i): return sum(j*x[j] for j in range(i,4))
sage: phi = X.module_morphism(ut, triangular="lower", codomain = X)
sage: phi(x[2])
2*B[2] + 3*B[3]
sage: phi.preimage(x[2])
1/2*B[2] - 1/2*B[3]
sage: phi(phi.preimage(x[2]))
B[2]

sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i+1,6)  )
sage: phi = X.module_morphism(uut, codomain = Y,
...        triangular=True, unitriangular=True,
...        inverse_on_support=lambda i: i-1 if i in [2,3,4] else None)
sage: phi(x[2])
B[3] + B[4] + B[5]
sage: phi.preimage(y[3])
B[2] - B[3]

co_kernel_projection(category=None)

Returns a projection on the co-kernel of self

INPUT:

- category -- the category of the result.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i+1,6)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y,
...        inverse_on_support=lambda i: i-1 if i in [2,3,4] else None)
sage: phipro = phi.co_kernel_projection()
sage: phipro(y[1] + y[2])
B[1]
sage: all(phipro(phi(x)).is_zero() for x in X.basis())
True
sage: phipro(y[1])
B[1]
sage: phipro(y[4])
-B[5]
sage: phipro(y[5])
B[5]

co_reduced(y)

Reduces element w.r.t image of self

Suppose that self is a morphism from $$X$$ to $$Y$$. Then for any $$y\in Y$$, the calls self.co_reduced(y) returns a normal form for $$y$$ in the quotient $$Y/I$$ where $$I$$ is the image of self.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i,4)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y)
sage: phi.co_reduced(y[1] + y[2])
0

preimage(f)

Returns the image of f by the inverse of self.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i,4)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y)
sage: phi.preimage(y[1] + y[2])
B[1] - B[3]

sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3, 4]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i,5)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y)
sage: phi.preimage(y[1] + y[2])
B[1] - B[3]

sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis()
sage: X.rename("X")
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i+1,6)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y,
...        inverse_on_support=lambda i: i-1 if i in [2,3,4] else None)
sage: phi.preimage(y[2] + y[3])
B[1] - B[3]
sage: phi(phi.preimage(y[2] + y[3])) == y[2] + y[3]
True
sage: el = x[1] + 3*x[2] + 2*x[3]
sage: phi.preimage(phi(el)) == el
True

sage: phi = X.module_morphism(uut, triangular=True, codomain = Y,
...        inverse_on_support=lambda i: i-1 if i in [2,3,4] else None)
sage: phi.preimage(y[1])
Traceback (most recent call last):
...
ValueError: B[1] is not in the image of Generic morphism:
From: X
To:   Free module generated by {1, 2, 3, 4, 5} over Rational Field

section()

Returns the section (partial inverse) of self.

Returns a partial triangular morphism which is a section of self. The section morphism raise a ValueError if asked to apply on an element which is not in the image of self.

EXAMPLES:

sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis()
sage: X.rename('X')
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis()
sage: uut = lambda i: sum(  y[j] for j in range(i+1,6)  ) # uni-upper
sage: phi = X.module_morphism(uut, triangular=True, codomain = Y,
...        inverse_on_support=lambda i: i-1 if i in [2,3,4] else None)
sage: ~phi
Traceback (most recent call last):
...
ValueError: Non invertible morphism
sage: phiinv = phi.section()
sage: map(phiinv*phi, X.basis().list()) == X.basis().list()
True
sage: phiinv(Y.basis()[1])
Traceback (most recent call last):
...
ValueError: B[1] is not in the image of Generic morphism:
From: X
To:   Free module generated by {1, 2, 3, 4, 5} over Rational Field

sage.categories.modules_with_basis.pointwise_inverse_function(f)
INPUT:
• f: a function

Returns the function (...) -> 1 / f(...)

EXAMPLES:

sage: from sage.categories.modules_with_basis import pointwise_inverse_function
sage: def f(x): return x
...
sage: g = pointwise_inverse_function(f)
sage: g(1), g(2), g(3)
(1, 1/2, 1/3)


pointwise_inverse_function is an involution:

sage: f is pointwise_inverse_function(g)
True


Todo: this has nothing to do here!!! Should there be a library for pointwise operations on functions somewhere in Sage?

Modules

Monoid algebras