Bases: object
A class for cartesian product constructor, with partial flattening
Bases: sage.structure.unique_representation.UniqueRepresentation, sage.modules.module.Module, sage.structure.indexed_generators.IndexedGenerators
Class for free modules with a named basis
INPUT:
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]
alias of CombinatorialFreeModuleElement
alias of CombinatorialFreeModule_Tensor
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
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
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'])
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]]
INPUT:
Returns the linear combination
(resp. the linear combination
)
where iter_of_elements_coeff iterates through the sequence
.
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]
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
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
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]]
overrides method inherited from commutative additive monoid as it is much faster on dicts directly
INPUT:
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]
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
Constructs a sum of terms of self
INPUT:
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
Constructs a term in self
INPUT:
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?
EXAMPLES:
sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
sage: F.zero()
0
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
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
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]
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
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
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
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()
[]
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]]
Returns a list of the terms of self
See also
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']]
Returns self as a dense vector
INPUT:
OUTPUT: a dense FreeModule() vector
Warning
This will crash/run forever if self is infinite dimensional!
See also
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.
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
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
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!!!!
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)
Return the natural projection onto the -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
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!!!!
Return the natural projection onto the -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
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
INPUT:
- modules – a tuple
of free modules whose tensor product is self
Returns the canonical multilinear morphism from
to
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]