Ticket #9370: trac_9370-module-elt-repr.patch

File trac_9370-module-elt-repr.patch, 25.3 KB (added by jhpalmieri, 11 years ago)
  • sage/combinat/free_module.py

    # HG changeset patch
    # User J. H. Palmieri <palmieri@math.washington.edu>
    # Date 1285891445 25200
    # Node ID 761040d4920bde9bbf0f4bb37caf7d0506a7a31c
    # Parent  12663152c47016462d0248e5b32740a5a1c406c4
    #9370: customize printing of CombinatorialFreeModuleElements
    
    diff -r 12663152c470 -r 761040d4920b sage/combinat/free_module.py
    a b class CombinatorialFreeModuleElement(Ele 
    130130            sage: e = F.basis()
    131131            sage: e['a'] + 2*e['b'] # indirect doctest
    132132            F['a'] + 2*F['b']
     133            sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix='')
     134            sage: e = F.basis()
     135            sage: e['a'] + 2*e['b'] # indirect doctest
     136            ['a'] + 2*['b']
     137            sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix='', scalar_mult=' ', bracket=False)
     138            sage: e = F.basis()
     139            sage: e['a'] + 2*e['b'] # indirect doctest
     140            'a' + 2 'b'
    133141        """
    134142        v = self._monomial_coefficients.items()
    135143        try:
    class CombinatorialFreeModuleElement(Ele 
    141149        cffs = [ x for (_, x) in v ]
    142150        x = repr_lincomb(mons, cffs).replace("*1 "," ")
    143151        if x[len(x)-2:] == "*1":
    144             return x[:len(x)-2]
    145         else:
    146             return x
     152            x = x[:len(x)-2]
     153        ast = self.parent()._print_options.get('scalar_mult', "*")
     154        x = x.replace("*", ast)
     155        return x
    147156
    148157    def _latex_(self):
    149158        """
    class CombinatorialFreeModuleElement(Ele 
    160169            sage: QS3 = SymmetricGroupAlgebra(QQ,3)
    161170            sage: a = 2 + QS3([2,1,3])
    162171            sage: latex(a) #indirect doctest
    163             2[1,2,3] + [2,1,3]
     172            2[1, 2, 3] + [2, 1, 3]
    164173        """
    165174        v = self._monomial_coefficients.items()
    166175        v.sort()
    167176        prefix = self.parent().prefix()
    168         if prefix == "":
    169             mons = [ prefix + '[' + ",".join(map(str, m)) + ']' for (m, _) in v ]
    170         else:
    171             mons = [ prefix + '_{' + ",".join(map(str, m)) + '}' for (m, _) in v ]
     177        latex_term = self.parent()._latex_term
     178        mons = [ latex_term(m) for (m, _) in v ]
    172179        cffs = [ x for (_, x) in v ]
    173180        x = repr_lincomb(mons, cffs, is_latex=True).replace("*1 "," ")
    174181        if x[len(x)-2:] == "*1":
    def _divide_if_possible(x, y): 
    714721
    715722class CombinatorialFreeModule(UniqueRepresentation, Module):
    716723    r"""
     724    Class for free modules with a named basis
     725
     726    INPUT:
     727
     728    - ``R`` - base ring
     729
     730    - ``basis_keys`` - list, tuple, family, set, etc. defining the
     731      indexing set for the basis of this module
     732
     733    - ``element_class`` - the class of which elements of this module
     734      should be instances (optional, default None, in which case the
     735      elements are instances of
     736      :class:`CombinatorialFreeModuleElement`)
     737
     738    - ``category`` - the category in which this module lies (optional,
     739      default None, in which case use the "category of modules with
     740      basis" over the base ring ``R``)
     741
     742    Options controlling the printing of elements:
     743
     744    - ``prefix`` - string, prefix used for printing elements of this
     745      module (optional, default 'B').  With the default, a monomial
     746      indexed by 'a' would be printed as ``B['a']``.
     747
     748    - ``latex_prefix`` - string, prefix used in the LaTeX
     749      representation of elements (optional, default same value as
     750      ``prefix``).  With the default, a monomial indexed by 'a' would
     751      be printed as ``B_{a}``.  If this is the empty string, then
     752      don't print monomials as subscripts: the monomial indexed by 'a'
     753      would be printed as ``a``, or as ``[a]`` if ``latex_bracket`` is
     754      True.
     755
     756    - ``bracket`` - None, bool, string, or list or tuple of
     757      strings (optional, default None): if None, use the value of the
     758      attribute ``self._repr_option_bracket``, which has default value
     759      True.  (``self._repr_option_bracket`` is available for backwards
     760      compatibility.  Users should set ``bracket`` instead.  If
     761      ``bracket`` is set to anything except None, it overrides
     762      the value of ``self._repr_option_bracket``.)  If False, do not
     763      include brackets when printing elements: a monomial indexed by
     764      'a' would be printed as ``B'a'``, and a monomial indexed by
     765      (1,2,3) would be printed as ``B(1,2,3)``.  If True, use "[" and
     766      "]" as brackets.  If it is one of "[", "(", or "{", use it and
     767      its partner as brackets.  If it is any other string, use it as
     768      both brackets.  If it is a list or tuple of strings, use the
     769      first entry as the left bracket and the second entry as the
     770      right bracket.
     771
     772    - ``latex_bracket`` - bool, string, or list or tuple of strings
     773      (optional, default False): if False, do not include brackets in
     774      the LaTeX representation of elements.  This option is only
     775      relevant if ``latex_prefix`` is the empty string; otherwise,
     776      brackets are not used regardless.  If True, use "\\left[" and
     777      "\\right]" as brackets.  If this is one of "[", "(", "\\{", "|",
     778      or "||", use it and its partner, prepended with "\\left" and
     779      "\\right", as brackets.  If this is any other string, use it as
     780      both brackets.  If this is a list or tuple of strings, use the
     781      first entry as the left bracket and the second entry as the
     782      right bracket.
     783
     784    - ``scalar_mult`` - string to use for scalar multiplication in
     785      the print representation (optional, default "*")
     786
     787    These print options may also be accessed and modified using the
     788    :meth:`print_options` method, after the module has been defined.
     789
    717790    EXAMPLES:
    718791
    719792    We construct a free module whose basis is indexed by the letters a, b, c::
    class CombinatorialFreeModule(UniqueRepr 
    754827        sage: F.sum(F.monomial(i) for i in [1,2,3])
    755828        B[1] + B[2] + B[3]
    756829
    757     Note that the constructed free module depends on the order of the basis::
     830    Note that free modules with a given basis and parameters are unique::
     831
     832        sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
     833        sage: F1 is F
     834        True
     835
     836    The constructed free module depends on the order of the basis and
     837    on the other parameters, like the prefix::
    758838
    759839        sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
    760840        sage: F1 is F
    class CombinatorialFreeModule(UniqueRepr 
    762842        sage: F1 = CombinatorialFreeModule(QQ, [4,3,2,1])
    763843        sage: F1 == F
    764844        False
     845        sage: F2 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F')
     846        sage: F2 == F
     847        False
     848
     849    Because of this, if you create a free module with certain
     850    parameters and then modify its prefix or other print options, this
     851    affects all modules which were defined using the same parameters::
     852
     853        sage: F2.print_options(prefix='x')
     854        sage: F2.prefix()
     855        'x'
     856        sage: F3 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F')
     857        sage: F3 is F2   # F3 was defined just like F2
     858        True
     859        sage: F3.prefix()
     860        'x'
     861        sage: F4 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F', bracket=True)
     862        sage: F4 == F2   # F4 was NOT defined just like F2
     863        False
     864        sage: F4.prefix()
     865        'F'
     866
     867    The default category is the category of modules with basis over
     868    the base ring::
     869
     870        sage: CombinatorialFreeModule(GF(3), ((1,2), (3,4))).category()
     871        Category of modules with basis over Finite Field of size 3
     872
     873    See :mod:`sage.categories.examples.algebras_with_basis` and
     874    :mod:`sage.categories.examples.hopf_algebras_with_basis` for
     875    illustrations of the use of the ``category`` keyword, and see
     876    :class:`sage.combinat.root_system.weight_space.WeightSpace` for an
     877    example of the use of ``element_class``.
     878
     879    Customizing print and LaTeX representations of elements::
     880
     881        sage: F = CombinatorialFreeModule(QQ, ['a','b'], prefix='x')
     882        sage: e = F.basis()
     883        sage: e['a'] - 3 * e['b']
     884        x['a'] - 3*x['b']
     885
     886        sage: F.print_options(prefix='x', scalar_mult=' ', bracket='{')
     887        sage: e['a'] - 3 * e['b']
     888        x{'a'} - 3 x{'b'}
     889        sage: latex(e['a'] - 3 * e['b'])
     890        x_{a} + \left(-3\right)x_{b}
     891
     892        sage: F.print_options(latex_prefix='y')
     893        sage: latex(e['a'] - 3 * e['b'])
     894        y_{a} + \left(-3\right)y_{b}
     895       
     896        sage: F = CombinatorialFreeModule(QQ, [(1,2), (3,4)])
     897        sage: e = F.basis()
     898        sage: e[(1,2)] - 3 * e[(3,4)]
     899        B[(1, 2)] - 3*B[(3, 4)]
     900
     901        sage: F.print_options(bracket=['_{', '}'])
     902        sage: e[(1,2)] - 3 * e[(3,4)]
     903        B_{(1, 2)} - 3*B_{(3, 4)}
     904
     905        sage: F.print_options(prefix='', bracket=False)
     906        sage: e[(1,2)] - 3 * e[(3,4)]
     907        (1, 2) - 3*(3, 4)
    765908    """
    766909
    767910    @staticmethod
    class CombinatorialFreeModule(UniqueRepr 
    773916            sage: G = CombinatorialFreeModule(QQ, ('a','b','c'))
    774917            sage: F is G
    775918            True
     919
     920            sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], latex_bracket=['LEFT', 'RIGHT'])
     921            sage: F.print_options()['latex_bracket']
     922            ('LEFT', 'RIGHT')
    776923        """
    777924        # Convert the argument args[1] into a FiniteEumeratedSet
    778925        # if it is a list or a tuple in order it to have a cardinality() method.
    class CombinatorialFreeModule(UniqueRepr 
    780927        # to __init__ to let it handle proper exception raising.
    781928        if len(args) >= 2 and isinstance(args[1], (list, tuple)):
    782929            args = (args[0], FiniteEnumeratedSet(args[1])) + args[2:]
     930        # bracket or latex_bracket might be lists, so convert
     931        # them to tuples so that they're hashable.
     932        bracket = keywords.get('bracket', None)
     933        if isinstance(bracket, list):
     934            keywords['bracket'] = tuple(bracket)
     935        latex_bracket = keywords.get('latex_bracket', None)
     936        if isinstance(latex_bracket, list):
     937            keywords['latex_bracket'] = tuple(latex_bracket)
    783938        return super(CombinatorialFreeModule, cls).__classcall__(cls, *args, **keywords)
    784939
    785940    Element = CombinatorialFreeModuleElement
    786941
    787     def __init__(self, R, basis_keys, element_class = None, prefix="B", category = None):
     942    def __init__(self, R, basis_keys, element_class = None, prefix="B", category = None, **kwds):
    788943        r"""
    789944        TESTS::
    790945
    class CombinatorialFreeModule(UniqueRepr 
    838993        if not hasattr(self, "_prefix"):
    839994            self._prefix = prefix
    840995
     996        # printing options for elements.  These include self._prefix
     997        # (set when initializing self) and self._repr_option_bracket
     998        # (declared to be True by default, needs to be overridden
     999        # explicitly).
     1000        self._print_options = {}
     1001        self._print_options['prefix'] = self._prefix
     1002        # 'bracket': its default value here is None, meaning that
     1003        # the value of self._repr_option_bracket is used; the default
     1004        # value of that attribute is True -- see immediately before
     1005        # the method _repr_term.  If 'bracket' is any value
     1006        # except None, then it overrides the value of
     1007        # self._repr_option_bracket.  Future users might consider
     1008        # using 'bracket' instead of _repr_option_bracket.
     1009        self._print_options['bracket'] = kwds.get('bracket', None)
     1010        self._print_options['latex_bracket'] = kwds.get('latex_bracket', False)
     1011        self._print_options['latex_prefix'] = kwds.get('latex_prefix', self._prefix)
     1012        self._print_options['scalar_mult'] = kwds.get('scalar_mult', "*")
     1013
    8411014    # mostly for backward compatibility
    8421015    @lazy_attribute
    8431016    def _element_class(self):
    class CombinatorialFreeModule(UniqueRepr 
    11961369        """
    11971370        return self._prefix
    11981371
     1372    def print_options(self, **kwds):
     1373        """
     1374        Return the current print options, or set an option.
     1375
     1376        INPUT: all of the input is optional; if present, it should be
     1377        in the form of keyword pairs, such as
     1378        ``latex_bracket='('``.  The allowable keywords are:
     1379
     1380        - ``prefix``
     1381        - ``latex_prefix``
     1382        - ``bracket``
     1383        - ``latex_bracket``
     1384        - ``scalar_mult``
     1385        - ``tensor_symbol``
     1386
     1387        See the documentation for :class:`CombinatorialFreeModule` for
     1388        descriptions of the effects of setting each of these options.
     1389
     1390        OUTPUT: if the user provides any input, set the appropriate
     1391        option(s) and return nothing.  Otherwise, return the
     1392        dictionary of settings for print and LaTeX representations.
     1393
     1394        EXAMPLES::
     1395
     1396            sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix='x')
     1397            sage: F.print_options()
     1398            {'latex_bracket': False, 'prefix': 'x', 'bracket': None, 'scalar_mult': '*', 'latex_prefix': 'x'}
     1399            sage: F.print_options(bracket='(')
     1400            sage: F.print_options()
     1401            {'latex_bracket': False, 'prefix': 'x', 'bracket': '(', 'scalar_mult': '*', 'latex_prefix': 'x'}
     1402        """
     1403        # don't just use kwds.get(...) because I want to distinguish
     1404        # between an argument like "option=None" and the option not
     1405        # being there altogether.
     1406        args = False
     1407        if 'prefix' in kwds:
     1408            args = True
     1409            prefix = kwds['prefix']
     1410            self._prefix = prefix
     1411            self._print_options['prefix'] = prefix
     1412            if 'latex_prefix' not in kwds:
     1413                self._print_options['latex_prefix'] = prefix
     1414
     1415        for option in ['latex_prefix', 'bracket', 'latex_bracket',
     1416                       'scalar_mult', 'tensor_symbol']:
     1417            if option in kwds:
     1418                args = True
     1419                self._print_options[option] = kwds[option]
     1420
     1421        if not args:
     1422            return self._print_options
     1423        return
     1424
    11991425    _repr_option_bracket = True
    12001426
    12011427    def _repr_term(self, m):
    12021428        """
    1203         Returns a string representing the basis elements indexed by m.
     1429        Returns a string representing the basis element indexed by m.
    12041430
    1205         The output can be customized by mean of:
    1206          - self.prefix()
    1207          - self._repr_option_bracket # TODO: find a good name
    1208            (suggestions: _repr_with_bracket or _repr_add_bracket)
     1431        The output can be customized by setting any of the following
     1432        options when initializing the module:
     1433
     1434        - prefix
     1435        - bracket
     1436        - scalar_mult
     1437
     1438        Alternatively, one can use the :meth:`print_options` method
     1439        to achieve the same effect.  To modify the bracket setting,
     1440        one can also set ``self._repr_option_bracket`` as long as one
     1441        has *not* set the ``bracket`` option: if the
     1442        ``bracket`` option is anything but ``None``, it overrides
     1443        the value of ``self._repr_option_bracket``.
     1444
     1445        See the documentation for :class:`CombinatorialFreeModule` for
     1446        details on the initialization options.
    12091447
    12101448        EXAMPLES::
    12111449
    class CombinatorialFreeModule(UniqueRepr 
    12141452            sage: e['a'] + 2*e['b']    # indirect doctest
    12151453            B['a'] + 2*B['b']
    12161454
    1217             sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="C")
     1455            sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="F")
    12181456            sage: e = F.basis()
    12191457            sage: e['a'] + 2*e['b']    # indirect doctest
    1220             C['a'] + 2*C['b']
     1458            F['a'] + 2*F['b']
    12211459
    12221460            sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="")
    12231461            sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1])
    12241462            sage: a                      # indirect doctest
    12251463            2*[[1, 2, 3]] + 4*[[3, 2, 1]]
    12261464
    1227             sage: QS3._repr_option_bracket = False
     1465            sage: QS3.print_options(bracket = False)
    12281466            sage: a              # indirect doctest
    12291467            2*[1, 2, 3] + 4*[3, 2, 1]
    12301468
    1231             sage: QS3._repr_option_bracket = True
     1469            sage: QS3.print_options(prefix='')
    12321470            sage: a              # indirect doctest
    1233             2*[[1, 2, 3]] + 4*[[3, 2, 1]]
     1471            2*[1, 2, 3] + 4*[3, 2, 1]
     1472
     1473            sage: QS3.print_options(bracket="|", scalar_mult=" *@* ")
     1474            sage: a              # indirect doctest
     1475            2 *@* |[1, 2, 3]| + 4 *@* |[3, 2, 1]|
    12341476
    12351477        TESTS::
    12361478
    class CombinatorialFreeModule(UniqueRepr 
    12391481            sage: e[('a','b')] + 2*e[('c','d')]    # indirect doctest
    12401482            B[('a', 'b')] + 2*B[('c', 'd')]
    12411483        """
    1242         if self._repr_option_bracket:
    1243             return self.prefix()+"["+repr(m)+"]" # mind the (m), to accept a tuple for m
     1484        bracket = self._print_options.get('bracket', None)
     1485        bracket_d = {"{": "}", "[": "]", "(": ")"}
     1486        if bracket is None:
     1487            bracket = self._repr_option_bracket
     1488        if bracket is True:
     1489            left = "["
     1490            right = "]"
     1491        elif bracket is False:
     1492            left = ""
     1493            right = ""
     1494        elif isinstance(bracket, (tuple, list)):
     1495            left = bracket[0]
     1496            right = bracket[1]
     1497        elif bracket in bracket_d:
     1498            left = bracket
     1499            right = bracket_d[bracket]
    12441500        else:
    1245             return self.prefix()+repr(m)
     1501            left = bracket
     1502            right = bracket
     1503        return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m
    12461504
     1505    def _latex_term(self, m):
     1506        """
     1507        Returns a string for the LaTeX code for the basis element
     1508        indexed by m.
     1509
     1510        The output can be customized by setting any of the following
     1511        options when initializing the module:
     1512
     1513        - prefix
     1514        - latex_prefix
     1515        - latex_bracket
     1516
     1517        (Alternatively, one can use the :meth:`print_options` method
     1518        to achieve the same effect.)
     1519
     1520        See the documentation for :class:`CombinatorialFreeModule` for
     1521        details on the initialization options.
     1522
     1523        EXAMPLES::
     1524
     1525            sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
     1526            sage: e = F.basis()
     1527            sage: latex(e['a'] + 2*e['b'])    # indirect doctest
     1528            B_{a} + 2B_{b}
     1529
     1530            sage: F = CombinatorialFreeModule(QQ, ['a', 'b', 'c'], prefix="C")
     1531            sage: e = F.basis()
     1532            sage: latex(e['a'] + 2*e['b'])    # indirect doctest
     1533            C_{a} + 2C_{b}
     1534
     1535            sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="")
     1536            sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1])
     1537            sage: latex(a)                     # indirect doctest
     1538            2[1, 2, 3] + 4[3, 2, 1]
     1539            sage: QS3.print_options(latex_bracket=True)
     1540            sage: latex(a)                     # indirect doctest
     1541            2\left[[1, 2, 3]\right] + 4\left[[3, 2, 1]\right]
     1542            sage: QS3.print_options(latex_bracket="(")
     1543            sage: latex(a)                     # indirect doctest
     1544            2\left([1, 2, 3]\right) + 4\left([3, 2, 1]\right)
     1545            sage: QS3.print_options(latex_bracket=('\\myleftbracket', '\\myrightbracket'))
     1546            sage: latex(a)                     # indirect doctest
     1547            2\myleftbracket[1, 2, 3]\myrightbracket + 4\myleftbracket[3, 2, 1]\myrightbracket
     1548
     1549        TESTS::
     1550
     1551            sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), (0,1,2)])
     1552            sage: e = F.basis()
     1553            sage: latex(e[('a','b')])    # indirect doctest
     1554            B_{\left(a, b\right)}
     1555            sage: latex(2*e[(0,1,2)])    # indirect doctest
     1556            2B_{\left(0, 1, 2\right)}
     1557            sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), (0,1,2)], prefix="")
     1558            sage: e = F.basis()
     1559            sage: latex(2*e[(0,1,2)])    # indirect doctest
     1560            2\left(0, 1, 2\right)
     1561        """
     1562        from sage.misc.latex import latex
     1563        import re
     1564        s = latex(m)
     1565        s = re.sub("\\\\texttt{([^}]*)}", "\\1", s)
     1566        # dictionary with left-right pairs of "brackets".  put pairs
     1567        # in here accept \\left and \\right as prefixes.
     1568        bracket_d = {"{": "\\}", "[": "]", "(": ")", "\\{": "\\}",
     1569                     "|": "|", "||": "||"}
     1570        bracket = self._print_options.get('latex_bracket', False)
     1571        if bracket is True:
     1572            left = "\\left["
     1573            right = "\\right]"
     1574        elif bracket is False:
     1575            left = ""
     1576            right = ""
     1577        elif isinstance(bracket, (tuple, list)):
     1578            left = bracket[0]
     1579            right = bracket[1]
     1580        elif bracket in bracket_d:
     1581            left = bracket
     1582            right = bracket_d[bracket]
     1583            if left == "{":
     1584                left = "\\{"
     1585            left = "\\left" + left
     1586            right = "\\right" + right
     1587        else:
     1588            left = bracket
     1589            right = bracket
     1590        prefix = self._print_options.get('latex_prefix', self.prefix())
     1591        if prefix == "":
     1592            return left + s + right
     1593        return "%s_{%s}" % (prefix, s)
    12471594
    12481595    def __cmp__(self, other):
    12491596        """
    class CombinatorialFreeModule_Tensor(Com 
    16041951                sage: F = CombinatorialFreeModule(ZZ, [1,2]); F
    16051952                F
    16061953            """
     1954            from sage.categories.tensor import tensor
    16071955            self._sets = modules
    16081956            CombinatorialFreeModule.__init__(self, modules[0].base_ring(), CartesianProduct(*[module.basis().keys() for module in modules]).map(tuple), **options)
     1957            # the following is not the best option, but it's better than nothing.
     1958            self._print_options['tensor_symbol'] = options.get('tensor_symbol', tensor.symbol)
    16091959
    16101960        def _repr_(self):
    16111961            """
     1962            This is customizable by setting
     1963            ``self.print_options('tensor_symbol'=...)``.
     1964
     1965            TESTS::
     1966
     1967                sage: F = CombinatorialFreeModule(ZZ, [1,2,3])
     1968                sage: G = CombinatorialFreeModule(ZZ, [1,2,3,8])
     1969                sage: F.rename("F")
     1970                sage: G.rename("G")
     1971                sage: T = tensor([F, G])
     1972                sage: T # indirect doctest
     1973                F # G
     1974                sage: T.print_options(tensor_symbol= ' @ ')  # note the spaces
     1975                sage: T # indirect doctest
     1976                F @ G
     1977            """
     1978            from sage.categories.tensor import tensor
     1979            if hasattr(self, "_print_options"):
     1980                symb = self._print_options['tensor_symbol']
     1981            else:
     1982                symb = tensor.symbol
     1983            return symb.join(["%s"%module for module in self._sets])
     1984            # TODO: make this overridable by setting _name
     1985
     1986        def _latex_(self):
     1987            """
    16121988            TESTS::
    16131989
    16141990                sage: F = CombinatorialFreeModule(ZZ, [1,2,3])
    16151991                sage: G = CombinatorialFreeModule(ZZ, [1,2,3,8])
    1616                 sage: tensor([F, G]) # indirect doctest
    1617                 Free module generated by {1, 2, 3} over Integer Ring # Free module generated by {1, 2, 3, 8} over Integer Ring
     1992                sage: F.rename("F")
     1993                sage: G.rename("G")
     1994                sage: latex(tensor([F, F, G])) # indirect doctest
     1995                \texttt{F} \otimes \texttt{F} \otimes \texttt{G}
     1996                sage: F._latex_ = lambda : "F"
     1997                sage: G._latex_ = lambda : "G"
     1998                sage: latex(tensor([F, F, G])) # indirect doctest
     1999                F \otimes F \otimes G
    16182000            """
    1619             from sage.categories.tensor import tensor
    1620             return tensor.symbol.join(["%s"%module for module in self._sets])
    1621             # TODO: make this overridable by setting _name
     2001            from sage.misc.latex import latex
     2002            symb = " \\otimes "
     2003            return symb.join(["%s"%latex(module) for module in self._sets])
    16222004
    16232005        def _repr_term(self, term):
    16242006            """
    16252007            TESTS::
    16262008
    1627                 sage: F = CombinatorialFreeModule(ZZ, [1,2,3])
    1628                 sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4])
     2009                sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix="F")
     2010                sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix="G")
    16292011                sage: f =   F.monomial(1) + 2 * F.monomial(2)
    16302012                sage: g = 2*G.monomial(3) +     G.monomial(4)
    16312013                sage: tensor([f, g]) # indirect doctest
    1632                 2*B[1] # B[3] + B[1] # B[4] + 4*B[2] # B[3] + 2*B[2] # B[4]
     2014                2*F[1] # G[3] + F[1] # G[4] + 4*F[2] # G[3] + 2*F[2] # G[4]
    16332015            """
    16342016            from sage.categories.tensor import tensor
    1635             return tensor.symbol.join(module._repr_term(t) for (module, t) in zip(self._sets, term))
     2017            if hasattr(self, "_print_options"):
     2018                symb = self._print_options['tensor_symbol']
     2019            else:
     2020                symb = tensor.symbol
     2021            return symb.join(module._repr_term(t) for (module, t) in zip(self._sets, term))
    16362022
    1637         # TODO: latex
     2023        def _latex_term(self, term):
     2024            """
     2025            TESTS::
     2026
     2027                sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix='x')
     2028                sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix='y')
     2029                sage: f =   F.monomial(1) + 2 * F.monomial(2)
     2030                sage: g = 2*G.monomial(3) +     G.monomial(4)
     2031                sage: latex(tensor([f, g])) # indirect doctest
     2032                2x_{1} \otimes y_{3} + x_{1} \otimes y_{4} + 4x_{2} \otimes y_{3} + 2x_{2} \otimes y_{4}
     2033            """
     2034            symb = " \\otimes "
     2035            return symb.join(module._latex_term(t) for (module, t) in zip(self._sets, term))
    16382036
    16392037        @cached_method
    16402038        def tensor_constructor(self, modules):