Free modules - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# Free modules

class sage.combinat.free_module.CartesianProductWithFlattening(flatten)

  Bases: `object`

  A class for Cartesian product constructor, with partial flattening

class sage.combinat.free_module.CombinatorialFreeModule(R, basis_keys=None, element_class=None, category=None, prefix=None, names=None, **kwds)

  Bases: `UniqueRepresentation`, `Module`, `IndexedGenerators`

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

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

  Python

      >>> from sage.all import *
      >>> F = CombinatorialFreeModule(QQ, ['a','b','c'])
      >>> F
      Free module generated by {'a', 'b', 'c'} over Rational Field

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

  Sage

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

  [Python]

      >>> from sage.all import *
      >>> e = F.basis()
      >>> e
      Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']}

  Sage

      sage: [x for x in e]
      [B['a'], B['b'], B['c']]
      sage: [k for k in e.keys()]
      ['a', 'b', 'c']

  Python

      >>> from sage.all import *
      >>> [x for x in e]
      [B['a'], B['b'], B['c']]
      >>> [k for k in e.keys()]
      ['a', 'b', 'c']

  Let us construct some elements, and compute with them:

  Sage

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

  [Python]

      >>> from sage.all import *
      >>> e['a']
      B['a']
      >>> Integer(2)*e['a']
      2*B['a']
      >>> e['a'] + Integer(3)*e['b']
      B['a'] + 3*B['b']

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

  Sage

      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]

  Python

      >>> from sage.all import *
      >>> F = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4)])
      >>> F.summation(F.monomial(Integer(1)), F.monomial(Integer(3)))
      B[1] + B[3]

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

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

  Sage

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

  [Python]

      >>> from sage.all import *
      >>> F1 = CombinatorialFreeModule(QQ, (Integer(1),Integer(2),Integer(3),Integer(4)))
      >>> 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

      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

  Python

      >>> from sage.all import *
      >>> F1 = CombinatorialFreeModule(QQ, (Integer(1),Integer(2),Integer(3),Integer(4)))
      >>> F1 is F
      True
      >>> F1 = CombinatorialFreeModule(QQ, [Integer(4),Integer(3),Integer(2),Integer(1)])
      >>> F1 == F
      False
      >>> F2 = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4)], prefix='F')
      >>> 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

      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

  [Python]

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

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

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

  Python

      >>> from sage.all import *
      >>> CombinatorialFreeModule(QQ, Partitions()).category()                      # needs sage.combinat
      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

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

  [Python]

      >>> from sage.all import *
      >>> CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4)]).category()
      Category of finite dimensional vector spaces with basis over Rational Field
      >>> CombinatorialFreeModule(QQ, Partitions(Integer(3)),                                # needs sage.combinat
      ...                         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

      sage: F = CombinatorialFreeModule(QQ, ['a','b'], prefix='x')
      sage: original_print_options = F.print_options()
      sage: sorted(original_print_options.items())
      [('bracket', None),
       ('iterate_key', False),
       ('latex_bracket', False), ('latex_names', None),
       ('latex_prefix', None), ('latex_scalar_mult', None),
       ('names', 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)

  Python

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

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

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

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

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

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

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

      >>> F.print_options(prefix='', bracket=False)
      >>> e[(Integer(1),Integer(2))] - Integer(3) * e[(Integer(3),Integer(4))]
      (1, 2) - 3*(3, 4)

  CartesianProduct

    alias of `CombinatorialFreeModule_CartesianProduct`

  Element

    alias of `IndexedFreeModuleElement`

  Tensor

    alias of `CombinatorialFreeModule_Tensor`

  change_ring(R)

    Return the base change of `self` to \(R\).

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(ZZ, ['a','b','c']); F
        Free module generated by {'a', 'b', 'c'} over Integer Ring
        sage: F_QQ = F.change_ring(QQ); F_QQ
        Free module generated by {'a', 'b', 'c'} over Rational Field
        sage: F_QQ.change_ring(ZZ) == F
        True

        sage: T = F.tensor(F); T
        Free module generated by {'a', 'b', 'c'} over Integer Ring
         # Free module generated by {'a', 'b', 'c'} over Integer Ring
        sage: T.change_ring(QQ)
        Free module generated by {'a', 'b', 'c'} over Rational Field
         # Free module generated by {'a', 'b', 'c'} over Rational Field

        sage: G = CombinatorialFreeModule(ZZ, ['x','y']); G
        Free module generated by {'x', 'y'} over Integer Ring
        sage: T = F.cartesian_product(G); T
        Free module generated by {'a', 'b', 'c'} over Integer Ring
         (+) Free module generated by {'x', 'y'} over Integer Ring
        sage: T.change_ring(QQ)
        Free module generated by {'a', 'b', 'c'} over Rational Field
         (+) Free module generated by {'x', 'y'} over Rational Field

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, ['a','b','c']); F
        Free module generated by {'a', 'b', 'c'} over Integer Ring
        >>> F_QQ = F.change_ring(QQ); F_QQ
        Free module generated by {'a', 'b', 'c'} over Rational Field
        >>> F_QQ.change_ring(ZZ) == F
        True

        >>> T = F.tensor(F); T
        Free module generated by {'a', 'b', 'c'} over Integer Ring
         # Free module generated by {'a', 'b', 'c'} over Integer Ring
        >>> T.change_ring(QQ)
        Free module generated by {'a', 'b', 'c'} over Rational Field
         # Free module generated by {'a', 'b', 'c'} over Rational Field

        >>> G = CombinatorialFreeModule(ZZ, ['x','y']); G
        Free module generated by {'x', 'y'} over Integer Ring
        >>> T = F.cartesian_product(G); T
        Free module generated by {'a', 'b', 'c'} over Integer Ring
         (+) Free module generated by {'x', 'y'} over Integer Ring
        >>> T.change_ring(QQ)
        Free module generated by {'a', 'b', 'c'} over Rational Field
         (+) Free module generated by {'x', 'y'} over Rational Field

  construction()

    The construction functor and base ring for `self`.

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ))
        sage: F.construction()
        (VectorFunctor, Rational Field)

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ))
        >>> F.construction()
        (VectorFunctor, Rational Field)

  dimension()

    Return the dimension of the free module (which is given by the number of elements in the basis).

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        sage: F.dimension()
        3
        sage: F.basis().cardinality()
        3
        sage: F.basis().keys().cardinality()
        3

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        >>> F.dimension()
        3
        >>> F.basis().cardinality()
        3
        >>> F.basis().keys().cardinality()
        3

    Rank is available as a synonym:

    Sage

        sage: F.rank()
        3

    [Python]

        >>> from sage.all import *
        >>> F.rank()
        3

    Sage

        sage: s = SymmetricFunctions(QQ).schur()                                    # needs sage.combinat
        sage: s.dimension()                                                         # needs sage.combinat
        +Infinity

    Python

        >>> from sage.all import *
        >>> s = SymmetricFunctions(QQ).schur()                                    # needs sage.combinat
        >>> s.dimension()                                                         # needs sage.combinat
        +Infinity

  element_class()

    The (default) class for the elements of this parent.

    Overrides `Parent.element_class()` to force the construction of Python class. This is currently needed to inherit really all the features from categories, and in particular the initialization of `_mul_` in `Magmas.ParentMethods.__init_extra__()`.

    EXAMPLES:

    Sage

        sage: # needs sage.combinat
        sage: A = Algebras(QQ).WithBasis().example(); A
        An example of an algebra with basis:
        the free algebra on the generators ('a', 'b', 'c') over Rational Field
        sage: A.element_class.mro()
        [<class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category.element_class'>,
         <class 'sage.modules.with_basis.indexed_element.IndexedFreeModuleElement'>,
         ...]
        sage: a,b,c = A.algebra_generators()
        sage: a * b
        B[word: ab]

    Python

        >>> from sage.all import *
        >>> # needs sage.combinat
        >>> A = Algebras(QQ).WithBasis().example(); A
        An example of an algebra with basis:
        the free algebra on the generators ('a', 'b', 'c') over Rational Field
        >>> A.element_class.mro()
        [<class 'sage.categories.examples.algebras_with_basis.FreeAlgebra_with_category.element_class'>,
         <class 'sage.modules.with_basis.indexed_element.IndexedFreeModuleElement'>,
         ...]
        >>> a,b,c = A.algebra_generators()
        >>> a * b
        B[word: ab]

  from_vector(vector, order=None, coerce=True)

    Build an element of `self` from a (sparse) vector.

    See also

    `get_order()`, `CombinatorialFreeModule.Element._vector_()`

    EXAMPLES:

    Sage

        sage: # needs sage.combinat
        sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
        sage: b = QS3.from_vector(vector((2, 0, 0, 0, 0, 4))); b
        2*[1, 2, 3] + 4*[3, 2, 1]
        sage: a = 2*QS3([1,2,3]) + 4*QS3([3,2,1])
        sage: a == b
        True

    Python

        >>> from sage.all import *
        >>> # needs sage.combinat
        >>> QS3 = SymmetricGroupAlgebra(QQ, Integer(3))
        >>> b = QS3.from_vector(vector((Integer(2), Integer(0), Integer(0), Integer(0), Integer(0), Integer(4)))); b
        2*[1, 2, 3] + 4*[3, 2, 1]
        >>> a = Integer(2)*QS3([Integer(1),Integer(2),Integer(3)]) + Integer(4)*QS3([Integer(3),Integer(2),Integer(1)])
        >>> a == b
        True

  get_order()

    Return the order of the elements in the basis.

    EXAMPLES:

    Sage

        sage: QS2 = SymmetricGroupAlgebra(QQ,2)                                     # needs sage.combinat
        sage: QS2.get_order()  # note: order changed on 2009-03-13                  # needs sage.combinat
        [[2, 1], [1, 2]]

    Python

        >>> from sage.all import *
        >>> QS2 = SymmetricGroupAlgebra(QQ,Integer(2))                                     # needs sage.combinat
        >>> QS2.get_order()  # note: order changed on 2009-03-13                  # needs sage.combinat
        [[2, 1], [1, 2]]

  get_order_key()

    Return a comparison key on the basis indices that is compatible with the current term order.

    EXAMPLES:

    Sage

        sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example()
        sage: A.set_order(['x', 'y', 'a', 'b'])
        sage: Akey = A.get_order_key()
        sage: sorted(A.basis().keys(), key=Akey)
        ['x', 'y', 'a', 'b']
        sage: A.set_order(list(reversed(A.basis().keys())))
        sage: Akey = A.get_order_key()
        sage: sorted(A.basis().keys(), key=Akey)
        ['b', 'a', 'y', 'x']

    Python

        >>> from sage.all import *
        >>> A = FiniteDimensionalAlgebrasWithBasis(QQ).example()
        >>> A.set_order(['x', 'y', 'a', 'b'])
        >>> Akey = A.get_order_key()
        >>> sorted(A.basis().keys(), key=Akey)
        ['x', 'y', 'a', 'b']
        >>> A.set_order(list(reversed(A.basis().keys())))
        >>> Akey = A.get_order_key()
        >>> sorted(A.basis().keys(), key=Akey)
        ['b', 'a', 'y', 'x']

  is_exact()

    Return `True` if elements of `self` have exact representations, which is true of `self` if and only if it is true of `self.basis().keys()` and `self.base_ring()`.

    EXAMPLES:

    Sage

        sage: GroupAlgebra(GL(3, GF(7))).is_exact()                                 # needs sage.groups sage.rings.finite_rings
        True
        sage: GroupAlgebra(GL(3, GF(7)), RR).is_exact()                             # needs sage.groups sage.rings.finite_rings
        False
        sage: GroupAlgebra(GL(3, pAdicRing(7))).is_exact()  # not implemented, needs sage.groups sage.rings.padics
        False

    Python

        >>> from sage.all import *
        >>> GroupAlgebra(GL(Integer(3), GF(Integer(7)))).is_exact()                                 # needs sage.groups sage.rings.finite_rings
        True
        >>> GroupAlgebra(GL(Integer(3), GF(Integer(7))), RR).is_exact()                             # needs sage.groups sage.rings.finite_rings
        False
        >>> GroupAlgebra(GL(Integer(3), pAdicRing(Integer(7)))).is_exact()  # not implemented, needs sage.groups sage.rings.padics
        False

  linear_combination(iter_of_elements_coeff, factor_on_left=True)

    Return the linear combination \(\lambda_1 v_1 + \cdots + \lambda_k v_k\) (resp. the linear combination \(v_1 \lambda_1 + \cdots + v_k \lambda_k\)) where `iter_of_elements_coeff` iterates through the sequence \(((v_1, \lambda_1), ..., (v_k, \lambda_k))\).

    INPUT:

    - `iter_of_elements_coeff` – iterator of pairs `(element, coeff)` with `element` in `self` and `coeff` in `self.base_ring()`

    - `factor_on_left` – (optional) if `True`, the coefficients are multiplied from the left if `False`, the coefficients are multiplied from the right

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, [1,2])
        sage: f = F.an_element(); f
        2*B[1] + 2*B[2]
        sage: F.linear_combination( (f,i) for i in range(5) )
        20*B[1] + 20*B[2]

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, [Integer(1),Integer(2)])
        >>> f = F.an_element(); f
        2*B[1] + 2*B[2]
        >>> F.linear_combination( (f,i) for i in range(Integer(5)) )
        20*B[1] + 20*B[2]

  monomial()

    Return the basis element indexed by `i`.

    INPUT:

    - `i` – an element of the index set

    EXAMPLES:

    Sage

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

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        >>> F.monomial('a')
        B['a']

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

    Sage

        sage: F.monomial
        Term map from {'a', 'b', 'c'} to Free module generated by {'a', 'b', 'c'} over Rational Field

    [Python]

        >>> from sage.all import *
        >>> F.monomial
        Term map from {'a', 'b', 'c'} to Free module generated by {'a', 'b', 'c'} over Rational Field

  rank()

    alias of `dimension()`.

  set_order(order)

    Set the order of the elements of the basis.

    If `set_order()` has not been called, then the ordering is the one used in the generation of the elements of `self`’s associated enumerated set.

    Warning

    Many cached methods depend on this order, in particular for constructing subspaces and quotients. Changing the order after some computations have been cached does not invalidate the cache, and is likely to introduce inconsistencies.

    EXAMPLES:

    Sage

        sage: # needs sage.combinat
        sage: QS2 = SymmetricGroupAlgebra(QQ,2)
        sage: b = list(QS2.basis().keys())
        sage: b.reverse()
        sage: QS2.set_order(b)
        sage: QS2.get_order()
        [[2, 1], [1, 2]]

    Python

        >>> from sage.all import *
        >>> # needs sage.combinat
        >>> QS2 = SymmetricGroupAlgebra(QQ,Integer(2))
        >>> b = list(QS2.basis().keys())
        >>> b.reverse()
        >>> QS2.set_order(b)
        >>> QS2.get_order()
        [[2, 1], [1, 2]]

  sum(iter_of_elements)

    Return the sum of all elements in `iter_of_elements`.

    Overrides method inherited from commutative additive monoid as it is much faster on dicts directly.

    INPUT:

    - `iter_of_elements` – iterator of elements of `self`

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ,[1,2])
        sage: f = F.an_element(); f
        2*B[1] + 2*B[2]
        sage: F.sum( f for _ in range(5) )
        10*B[1] + 10*B[2]

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ,[Integer(1),Integer(2)])
        >>> f = F.an_element(); f
        2*B[1] + 2*B[2]
        >>> F.sum( f for _ in range(Integer(5)) )
        10*B[1] + 10*B[2]

  sum_of_terms(terms, distinct=False)

    Construct a sum of terms of `self`.

    INPUT:

    - `terms` – list (or iterable) of pairs `(index, coeff)`

    - `distinct` – boolean (default: `False`); whether the indices are guaranteed to be distinct

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        sage: F.sum_of_terms([('a',2), ('c',3)])
        2*B['a'] + 3*B['c']

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        >>> F.sum_of_terms([('a',Integer(2)), ('c',Integer(3))])
        2*B['a'] + 3*B['c']

    If `distinct` is True, then the construction is optimized:

    Sage

        sage: F.sum_of_terms([('a',2), ('c',3)], distinct = True)
        2*B['a'] + 3*B['c']

    [Python]

        >>> from sage.all import *
        >>> F.sum_of_terms([('a',Integer(2)), ('c',Integer(3))], distinct = True)
        2*B['a'] + 3*B['c']

    Warning

    Use `distinct=True` only if you are sure that the indices are indeed distinct:

    Sage

        sage: F.sum_of_terms([('a',2), ('a',3)], distinct = True)
        3*B['a']

    Python

        >>> from sage.all import *
        >>> F.sum_of_terms([('a',Integer(2)), ('a',Integer(3))], distinct = True)
        3*B['a']

    Extreme case:

    Sage

        sage: F.sum_of_terms([])
        0

    Python

        >>> from sage.all import *
        >>> F.sum_of_terms([])
        0

  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)

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        sage: F.term('a',3)
        3*B['a']
        sage: F.term('a')
        B['a']

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        >>> F.term('a',Integer(3))
        3*B['a']
        >>> F.term('a')
        B['a']

    Design: should this do coercion on the coefficient ring?

  zero()

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        sage: F.zero()
        0

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
        >>> F.zero()
        0

class sage.combinat.free_module.CombinatorialFreeModule_CartesianProduct(modules, **options)

  Bases: `CombinatorialFreeModule`

  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

      sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
      sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
      sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.rename('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})}

  Python

      >>> from sage.all import *
      >>> F = CombinatorialFreeModule(ZZ, [Integer(4),Integer(5)]); F.rename('F')
      >>> G = CombinatorialFreeModule(ZZ, [Integer(4),Integer(6)]); G.rename('G')
      >>> H = CombinatorialFreeModule(ZZ, [Integer(4),Integer(7)]); H.rename('H')
      >>> S = cartesian_product([F, G])
      >>> S
      F (+) G
      >>> 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

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

  [Python]

      >>> from sage.all import *
      >>> 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

      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

  Python

      >>> from sage.all import *
      >>> f =   F.monomial(Integer(4)) + Integer(2)*F.monomial(Integer(5))
      >>> g = Integer(2)*G.monomial(Integer(4)) +   G.monomial(Integer(6))
      >>> h =   H.monomial(Integer(4)) +   H.monomial(Integer(7))
      >>> cartesian_product([f, g])
      B[(0, 4)] + 2*B[(0, 5)] + 2*B[(1, 4)] + B[(1, 6)]
      >>> 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)]
      >>> cartesian_product([f, g, h]).parent()
      F (+) G (+) H

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

  Sage

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

  [Python]

      >>> from sage.all import *
      >>> S = cartesian_product([cartesian_product([F, G]), H])  # todo: not implemented
      F (+) G (+) H

  class Element

    Bases: `IndexedFreeModuleElement`

  cartesian_embedding(i)

    Return the natural embedding morphism of the `i`-th Cartesian factor (summand) of `self` into `self`.

    INPUT:

    - `i` – integer

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
        sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
        sage: S = cartesian_product([F, G])
        sage: phi = S.cartesian_embedding(0)
        sage: phi(F.monomial(4) + 2 * F.monomial(5))
        B[(0, 4)] + 2*B[(0, 5)]
        sage: phi(F.monomial(4) + 2 * F.monomial(6)).parent() == S
        True

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, [Integer(4),Integer(5)]); F.rename('F')
        >>> G = CombinatorialFreeModule(ZZ, [Integer(4),Integer(6)]); G.rename('G')
        >>> S = cartesian_product([F, G])
        >>> phi = S.cartesian_embedding(Integer(0))
        >>> phi(F.monomial(Integer(4)) + Integer(2) * F.monomial(Integer(5)))
        B[(0, 4)] + 2*B[(0, 5)]
        >>> phi(F.monomial(Integer(4)) + Integer(2) * F.monomial(Integer(6))).parent() == S
        True

  cartesian_factors()

    Return the factors of the Cartesian product.

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
        sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
        sage: S = cartesian_product([F, G])
        sage: S.cartesian_factors()
        (F, G)

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, [Integer(4),Integer(5)]); F.rename('F')
        >>> G = CombinatorialFreeModule(ZZ, [Integer(4),Integer(6)]); G.rename('G')
        >>> S = cartesian_product([F, G])
        >>> S.cartesian_factors()
        (F, G)

  cartesian_projection(i)

    Return the natural projection onto the \(i\)-th Cartesian factor (summand) of `self`.

    INPUT:

    - `i` – integer

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
        sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
        sage: S = cartesian_product([F, G])
        sage: x = S.monomial((0,4)) + 2 * S.monomial((0,5)) + 3 * S.monomial((1,6))
        sage: S.cartesian_projection(0)(x)
        B[4] + 2*B[5]
        sage: S.cartesian_projection(1)(x)
        3*B[6]
        sage: S.cartesian_projection(0)(x).parent() == F
        True
        sage: S.cartesian_projection(1)(x).parent() == G
        True

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, [Integer(4),Integer(5)]); F.rename('F')
        >>> G = CombinatorialFreeModule(ZZ, [Integer(4),Integer(6)]); G.rename('G')
        >>> S = cartesian_product([F, G])
        >>> x = S.monomial((Integer(0),Integer(4))) + Integer(2) * S.monomial((Integer(0),Integer(5))) + Integer(3) * S.monomial((Integer(1),Integer(6)))
        >>> S.cartesian_projection(Integer(0))(x)
        B[4] + 2*B[5]
        >>> S.cartesian_projection(Integer(1))(x)
        3*B[6]
        >>> S.cartesian_projection(Integer(0))(x).parent() == F
        True
        >>> S.cartesian_projection(Integer(1))(x).parent() == G
        True

  summand_embedding(i)

    alias of `cartesian_embedding()`.

  summand_projection(i)

    alias of `cartesian_projection()`.

class sage.combinat.free_module.CombinatorialFreeModule_Tensor(modules, **options)

  Bases: `CombinatorialFreeModule`

  Tensor Product of Free Modules.

  EXAMPLES:

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

  Sage

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

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

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

  Python

      >>> from sage.all import *
      >>> F = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2)]); F.rename('F')
      >>> G = CombinatorialFreeModule(ZZ, [Integer(3),Integer(4)]); G.rename('G')
      >>> T = tensor([F, G]); T
      F # G

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

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

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

  Sage

      sage: T.base_ring()
      Integer Ring

  [Python]

      >>> from sage.all import *
      >>> T.base_ring()
      Integer Ring

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

  Sage

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

  Python

      >>> from sage.all import *
      >>> T.basis().keys()
      Image of Cartesian product of {1, 2}, {3, 4}
            by The map <class 'tuple'> from Cartesian product of {1, 2}, {3, 4}
      >>> 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

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

  [Python]

      >>> from sage.all import *
      >>> T.basis().cardinality()
      4
      >>> 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

      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

  Python

      >>> from sage.all import *
      >>> H = CombinatorialFreeModule(ZZ, [Integer(5),Integer(6)]); H.rename('H')
      >>> tensor([F, tensor([G, H])])
      F # G # H
      >>> tensor([tensor([F, G]), H])
      F # G # H
      >>> tensor([F, G, H])
      F # G # H

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

  Sage

      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]

  [Python]

      >>> from sage.all import *
      >>> f =   F.monomial(Integer(1)) + Integer(2) * F.monomial(Integer(2))
      >>> g = Integer(2)*G.monomial(Integer(3)) +     G.monomial(Integer(4))
      >>> h =   H.monomial(Integer(5)) +     H.monomial(Integer(6))
      >>> 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

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

  Python

      >>> from sage.all import *
      >>> tensor([f, tensor([g, h])]) == tensor([f, g, h])
      True
      >>> tensor([tensor([f, g]), h]) == tensor([f, g, h])
      True

  Note further that the tensor product spaces need not preexist:

  Sage

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

  [Python]

      >>> from sage.all import *
      >>> t = tensor([f, g, h])
      >>> t.parent()
      F # G # H

  tensor_constructor(modules)

    INPUT:

    - `modules` – tuple \((F_1,\dots,F_n)\) of free modules whose tensor product is self

    Returns the canonical multilinear morphism from \(F_1 \times \dots \times F_n\) to \(F_1 \otimes \dots \otimes F_n\)

    EXAMPLES:

    Sage

        sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.rename('F')
        sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.rename('G')
        sage: H = CombinatorialFreeModule(ZZ, [5,6]); H.rename('H')

        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: FG = tensor([F, G])
        sage: phi_fg = FG.tensor_constructor((F, G))
        sage: phi_fg(f, g)
        2*B[1] # B[3] + B[1] # B[4] + 4*B[2] # B[3] + 2*B[2] # B[4]

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

        sage: phi_fg_h = FGH.tensor_constructor((FG, H))
        sage: phi_fg_h(phi_fg(f, g), h)
        2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5]
        + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6]
        + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6]

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2)]); F.rename('F')
        >>> G = CombinatorialFreeModule(ZZ, [Integer(3),Integer(4)]); G.rename('G')
        >>> H = CombinatorialFreeModule(ZZ, [Integer(5),Integer(6)]); H.rename('H')

        >>> f =   F.monomial(Integer(1)) + Integer(2)*F.monomial(Integer(2))
        >>> g = Integer(2)*G.monomial(Integer(3)) +   G.monomial(Integer(4))
        >>> h =   H.monomial(Integer(5)) +   H.monomial(Integer(6))
        >>> FG = tensor([F, G])
        >>> phi_fg = FG.tensor_constructor((F, G))
        >>> phi_fg(f, g)
        2*B[1] # B[3] + B[1] # B[4] + 4*B[2] # B[3] + 2*B[2] # B[4]

        >>> FGH = tensor([F, G, H])
        >>> phi_fgh = FGH.tensor_constructor((F, G, H))
        >>> phi_fgh(f, g, h)
        2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5]
        + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6]
        + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6]

        >>> phi_fg_h = FGH.tensor_constructor((FG, H))
        >>> phi_fg_h(phi_fg(f, g), h)
        2*B[1] # B[3] # B[5] + 2*B[1] # B[3] # B[6] + B[1] # B[4] # B[5]
        + B[1] # B[4] # B[6] + 4*B[2] # B[3] # B[5] + 4*B[2] # B[3] # B[6]
        + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6]

  tensor_factors()

    Return the tensor factors of this tensor product.

    EXAMPLES:

    Sage

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

    Python

        >>> from sage.all import *
        >>> F = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2)])
        >>> F.rename('F')
        >>> G = CombinatorialFreeModule(ZZ, [Integer(3),Integer(4)])
        >>> G.rename('G')
        >>> T = tensor([F, G]); T
        F # G
        >>> T.tensor_factors()
        (F, G)