Modules With Basis¶
AUTHORS:
- Nicolas M. Thiery (2008-2014): initial revision, axiomatization
- Jason Bandlow and Florent Hivert (2010): Triangular Morphisms
- Christian Stump (2010): trac ticket #9648 module_morphism’s to a wider class of codomains
-
class
sage.categories.modules_with_basis.
ModulesWithBasis
(base_category)¶ Bases:
sage.categories.category_with_axiom.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
and
be two modules with basis. We can build
:
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 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 Generic morphism: From: X To: Y
which we can apply to elements of
:
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])
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
andGradedModulesWithBasis
: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 homsets of modules with basis over Rational Field sage: Hom(H, H).category() Category of endsets of homsets of modules with basis over Rational Field
Todo
End(X)
is an algebra.TESTS:
sage: TestSuite(ModulesWithBasis(ZZ)).run()
-
class
CartesianProducts
(category, *args)¶ Bases:
sage.categories.cartesian_product.CartesianProductsCategory
The category of modules with basis constructed by cartesian products of modules with basis.
-
class
ParentMethods
¶
-
ModulesWithBasis.CartesianProducts.
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
-
class
ModulesWithBasis.
DualObjects
(category, *args)¶ Bases:
sage.categories.dual.DualObjectsCategory
TESTS:
sage: from sage.categories.covariant_functorial_construction import CovariantConstructionCategory sage: class FooBars(CovariantConstructionCategory): ....: _functor_category = "FooBars" ....: _base_category_class = (Category,) 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().super_categories() [Category of duals of vector spaces over Rational Field, Category of duals of modules with basis over Rational Field]
-
-
class
ModulesWithBasis.
ElementMethods
¶ -
leading_coefficient
(cmp=None)¶ 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 ifx < y
, 0 ifx == y
and a positive value ifx > 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) sage: x.leading_coefficient() 1 sage: def cmp(x,y): return y-x sage: x.leading_coefficient(cmp=cmp) 3 sage: s = SymmetricFunctions(QQ).schur() sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] sage: f.leading_coefficient() -5
-
leading_item
(cmp=None)¶ Return the pair
(k, c)
whereis 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,cmp(x,y)
, can be provided. This should return a negative value ifx < y
,0
ifx == y
and a positive value ifx > 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.leading_item() (3, 4) sage: def cmp(x,y): return y-x sage: x.leading_item(cmp=cmp) (1, 3) sage: s = SymmetricFunctions(QQ).schur() sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] sage: f.leading_item() ([3], -5)
-
leading_monomial
(cmp=None)¶ 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 function,cmp(x,y)
, can be provided. This should return a negative value ifx < y
,0
ifx == y
and a positive value ifx > 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.leading_monomial() B[3] sage: def cmp(x,y): return y-x sage: x.leading_monomial(cmp=cmp) B[1] sage: s = SymmetricFunctions(QQ).schur() sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] sage: f.leading_monomial() s[3]
-
leading_support
(cmp=None)¶ Return the maximal element of the support of
self
. Note that this may not be the term which actually appears first whenself
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 ifx < y
,0
ifx == y
and a positive value ifx > 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.leading_support() 3 sage: def cmp(x,y): return y-x sage: x.leading_support(cmp=cmp) 1 sage: s = SymmetricFunctions(QQ).schur() sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] sage: f.leading_support() [3]
-
leading_term
(cmp=None)¶ 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 function,cmp(x,y)
, can be provided. This should return a negative value ifx < y
, 0 ifx == y
and a positive value ifx > 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.leading_term() B[3] sage: def cmp(x,y): return y-x sage: x.leading_term(cmp=cmp) 3*B[1] sage: s = SymmetricFunctions(QQ).schur() sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] sage: f.leading_term() -5*s[3]
-
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 functionf
to all of the coefficients ofself
.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
Return a new element of
self.parent()
obtained by applying the functionto all items
(index, coeff)
ofself
.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]
-
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 functionf
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 sage: y = B.zero().map_support(lambda i: i/0); y 0 sage: y.parent() is B True
-
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 functionto 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_skip_none(lambda i: -i if i else None) 3*B[-1] + 2*B[1]
f
needs not be injective:sage: x.map_support_skip_none(lambda i: 1 if i else None) 5*B[1]
TESTS:
sage: y = x.map_support_skip_none(lambda i: None); y 0 sage: y.parent() is B True
-
support_of_term
()¶ Return the support of
self
, whereself
is a monomial (possibly with coefficient).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)¶ 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() 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)¶ 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 functioncmp(x,y)
, can be provided. This should return a negative value ifx < y
, 0 ifx == y
and a positive value ifx > 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)
wherec*self.parent().monomial(k)
is the trailing term ofself
.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 functioncmp(x,y)
, can be provided. This should return a negative value ifx < y
, 0 ifx == y
and a positive value ifx > 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)¶ 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 functioncmp(x,y)
, can be provided. This should return a negative value ifx < y
, 0 ifx == y
and a positive value ifx > 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)¶ Return the minimal element of the support of
self
. Note that this may not be the term which actually appears last whenself
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 ifx < y
,if
x == y
and a positive value ifx > 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)¶ 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 functioncmp(x,y)
, can be provided. This should return a negative value ifx < y
, 0 ifx == y
and a positive value ifx > 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]
-
-
ModulesWithBasis.
FiniteDimensional
¶ alias of
FiniteDimensionalModulesWithBasis
-
ModulesWithBasis.
Graded
¶ alias of
GradedModulesWithBasis
-
class
ModulesWithBasis.
Homsets
(category, *args)¶ Bases:
sage.categories.homsets.HomsetsCategory
TESTS:
sage: from sage.categories.covariant_functorial_construction import CovariantConstructionCategory sage: class FooBars(CovariantConstructionCategory): ....: _functor_category = "FooBars" ....: _base_category_class = (Category,) 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()
-
class
ParentMethods
¶
-
class
-
class
ModulesWithBasis.
MorphismMethods
¶ -
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") sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); Y.rename("Y") sage: H = Hom(X, Y) sage: x = X.basis() sage: f = H(lambda x: Y.zero()).on_basis() sage: f(2) 0 sage: f = lambda i: Y.monomial(i) + 2*Y.monomial(i+1) sage: g = H(on_basis = f).on_basis() sage: g(2) B[2] + 2*B[3] sage: g == f True
-
-
class
ModulesWithBasis.
ParentMethods
¶ -
basis
()¶ Return 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]]
-
echelon_form
(elements)¶ 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 ofself
.
OUTPUT:
A list of elements of
self
whose expressions as vectors form a matrix in echelon form. Ifbase_ring
is specified, then the calculation is achieved in this base ring.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() sage: V = X.echelon_form([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V [x[0] - x[2], x[1] - x[2]] sage: matrix(map(vector, V)) [ 1 0 -1] [ 0 1 -1]
sage: F = CombinatorialFreeModule(ZZ, [1,2,3,4]) sage: B = F.basis() sage: elements = [B[1]-17*B[2]+6*B[3], B[1]-17*B[2]+B[4]] sage: F.echelon_form(elements) [B[1] - 17*B[2] + B[4], 6*B[3] - B[4]]
sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: a,b,c = F.basis() sage: F.echelon_form([8*a+b+10*c, -3*a+b-c, a-b-c]) [B['a'] + B['c'], B['b'] + 2*B['c']]
-
module_morphism
(on_basis=None, matrix=None, function=None, diagonal=None, triangular=None, unitriangular=False, **keywords)¶ Construct a module morphism from
self
tocodomain
.Let
self
be a modulewith a basis indexed by
. This constructs a morphism
by linearity from a map
which is to be its restriction to the basis
of
. Some variants are possible too.
INPUT:
self
– a parentin
ModulesWithBasis(R)
with basis.
Exactly one of the four following options must be specified in order to define the morphism:
on_basis
– a functionfrom
to
diagonal
– a functionfrom
to
function
– a functionfrom
to
matrix
– a matrix of sizeor
Further options include:
codomain
– the codomainof the morphism (default:
f.codomain()
if it’s defined; otherwise it must be specified)category
– a category orNone
(default:)
zero
– the zero of the codomain (default:codomain.zero()
); can be used (with care) to define affine maps. Only meaningful withon_basis
.position
– a non-negative integer specifying which positional argument in used as the input of the function(default: 0); this is currently only used with
on_basis
.triangular
– (default:None
)"upper"
or"lower"
orNone
:"upper"
- if theleading_support()
of the image of the basis vectoris
, or
"lower"
- if thetrailing_support()
of the image of the basis vectoris
.
unitriangular
– (default:False
) a boolean. Only meaningful for a triangular morphism. As a shorthand, one may useunitriangular="lower"
fortriangular="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 functionobtained by extending
by linearity on the
position
-th positional argument. For example, forposition == 1
and a ternary function, one has:
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: x = X.basis(); y = Y.basis() sage: phi(x[1] + x[3]) B[1] + 2*B[2] + B[3] + 2*B[4] sage: phi Generic morphism: From: X To: Y
By default, the category is the first of
Modules(R).WithBasis().FiniteDimensional()
,Modules(R).WithBasis()
,Modules(R)
, andCommutativeAdditiveMonoids()
that contains both the domain and the codomain:sage: phi.category_for() Category of finite dimensional vector spaces with basis over Rational Field
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]
In this special case, the default category is
Sets()
: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() Category of commutative additive semigroups 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() Category of commutative additive semigroups 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): ... 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
to
:
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() Category of commutative additive semigroups 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): ... 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']) sage: phi = Y.module_morphism( on_basis=on_basis, codomain=X ) 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 morphismsuch that
This assumes that the respective bases
and
of
and
have the same index set
:
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") sage: phi = X.module_morphism(diagonal=factorial, codomain=X) sage: x = X.basis() sage: phi(x[1]), phi(x[2]), phi(x[3]) (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 ofand
is
:
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X"); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [3,4]); Y.rename("Y"); y = Y.basis() sage: m = matrix([[0,1,2],[3,5,0]]) sage: phi = X.module_morphism(matrix=m, codomain=Y) sage: phi(x[1]) 3*B[4] sage: phi(x[2]) 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 ofand
would be upper triangular with invertible elements on its diagonal. This is used to compute preimages and to invert 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]
Since trac ticket #8678, one can also define a triangular morphism from a function:
sage: X = CombinatorialFreeModule(QQ, [0,1,2,3,4]); x = X.basis() sage: from sage.modules.with_basis.morphism import TriangularModuleMorphismFromFunction sage: def f(x): return x + X.term(0, sum(x.coefficients())) sage: phi = X.module_morphism(function=f, codomain=X, triangular="upper") sage: phi(x[2] + 3*x[4]) 4*B[0] + B[2] + 3*B[4] sage: phi.preimage(_) 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
TESTS:
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") sage: phi = X.module_morphism(codomain=X) Traceback (most recent call last): ... ValueError: module_morphism() takes exactly one option out of `matrix`, `on_basis`, `function`, `diagonal`
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") sage: phi = X.module_morphism(diagonal=factorial, matrix=matrix(), codomain=X) Traceback (most recent call last): ... ValueError: module_morphism() takes exactly one option out of `matrix`, `on_basis`, `function`, `diagonal`
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") sage: phi = X.module_morphism(matrix=factorial, codomain=X) Traceback (most recent call last): ... ValueError: matrix (=factorial) should be a matrix
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); X.rename("X") sage: phi = X.module_morphism(diagonal=3, codomain=X) Traceback (most recent call last): ... ValueError: diagonal (=3) should be a function
-
submodule
(gens, check=True, already_echelonized=False, category=None)¶ The submodule spanned by a finite set of elements.
INPUT:
gens
– a list or family of elements ofself
check
– (default:True
) whether to verify that theelements of
gens
are inself
.
already_echelonized
– (default:False
) whetherthe elements of
gens
are already in (not necessarily reduced) echelon form.
If
already_echelonized
isFalse
, then the generators are put in reduced echelon form usingechelonize()
, and reindexed by.
Warning
At this point, this method only works for finite dimensional submodules and if matrices can be echelonized over the base ring.
The basis of the submodule uses the same index set as the generators, and the lifting map sends
to
.
See also
ModulesWithBasis.FiniteDimensional.ParentMethods.quotient_module()
sage.modules.with_basis.subquotient.SubmoduleWithBasis
EXAMPLES:
We construct a submodule of the free
-module generated by
. The submodule is spanned by
and
, and its basis elements are indexed by
and
:
sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() sage: gens = [x[0] - x[1], x[1] - x[2]]; gens [x[0] - x[1], x[1] - x[2]] sage: Y = X.submodule(gens, already_echelonized=True) sage: Y.print_options(prefix='y'); Y Free module generated by {0, 1} over Rational Field sage: y = Y.basis() sage: y[1] y[1] sage: y[1].lift() x[1] - x[2] sage: Y.retract(x[0]-x[2]) y[0] + y[1] sage: Y.retract(x[0]) 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") sage: x = X.basis() sage: gens = Family({1 : x[0] - x[1], 3: x[1] - x[2]}); gens Finite family {1: x[0] - x[1], 3: x[1] - x[2]} sage: Y = X.submodule(gens, already_echelonized=True) sage: Y.print_options(prefix='y'); Y Free module generated by {1, 3} over Rational Field sage: y = Y.basis() sage: y[1] y[1] sage: y[1].lift() x[0] - x[1] sage: y[3].lift() x[1] - x[2] sage: Y.retract(x[0]-x[2]) y[1] + y[3] sage: Y.retract(x[0]) 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") sage: x = X.basis() sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]; gens [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]] sage: Y = X.submodule(gens, already_echelonized=False) sage: Y.print_options(prefix='y') sage: Y Free module generated by {0, 1} over Rational Field sage: [b.lift() for b in Y.basis()] [x[0] - x[2], x[1] - x[2]]
We now implement by hand the center of the algebra of the symmetric group
:
sage: S3 = SymmetricGroup(3) sage: S3A = S3.algebra(QQ) sage: basis = S3A.annihilator_basis(S3A.algebra_generators(), S3A.bracket) sage: basis [(), (2,3) + (1,2) + (1,3), (1,2,3) + (1,3,2)] sage: center = S3A.submodule(basis, ....: category=AlgebrasWithBasis(QQ).Subobjects(), ....: already_echelonized=True) sage: center Free module generated by {0, 1, 2} over Rational Field sage: center in Algebras True sage: center.print_options(prefix='c') sage: c = center.basis() sage: c[1].lift() (2,3) + (1,2) + (1,3) sage: c[0]^2 c[0] sage: e = 1/6*(c[0]+c[1]+c[2]) sage: e.is_idempotent() True
Of course, this center is best constructed using:
sage: center = S3A.center()
TESTS:
sage: TestSuite(Y).run() sage: TestSuite(center).run()
-
tensor
(*parents)¶ Return 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)¶ Bases:
sage.categories.tensor.TensorProductsCategory
The category of modules with basis constructed by tensor product of modules with basis.
-
class
ElementMethods
¶ 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
toself
.INPUT:
f
– a multilinear morphism from the component modules of the parent tensor product to any modulecodomain
– the codomain off
(optional)
By the universal property of the tensor product,
f
induces a linear morphism fromto 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
and
:
sage: A = CombinatorialFreeModule(ZZ, [1,2], prefix="A"); A.rename("A") sage: B = CombinatorialFreeModule(ZZ, [3,4], prefix="B"); B.rename("B")
and
the bilinear morphism
from
to
:
sage: def f(a,b): ....: return tensor([b,a])
Now, calling applying
on
returns the same as
:
sage: a = A.monomial(1) + 2 * A.monomial(2); a A[1] + 2*A[2] sage: b = B.monomial(3) - 2 * B.monomial(4); b B[3] - 2*B[4] sage: f(a,b) 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) B[3] # A[1] + 2*B[3] # A[2] - 2*B[4] # A[1] - 4*B[4] # A[2]
may be a bilinear morphism to any module over the base ring of
and
. Here the codomain is
:
sage: def f(a,b): ....: return sum(a.coefficients(), 0) * sum(b.coefficients(), 0) sage: f(a,b) -3 sage: tensor([a,b]).apply_multilinear_morphism(f) -3
Mind the
in the sums above; otherwise
would not return
in
:
sage: def f(a,b): ....: return sum(a.coefficients()) * sum(b.coefficients()) sage: type(f(A.zero(), B.zero())) <type 'int'>
Which would be wrong and break this method:
sage: tensor([a,b]).apply_multilinear_morphism(f) 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"); C.rename("C") 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) C[(1, 3)] - 4*C[(2, 4)] sage: tensor([a,b]).apply_multilinear_morphism(f) 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) sage: s = Sym.schur() sage: def f(a,b): return a*b.antipode() sage: x = 4*s.an_element(); x 8*s[] + 8*s[1] + 12*s[2] sage: x.coproduct().apply_multilinear_morphism(f) 8*s[] sage: x.coproduct().apply_multilinear_morphism(f) == x.counit() True
We recover the constant term of
, as desired.
Todo
Extract a method to linearize a multilinear morphism, and delegate the work there.
-
-
class
ModulesWithBasis.TensorProducts.
ParentMethods
¶ Implements operations on tensor products of modules with basis.
-
ModulesWithBasis.TensorProducts.
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]
-
class
-
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
-
class