Free modules

class sage.combinat.free_module.CartesianProductWithFlattening(flatten)

Bases: object

A class for Cartesian product constructor, with partial flattening

sage.combinat.free_module.CombinatorialFreeModule

Class for free modules with a named basis

INPUT:

  • R - base ring
  • basis_keys - list, tuple, family, set, etc. defining the indexing set for the basis of this module
  • element_class - the class of which elements of this module should be instances (optional, default None, in which case the elements are instances of IndexedFreeModuleElement)
  • category - the category in which this module lies (optional, default None, in which case use the “category of modules with basis” over the base ring R); this should be a subcategory of ModulesWithBasis

For the options controlling the printing of elements, see IndexedGenerators.

Note

These print options may also be accessed and modified using the print_options() method, after the module has been defined.

EXAMPLES:

We construct a free module whose basis is indexed by the letters a, b, c:

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
sage: F
Free module generated by {'a', 'b', 'c'} over Rational Field

Its basis is a family, indexed by a, b, c:

sage: e = F.basis()
sage: e
Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']}
sage: [x for x in e]
[B['a'], B['b'], B['c']]
sage: [k for k in e.keys()]
['a', 'b', 'c']

Let us construct some elements, and compute with them:

sage: e['a']
B['a']
sage: 2*e['a']
2*B['a']
sage: e['a'] + 3*e['b']
B['a'] + 3*B['b']

Some uses of sage.categories.commutative_additive_semigroups.CommutativeAdditiveSemigroups.ParentMethods.summation() and sum():

sage: F = CombinatorialFreeModule(QQ, [1,2,3,4])
sage: F.summation(F.monomial(1), F.monomial(3))
B[1] + B[3]

sage: F = CombinatorialFreeModule(QQ, [1,2,3,4])
sage: F.sum(F.monomial(i) for i in [1,2,3])
B[1] + B[2] + B[3]

Note that free modules with a given basis and parameters are unique:

sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
sage: F1 is F
True

The identity of the constructed free module depends on the order of the basis and on the other parameters, like the prefix. Note that CombinatorialFreeModule is a UniqueRepresentation. Hence, two combinatorial free modules evaluate equal if and only if they are identical:

sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
sage: F1 is F
True
sage: F1 = CombinatorialFreeModule(QQ, [4,3,2,1])
sage: F1 == F
False
sage: F2 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F')
sage: F2 == F
False

Because of this, if you create a free module with certain parameters and then modify its prefix or other print options, this affects all modules which were defined using the same parameters.

sage: F2.print_options(prefix='x')
sage: F2.prefix()
'x'
sage: F3 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F')
sage: F3 is F2   # F3 was defined just like F2
True
sage: F3.prefix()
'x'
sage: F4 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F', bracket=True)
sage: F4 == F2   # F4 was NOT defined just like F2
False
sage: F4.prefix()
'F'

sage: F2.print_options(prefix='F') #reset for following doctests

The constructed module is in the category of modules with basis over the base ring:

sage: CombinatorialFreeModule(QQ, Partitions()).category()
Category of vector spaces with basis over Rational Field

If furthermore the index set is finite (i.e. in the category Sets().Finite()), then the module is declared as being finite dimensional:

sage: CombinatorialFreeModule(QQ, [1,2,3,4]).category()
Category of finite dimensional vector spaces with basis over Rational Field
sage: CombinatorialFreeModule(QQ, Partitions(3),
....:                         category=Algebras(QQ).WithBasis()).category()
Category of finite dimensional algebras with basis over Rational Field

See sage.categories.examples.algebras_with_basis and sage.categories.examples.hopf_algebras_with_basis for illustrations of the use of the category keyword, and see sage.combinat.root_system.weight_space.WeightSpace for an example of the use of element_class.

Customizing print and LaTeX representations of elements:

sage: F = CombinatorialFreeModule(QQ, ['a','b'], prefix='x')
sage: original_print_options = F.print_options()
sage: sorted(original_print_options.items())
[('bracket', None),
 ('latex_bracket', False), ('latex_prefix', None),
 ('latex_scalar_mult', None), ('prefix', 'x'),
 ('scalar_mult', '*'),
 ('sorting_key', <function ...<lambda> at ...>),
 ('sorting_reverse', False), ('string_quotes', True),
 ('tensor_symbol', None)]

sage: e = F.basis()
sage: e['a'] - 3 * e['b']
x['a'] - 3*x['b']

sage: F.print_options(prefix='x', scalar_mult=' ', bracket='{')
sage: e['a'] - 3 * e['b']
x{'a'} - 3 x{'b'}
sage: latex(e['a'] - 3 * e['b'])
x_{a} - 3 x_{b}

sage: F.print_options(latex_prefix='y')
sage: latex(e['a'] - 3 * e['b'])
y_{a} - 3  y_{b}

sage: F.print_options(sorting_reverse=True)
sage: e['a'] - 3 * e['b']
-3 x{'b'} + x{'a'}
sage: F.print_options(**original_print_options) # reset print options

sage: F = CombinatorialFreeModule(QQ, [(1,2), (3,4)])
sage: e = F.basis()
sage: e[(1,2)] - 3 * e[(3,4)]
B[(1, 2)] - 3*B[(3, 4)]

sage: F.print_options(bracket=['_{', '}'])
sage: e[(1,2)] - 3 * e[(3,4)]
B_{(1, 2)} - 3*B_{(3, 4)}

sage: F.print_options(prefix='', bracket=False)
sage: e[(1,2)] - 3 * e[(3,4)]
(1, 2) - 3*(3, 4)
sage.combinat.free_module.CombinatorialFreeModule_CartesianProduct

An implementation of Cartesian products of modules with basis

EXAMPLES:

We construct two free modules, assign them short names, and construct their Cartesian product:

sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F"
sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G"
sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.__custom_name = "H"
sage: S = cartesian_product([F, G])
sage: S
F (+) G
sage: S.basis()
Lazy family (Term map from Disjoint union of Family ({4, 5}, {4, 6}) to F (+) G(i))_{i in Disjoint union of Family ({4, 5}, {4, 6})}

Note that the indices of the basis elements of F and G intersect non trivially. This is handled by forcing the union to be disjoint:

sage: list(S.basis())
[B[(0, 4)], B[(0, 5)], B[(1, 4)], B[(1, 6)]]

We now compute the Cartesian product of elements of free modules:

sage: f =   F.monomial(4) + 2 * F.monomial(5)
sage: g = 2*G.monomial(4) +     G.monomial(6)
sage: h =   H.monomial(4) +     H.monomial(7)
sage: cartesian_product([f,g])
B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)]
sage: cartesian_product([f,g,h])
B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)] + B[(2, 4)] + B[(2, 7)]
sage: cartesian_product([f,g,h]).parent()
F (+) G (+) H

TODO: choose an appropriate semantic for Cartesian products of Cartesian products (associativity?):

sage: S = cartesian_product([cartesian_product([F, G]), H]) # todo: not implemented
F (+) G (+) H
sage.combinat.free_module.CombinatorialFreeModule_Tensor

Tensor Product of Free Modules

EXAMPLES:

We construct two free modules, assign them short names, and construct their tensor product:

sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.__custom_name = "F"
sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.__custom_name = "G"
sage: T = tensor([F, G]); T
F # G

sage: T.category()
Category of finite dimensional tensor products of modules with basis over Integer Ring

sage: T.construction() # todo: not implemented
[tensor, ]

T is a free module, with same base ring as F and G:

sage: T.base_ring()
Integer Ring

The basis of T is indexed by tuples of basis indices of F and G:

sage: T.basis().keys()
Image of Cartesian product of {1, 2}, {3, 4} by <... 'tuple'>
sage: T.basis().keys().list()
[(1, 3), (1, 4), (2, 3), (2, 4)]

FIXME: Should elements of a CartesianProduct be tuples (making them hashable)?

Here are the basis elements themselves:

sage: T.basis().cardinality()
4
sage: list(T.basis())
[B[1] # B[3], B[1] # B[4], B[2] # B[3], B[2] # B[4]]

The tensor product is associative and flattens sub tensor products:

sage: H = CombinatorialFreeModule(ZZ, [5,6]); H.rename("H")
sage: tensor([F, tensor([G, H])])
F # G # H
sage: tensor([tensor([F, G]), H])
F # G # H
sage: tensor([F, G, H])
F # G # H

We now compute the tensor product of elements of free modules:

sage: f =   F.monomial(1) + 2 * F.monomial(2)
sage: g = 2*G.monomial(3) +     G.monomial(4)
sage: h =   H.monomial(5) +     H.monomial(6)
sage: tensor([f, g])
2*B[1] # B[3] + B[1] # B[4] + 4*B[2] # B[3] + 2*B[2] # B[4]

Again, the tensor product is associative on elements:

sage: tensor([f, tensor([g, h])]) == tensor([f, g, h])
True
sage: tensor([tensor([f, g]), h]) == tensor([f, g, h])
True

Note further that the tensor product spaces need not preexist:

sage: t = tensor([f, g, h])
sage: t.parent()
F # G # H