### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Combinatorial Algebras »

# 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, element_class=None, category=None, prefix='B', **kwds)

  Bases: `sage.structure.unique_representation.UniqueRepresentation`, `sage.modules.module.Module`, `sage.structure.indexed_generators.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 (optional, default None, in which case the elements are instances of `CombinatorialFreeModuleElement`)
  - `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`)

  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'], 'c': B['c'], 'b': B['b']}

      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 default category is the category of modules with basis over the base ring:

      sage: CombinatorialFreeModule(GF(3), ((1,2), (3,4))).category()
      Category of vector spaces with basis over Finite Field of size 3

  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), ('generator_cmp', <built-in function cmp>),
       ('latex_bracket', False), ('latex_prefix', None),
       ('latex_scalar_mult', None), ('prefix', 'x'),
       ('scalar_mult', '*'), ('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(generator_cmp = lambda x,y: -cmp(x,y))
      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)

  TESTS:

  Before trac ticket #14054, combinatorial free modules violated the unique parent condition. That caused a problem. The tensor product construction involves maps, but maps check that their domain and the parent of a to-be-mapped element are identical (not just equal). However, the tensor product was cached by a `cached_method`, which involves comparison by equality (not identity). Hence, the last line of the following example used to fail with an assertion error:

      sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix="F")
      sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix="G")
      sage: f =   F.monomial(1) + 2 * F.monomial(2)
      sage: g = 2*G.monomial(3) +     G.monomial(4)
      sage: tensor([f, g])
      2*F[1] # G[3] + F[1] # G[4] + 4*F[2] # G[3] + 2*F[2] # G[4]
      sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix='x')
      sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix='y')
      sage: f =   F.monomial(1) + 2 * F.monomial(2)
      sage: g = 2*G.monomial(3) +     G.monomial(4)
      sage: tensor([f, g])
      2*x[1] # y[3] + x[1] # y[4] + 4*x[2] # y[3] + 2*x[2] # y[4]

  `CartesianProduct`

    alias of `CombinatorialFreeModule_CartesianProduct`

  `Element`

    alias of `CombinatorialFreeModuleElement`

  `Tensor`

    alias of `CombinatorialFreeModule_Tensor`

  `dimension`()

    Returns the dimension of the combinatorial algebra (which is given by the number of elements in the basis).

    EXAMPLES:

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

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

  `from_vector`(vector)

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

    See also

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

    EXAMPLES:

        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

  `gens`()

    Return a tuple consisting of the basis elements of `self`.

    EXAMPLES:

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

  `get_order`()

    Returns the order of the elements in the basis.

    EXAMPLES:

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

  `linear_combination`(iter_of_elements_coeff, factor_on_left=True)

    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

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

    EXAMPLES:

        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]

  `monomial`()

    INPUT:

    > - ‘’i’‘

    Returns the basis element indexed by i

    EXAMPLES:

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

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

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

  `monomial_or_zero_if_none`(i)

    EXAMPLES:

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

  `set_order`(order)

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

    EXAMPLES:

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

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

    Returns the sum of all elements in `iter_of_elements`

    EXAMPLES:

        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]

  `sum_of_monomials`()

    INPUT:

    > - ‘’indices’’ – an list (or iterable) of indices of basis elements

    Returns the sum of the corresponding basis elements

    EXAMPLES:

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

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

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

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

  `sum_of_terms`(terms, distinct=False)

    Constructs a sum of terms of `self`

    INPUT:

    - `terms` – a list (or iterable) of pairs (index, coeff)
    - `distinct` – whether the indices are guaranteed to be distinct (default: `False`)

    EXAMPLES:

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

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

        sage: F.sum_of_terms([('a',2), ('c',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: F.sum_of_terms([('a',2), ('a',3)], distinct = True)
        3*B['a']

    Extreme case:

        sage: F.sum_of_terms([])
        0

  `term`(index, coeff=None)

    Constructs a term in `self`

    INPUT:

    - `index` – the index of a basis element
    - `coeff` – an element of the coefficient ring (default: one)

    EXAMPLES:

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

    Design: should this do coercion on the coefficient ring?

  `zero`()

    EXAMPLES:

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

class `sage.combinat.free_module.``CombinatorialFreeModuleElement`(M, x)

  Bases: `sage.structure.element.Element`

  Create a combinatorial module element. This should never be called directly, but only through the parent combinatorial free module’s `__call__()` method.

  TESTS:

      sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
      sage: B = F.basis()
      sage: f = B['a'] + 3*B['c']; f
      B['a'] + 3*B['c']
      sage: f == loads(dumps(f))
      True

  `coefficient`(m)

    EXAMPLES:

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

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

        sage: G = DihedralGroup(3)
        sage: F = CombinatorialFreeModule(QQ, G)
        sage: hasattr(G, "element_class")
        False
        sage: g = G.an_element()
        sage: (2*F.monomial(g)).coefficient(g)
        2

  `coefficients`()

    Returns a list of the coefficients appearing on the basis elements in self.

    EXAMPLES:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] - 3*B['c']
        sage: f.coefficients()
        [1, -3]

        sage: s = SymmetricFunctions(QQ).schur()
        sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])
        sage: z.coefficients()
        [1, 1, 1, 1]

  `is_zero`()

    Returns True if and only self == 0.

    EXAMPLES:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] - 3*B['c']
        sage: f.is_zero()
        False
        sage: F.zero().is_zero()
        True

        sage: s = SymmetricFunctions(QQ).schur()
        sage: s([2,1]).is_zero()
        False
        sage: s(0).is_zero()
        True
        sage: (s([2,1]) - s([2,1])).is_zero()
        True

  `length`()

    Returns the number of basis elements of self with nonzero coefficients.

    EXAMPLES:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] - 3*B['c']
        sage: f.length()
        2

        sage: s = SymmetricFunctions(QQ).schur()
        sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])
        sage: z.length()
        4

  `monomial_coefficients`()

    Return the internal dictionary which has the combinatorial objects indexing the basis as keys and their corresponding coefficients as values.

    EXAMPLES:

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

    To run through the monomials of an element, it is better to use the idiom:

        sage: for (t,c) in f:
        ...       print t,c
        a 1
        c 3

        sage: s = SymmetricFunctions(QQ).schur()
        sage: a = s([2,1])+2*s([3,2])
        sage: d = a.monomial_coefficients()
        sage: type(d)
        <type 'dict'>
        sage: d[ Partition([2,1]) ]
        1
        sage: d[ Partition([3,2]) ]
        2

  `monomials`()

    EXAMPLES:

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

        sage: (F.zero()).monomials()
        []

  `support`()

    Returns a list of the combinatorial objects indexing the basis elements of self which non-zero coefficients.

    EXAMPLES:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] - 3*B['c']
        sage: f.support()
        ['a', 'c']

        sage: s = SymmetricFunctions(QQ).schur()
        sage: z = s([4]) + s([2,1]) + s([1,1,1]) + s([1])
        sage: z.support()
        [[1], [1, 1, 1], [2, 1], [4]]

  `terms`()

    Returns a list of the terms of `self`

    See also

    `monomials()`

    EXAMPLES:

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

  `to_vector`(new_base_ring=None)

    Returns `self` as a dense vector

    INPUT:

    - `new_base_ring` – a ring (default: None)

    OUTPUT: a dense `FreeModule()` vector

    Warning

    This will crash/run forever if `self` is infinite dimensional!

    See also

    - `vector()`
    - `CombinatorialFreeModule.get_order()`
    - `CombinatorialFreeModule.from_vector()`
    - `CombinatorialFreeModule._dense_free_module()`

    EXAMPLES:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] - 3*B['c']
        sage: f._vector_()
        (1, 0, -3)

    One can use equivalently:

        sage: f.to_vector()
        (1, 0, -3)
        sage: vector(f)
        (1, 0, -3)

    More examples:

        sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
        sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1])
        sage: a._vector_()
        (2, 0, 0, 0, 0, 4)
        sage: a.to_vector()
        (2, 0, 0, 0, 0, 4)
        sage: vector(a)
        (2, 0, 0, 0, 0, 4)
        sage: a == QS3.from_vector(a.to_vector())
        True

    If ‘’new_base_ring’’ is specified, then a vector over ‘’new_base_ring’’ is returned:

        sage: a._vector_(RDF)
        (2.0, 0.0, 0.0, 0.0, 0.0, 4.0)

    Note

    #13406: the current implementation has been optimized, at #the price of breaking the encapsulation for FreeModule elements creation, with the following use case as metric, on a 2008’ Macbook Pro:

           sage: F = CombinatorialFreeModule(QQ, range(10))
           sage: f = F.an_element()
           sage: %timeit f._vector_()   # not tested
           625 loops, best of 3: 17.5 micros per loop

        Other use cases may call for different or further
        optimizations.

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

  Bases: `sage.combinat.free_module.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: 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

  class `Element`(M, x)

    Bases: `sage.combinat.free_module.CombinatorialFreeModuleElement`

    Create a combinatorial module element. This should never be called directly, but only through the parent combinatorial free module’s `__call__()` method.

    TESTS:

        sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
        sage: B = F.basis()
        sage: f = B['a'] + 3*B['c']; f
        B['a'] + 3*B['c']
        sage: f == loads(dumps(f))
        True

  `CombinatorialFreeModule_CartesianProduct.``cartesian_embedding`(i)

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

    INPUTS:

    > - `i` – an integer

    EXAMPLES:

        sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F"
        sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G"
        sage: S = cartesian_product([F, G])
        sage: phi = S.summand_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
        sage: phi(G.monomial(4)) # not implemented Should raise an error!  problem: G(F.monomial(4)) does not complain!!!!

  `CombinatorialFreeModule_CartesianProduct.``cartesian_factors`()

    Return the factors of the cartesian product.

    EXAMPLES:

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

  `CombinatorialFreeModule_CartesianProduct.``cartesian_projection`(i)

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

    INPUTS:

    > - `i` – an integer

    EXAMPLE:

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

  `CombinatorialFreeModule_CartesianProduct.``summand_embedding`(i)

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

    INPUTS:

    > - `i` – an integer

    EXAMPLES:

        sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F"
        sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G"
        sage: S = cartesian_product([F, G])
        sage: phi = S.summand_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
        sage: phi(G.monomial(4)) # not implemented Should raise an error!  problem: G(F.monomial(4)) does not complain!!!!

  `CombinatorialFreeModule_CartesianProduct.``summand_projection`(i)

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

    INPUTS:

    > - `i` – an integer

    EXAMPLE:

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

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

  Bases: `sage.combinat.free_module.CombinatorialFreeModule`

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

  TESTS:

      sage: tensor([tensor([F, G]), H]) == tensor([F, G, H])
      True
      sage: tensor([F, tensor([G, H])]) == tensor([F, G, H])
      True

  `tensor_constructor`(modules)

    INPUT:

    > - `modules` – a 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: F = CombinatorialFreeModule(ZZ, [1,2]); F.__custom_name = "F"
        sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.__custom_name = "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]

### Navigation

- index
- modules |
- next |
- previous |
- Combinatorics »
- Combinatorial Algebras »