Ticket #13605: trac_13605-partition_options-review-am.patch

File trac_13605-partition_options-review-am.patch, 141.3 KB (added by andrew.mathas, 8 years ago)

Review patch which primarily imporves option handling and fixes tex_from_array

  • doc/en/developer/conventions.rst

    # HG changeset patch
    # User "sage-combinat script"
    # Date 1361159890 -39600
    # Node ID 098a58915201dc03602b04123f6b000c78caa8c1
    # Parent  58c0551f4f20187c652a798027b98f916cb7d4c5
    #13605: Review patch: minor fixes and improvements to documentation
    
    diff --git a/doc/en/developer/conventions.rst b/doc/en/developer/conventions.rst
    a b For example, see the file 
    10521052
    10531053
    10541054.. [2]  See http://www.sagemath.org/development-map.html
     1055
     1056GlobalOptions
     1057=============
     1058
     1059Global options for classes can be defined in sage using :class:`GobalOptions`.
  • doc/en/reference/combinat/index.rst

    diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
    a b Combinatorics 
    3434   ../sage/combinat/lyndon_word
    3535   ../sage/combinat/necklace
    3636   ../sage/combinat/non_decreasing_parking_function
    37    ../sage/combinat/partition
    38    ../sage/combinat/partition_options
    39    ../sage/combinat/partition_tuple
    4037   ../sage/combinat/permutation
    4138   ../sage/combinat/perfect_matching
    4239   ../sage/combinat/q_analogues
    Combinatorics 
    4441   ../sage/combinat/sidon_sets
    4542   ../sage/combinat/set_partition_ordered
    4643   ../sage/combinat/set_partition
    47    ../sage/combinat/skew_partition
    4844   ../sage/combinat/subset
    4945   ../sage/combinat/subsets_pairwise
    5046   ../sage/combinat/subword
    Combinatorics 
    5349   cluster_algebras
    5450
    5551   algebra
     52   partitions
    5653   tableaux
    5754   symmetric_functions
    5855   ncsf_qsym
  • new file doc/en/reference/combinat/partitions.rst

    diff --git a/doc/en/reference/combinat/partitions.rst b/doc/en/reference/combinat/partitions.rst
    new file mode 100644
    - +  
     1Partitions and Partition-like Objects
     2=====================================
     3
     4.. toctree::
     5   :maxdepth: 2
     6
     7   ../sage/combinat/partition
     8   ../sage/combinat/partition_tuple
     9   ../sage/combinat/skew_partition
  • doc/en/reference/structure.rst

    diff --git a/doc/en/reference/structure.rst b/doc/en/reference/structure.rst
    a b Basic Structures 
    2020   sage/structure/mutability
    2121   sage/structure/sequence
    2222   sage/structure/element_wrapper
     23   sage/structure/global_options
    2324
    2425   sage/sets/cartesian_product
    2526   sage/sets/family
  • sage/combinat/core.py

    diff --git a/sage/combinat/core.py b/sage/combinat/core.py
    a b class Core(CombinatorialObject, Element) 
    117117            sage: c = Core([2,1],4)
    118118            sage: latex(c)
    119119            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    120             \raisebox{-.6ex}{$\begin{array}[b]{cc}
    121             \cline{1-1}\cline{2-2}
    122             \lr{\phantom{x}}&\lr{\phantom{x}}\\
    123             \cline{1-1}\cline{2-2}
    124             \lr{\phantom{x}}\\
    125             \cline{1-1}
     120            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     121            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     122            \lr{\phantom{x}}\\\cline{1-1}
    126123            \end{array}$}
    127124            }
    128125        """
  • sage/combinat/crystals/spins.py

    diff --git a/sage/combinat/crystals/spins.py b/sage/combinat/crystals/spins.py
    a b class Spin(Letter): 
    331331
    332332            sage: C = CrystalOfSpins(['B',3])
    333333            sage: b = C([1,1,-1])
    334             sage: b._latex_()
    335             '{\\def\\lr#1{\\multicolumn{1}{|@{\\hspace{.6ex}}c@{\\hspace{.6ex}}|}{\\raisebox{-.3ex}{$#1$}}}\n\\raisebox{-.6ex}{$\\begin{array}[b]{c}\n\\cline{1-1}\n\\lr{-}\\\\\n\\cline{1-1}\n\\lr{+}\\\\\n\\cline{1-1}\n\\lr{+}\\\\\n\\cline{1-1}\n\\end{array}$}\n}'
     334            sage: print b._latex_()
     335            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     336            \raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1}
     337            \lr{-}\\\cline{1-1}
     338            \lr{+}\\\cline{1-1}
     339            \lr{+}\\\cline{1-1}
     340            \end{array}$}
     341            }
    336342        """
    337343        return Tableau([[i] for i in reversed(self.signature())])._latex_()
    338344
  • sage/combinat/crystals/tensor_product.py

    diff --git a/sage/combinat/crystals/tensor_product.py b/sage/combinat/crystals/tensor_product.py
    a b class TensorProductOfCrystalsElement(Imm 
    612612            sage: C = CrystalOfLetters(["A",2])
    613613            sage: D = CrystalOfTableaux(["A",2], shape=[2])
    614614            sage: E = TensorProductOfCrystals(C,D)
    615             sage: E.module_generators[0]._latex_()
    616             '1\\otimes{\\def\\lr#1{\\multicolumn{1}{|@{\\hspace{.6ex}}c@{\\hspace{.6ex}}|}{\\raisebox{-.3ex}{$#1$}}}\n\\raisebox{-.6ex}{$\\begin{array}[b]{cc}\n\\cline{1-1}\\cline{2-2}\n\\lr{1}&\\lr{1}\\\\\n\\cline{1-1}\\cline{2-2}\n\\end{array}$}\n}'
     615            sage: print E.module_generators[0]._latex_()
     616            1\otimes{\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     617            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     618            \lr{1}&\lr{1}\\\cline{1-2}
     619            \end{array}$}
     620            }
    617621        """
    618622        return '\otimes'.join(latex(c) for c in self)
    619623
    class CrystalOfTableauxElement(TensorPro 
    11951199            sage: t = T(rows=[[1,1,2,3],[2,3]])
    11961200            sage: latex(t) # indirect doctest
    11971201            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    1198             \raisebox{-.6ex}{$\begin{array}[b]{cccc}
    1199             \cline{1-1}\cline{2-2}\cline{3-3}\cline{4-4}
    1200             \lr{1}&\lr{1}&\lr{2}&\lr{3}\\
    1201             \cline{1-1}\cline{2-2}\cline{3-3}\cline{4-4}
    1202             \lr{2}&\lr{3}\\
    1203             \cline{1-1}\cline{2-2}
     1202            \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{1-4}
     1203            \lr{1}&\lr{1}&\lr{2}&\lr{3}\\\cline{1-4}
     1204            \lr{2}&\lr{3}\\\cline{1-2}
    12041205            \end{array}$}
    12051206            }
    12061207        """
  • sage/combinat/output.py

    diff --git a/sage/combinat/output.py b/sage/combinat/output.py
    a b  
    11"""
    22Output functions
    33
    4 These are the output functions for partitions and tableaux.
     4These are the output functions for latexing partitions and tableaux.
    55
    66AUTHORS::
    77
    8 - Travis Scrimshaw (2012-10-16): Added different conventions and lines option
     8- Mike Hansen (?): initial version
     9- Travis Scrimshaw (2012-10-16): Added support for different conventions and with_lines option
     10- Andrew Mathas (2013-02-14): Rewrote adding support for tableaux of skew
     11  partition, composition and skew/composition/partition tuple shape.
    912"""
    10 # Only call tex_from_array(), the rest are helper functions
    1113
    12 from sage.combinat.partition_options import partition_options
     14from string import Template
     15from sage.combinat.tableau import Tableaux
    1316
    14 def tex_from_array(a, lines=True):
     17# The tex macro used to latex individual cells in an array (as a template).
     18# When using bar should be replaced by '|' or ''.
     19lr_macro=Template(r'\def\lr#1{\multicolumn{1}{$bar@{\hspace{.6ex}}c@{\hspace{.6ex}}$bar}{\raisebox{-.3ex}{$$#1$$}}}')
     20
     21def tex_from_array(array, with_lines=True):
    1522    r"""
    16     Convert a 2-d array ``a`` into a tableau-like display.
     23    Return a string for latexing a two dimensional array ``array`` as Young
     24    diagram The array ``array`` must be of partition, composition or skew
     25    composition shape. Empty rows are allowed, however, such rows should be
     26    given as `[None]`` rather than ``[]``.
     27   
     28    The arrays are drawn using either the ``English`` or ``French`` convention
     29    following :meth:`Tableaux.global_options``.
    1730   
    1831    INPUT:
    1932   
    20     - ``a`` -- The array
     33    - ``array`` -- The array
    2134   
    22     - ``lines`` -- (Default: ``True``) Boolean if the output use lines to
    23       separate the cells.
     35    - ``with_lines`` -- (Default: ``True``) If ``True`` then lines will be drawn to
     36        separate the entries in the array.
    2437   
    2538    EXAMPLES::
    2639   
    2740        sage: from sage.combinat.output import tex_from_array
    2841        sage: print tex_from_array([[1,2,3],[4,5]])
    2942        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    30         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    31         \cline{1-1}\cline{2-2}\cline{3-3}
    32         \lr{1}&\lr{2}&\lr{3}\\
    33         \cline{1-1}\cline{2-2}\cline{3-3}
    34         \lr{4}&\lr{5}\\
    35         \cline{1-1}\cline{2-2}
     43        \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{1-3}
     44        \lr{1}&\lr{2}&\lr{3}\\\cline{1-3}
     45        \lr{4}&\lr{5}\\\cline{1-2}
    3646        \end{array}$}
    3747        }
    38         sage: Partitions.options(convention="french")
    39         sage: print tex_from_array([[1,2,3],[4,5]])
    40         {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    41         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    42         \cline{1-1}\cline{2-2}
    43         \lr{4}&\lr{5}\\
    44         \cline{1-1}\cline{2-2}\cline{3-3}
    45         \lr{1}&\lr{2}&\lr{3}\\
    46         \cline{1-1}\cline{2-2}\cline{3-3}
    47         \end{array}$}
    48         }
    49         sage: Partitions.options(convention="english")
    50         sage: print tex_from_array([[1,2,3],[4,5]], False)
    51         {\def\lr#1{\multicolumn{1}{@{\hspace{.4ex}}c@{\hspace{.4ex}}}{\raisebox{-.3ex}{$#1$}}}
    52         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
     48        sage: print tex_from_array([[1,2,3],[4,5]], with_lines=False)
     49        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     50        \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\\
    5351        \lr{1}&\lr{2}&\lr{3}\\
    5452        \lr{4}&\lr{5}\\
    5553        \end{array}$}
    5654        }
    57     """
    58     global partition_options
    59     convention = partition_options["convention"]
    60     if convention == "english":
    61         if lines:
    62             return _tex_from_array_english(a)
    63         return _tex_from_array_no_lines_english(a)
    64     elif convention == "french":
    65         if lines:
    66             return _tex_from_array_french(a)
    67         return _tex_from_array_no_lines_french(a)
    68     else:
    69         raise ValueError, "convention must be either 'english' or 'french'"
    70 
    71 def _tex_from_array_english(a):
    72     """
    73     Output in English convention with lines.
    74    
    75     EXAMPLES::
    76 
    77         sage: from sage.combinat.output import _tex_from_array_english
    78         sage: print _tex_from_array_english([[1,2,3],[4,5]])
     55        sage: print tex_from_array([[1,2,3],[4,5,6,7],[8]])
    7956        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    80         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    81         \cline{1-1}\cline{2-2}\cline{3-3}
    82         \lr{1}&\lr{2}&\lr{3}\\
    83         \cline{1-1}\cline{2-2}\cline{3-3}
    84         \lr{4}&\lr{5}\\
    85         \cline{1-1}\cline{2-2}
     57        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{1-3}
     58        \lr{1}&\lr{2}&\lr{3}\\\cline{1-4}
     59        \lr{4}&\lr{5}&\lr{6}&\lr{7}\\\cline{1-4}
     60        \lr{8}\\\cline{1-1}
    8661        \end{array}$}
    8762        }
    88     """
    89     rows = len(a)
    90     cols = len(a[0])
    91     s = ""
    92     s += "{\\def\\lr#1{\\multicolumn{1}{|@{\\hspace{.6ex}}c@{\\hspace{.6ex}}|}{\\raisebox{-.3ex}{$#1$}}}\n"
    93     s += "\\raisebox{-.6ex}{$"
    94     s += "\\begin{array}[b]{"+"c"*cols+"}\n"
    95     for j in range(cols):
    96         if a[0][j] is not None:
    97             s += "\\cline{" + str(j+1) + "-" + str(j+1) + "}"
    98     s += "\n"
    99     for i in range(rows):
    100         cols = len(a[i])
    101         if len(a[i])>0 and a[i][0] is not None:
    102             for j in range(cols):
    103                 if a[i][j] is not None:
    104                     s += "\\lr{" + str(a[i][j]) + "}"
    105                     if j < cols-1:
    106                         s += "&"
    107             s += "\\\\\n"
    108             for j in range(cols):
    109                 if a[i][j] is not None:
    110                     s += "\\cline{" + str(j+1) + "-" + str(j+1) + "}"
    111             s += "\n"
    112     s += "\\end{array}$}\n}"
    113     return s
    114 
    115 def _tex_from_array_french(a):
    116     r"""
    117     Output in French convention with lines.
    118    
    119     EXAMPLES::
    120    
    121         sage: from sage.combinat.output import _tex_from_array_french
    122         sage: print _tex_from_array_french([[1,2,3],[4,5]])
    123         {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    124         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    125         \cline{1-1}\cline{2-2}
    126         \lr{4}&\lr{5}\\
    127         \cline{1-1}\cline{2-2}\cline{3-3}
     63        sage: print tex_from_array([[1,2,3],[4,5,6,7],[8]], with_lines=False)
     64        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     65        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\\
    12866        \lr{1}&\lr{2}&\lr{3}\\
    129         \cline{1-1}\cline{2-2}\cline{3-3}
     67        \lr{4}&\lr{5}&\lr{6}&\lr{7}\\
     68        \lr{8}\\
    13069        \end{array}$}
    13170        }
    132     """
    133     rows = len(a)
    134     cols = len(a[0])
    135     s = ""
    136     s += "{\\def\\lr#1{\\multicolumn{1}{|@{\\hspace{.6ex}}c@{\\hspace{.6ex}}|}{\\raisebox{-.3ex}{$#1$}}}\n"
    137     s += "\\raisebox{-.6ex}{$"
    138     s += "\\begin{array}[b]{"+"c"*cols+"}\n"
    139     for i in reversed(range(rows)):
    140         cols = len(a[i])
    141         if len(a[i])>0 and a[i][0] is not None:
    142             for j in range(cols):
    143                 if a[i][j] is not None:
    144                     s += "\\cline{" + str(j+1) + "-" + str(j+1) + "}"
    145             s += "\n"
    146             for j in range(cols):
    147                 if a[i][j] is not None:
    148                     s += "\\lr{" + str(a[i][j]) + "}"
    149                     if j < cols-1:
    150                         s += "&"
    151             s += "\\\\\n"
    152     for j in range(cols):
    153         if a[0][j] is not None:
    154             s += "\\cline{" + str(j+1) + "-" + str(j+1) + "}"
    155     s += "\n\\end{array}$}\n}"
    156     return s
    157 
    158 def _tex_from_array_no_lines_english(a):
    159     r"""
    160     Output in English convention with no lines.
    161    
    162     EXAMPLES::
    163    
    164         sage: from sage.combinat.output import _tex_from_array_no_lines_english
    165         sage: print _tex_from_array_no_lines_english([[1,2,3],[4,5]])
    166         {\def\lr#1{\multicolumn{1}{@{\hspace{.4ex}}c@{\hspace{.4ex}}}{\raisebox{-.3ex}{$#1$}}}
    167         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    168         \lr{1}&\lr{2}&\lr{3}\\
    169         \lr{4}&\lr{5}\\
     71        sage: print tex_from_array([[None,None,3],[None,5,6,7],[8]])
     72        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     73        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{3-3}
     74        &&\lr{3}\\\cline{2-4}
     75        &\lr{5}&\lr{6}&\lr{7}\\\cline{1-4}
     76        \lr{8}\\\cline{1-1}
    17077        \end{array}$}
    17178        }
    172     """
    173     rows = len(a)
    174     cols = len(a[0])
    175     s = ""
    176     s += "{\\def\\lr#1{\\multicolumn{1}{@{\\hspace{.4ex}}c@{\\hspace{.4ex}}}{\\raisebox{-.3ex}{$#1$}}}\n"
    177     s += "\\raisebox{-.6ex}{$"
    178     s += "\\begin{array}[b]{"+"c"*cols+"}\n"
    179     for i in range(rows):
    180         cols = len(a[i])
    181         if len(a[i])>0 and a[i][0] is not None:
    182             for j in range(cols):
    183                 if a[i][j] is not None:
    184                     s += "\\lr{" + str(a[i][j]) + "}"
    185                     if j < cols-1:
    186                         s += "&"
    187             s += "\\\\\n"
    188     s += "\\end{array}$}\n}"
    189     return s
    190 
    191 def _tex_from_array_no_lines_french(a):
    192     r"""
    193     Output in French convention with no lines.
    194    
    195     EXAMPLES::
    196    
    197         sage: from sage.combinat.output import _tex_from_array_no_lines_french
    198         sage: print _tex_from_array_no_lines_french([[1,2,3],[4,5]])
    199         {\def\lr#1{\multicolumn{1}{@{\hspace{.4ex}}c@{\hspace{.4ex}}}{\raisebox{-.3ex}{$#1$}}}
    200         \raisebox{-.6ex}{$\begin{array}[b]{ccc}
     79        sage: print tex_from_array([[None,None,3],[None,5,6,7],[None,8]])
     80        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     81        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\cline{3-3}
     82        &&\lr{3}\\\cline{2-4}
     83        &\lr{5}&\lr{6}&\lr{7}\\\cline{2-4}
     84        &\lr{8}\\\cline{2-2}
     85        \end{array}$}
     86        }
     87        sage: print tex_from_array([[None,None,3],[None,5,6,7],[8]], with_lines=False)
     88        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     89        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\\
     90        &&\lr{3}\\
     91        &\lr{5}&\lr{6}&\lr{7}\\
     92        \lr{8}\\
     93        \end{array}$}
     94        }
     95        sage: print tex_from_array([[None,None,3],[None,5,6,7],[None,8]], with_lines=False)
     96        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     97        \raisebox{-.6ex}{$\begin{array}[b]{*{4}c}\\
     98        &&\lr{3}\\
     99        &\lr{5}&\lr{6}&\lr{7}\\
     100        &\lr{8}\\
     101        \end{array}$}
     102        }
     103        sage: Tableaux.global_options(convention="french")
     104        sage: print tex_from_array([[1,2,3],[4,5]])
     105        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     106        \raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\cline{1-2}
     107        \lr{4}&\lr{5}\\\cline{1-3}
     108        \lr{1}&\lr{2}&\lr{3}\\\cline{1-3}
     109        \end{array}$}
     110        }
     111        sage: print tex_from_array([[1,2,3],[4,5]], with_lines=False)
     112        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     113        \raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\\
    201114        \lr{4}&\lr{5}\\
    202115        \lr{1}&\lr{2}&\lr{3}\\
    203116        \end{array}$}
    204117        }
     118        sage: print tex_from_array([[1,2,3],[4,5,6,7],[8]])
     119        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     120        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\cline{1-1}
     121        \lr{8}\\\cline{1-4}
     122        \lr{4}&\lr{5}&\lr{6}&\lr{7}\\\cline{1-4}
     123        \lr{1}&\lr{2}&\lr{3}\\\cline{1-3}
     124        \end{array}$}
     125        }
     126        sage: print tex_from_array([[1,2,3],[4,5,6,7],[8]], with_lines=False)
     127        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     128        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\\
     129        \lr{8}\\
     130        \lr{4}&\lr{5}&\lr{6}&\lr{7}\\
     131        \lr{1}&\lr{2}&\lr{3}\\
     132        \end{array}$}
     133        }
     134        sage: print tex_from_array([[None,None,3],[None,5,6,7],[8]])
     135        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     136        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\cline{1-1}
     137        \lr{8}\\\cline{1-4}
     138        &\lr{5}&\lr{6}&\lr{7}\\\cline{2-4}
     139        &&\lr{3}\\\cline{3-3}
     140        \end{array}$}
     141        }
     142        sage: print tex_from_array([[None,None,3],[None,5,6,7],[None,8]])
     143        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     144        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\cline{2-2}
     145        &\lr{8}\\\cline{2-4}
     146        &\lr{5}&\lr{6}&\lr{7}\\\cline{2-4}
     147        &&\lr{3}\\\cline{3-3}
     148        \end{array}$}
     149        }
     150        sage: print tex_from_array([[None,None,3],[None,5,6,7],[8]], with_lines=False)
     151        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     152        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\\
     153        \lr{8}\\
     154        &\lr{5}&\lr{6}&\lr{7}\\
     155        &&\lr{3}\\
     156        \end{array}$}
     157        }
     158        sage: print tex_from_array([[None,None,3],[None,5,6,7],[None,8]], with_lines=False)
     159        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     160        \raisebox{-.6ex}{$\begin{array}[t]{*{4}c}\\
     161        &\lr{8}\\
     162        &\lr{5}&\lr{6}&\lr{7}\\
     163        &&\lr{3}\\
     164        \end{array}$}
     165        }
     166        sage: Tableaux.global_options.reset()
    205167    """
    206     rows = len(a)
    207     cols = len(a[0])
    208     s = ""
    209     s += "{\\def\\lr#1{\\multicolumn{1}{@{\\hspace{.4ex}}c@{\\hspace{.4ex}}}{\\raisebox{-.3ex}{$#1$}}}\n"
    210     s += "\\raisebox{-.6ex}{$"
    211     s += "\\begin{array}[b]{"+"c"*cols+"}\n"
    212     for i in reversed(range(rows)):
    213         cols = len(a[i])
    214         if len(a[i])>0 and a[i][0] is not None:
    215             for j in range(cols):
    216                 if a[i][j] is not None:
    217                     s += "\\lr{" + str(a[i][j]) + "}"
    218                     if j < cols-1:
    219                         s += "&"
    220             s += "\\\\\n"
    221     s += "\\end{array}$}\n}"
    222     return s
     168    lr=lr_macro.substitute(bar='|' if with_lines else '')
     169    if Tableaux.global_options("convention")=='english':
     170        return '{%s\n%s\n}' % (lr, tex_from_skew_array(array, with_lines))
     171    else:
     172        return '{%s\n%s\n}' % (lr, tex_from_skew_array(array[::-1], with_lines, align='t'))
     173
     174
     175def tex_from_array_tuple(a_tuple, with_lines=True):
     176    r"""
     177    Return a string for latexing a tuple of two dimensional arrays ``a_tuple``
     178    as a Young diagram The array ``a_tuple`` must be of partition, composition
     179    or skew composition shape. Empty rows are allowed, however, they should be
     180    given as `[None]`` rather than ``[]``.
     181
     182    The arrays are drawn using either the ``English`` or ``French`` convention
     183    following :meth:`Tableaux.global_options``.
     184   
     185    INPUT:
     186   
     187    - ``a_tuple`` -- The tuple of arrays
     188   
     189    - ``with_lines`` -- (Default: ``True``) If ``True`` then lines will be drawn to
     190        separate the entries in the components of ``a_tuple``.
     191
     192    EXAMPLES::
     193
     194        sage: from sage.combinat.output import tex_from_array_tuple
     195       
     196        sage: print tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]])
     197        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     198        \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{1-3}
     199        \lr{1}&\lr{2}&\lr{3}\\\cline{1-3}
     200        \lr{4}&\lr{5}\\\cline{1-2}
     201        \end{array}$},\emptyset,\raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{2-3}
     202        &\lr{6}&\lr{7}\\\cline{2-3}
     203        &\lr{8}\\\cline{1-2}
     204        \lr{9}\\\cline{1-1}
     205        \end{array}$}
     206        }
     207        sage: print tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]], with_lines=False)
     208        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     209        \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\\
     210        \lr{1}&\lr{2}&\lr{3}\\
     211        \lr{4}&\lr{5}\\
     212        \end{array}$},\emptyset,\raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\\
     213        &\lr{6}&\lr{7}\\
     214        &\lr{8}\\
     215        \lr{9}\\
     216        \end{array}$}
     217        }
     218        sage: Tableaux.global_options(convention="french")
     219        sage: print tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]])
     220        {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     221        \raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\cline{1-2}
     222        \lr{4}&\lr{5}\\\cline{1-3}
     223        \lr{1}&\lr{2}&\lr{3}\\\cline{1-3}
     224        \end{array}$},r\emptyset,\raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\cline{1-1}
     225        \lr{9}\\\cline{1-2}
     226        &\lr{8}\\\cline{2-3}
     227        &\lr{6}&\lr{7}\\\cline{2-3}
     228        \end{array}$}
     229        }
     230        sage: print tex_from_array_tuple([[[1,2,3],[4,5]],[],[[None,6,7],[None,8],[9]]], with_lines=False)
     231        {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     232        \raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\\
     233        \lr{4}&\lr{5}\\
     234        \lr{1}&\lr{2}&\lr{3}\\
     235        \end{array}$},r\emptyset,\raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\\
     236        \lr{9}\\
     237        &\lr{8}\\
     238        &\lr{6}&\lr{7}\\
     239        \end{array}$}
     240        }
     241
     242    """
     243    lr=lr_macro.substitute(bar='|' if with_lines else '')
     244    if Tableaux.global_options("convention")=='english':
     245        return '{%s\n%s\n}' % (lr, ','.join(
     246            r'\emptyset' if comp==[] else tex_from_skew_array(comp, with_lines) for comp in a_tuple))
     247    else:
     248        return '{%s\n%s\n}' % (lr, ','.join(
     249            'r\emptyset' if comp==[] else tex_from_skew_array(comp[::-1], with_lines, align='t') for comp in a_tuple))
     250
     251
     252def tex_from_skew_array(array, with_lines=False, align='b'):
     253    r"""
     254    This function creates latex code for a "skew composition" ``array``.
     255    That is, for a two dimensional array in which each row can begin with
     256    an arbitrary number ``None``'s and the remaining entries could, in
     257    principe, be anything but probably should be strings or integers of similar
     258    width. A row consisting completely of ``None``'s is allowed.
     259
     260    INPUTS:
     261
     262    - array:       the array
     263    - with_lines:  if ``True`` lines are drawn, if ``False`` they are not.
     264    - align:       determines the alignment on the latex array environments. Defaults to b=bottom.
     265
     266    EXAMPLES::
     267
     268        sage: array=[[None, 2,3,4],[None,None],[5,6,7,8]]
     269        sage: sage.combinat.output.tex_from_skew_array(array)
     270        '\\raisebox{-.6ex}{$\\begin{array}[b]{*{4}c}\\\\\n&\\lr{2}&\\lr{3}&\\lr{4}\\\\\n&\\\\\n\\lr{5}&\\lr{6}&\\lr{7}&\\lr{8}\\\\\n\\end{array}$}'
     271    """
     272    # first identify where the None's appear in ``array`` and define a
     273    # function end_line which puts in the required \cline's.
     274    if with_lines:
     275        # last position of None in each row
     276        nones=[1 if not None in row else 1+len(row)-row[::-1].index(None) for row in array]
     277        def end_line(r):
     278            # in a slightly unpythonic way, we label the lines as 0, 1, ..., len(array)
     279            if r==0:
     280                return r'\cline{%s-%s}'%(nones[0],len(array[0]))
     281            elif r==len(array):
     282                start=nones[r-1]
     283                finish=len(array[r-1])
     284            else:
     285                start=min(nones[r], nones[r-1])
     286                finish=max(len(array[r]), len(array[r-1]))
     287            return r'\\' if start>finish else r'\\\cline{%s-%s}'%(start, finish)
     288    else:
     289        end_line=lambda r: r'\\'
     290
     291    # now we draw the array
     292    tex=r'\raisebox{-.6ex}{$\begin{array}[%s]{*{%s}c}'%(align,max(map(len,array)))
     293    tex+=end_line(0)+'\n'
     294    for r in xrange(len(array)):
     295        tex+='&'.join('' if c is None else r'\lr{%s}'%c for c in array[r])
     296        tex+=end_line(r+1)+'\n'
     297    return tex+r'\end{array}$}'
  • sage/combinat/partition.py

    diff --git a/sage/combinat/partition.py b/sage/combinat/partition.py
    a b The coordinate system related to a parti 
    1313to the bottom and from left to right. So, the corners of the
    1414partition `[5, 3, 1]` are `[[0,4], [1,2], [2,0]]`.
    1515
    16 For display options, see :meth:`Partitions.options`.
     16For display options, see :meth:`Partitions.global_options`.
    1717
    1818.. NOTE::
    1919
    AUTHORS: 
    5555- Andrew Mathas (2012-06-01): Removed depreciated functions and added
    5656  compatibility with the PartitionTuple classes.  See :trac:`13072`
    5757
    58 - Travis Scrimshaw (2012-10-12): Added partition options. Made
     58- Travis Scrimshaw (2012-10-12): Added PartitionOptions. Made
    5959  ``Partition_class`` to the element ``Partition``. ``Partitions*`` are now
    6060  all in the category framework except ``PartitionsRestricted`` (which will
    6161  eventually be removed). Cleaned up documentation.
    We use the lexicographic ordering:: 
    266266from sage.interfaces.all import gap, gp
    267267from sage.libs.all import pari
    268268
     269from sage.structure.global_options import GlobalOptions
    269270from sage.structure.parent import Parent
    270271from sage.structure.unique_representation import UniqueRepresentation
    271272from sage.structure.element import Element
    from sage.combinat.partitions import num 
    294295from sage.combinat.integer_vector import IntegerVectors
    295296from sage.combinat.cartesian_product import CartesianProduct
    296297from sage.combinat.integer_list import IntegerListsLex
    297 from sage.combinat.partition_options import PartitionOptions, partition_options
    298298
    299299from sage.groups.perm_gps.permgroup import PermutationGroup
    300300
     301
     302PartitionOptions=GlobalOptions(name='partitions',
     303    doc=r'''
     304    Sets and displays the global options for elements of the partition, skew
     305    partition, and partition tuple classes.  If no parameters are set, then the
     306    function returns a copy of the options dictionary.
     307
     308    The ``options`` to partitions can be accessed as the method
     309    :meth:`Partitions.global_options` of :class:`Partitions` and related parent
     310    classes.''',
     311    end_doc='''
     312
     313    EXAMPLES::
     314
     315        sage: P = Partition([4,2,2,1]) sage: P [4, 2, 2, 1] sage:
     316        Partitions.global_options(display="exp") sage: P 1, 2^2, 4 sage:
     317        Partitions.global_options(display="exp_high") sage: P 4, 2^2, 1
     318
     319    It is also possible to use user defined functions for the ``display`` and
     320    ``latex`` options::
     321
     322        sage: Partitions.global_options(display=lambda mu: '<%s>' % ','.join('%s'%m for m in mu._list)); P
     323        <4,2,2,1>
     324        sage: Partitions.global_options(latex=lambda mu: '\\Diagram{%s}' % ','.join('%s'%m for m in mu._list)); latex(P)
     325        \Diagram{4,2,2,1}
     326        sage: Partitions.global_options(display="diagram", diagram_str="#")
     327        sage: P
     328        ####
     329        ##
     330        ##
     331        #
     332        sage: Partitions.global_options(diagram_str="*", convention="french")
     333        sage: print P.ferrers_diagram()
     334        *
     335        **
     336        **
     337        ****
     338
     339    Changing the ``convention`` for partitions also changes the ``convention``
     340    option for tableaux and vice versa::
     341
     342        sage: T = Tableau([[1,2,3],[4,5]])
     343        sage: T.pp()
     344          4  5
     345          1  2  3
     346        sage: Tableaux.global_options(convention="english")
     347        sage: print P.ferrers_diagram()
     348        ****
     349        **
     350        **
     351        *
     352        sage: T.pp()
     353          1  2  3
     354          4  5
     355        sage: Partitions.global_options.reset()''',
     356    display=dict(default="list",
     357                 description='Specifies how partitions should be printed',
     358                 values=dict(list='displayed as a list',
     359                           exp_low='in exponential form (lowest first)',
     360                           exp_high='in exponential form (highest first)',
     361                           diagram='as a Ferrers diagram',
     362                           compact_low='compact form of exp_low',
     363                           compact_high='compact form of exp_high'),
     364                 alias=dict(exp="exp_low", compact="compact_low", array="diagram",
     365                           ferrers_diagram="diagram", young_diagram="diagram",
     366                           ferrers_diagram_str="diagram_str",young_diagram_str="diagram_str"),
     367                ),
     368    latex=dict(default="young_diagram",
     369               description='Specifies how partitions should be latexed',
     370               values=dict(diagram='latex as a Ferrers diagram',
     371                           young_diagram='latex as a Young diagam',
     372                           list='latex as a list',
     373                           exp_high='latex as a list in exponential notation (highest first)',
     374                           exp_low='as a list latex in exponential notation (lowest first)'),
     375               alias=dict(exp="exp_low", array="diagram", ferrers_diagram="diagram")
     376              ),
     377    diagram_str=dict(default="*",
     378                     description='The character used for the cells when printing Ferrers diagrams',
     379                     checker=lambda char: isinstance(char,str)),
     380    latex_diagram_str=dict(default="\\ast",
     381                     description='The character used for the cells when latexing Ferrers diagrams',
     382                     checker=lambda char: isinstance(char,str)),
     383    convention=dict(link_to=(tableau.TableauOptions,'convention'))
     384)
     385
    301386def from_frobenius_coordinates(coords):
    302387    """
    303388    This has been deprecated in :trac:`13605`. Use
    class Partition(CombinatorialObject, Ele 
    368453    non-increasing list of positive integers (the *parts* of the
    369454    partition) with total sum `n`.
    370455
    371     A partition can be depicted by a diagram made of rows of cells,
    372     where the number of cells in the `i^{th}` row starting from
    373     the top is the `i^{th}` part of the partition.
     456    A partition is often representation by a diagram consisting of `cells`, or
     457    `boxes`, placed in rows on top of each other with the number of cells in the
     458    `i^{th}` row, reading from  top to bottom, is the `i^{th}` part of the
     459    partition.
    374460
    375461    The coordinate system related to a partition applies from the top
    376462    to the bottom and from left to right. So, the corners of the
    377463    partition ``[5, 3, 1]`` are ``[[0,4], [1,2], [2,0]]``.
    378464
    379     For display options, see :meth:`Partitions.options`.
     465    For display options, see :meth:`Partitions.global_options`.
    380466
    381467    .. NOTE::
    382468
    class Partition(CombinatorialObject, Ele 
    478564
    479565    Check that only trailing zeros are stripped::
    480566
     567        sage: TestSuite( Partition([]) ).run()
     568        sage: TestSuite( Partition([4,3,2,2,2,1]) ).run()
    481569        sage: Partition([3,2,2,2,1,0,0,0])
    482570        [3, 2, 2, 2, 1]
    483571        sage: Partition([3,0,2,2,2,1,0])
    class Partition(CombinatorialObject, Ele 
    575663    def _repr_(self, compact=False):
    576664        r"""
    577665        Return a string representation of ``self`` depending on
    578         :meth:`Partitions.options()`.
     666        :meth:`Partitions.global_options`.
    579667
    580668        EXAMPLES::
    581669
    582670            sage: mu=Partition([7,7,7,3,3,2,1,1,1,1,1,1,1]); mu # indirect doctest
    583671            [7, 7, 7, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1]
    584             sage: Partitions.options(display="exp_high")
    585             sage: mu # indirect doctest
     672            sage: Partitions.global_options(display="diagram"); mu
     673            *******
     674            *******
     675            *******
     676            ***
     677            ***
     678            **
     679            *
     680            *
     681            *
     682            *
     683            *
     684            *
     685            *
     686            sage: Partitions.global_options(display="list"); mu
     687            [7, 7, 7, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1]
     688            sage: Partitions.global_options(display="compact_low"); mu
     689            1^7,2,3^2,7^3
     690            sage: Partitions.global_options(display="compact_high"); mu
     691            7^3,3^2,2,1^7
     692            sage: Partitions.global_options(display="exp_low"); mu
     693            1^7, 2, 3^2, 7^3
     694            sage: Partitions.global_options(display="exp_high"); mu
    586695            7^3, 3^2, 2, 1^7
    587             sage: Partitions.options(display="list")
    588         """
    589         global partition_options
     696
     697            sage: Partitions.global_options(convention="French");
     698            sage: mu=Partition([7,7,7,3,3,2,1,1,1,1,1,1,1]); mu # indirect doctest
     699            7^3, 3^2, 2, 1^7
     700            sage: Partitions.global_options(display="diagram"); mu
     701            *
     702            *
     703            *
     704            *
     705            *
     706            *
     707            *
     708            **
     709            ***
     710            ***
     711            *******
     712            *******
     713            *******
     714            sage: Partitions.global_options(display="list"); mu
     715            [7, 7, 7, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1]
     716            sage: Partitions.global_options(display="compact_low"); mu
     717            1^7,2,3^2,7^3
     718            sage: Partitions.global_options(display="compact_high"); mu
     719            7^3,3^2,2,1^7
     720            sage: Partitions.global_options(display="exp_low"); mu
     721            1^7, 2, 3^2, 7^3
     722            sage: Partitions.global_options(display="exp_high"); mu
     723            7^3, 3^2, 2, 1^7
     724           
     725            sage: Partitions.global_options.reset()
     726        """
    590727
    591728        if compact != False:
    592729            from sage.misc.superseded import deprecation
    593             deprecation(13605, 'compact option is deprecated. Use Partitions.options instead.')
     730            deprecation(13605, 'compact option is deprecated. Use :meth:`Partitions.global_options` instead.')
    594731            return self._repr_compact_high()
    595732
    596         try:
    597             repr = getattr(self, '_repr_' + partition_options["display"])
    598         except AttributeError:
    599             raise ValueError("Invalid display option")
    600 
    601         return repr()
     733        return self.parent().global_options.dispatch(self, '_repr_', 'display')
    602734
    603735    def _repr_list(self):
    604736        """
    class Partition(CombinatorialObject, Ele 
    606738
    607739        EXAMPLES::
    608740
    609             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    610             sage: mu._repr_list()
    611             '[7, 7, 7, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1]'
     741            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_list()
     742            [7, 7, 7, 3, 3, 2, 1, 1, 1, 1, 1, 1, 1]
    612743        """
    613744        return '[%s]' % ', '.join('%s'%m for m in self)
    614745
    615     def _repr_exp(self):
     746    def _repr_exp_low(self):
    616747        """
    617748        Return a string representation of ``self`` in exponential form (lowest
    618749        first).
    619750
    620751        EXAMPLES::
    621752
    622             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    623             sage: mu._repr_exp()
    624             '1^7, 2, 3^2, 7^3'
     753            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_exp_low()
     754            1^7, 2, 3^2, 7^3
    625755        """
    626756        exp = self.to_exp()
    627757        return '%s' % ', '.join('%s%s' % (m+1, '' if e==1 else '^%s'%e)
    class Partition(CombinatorialObject, Ele 
    634764
    635765        EXAMPLES::
    636766
    637             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    638             sage: mu._repr_exp_high()
    639             '7^3, 3^2, 2, 1^7'
    640         """
    641         exp = self.to_exp()[::-1]  # reversed list of exponents
     767            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_exp_high()
     768            7^3, 3^2, 2, 1^7
     769        """
     770        if len(self._list)==0: return ''  # exceptional case as max(self) fails
     771        exp = self.to_exp()[::-1]         # reversed list of exponents
    642772        M=max(self)
    643773        return '%s' % ', '.join('%s%s' % (M-m, '' if e==1 else '^%s'%e)
    644774                                 for (m,e) in enumerate(exp) if e>0)
    645775
    646     def _repr_compact(self):
     776    def _repr_compact_low(self):
    647777        """
    648778        Return a string representation of ``self`` in compact form (exponential
    649779        form with lowest first).
    650780
    651781        EXAMPLES::
    652782
    653             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    654             sage: mu._repr_compact()
    655             '1^7,2,3^2,7^3'
     783            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_compact_low()
     784            1^7,2,3^2,7^3
    656785        """
    657786        exp = self.to_exp()
    658787        return '%s' % ','.join('%s%s' % (m+1, '' if e==1 else '^%s'%e)
    class Partition(CombinatorialObject, Ele 
    665794
    666795        EXAMPLES::
    667796
    668             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    669             sage: mu._repr_compact_high()
    670             '7^3,3^2,2,1^7'
    671         """
    672         exp = self.to_exp()[::-1]  # reversed list of exponents
     797            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_compact_high()
     798            7^3,3^2,2,1^7
     799        """
     800        if len(self._list)==0: return ''  # exceptional case as max(self) fails
     801        exp = self.to_exp()[::-1]         # reversed list of exponents
    673802        M=max(self)
    674803        return '%s' % ','.join('%s%s' % (M-m, '' if e==1 else '^%s'%e)
    675804                                 for (m,e) in enumerate(exp) if e>0)
    676805
    677     def _repr_ferrers_diagram(self):
     806    def _repr_diagram(self):
    678807        """
    679808        Return a representation of ``self`` as a Ferrers diagram.
    680809
    681810        EXAMPLES::
    682811
    683             sage: mu = Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])
    684             sage: print mu._repr_ferrers_diagram()
     812            sage: print Partition([7,7,7,3,3,2,1,1,1,1,1,1,1])._repr_diagram()
    685813            *******
    686814            *******
    687815            *******
    class Partition(CombinatorialObject, Ele 
    766894        r"""
    767895        Returns a LaTeX version of ``self``.
    768896       
    769         For more on the latex options, see :meth:`Partitions.options()`.
     897        For more on the latex options, see :meth:`Partitions.option`.
    770898
    771899        EXAMPLES::
    772900
    773             sage: P = Partition([2, 1])
    774             sage: latex(P)       # indirect doctest
    775             {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    776             \raisebox{-.6ex}{$\begin{array}[b]{cc}
    777             \cline{1-1}\cline{2-2}
    778             \lr{\phantom{x}}&\lr{\phantom{x}}\\
    779             \cline{1-1}\cline{2-2}
    780             \lr{\phantom{x}}\\
    781             \cline{1-1}
    782             \end{array}$}
    783             }
    784             sage: Partitions.options(latex="ferrers_diagram")
    785             sage: latex(P)
    786             {\def\lr#1{\multicolumn{1}{@{\hspace{.4ex}}c@{\hspace{.4ex}}}{\raisebox{-.3ex}{$#1$}}}
    787             \raisebox{-.6ex}{$\begin{array}[b]{cc}
     901            sage: mu = Partition([2, 1])
     902            sage: Partitions.global_options(latex='diagram'); latex(mu)       # indirect doctest
     903            {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     904            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\\
    788905            \lr{\ast}&\lr{\ast}\\
    789906            \lr{\ast}\\
    790907            \end{array}$}
    791908            }
    792             sage: Partitions.options(latex="young_diagram", convention="french")
    793             sage: latex(P)
     909            sage: Partitions.global_options(latex='exp_high'); latex(mu)      # indirect doctest
     910            2,1
     911            sage: Partitions.global_options(latex='exp_low'); latex(mu)       # indirect doctest
     912            1,2
     913            sage: Partitions.global_options(latex='list'); latex(mu)          # indirect doctest
     914            [2, 1]
     915            sage: Partitions.global_options(latex='young_diagram'); latex(mu) # indirect doctest
    794916            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    795             \raisebox{-.6ex}{$\begin{array}[b]{cc}
    796             \cline{1-1}
    797             \lr{\phantom{x}}\\
    798             \cline{1-1}\cline{2-2}
    799             \lr{\phantom{x}}&\lr{\phantom{x}}\\
    800             \cline{1-1}\cline{2-2}
     917            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     918            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     919            \lr{\phantom{x}}\\\cline{1-1}
    801920            \end{array}$}
    802921            }
    803             sage: Partitions.options(convention="english")
    804         """
    805         global partition_options
    806 
    807         try:
    808             latex_disp = getattr(self, '_latex_' + partition_options["latex"])
    809         except AttributeError:
    810             raise ValueError("Invalid latex option")
    811 
    812         return latex_disp()
    813 
    814     def _latex_young_diagram(self):
    815         """
    816         LaTeX output as a young diagram.
    817 
    818         EXAMPLES::
    819 
    820             sage: P = Partition([2, 1])
    821             sage: print P._latex_young_diagram()
     922           
     923            sage: Partitions.global_options(latex="young_diagram", convention="french")
     924            sage: Partitions.global_options(latex='exp_high'); latex(mu)      # indirect doctest
     925            2,1
     926            sage: Partitions.global_options(latex='exp_low'); latex(mu)       # indirect doctest
     927            1,2
     928            sage: Partitions.global_options(latex='list'); latex(mu)          # indirect doctest
     929            [2, 1]
     930            sage: Partitions.global_options(latex='young_diagram'); latex(mu) # indirect doctest
    822931            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    823             \raisebox{-.6ex}{$\begin{array}[b]{cc}
    824             \cline{1-1}\cline{2-2}
    825             \lr{\phantom{x}}&\lr{\phantom{x}}\\
    826             \cline{1-1}\cline{2-2}
    827             \lr{\phantom{x}}\\
    828             \cline{1-1}
     932            \raisebox{-.6ex}{$\begin{array}[t]{*{2}c}\cline{1-1}
     933            \lr{\phantom{x}}\\\cline{1-2}
     934            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
    829935            \end{array}$}
    830936            }
     937           
     938            sage: Partitions.global_options.reset()
     939        """
     940        return self.parent().global_options.dispatch(self, '_latex_', 'latex')
     941
     942    def _latex_young_diagram(self):
     943        """
     944        LaTeX output as a young diagram.
     945
     946        EXAMPLES::
     947
     948            sage: print Partition([2, 1])._latex_young_diagram()
     949            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     950            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     951            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     952            \lr{\phantom{x}}\\\cline{1-1}
     953            \end{array}$}
     954            }
    831955        """
    832956        if len(self._list) == 0:
    833957            return "{\\emptyset}"
    class Partition(CombinatorialObject, Ele 
    835959        from sage.combinat.output import tex_from_array
    836960        return tex_from_array([ ["\\phantom{x}"]*row_size for row_size in self._list ])
    837961
    838     def _latex_ferrers_diagram(self):
     962    def _latex_diagram(self):
    839963        """
    840964        LaTeX output as a Ferrers' diagram.
    841965
    842966        EXAMPLES::
    843967
    844             sage: P = Partition([2, 1])
    845             sage: print P._latex_ferrers_diagram()
    846             {\def\lr#1{\multicolumn{1}{@{\hspace{.4ex}}c@{\hspace{.4ex}}}{\raisebox{-.3ex}{$#1$}}}
    847             \raisebox{-.6ex}{$\begin{array}[b]{cc}
     968            sage: print Partition([2, 1])._latex_diagram()
     969            {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     970            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\\
    848971            \lr{\ast}&\lr{\ast}\\
    849972            \lr{\ast}\\
    850973            \end{array}$}
    class Partition(CombinatorialObject, Ele 
    853976        if len(self._list) == 0:
    854977            return "{\\emptyset}"
    855978
    856         global partition_options
    857         entry = partition_options["ferrers_diagram_latex"]
     979        entry = self.parent().global_options("latex_diagram_str")
    858980        from sage.combinat.output import tex_from_array
    859981        return tex_from_array([ [entry]*row_size for row_size in self._list ], False)
    860982
    class Partition(CombinatorialObject, Ele 
    864986
    865987        EXAMPLES::
    866988
    867             sage: P = Partition([2, 1])
    868             sage: print P._latex_list()
     989            sage: print Partition([2, 1])._latex_list()
    869990            [2, 1]
    870991        """
    871992        return repr(self._list)
    872993
    873     def _latex_exp(self):
     994    def _latex_exp_low(self):
    874995        """
    875996        LaTeX output in exponential notation (lowest first).
    876997
    877998        EXAMPLES::
    878999
    879             sage: P = Partition([2,2,1])
    880             sage: print P._latex_exp()
     1000            sage: print Partition([2,2,1])._latex_exp_low()
    8811001            1,2^{2}
    8821002        """
    8831003        exp = self.to_exp()
    class Partition(CombinatorialObject, Ele 
    8901010
    8911011        EXAMPLES::
    8921012
    893             sage: P = Partition([2,2,1])
    894             sage: print P._latex_exp_high()
     1013            sage: print Partition([2,2,1])._latex_exp_high()
    8951014            2^{2},1
    8961015        """
    8971016        exp = self.to_exp()[::-1]  # reversed list of exponents
    class Partition(CombinatorialObject, Ele 
    8991018        return '%s' % ','.join('%s%s' % (M-m, '' if e==1 else '^{%s}'%e)
    9001019                                 for (m,e) in enumerate(exp) if e>0)
    9011020
     1021
    9021022    def ferrers_diagram(self):
    9031023        r"""
    9041024        Return the Ferrers diagram of ``self``.
    9051025
    9061026        EXAMPLES::
    9071027
    908             sage: Partitions.options(ferrers_diagram_str='*', convention="english")
    909             sage: print Partition([5,5,2,1]).ferrers_diagram()
     1028            sage: mu=Partition([5,5,2,1])
     1029            sage: Partitions.global_options(diagram_str='*', convention="english")
     1030            sage: print mu.ferrers_diagram()
    9101031            *****
    9111032            *****
    9121033            **
    9131034            *
    914             sage: Partitions.options(ferrers_diagram_str='#')
    915             sage: print Partition([5,5,2,1]).ferrers_diagram()
     1035            sage: Partitions.global_options(diagram_str='#')
     1036            sage: print mu.ferrers_diagram()
    9161037            #####
    9171038            #####
    9181039            ##
    9191040            #
    920             sage: Partitions.options(convention="french")
    921             sage: print Partition([5,5,2,1]).ferrers_diagram()
     1041            sage: Partitions.global_options(convention="french")
     1042            sage: print mu.ferrers_diagram()
    9221043            #
    9231044            ##
    9241045            #####
    9251046            #####
    926             sage: Partitions.options(ferrers_diagram_str='*', convention="english")
    927         """
    928         global partition_options
    929         str = partition_options["ferrers_diagram_str"]
    930         convention = partition_options["convention"]
    931         if convention == "english":
    932             return '\n'.join([str*p for p in self])
    933         elif convention == "french":
    934             return '\n'.join([str*p for p in reversed(self)])
     1047            sage: Partitions.global_options.reset()
     1048        """
     1049        diag_str = self.parent().global_options('diagram_str')
     1050        if self.parent().global_options('convention') == 'english':
     1051            return '\n'.join([diag_str*p for p in self])
    9351052        else:
    936             raise ValueError("convention must be either 'english' or 'french'")
     1053            return '\n'.join([diag_str*p for p in reversed(self)])
    9371054
    9381055    def pp(self):
    939         """
     1056        r"""
    9401057        Prints the Ferrers diagram.
    9411058       
    9421059        See :meth:`ferrers_diagram` for more on the ferrers diagram.
    class Partition(CombinatorialObject, Ele 
    9481065            *****
    9491066            **
    9501067            *
     1068            sage: Partitions.global_options(convention='French')
     1069            sage: Partition([5,5,2,1]).pp()
     1070            *
     1071            **
     1072            *****
     1073            *****
     1074            sage: Partitions.global_options.reset()
    9511075        """
    9521076        print self.ferrers_diagram()
    9531077
    class Partitions(UniqueRepresentation, P 
    36813805
    36823806    TESTS::
    36833807
    3684         sage: P = Partitions(5, min_part=2)
    3685         sage: P == loads(dumps(P))
    3686         True
     3808        sage: TestSuite( Partitions(0) ).run()
     3809        sage: TestSuite( Partitions(5) ).run()
     3810        sage: TestSuite(Partitions(5, min_part=2)).run()
    36873811
    36883812        sage: repr( Partitions(5, min_part=2) )
    36893813        'Partitions of the integer 5 satisfying constraints min_part=2'
    class Partitions(UniqueRepresentation, P 
    38103934            Parent.__init__(self, category=FiniteEnumeratedSets())
    38113935
    38123936    Element = Partition
     3937    global_options = PartitionOptions
    38133938
    38143939    def __reversed__(self):
    38153940        """
    class Partitions(UniqueRepresentation, P 
    38433968            raise ValueError("%s not in %s"%(elt, self))
    38443969        return elt
    38453970
    3846     options = staticmethod(PartitionOptions)
    38473971
    38483972    def from_frobenius_coordinates(self, frobenius_coordinates):
    38493973        """
    class Partitions_constraints(IntegerList 
    40224146class Partitions_all(Partitions):
    40234147    """
    40244148    Class of all partitions.
     4149
     4150    TESTS::
     4151
     4152        sage: TestSuite( sage.combinat.partition.Partitions_all() ).run()
    40254153    """
    40264154
    40274155    @staticmethod
    class Partitions_all_bounded(Partitions) 
    42074335        """
    42084336        TESTS::
    42094337
    4210             sage: from sage.combinat.sf.k_dual import Partitions_all_bounded
    4211             sage: P = Partitions_all_bounded(3)
    4212             sage: P == loads(dumps(P))
    4213             True
    4214             sage: TestSuite(P).run()
     4338            sage: TestSuite( sage.combinat.partition.Partitions_all_bounded(3) ).run()
    42154339        """
    42164340        self.k = k
    42174341        Partitions.__init__(self, is_infinite=True)
    class Partitions_all_bounded(Partitions) 
    42204344        """
    42214345        TESTS::
    42224346
    4223             sage: from sage.combinat.sf.k_dual import Partitions_all_bounded
     4347            sage: from sage.combinat.partition import Partitions_all_bounded
    42244348            sage: P = Partitions_all_bounded(3)
    42254349            sage: Partition([2,1]) in P
    42264350            True
    class Partitions_all_bounded(Partitions) 
    42484372        """
    42494373        TESTS::
    42504374
    4251             sage: from sage.combinat.sf.k_dual import Partitions_all_bounded
     4375            sage: from sage.combinat.partition import Partitions_all_bounded
    42524376            sage: repr(Partitions_all_bounded(3))
    42534377            '3-Bounded Partitions'
    42544378        """
    class Partitions_all_bounded(Partitions) 
    42754399class Partitions_n(Partitions):
    42764400    """
    42774401    Partitions of the integer `n`.
     4402
     4403    TESTS::
     4404   
     4405        sage: TestSuite( sage.combinat.partition.Partitions_n(0) ).run()
     4406        sage: TestSuite( sage.combinat.partition.Partitions_n(0) ).run()
    42784407    """
    42794408
    42804409    @staticmethod
    class Partitions_n(Partitions): 
    42974426
    42984427        TESTS::
    42994428
    4300             sage: p = Partitions(5)
    4301             sage: p == loads(dumps(p))
    4302             True
    4303             sage: TestSuite(p).run()
     4429            sage: TestSuite(  Partitions(5) ).run()
    43044430        """
    43054431        Partitions.__init__(self)
    43064432        self.n = n
    class Partitions_n(Partitions): 
    46654791class Partitions_parts_in(Partitions):
    46664792    """
    46674793    Partitions of `n` with parts in a given set `S`.
     4794
     4795    TESTS::
     4796   
     4797        sage: TestSuite( sage.combinat.partition.Partitions_parts_in(6, parts=[2,1]) ).run()
    46684798    """
    46694799
    46704800    @staticmethod
    class Partitions_parts_in(Partitions): 
    46884818
    46894819        TESTS::
    46904820
    4691             sage: p = Partitions(5, parts_in=[1,2,3])
    4692             sage: p == loads(dumps(p))
    4693             True
    4694             sage: TestSuite(p).run()
     4821            sage: TestSuite(Partitions(5, parts_in=[1,2,3])).run()
    46954822        """
    46964823        Partitions.__init__(self)
    46974824        self.n = n
    class Partitions_starting(Partitions): 
    49785105        TESTS::
    49795106
    49805107            sage: p = Partitions(3, starting=[2,1])
    4981             sage: p == loads(dumps(p))
    4982             True
    49835108            sage: TestSuite(p).run()
    49845109        """
    49855110        Partitions.__init__(self)
    class Partitions_ending(Partitions): 
    50745199        TESTS::
    50755200
    50765201            sage: p = Partitions(4, ending=[1,1,1,1])
    5077             sage: p == loads(dumps(p))
    5078             True
    50795202            sage: TestSuite(p).run()
    50805203        """
    50815204        Partitions.__init__(self)
    class PartitionsInBox(Partitions): 
    51695292        TESTS::
    51705293
    51715294            sage: p = PartitionsInBox(2,2)
    5172             sage: p == loads(dumps(p))
    5173             True
    51745295            sage: TestSuite(p).run()
    51755296        """
    51765297        Partitions.__init__(self)
    class OrderedPartitions(Partitions): 
    53285449        EXAMPLES::
    53295450
    53305451            sage: o = OrderedPartitions(4,2)
    5331             sage: o == loads(dumps(o))
    5332             True
     5452
     5453        TESTS::
     5454
     5455            sage: TestSuite( OrderedPartitions(5,3) ).run()
    53335456        """
    53345457        Partitions.__init__(self)
    53355458        self.n = n
    class PartitionsGreatestLE(IntegerListsL 
    54735596        TESTS::
    54745597
    54755598            sage: p = PartitionsGreatestLE(10,2)
    5476             sage: p == loads(dumps(p))
    5477             True
    54785599            sage: p.n, p.k
    54795600            (10, 2)
    54805601            sage: TestSuite(p).run()
    class PartitionsGreatestLE(IntegerListsL 
    54945615        return "Partitions of %s having parts less than or equal to %s"%(self.n, self.k)
    54955616
    54965617    Element = Partition
     5618    global_options=PartitionOptions
    54975619
    54985620def PartitionsGreatestLE_nk(n, k):
    54995621    """
    class PartitionsGreatestEQ(IntegerListsL 
    55635685        TESTS::
    55645686
    55655687            sage: p = PartitionsGreatestEQ(10,2)
    5566             sage: p == loads(dumps(p))
    5567             True
    55685688            sage: p.n, p.k
    55695689            (10, 2)
    55705690            sage: TestSuite(p).run()
    class PartitionsGreatestEQ(IntegerListsL 
    55845704        return "Partitions of %s having greatest part equal to %s"%(self.n, self.k)
    55855705
    55865706    Element = Partition
     5707    global_options=PartitionOptions
    55875708
    55885709def PartitionsGreatestEQ_nk(n, k):
    55895710    """
    class RestrictedPartitions_nsk(Combinato 
    56725793        self.k = k
    56735794
    56745795    Element = Partition
     5796    global_options=PartitionOptions
    56755797
    56765798    def __contains__(self, x):
    56775799        """
  • deleted file sage/combinat/partition_options.py

    diff --git a/sage/combinat/partition_options.py b/sage/combinat/partition_options.py
    deleted file mode 100644
    + -  
    1 r"""
    2 Partition options
    3 
    4 AUTHORS:
    5 
    6 - Travis Scrimshaw (2012-08-16): Initial version
    7 
    8 """
    9 #*****************************************************************************
    10 #       Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu>,
    11 #
    12 #  Distributed under the terms of the GNU General Public License (GPL)
    13 #
    14 #    This code is distributed in the hope that it will be useful,
    15 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    16 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    17 #    General Public License for more details.
    18 #
    19 #  The full text of the GPL is available at:
    20 #
    21 #                  http://www.gnu.org/licenses/
    22 #*****************************************************************************
    23 
    24 import copy
    25 
    26 partition_options = {"display" : "list",
    27                      "ferrers_diagram_str" : '*',
    28                      "ferrers_diagram_latex" : "\\ast",
    29                      "latex" : "young_diagram",
    30                      "convention" : "english"}
    31 
    32 def PartitionOptions(**kwargs):
    33     """
    34     Sets the global options for elements of the partition, skew partition,
    35     and partition tuple classes. The defaults are for partitions to be
    36     displayed as a list, latex as a Young diagram, the Ferrers' diagram with
    37     asterisks ``*``, and using English convention.
    38    
    39     .. NOTE::
    40 
    41         Changing the notation here also changes the notation for tableaux.
    42    
    43     - ``display``:
    44 
    45       - ``list`` -- In list notation
    46       - ``exp``, ``exp_high`` -- In exponential form (with highest first)
    47       - ``exp_low`` -- In exponential form (with lowest first)
    48       - ``compact``, ``compact_high`` -- In compact form (``exp`` or
    49         ``exp_high`` with no spaces)
    50       - ``compact_low`` -- In lowest compact form (``exp_low`` with no spaces)
    51       - ``ferrers_diagram`` -- As a Ferrers' diagram
    52 
    53     - ``ferrers_diagram_str`` -- The string used in the Ferrers' diagram
    54 
    55     - ``ferrers_diagram_latex`` -- The latex used in the Ferrers' diagram
    56 
    57     - ``latex``:
    58 
    59       - ``boxes``, ``cells``, ``young_diagram`` -- The Young diagram
    60       - ``ferrers_diagram`` -- The Ferrers' diagram
    61       - ``list`` -- In list notation
    62       - ``exp`` -- In exponential form
    63 
    64     - ``convention``, ``notation``:
    65 
    66       - ``english`` -- Use English convention
    67       - ``french`` -- Use French convention
    68 
    69     If no parameters are set, then the function returns a copy of the
    70     options dictionary.
    71    
    72     EXAMPLES::
    73    
    74         sage: P = Partition([4,2,2,1])
    75         sage: P
    76         [4, 2, 2, 1]
    77         sage: Partitions.options(display="exp")
    78         sage: P
    79         1, 2^2, 4
    80         sage: Partitions.options(display="exp_high")
    81         sage: P
    82         4, 2^2, 1
    83         sage: Partitions.options(display="ferrers_diagram", ferrers_diagram_str="#")
    84         sage: P
    85         ####
    86         ##
    87         ##
    88         #
    89         sage: Partitions.options(ferrers_diagram_str="*", convention="french")
    90         sage: print P.ferrers_diagram()
    91         *
    92         **
    93         **
    94         ****
    95        
    96     Changing notation for partitions also changes the notation for tableaux
    97     and vice versa::
    98    
    99         sage: T = Tableau([[1,2,3],[4,5]])
    100         sage: T.pp()
    101           4  5
    102           1  2  3
    103         sage: Tableaux.options(notation="english")
    104         sage: print P.ferrers_diagram()
    105         ****
    106         **
    107         **
    108         *
    109         sage: T.pp()
    110           1  2  3
    111           4  5
    112         sage: Partitions.options(display="list")
    113     """
    114     global partition_options
    115     if kwargs == {}:
    116         return copy.copy(partition_options)
    117 
    118     if "display" in kwargs:
    119         if kwargs["display"] not in ["list", "exp", "exp_low", "exp_high",
    120                                      "ferrers_diagram", "compact",
    121                                      "compact_low", "compact_high"]:
    122             raise ValueError("invalid display option")
    123         elif kwargs["display"] == "exp_low":
    124             partition_options["display"] = "exp"
    125         elif kwargs["display"] == "compact_low":
    126             partition_options["display"] = "compact"
    127         else:
    128             partition_options["display"] = kwargs["display"]
    129 
    130     if "ferrers_diagram_str" in kwargs:
    131         partition_options["ferrers_diagram_str"] = kwargs["ferrers_diagram_str"]
    132 
    133     if "ferrers_diagram_latex" in kwargs:
    134         partition_options["ferrers_diagram_latex"] = kwargs["ferrers_diagram_latex"]
    135 
    136     if "latex" in kwargs:
    137         if kwargs["latex"] not in ["boxes", "cells", "young_diagram",
    138                                    "ferrers_diagram", "list", "exp"]:
    139             raise ValueError("invalid latex option")
    140         elif kwargs["latex"] in ["boxes", "cells"]:
    141             # boxes and cells are synonyms for young_diagram
    142             partition_options["latex"] = "young_diagram"
    143         else:
    144             partition_options["latex"] = kwargs["latex"]
    145 
    146     if "notation" in kwargs:
    147         kwargs["convention"] = kwargs["notation"]
    148 
    149     if "convention" in kwargs:
    150         if kwargs["convention"] not in ["english", "french"]:
    151             raise ValueError("convention must be either 'english' or 'french'")
    152 
    153         from sage.combinat.tableau_options import tableau_options
    154         global tableau_options
    155         tableau_options["convention"] = kwargs["convention"]
    156         partition_options["convention"] = kwargs["convention"]
  • sage/combinat/partition_tuple.py

    diff --git a/sage/combinat/partition_tuple.py b/sage/combinat/partition_tuple.py
    a b from sage.rings.integer import Integer 
    255255from sage.structure.element import Element
    256256from sage.structure.parent import Parent
    257257from sage.structure.unique_representation import UniqueRepresentation
    258 from sage.combinat.partition_options import PartitionOptions, partition_options
    259258
    260259import tableau_tuple
    261260
    class PartitionTuple(CombinatorialObject 
    479478    def _repr_(self, compact=False):
    480479        """
    481480        Return a string representation of ``self`` depending on
    482         :meth:`PartitionTuples.options`.
     481        :meth:`PartitionTuples.global_options`.
    483482
    484483        EXAMPLES::
    485484
    486             sage: PartitionTuple(([2,1],[3,2],[1,1,1]))      # indirect doctest
     485            sage: mu=PartitionTuple(([2,1],[3,2],[1,1,1]))      # indirect doctest
     486           
     487            sage: PartitionTuples.global_options(display="list"); mu
    487488            ([2, 1], [3, 2], [1, 1, 1])
    488             sage: PartitionTuple([[2,1],[3,2],[1,1,1]])
     489            sage: PartitionTuples.global_options(display="diagram"); mu
     490            **   ***   *
     491            *    **    *
     492            *
     493            sage: PartitionTuples.global_options(display="compact_low"); mu
     494            1,2|2,3|1^3
     495            sage: PartitionTuples.global_options(display="compact_high"); mu
     496            2,1|3,2|1^3
     497            sage: PartitionTuples.global_options(display="exp_low"); mu
     498            1, 2 | 2, 3 | 1^3
     499            sage: PartitionTuples.global_options(display="exp_high"); mu
     500            2, 1 | 3, 2 | 1^3
     501            sage: PartitionTuples.global_options.reset()
     502
     503            sage: Partitions.global_options(convention="French");
     504            sage: PartitionTuples.global_options(display="diagram"); mu
     505            *
     506            *    **    *
     507            **   ***   *
     508            sage: PartitionTuples.global_options(display="list"); mu
    489509            ([2, 1], [3, 2], [1, 1, 1])
    490             sage: PartitionTuples.options(display="exp_high")
    491             sage: repr(PartitionTuple([[2,1],[3,2],[1,1,1]])) # indirect doctest
    492             '2, 1 | 3, 2 | 1^3'
    493             sage: PartitionTuples.options(display="list")
     510            sage: PartitionTuples.global_options(display="compact_low"); mu
     511            1,2|2,3|1^3
     512            sage: PartitionTuples.global_options(display="compact_high"); mu
     513            2,1|3,2|1^3
     514            sage: PartitionTuples.global_options(display="exp_low"); mu
     515            1, 2 | 2, 3 | 1^3
     516            sage: PartitionTuples.global_options(display="exp_high"); mu
     517            2, 1 | 3, 2 | 1^3
     518            sage: PartitionTuples.global_options.reset()
    494519        """
    495520        if compact:
    496             from sage.misc.superseded import deprecation
    497             deprecation(13605, 'compact option is deprecated. Use PartitionTuples.options instead.')
     521            deprecation(13605, 'compact option is deprecated. Use PartitionTuples.global_options instead.')
    498522            return self._repr_compact_high()
    499523
    500         try:
    501             repr = getattr(self, '_repr_' + partition_options["display"])
    502         except AttributeError:
    503             raise ValueError("Invalid display option")
     524        return self.parent().global_options.dispatch(self, '_repr_', 'display')
    504525
    505         return repr()
     526    def _repr_diagram(self):
     527        """
     528        Return a string representation of ``self`` as a Ferrers diagram.
     529
     530        EXAMPLES::
     531
     532            sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_diagram()
     533            '   **   ***   *\n   *    **    *\n              *'
     534        """
     535        return self.diagram()
    506536
    507537    def _repr_list(self):
    508538        """
    class PartitionTuple(CombinatorialObject 
    515545        """
    516546        return '('+', '.join(nu._repr_() for nu in self)+')'
    517547
    518     def _repr_exp(self):
     548    def _repr_exp_low(self):
    519549        """
    520550        Return a string representation of ``self`` in compact form (exponential
    521551        form with highest first).
    522552
    523553        EXAMPLES::
    524554
    525             sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_exp()
     555            sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_exp_low()
    526556            '1, 2 | 2, 3 | 1^3'
    527557        """
    528         return ' | '.join(nu._repr_exp() for nu in self)
     558        return ' | '.join(nu._repr_exp_low() for nu in self)
    529559
    530560    def _repr_exp_high(self):
    531561        """
    class PartitionTuple(CombinatorialObject 
    534564
    535565        EXAMPLES::
    536566
    537             sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_exp_high()
    538             '2, 1 | 3, 2 | 1^3'
     567            sage: PartitionTuple(([2,1],[3,2],[1,1,1,1,1,1,1,1,1,1]))._repr_exp_high()
     568            '2, 1 | 3, 2 | 1^10'
    539569        """
    540570        return ' | '.join(nu._repr_exp_high() for nu in self)
    541571
    542     def _repr_compact(self):
     572    def _repr_compact_low(self):
    543573        """
    544574        Return a string representation of ``self`` in compact form (exponential
    545575        form with highest first).
    546576
    547577        EXAMPLES::
    548578
    549             sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_compact()
     579            sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_compact_low()
    550580            '1,2|2,3|1^3'
    551581        """
    552         return '%s' % '|'.join('-' if mu==[] else mu._repr_compact() for mu in self)
     582        return '%s' % '|'.join('-' if mu==[] else mu._repr_compact_low() for mu in self)
    553583
    554584    def _repr_compact_high(self):
    555585        """
    class PartitionTuple(CombinatorialObject 
    567597    __str__=lambda self: self._repr_()
    568598
    569599
     600    def _latex_(self):
     601        r"""
     602        Returns a LaTeX version of ``self``.
     603       
     604        For more on the latex options, see :meth:`Partitions.option`.
     605
     606        EXAMPLES::
     607
     608            sage: mu = PartitionTuple([[2, 1],[1,1,1]])
     609            sage: PartitionTuples.global_options(latex='diagram'); latex(mu)       # indirect doctest
     610            {\def\lr#1{\multicolumn{1}{@{\hspace{.6ex}}c@{\hspace{.6ex}}}{\raisebox{-.3ex}{$#1$}}}
     611            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\\
     612            \lr{\ast}&\lr{\ast}\\
     613            \lr{\ast}\\
     614            \end{array}$},\raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\\
     615            \lr{\ast}\\
     616            \lr{\ast}\\
     617            \lr{\ast}\\
     618            \end{array}$}
     619            }
     620            sage: PartitionTuples.global_options(latex='exp_high'); latex(mu)      # indirect doctest
     621            (2,1|1^{3})
     622            sage: PartitionTuples.global_options(latex='exp_low'); latex(mu)       # indirect doctest
     623            (1,2|1^{3})
     624            sage: PartitionTuples.global_options(latex='list'); latex(mu)          # indirect doctest
     625            [[2, 1], [1, 1, 1]]
     626            sage: PartitionTuples.global_options(latex='young_diagram'); latex(mu) # indirect doctest
     627            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     628            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     629            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     630            \lr{\phantom{x}}\\\cline{1-1}
     631            \end{array}$},\raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1}
     632            \lr{\phantom{x}}\\\cline{1-1}
     633            \lr{\phantom{x}}\\\cline{1-1}
     634            \lr{\phantom{x}}\\\cline{1-1}
     635            \end{array}$}
     636            }
     637           
     638            sage: PartitionTuples.global_options(latex="young_diagram", convention="french")
     639            sage: PartitionTuples.global_options(latex='exp_high'); latex(mu)      # indirect doctest
     640            (2,1|1^{3})
     641            sage: PartitionTuples.global_options(latex='exp_low'); latex(mu)       # indirect doctest
     642            (1,2|1^{3})
     643            sage: PartitionTuples.global_options(latex='list'); latex(mu)          # indirect doctest
     644            [[2, 1], [1, 1, 1]]
     645            sage: PartitionTuples.global_options(latex='young_diagram'); latex(mu) # indirect doctest
     646            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     647            \raisebox{-.6ex}{$\begin{array}[t]{*{2}c}\cline{1-1}
     648            \lr{\phantom{x}}\\\cline{1-2}
     649            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     650            \end{array}$},\raisebox{-.6ex}{$\begin{array}[t]{*{1}c}\cline{1-1}
     651            \lr{\phantom{x}}\\\cline{1-1}
     652            \lr{\phantom{x}}\\\cline{1-1}
     653            \lr{\phantom{x}}\\\cline{1-1}
     654            \end{array}$}
     655            }
     656           
     657            sage: PartitionTuples.global_options.reset()
     658        """
     659        return self.parent().global_options.dispatch(self, '_latex_', 'latex')
     660
     661    def _latex_young_diagram(self):
     662        """
     663        LaTeX output as a young diagram.
     664
     665        EXAMPLES::
     666
     667            sage: mu = PartitionTuple([[2, 1],[1,1,1]])._latex_young_diagram()
     668        """
     669        from sage.combinat.output import tex_from_array_tuple
     670        return tex_from_array_tuple([ [["\\phantom{x}"]*row for row in mu] for mu in self._list ])
     671
     672    def _latex_diagram(self):
     673        """
     674        LaTeX output as a Ferrers' diagram.
     675
     676        EXAMPLES::
     677
     678            sage: mu = PartitionTuple([[2, 1],[1,1,1]])._latex_diagram()
     679        """
     680        entry = self.parent().global_options("latex_diagram_str")
     681        from sage.combinat.output import tex_from_array_tuple
     682        return tex_from_array_tuple([ [[entry]*row for row in mu] for mu in self._list ], with_lines=False)
     683
     684    def _latex_list(self):
     685        """
     686        LaTeX output as a list.
     687
     688        EXAMPLES::
     689
     690            sage: mu = PartitionTuple([[2, 1],[1,1,1]])._latex_list()
     691        """
     692        return repr(self._list)
     693
     694    def _latex_exp_low(self):
     695        """
     696        LaTeX output in exponential notation (lowest first).
     697
     698        EXAMPLES::
     699
     700            sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_low()
     701        """
     702        return '(%s)' % '|'.join(','.join('%s%s'%(a+1,'' if e==1 else '^{%s}'%e)
     703                        for (a,e) in enumerate(mu)) for mu in self.to_exp())
     704
     705    def _latex_exp_high(self):
     706        """
     707        LaTeX output in exponential notation (highest first).
     708
     709        EXAMPLES::
     710
     711            sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_high()
     712        """
     713        return '(%s)' % '|'.join(','.join(['%s%s'%(a+1,'' if e==1 else '^{%s}'%e)
     714            for (a,e) in enumerate(mu)][::-1]) for mu in self.to_exp())
     715
     716
    570717    def components(self):
    571718        r"""
    572719        Return a list containing the shape of this partition.
    class PartitionTuple(CombinatorialObject 
    610757               **    *        *
    611758                              *
    612759                              *
    613             sage: PartitionTuples.options(convention="french")
     760            sage: PartitionTuples.global_options(convention="french")
    614761            sage: print PartitionTuple([[3,2],[2,1],[],[1,1,1,1]]).diagram()
    615                **     *   -   *
    616                ***    **      *
    617762                              *
    618763                              *
    619             sage: PartitionTuples.options(convention="english")
     764               **    *        *
     765               ***   **   -   *
     766            sage: PartitionTuples.global_options.reset()
    620767        """
    621         global partition_options
    622         str = partition_options["ferrers_diagram_str"]
    623         convention = partition_options["convention"]
    624         if convention not in ["english", "french"]:
    625             raise ValueError("convention must be either 'english' or 'french'")
    626 
    627768        col_len = [len(mu)>0 and mu[0] or 1 for mu in self]  # columns per component
    628769        row_max = max(len(mu) for mu in self)                # maximum row length
    629770        # There should be a fancier list compression for this but I couldn't get
    630771        # one to work in the cases where a component was the empty partition
    631         diag = ''
     772        diag = []
     773        diag_str=PartitionTuples.global_options('diagram_str')
    632774        for row in range(row_max):
    633             if row > 0:
    634                 diag += '\n'
     775            line=''
    635776            for c in range(len(self)):
    636777                if row == 0 and self[c] == []:
    637                     diag += '   -'
     778                    line += '   -'
    638779                elif row < len(self[c]):
    639                         if convention == "english":
    640                             diag += '   {0:{1}}'.format(str*(self[c][row]),col_len[c])
    641                         else: # convention == "french"
    642                             diag += '   {0:{1}}'.format(str*(self[c][len(self[c])-1-row]),col_len[c])
     780                    line += '   {:{}}'.format(diag_str*self[c][row],col_len[c])
    643781                else:
    644                     diag += '   {0:{1}}'.format('',col_len[c])
    645         return diag.rstrip()
     782                    line += '   {:{}}'.format('',col_len[c])
     783            diag.append(line.rstrip())
     784        if PartitionTuples.global_options('convention')=='english':
     785            return '\n'.join(map(str, diag))
     786        else:
     787            return '\n'.join(map(str, diag[::-1]))
    646788
    647789    ferrers_diagram = diagram
    648790
    class PartitionTuples(UniqueRepresentati 
    13511493            return PartitionTuples_all()
    13521494
    13531495    Element = PartitionTuple
     1496    global_options=Partitions.global_options
    13541497
    13551498    def _element_constructor_(self, mu):
    13561499        r"""
    class PartitionTuples(UniqueRepresentati 
    14831626        """
    14841627        return PartitionTuple( ([1,1,1,1],[2,1,1],[3,1],[4]) )
    14851628
    1486     options = staticmethod(PartitionOptions)
    14871629
    14881630class PartitionTuples_all(PartitionTuples):
    14891631    """
  • sage/combinat/rigged_configurations/kr_tableaux.py

    diff --git a/sage/combinat/rigged_configurations/kr_tableaux.py b/sage/combinat/rigged_configurations/kr_tableaux.py
    a b class KirillovReshetikhinTableauxElement 
    521521            sage: KRT = KirillovReshetikhinTableaux(['A', 4, 1], 2, 3)
    522522            sage: latex(KRT([3,2,4,2,4,3])) # indirect doctest
    523523            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    524             \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    525             \cline{1-1}\cline{2-2}\cline{3-3}
    526             \lr{2}&\lr{2}&\lr{3}\\
    527             \cline{1-1}\cline{2-2}\cline{3-3}
    528             \lr{3}&\lr{4}&\lr{4}\\
    529             \cline{1-1}\cline{2-2}\cline{3-3}
     524            \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{1-3}
     525            \lr{2}&\lr{2}&\lr{3}\\\cline{1-3}
     526            \lr{3}&\lr{4}&\lr{4}\\\cline{1-3}
    530527            \end{array}$}
    531528            }
    532529        """
  • sage/combinat/rigged_configurations/rigged_configurations.py

    diff --git a/sage/combinat/rigged_configurations/rigged_configurations.py b/sage/combinat/rigged_configurations/rigged_configurations.py
    a b RiggedConfigurations.Element = RiggedCon 
    931931#        x2 = RC2(*x)
    932932#        ret_list.append([x.to_tensor_product_of_Kirillov_Reshetikhin_tableaux(),
    933933#                         x2.to_tensor_product_of_Kirillov_Reshetikhin_tableaux()])
    934 #    return ret_list
    935  No newline at end of file
     934#    return ret_list
  • sage/combinat/rigged_configurations/rigged_partition.py

    diff --git a/sage/combinat/rigged_configurations/rigged_partition.py b/sage/combinat/rigged_configurations/rigged_partition.py
    a b AUTHORS: 
    3737#*****************************************************************************
    3838
    3939from sage.combinat.combinat import CombinatorialObject
    40 from sage.combinat.partition_options import partition_options
    4140
    4241class RiggedPartition(CombinatorialObject):
    4342    r"""
    class RiggedPartition(CombinatorialObjec 
    120119            0[ ][ ]0
    121120            -1[ ]-1
    122121            <BLANKLINE>
    123             sage: Partitions.options(convention="french")
     122            sage: Partitions.global_options(convention="french")
    124123            sage: elt # indirect doctest
    125124            -1[ ]-1
    126125            0[ ][ ]0
    127126            <BLANKLINE>
    128             sage: Partitions.options(convention="english")
     127            sage: Partitions.global_options.reset()
    129128        """
    130129        # If it is empty, return saying so
    131130        if len(self._list) == 0:
    132131            return("(/)\n")
    133132
    134         global partition_options
    135         if partition_options["convention"] == "french":
     133        from sage.combinat.partition import Partitions
     134        if Partitions.global_options("convention") == "french":
    136135            itr = reversed(list(enumerate(self._list)))
    137136        else:
    138137            itr = enumerate(self._list)
  • sage/combinat/skew_partition.py

    diff --git a/sage/combinat/skew_partition.py b/sage/combinat/skew_partition.py
    a b from sage.sets.set import Set 
    145145from sage.graphs.digraph import DiGraph
    146146from combinat import CombinatorialClass, CombinatorialObject
    147147from sage.matrix.matrix_space import MatrixSpace
    148 from sage.combinat.partition_options import partition_options
    149148from sage.rings.infinity import PlusInfinity
    150149infinity = PlusInfinity()
    151150
    class SkewPartition_class(CombinatorialO 
    196195             ***
    197196            ***
    198197            *
    199             sage: Partitions.options(ferrers_diagram_str='#', convention="french")
     198            sage: Partitions.global_options(diagram_str='#', convention="French")
    200199            sage: print SkewPartition([[5,4,3,1],[3,1]]).diagram()
    201200            #
    202201            ###
    203202             ###
    204203               ##
    205             sage: Partitions.options(ferrers_diagram_str='*', convention="english")
     204            sage: Partitions.global_options.reset()
    206205        """
    207         global partition_options
    208         char = partition_options['ferrers_diagram_str']
    209         convention = partition_options["convention"]
     206        # TODO: Should be SkewPartitions.global_options
     207        char, convention = sage.combinat.partition.Partitions.global_options('diagram_str','convention')
    210208
    211         s = ""
    212         L = None
    213209        if convention == "english":
    214210            L = range(len(self[0]))
    215         elif convention == "french":
     211        else:
    216212            L = reversed(range(len(self[0])))
     213        s = ""
    217214        for i in L:
    218215            if len(self[1]) > i:
    219216                s += " "*self[1][i]
    class SkewPartitions_all(CombinatorialCl 
    860857        """
    861858        return "Skew partitions"
    862859   
     860
     861    def _latex_(self):
     862        """
     863        LaTeX output as a young diagram.
     864
     865        EXAMPLES::
     866
     867            sage: P = Partition([2, 1])
     868            sage: print P._latex_young_diagram()
     869            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     870            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     871            \lr{\phantom{x}}&\lr{\phantom{x}}\\\cline{1-2}
     872            \lr{\phantom{x}}\\\cline{1-1}
     873            \end{array}$}
     874            }
     875        """
     876        if len(self._list) == 0:
     877            return "{\\emptyset}"
     878
     879        from sage.combinat.output import tex_from_array
     880        return tex_from_array([ ["\\phantom{x}"]*row_size for row_size in self._list ])
     881 
    863882    def list(self):
    864883        """
    865884        TESTS::
  • sage/combinat/tableau.py

    diff --git a/sage/combinat/tableau.py b/sage/combinat/tableau.py
    a b AUTHORS: 
    88- Jason Bandlow (2011): updated to use Parent/Element model, and many
    99  minor fixes
    1010
     11- Andrew Mathas (2012): completed the transition to the parent/element model
     12  begun by Jason Bandlow
     13
    1114- Travis Scrimshaw (11-22-2012): Added tuple options, changed ``*katabolism*``
    1215  to ``*catabolism*``. Cleaned up documentation.
    1316
    Parent classes: 
    4043* :class:`StandardTableaux_size`
    4144* :class:`StandardTableaux_shape`
    4245
    43 For display options, see :meth:`Tableaux.options`.
     46For display options, see :meth:`Tableaux.global_options`.
    4447
    4548.. TODO:
    4649
    from sage.sets.disjoint_union_enumerated 
    6871from sage.sets.family import Family
    6972from sage.sets.non_negative_integers import NonNegativeIntegers
    7073from sage.structure.element import Element
     74from sage.structure.global_options import GlobalOptions
    7175from sage.structure.unique_representation import UniqueRepresentation
    7276from sage.structure.parent import Parent
    7377from sage.misc.classcall_metaclass import ClasscallMetaclass
     78from sage.misc.decorators import rename_keyword
    7479from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    7580from sage.rings.infinity import PlusInfinity
    7681from sage.rings.arith import factorial
    from sage.misc.sage_unittest import Test 
    8994from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
    9095from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
    9196from sage.categories.sets_cat import Sets
    92 from sage.combinat.tableau_options import TableauOptions, tableau_options
    9397import __builtin__
    9498from sage.combinat.combinatorial_map import combinatorial_map
    9599
     100
     101TableauOptions=GlobalOptions(name='tableaux',
     102    doc="""
     103    Sets the global options for elements of the tableau, skew_tableau,
     104    and tableau tuple classes. The defaults are for tableau to be
     105    displayed as a list, latexed as a Young diagram using the English
     106    convention.
     107    ''',
     108    doc_end='''
     109
     110    .. NOTE::
     111
     112        Changing the ``convention`` for tableaux also changes the ``convention`` for partitions.
     113
     114    If no parameters are set, then the function returns a copy of the
     115    options dictionary.
     116   
     117    EXAMPLES::
     118
     119        sage: T = Tableau([[1,2,3],[4,5]])
     120        sage: T
     121        [[1, 2, 3], [4, 5]]
     122        sage: Tableaux.global_options(display="array")
     123        sage: T
     124          1  2  3
     125          4  5
     126        sage: Tableaux.global_options(convention="french")
     127        sage: T
     128          4  5
     129          1  2  3
     130
     131    Changing the ``convention`` for tableaux also changes the ``convention`` for partitions
     132    and vice versa::
     133
     134        sage: P = Partition([3,3,1])
     135        sage: print P.ferrers_diagram()
     136        *
     137        ***
     138        ***
     139        sage: Partitions.global_options(convention="english")
     140        sage: print P.ferrers_diagram()
     141        ***
     142        ***
     143        *
     144        sage: T
     145          1  2  3
     146          4  5
     147        sage: Tableaux.global_options.reset()
     148    """,
     149    display=dict(default="list",
     150                 description='Controls the way in which tableaux are printed',
     151                 values=dict(list='print tableaux as lists',
     152                             diagram='display as Young diagram (simlar to :meth:`~sage.combinat.tableau.Tableau.pp()',
     153                             compact='miniml length string representation'),
     154                 alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram")
     155                ),
     156    latex=dict(default="diagram",
     157               description='Controls the way in wich tableaux are latexed',
     158               values=dict(list='as a list', diagram='as a Young diagram'),
     159               alias=dict(array="diagram", ferrers_diagram="diagram", young_diagram="diagram")
     160              ),
     161    convention=dict(default="english",
     162                    description='Sets the convention used for displaying tableaux and partitions',
     163                    values=dict(English='use the English convention',French='use the French convention'))
     164)
     165
     166
    96167class Tableau(CombinatorialObject, Element):
    97168    """
    98169    A class to model a tableau.
    class Tableau(CombinatorialObject, Eleme 
    214285        if not map(len,t) in sage.combinat.partition.Partitions():
    215286            raise ValueError, "A tableau must be a list of lists of weakly decreasing length."
    216287
     288
    217289    def __setstate__(self, state):
    218290        """
    219291        In order to maintain backward compatibility and be able to unpickle an
    class Tableau(CombinatorialObject, Eleme 
    240312
    241313        EXAMPLES::
    242314
    243             sage: T = Tableau([[1,2,3],[4,5]])
    244             sage: Tableaux.options(display="list")
    245             sage: T
     315            sage: t = Tableau([[1,2,3],[4,5]])
     316            sage: Tableaux.global_options(display="list")
     317            sage: t
    246318            [[1, 2, 3], [4, 5]]
    247             sage: Tableaux.options(display="array")
    248             sage: T
     319            sage: Tableaux.global_options(display="array")
     320            sage: t
    249321              1  2  3
    250322              4  5
    251             sage: Tableaux.options(display="list")
    252         """
    253         global tableau_options
    254 
    255         try:
    256             repr = getattr(self, '_repr_' + tableau_options["display"])
    257         except AttributeError:
    258             raise ValueError("Invalid display option")
    259 
    260         return repr()
     323            sage: Tableaux.global_options(display="compact"); t
     324            1,2,3/4,5
     325            sage: Tableaux.global_options.reset()
     326        """
     327        return self.parent().global_options.dispatch(self,'_repr_','display')
    261328   
    262329    def _repr_list(self):
    263330        """
    class Tableau(CombinatorialObject, Eleme 
    271338        """
    272339        return repr(self._list)
    273340
    274     def _repr_array(self):
     341    def _repr_diagram(self):
    275342        """
    276343        Return a string representation of ``self`` as an array.
    277344
    278345        EXAMPLES::
    279346
    280             sage: T = Tableau([[1,2,3],[4,5]])
    281             sage: print T._repr_array()
     347            sage: t = Tableau([[1,2,3],[4,5]])
     348            sage: print t._repr_diagram()
    282349              1  2  3
    283350              4  5
    284             sage: Tableaux.options(convention="french")
    285             sage: print T._repr_array()
     351            sage: Tableaux.global_options(convention="french")
     352            sage: print t._repr_diagram()
    286353              4  5
    287354              1  2  3
    288             sage: Tableaux.options(convention="english")
    289         """
    290         global tableau_options
    291         convention = tableau_options["convention"]
    292         if convention == "english":
     355            sage: Tableaux.global_options.reset()
     356        """
     357        if self.parent().global_options('convention') == "english":
    293358            return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in self])
    294         elif convention == "french":
     359        else:
    295360            return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in reversed(self)])
    296         else:
    297             raise ValueError("convention must be either 'english' or 'french'")
     361
     362    def _repr_compact(self):
     363        """
     364        Return a compact string representation of ``self``.
     365
     366        EXAMPLES::
     367
     368            sage: Tableau([[1,2,3],[4,5]])._repr_compact()
     369            '1,2,3/4,5'
     370            sage: Tableau([])._repr_compact()
     371            '-'
     372        """
     373        if len(self._list)==0:
     374            return '-'
     375        else: return '/'.join(','.join('%s'%r for r in row) for row in self._list)
     376
    298377
    299378    def _latex_(self):
    300379        r"""
    class Tableau(CombinatorialObject, Eleme 
    302381
    303382        EXAMPLES::
    304383
    305             sage: latex(Tableau([[1,1,2],[2,3],[3]]))    # indirect doctest
     384            sage: t=Tableau([[1,1,2],[2,3],[3]])
     385            sage: latex(t)    # indirect doctest
    306386            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    307             \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    308             \cline{1-1}\cline{2-2}\cline{3-3}
    309             \lr{1}&\lr{1}&\lr{2}\\
    310             \cline{1-1}\cline{2-2}\cline{3-3}
    311             \lr{2}&\lr{3}\\
    312             \cline{1-1}\cline{2-2}
    313             \lr{3}\\
    314             \cline{1-1}
     387            \raisebox{-.6ex}{$\begin{array}[b]{*{3}c}\cline{1-3}
     388            \lr{1}&\lr{1}&\lr{2}\\\cline{1-3}
     389            \lr{2}&\lr{3}\\\cline{1-2}
     390            \lr{3}\\\cline{1-1}
    315391            \end{array}$}
    316392            }
    317             sage: Tableaux.options(convention="french")
    318             sage: latex(Tableau([[1,1,2],[2,3],[3]]))    # indirect doctest
     393            sage: Tableaux.global_options(convention="french")
     394            sage: latex(t)    # indirect doctest
    319395            {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
    320             \raisebox{-.6ex}{$\begin{array}[b]{ccc}
    321             \cline{1-1}
    322             \lr{3}\\
    323             \cline{1-1}\cline{2-2}
    324             \lr{2}&\lr{3}\\
    325             \cline{1-1}\cline{2-2}\cline{3-3}
    326             \lr{1}&\lr{1}&\lr{2}\\
    327             \cline{1-1}\cline{2-2}\cline{3-3}
     396            \raisebox{-.6ex}{$\begin{array}[t]{*{3}c}\cline{1-1}
     397            \lr{3}\\\cline{1-2}
     398            \lr{2}&\lr{3}\\\cline{1-3}
     399            \lr{1}&\lr{1}&\lr{2}\\\cline{1-3}
    328400            \end{array}$}
    329401            }
    330             sage: Tableaux.options(convention="english")
    331         """
     402            sage: Tableaux.global_options.reset()
     403        """
     404        return self.parent().global_options.dispatch(self,'_latex_', 'latex')
     405
     406    _latex_list=_repr_list
     407
     408    def _latex_diagram(self):
    332409        if len(self) == 0:
    333410            return "{\\emptyset}"
    334411        from output import tex_from_array
    class Tableau(CombinatorialObject, Eleme 
    499576              1  2  3
    500577              3  4
    501578              5
    502             sage: Tableaux.options(convention="french")
     579            sage: Tableaux.global_options(convention="french")
    503580            sage: T.pp()
    504581              5
    505582              3  4
    506583              1  2  3
    507             sage: Tableaux.options(convention="english")
    508         """
    509         print self._repr_array()
     584            sage: Tableaux.global_options.reset()
     585        """
     586        print self._repr_diagram()
    510587
    511588    def to_word_by_row(self):
    512589        """
    def from_chain(chain): 
    23802457                res[j][k] = i -1
    23812458    return Tableau(res)
    23822459
    2383 def from_shape_and_word(shape, w, order="French"):
     2460@rename_keyword(deprecation=13605, order='convention')
     2461def from_shape_and_word(shape, w, convention="French"):
    23842462    r"""
    23852463    Returns a tableau from a shape and word.
    23862464
    def from_shape_and_word(shape, w, order= 
    23902468
    23912469    - ``w`` -- a word whose length equals that of the partition
    23922470
    2393     - ``order`` -- a string which can take values ``"French"`` or
     2471    - ``convention`` -- a string which can take values ``"French"`` or
    23942472      ``"English"``; the default is ``"French"``
    23952473
    23962474    OUTPUT:
    23972475
    23982476    A tableau, whose shape is ``shape`` and whose reading word is ``w``.
    2399     If the order is specified to ``"French"``, the reading word is to be read
     2477    If the ``convention`` is specified as ``"French"``, the reading word is to be read
    24002478    starting from the top row in French convention (= the bottom row in English
    2401     convention). If the order is specified to ``"English"``, the reading word
     2479    convention). If the ``convention`` is specified as ``"English"``, the reading word
    24022480    is to be read starting with the top row in English convention.
    24032481
    24042482    EXAMPLES::
    def from_shape_and_word(shape, w, order= 
    24122490        sage: from_shape_and_word(shape, word)
    24132491        [[1, 3], [2], [4]]
    24142492        sage: word = Word(flatten(t))
    2415         sage: from_shape_and_word(shape, word, order = "English")
     2493        sage: from_shape_and_word(shape, word, convention = "English")
    24162494        [[1, 3], [2], [4]]
    24172495    """
    24182496    res = []
    24192497    j = 0
    2420     if order == "French":
     2498    if convention == "French":
    24212499        shape = reversed(shape)
    24222500    for l in shape:
    24232501        res.append( list(w[j:j+l]) )
    24242502        j += l
    2425     if order == "French":
     2503    if convention == "French":
    24262504        res.reverse()
    24272505    return Tableau(res)
    24282506
    class Tableaux(UniqueRepresentation, Par 
    25322610                raise ValueError, "The argument to Tableaux() must be a non-negative integer."
    25332611            return Tableaux_size(n)
    25342612
    2535     options = staticmethod(TableauOptions)
    2536 
    25372613    Element = Tableau
     2614    global_options = TableauOptions
    25382615
    25392616    def _element_constructor_(self, t):
    25402617        r"""
  • deleted file sage/combinat/tableau_options.py

    diff --git a/sage/combinat/tableau_options.py b/sage/combinat/tableau_options.py
    deleted file mode 100644
    + -  
    1 r"""
    2 Tableau options
    3 
    4 AUTHORS:
    5 
    6 - Travis Scrimshaw (2012-08-16): Initial version
    7 
    8 """
    9 #*****************************************************************************
    10 #       Copyright (C) 2012 Travis Scrimshaw <tscrim@ucdavis.edu>,
    11 #
    12 #  Distributed under the terms of the GNU General Public License (GPL)
    13 #
    14 #    This code is distributed in the hope that it will be useful,
    15 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    16 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    17 #    General Public License for more details.
    18 #
    19 #  The full text of the GPL is available at:
    20 #
    21 #                  http://www.gnu.org/licenses/
    22 #*****************************************************************************
    23 
    24 import copy
    25 
    26 tableau_options = {"display" : "list",
    27                    "latex" : "young_diagram",
    28                    "convention" : "english"}
    29 
    30 def TableauOptions(**kwargs):
    31     """
    32     Sets the global options for elements of the tableau, skew_tableau,
    33     and tableau tuple classes. The defaults are for tableau to be
    34     displayed as a list, latex as a Young diagram, and using English
    35     convention.
    36 
    37     .. NOTE::
    38 
    39         Changing the notation here also changes the notation for partitions.
    40 
    41     - ``display``:
    42 
    43       - ``list`` -- In list notation (in particular, a list of each row as a
    44         list)
    45       - ``array`` -- As an array (similar to calling
    46         :meth:`~sage.combinat.tableau.Tableau.pp()`)
    47 
    48     - ``latex``:
    49 
    50       - ``young_diagram`` -- The Young diagram
    51       - ``list`` -- In list notation
    52 
    53     - ``convention``, ``notation``:
    54 
    55       - ``english`` -- Use English convention
    56       - ``french`` -- Use French convention
    57 
    58     If no parameters are set, then the function returns a copy of the
    59     options dictionary.
    60    
    61     EXAMPLES::
    62 
    63         sage: T = Tableau([[1,2,3],[4,5]])
    64         sage: T
    65         [[1, 2, 3], [4, 5]]
    66         sage: Tableaux.options(display="array")
    67         sage: T
    68           1  2  3
    69           4  5
    70         sage: Tableaux.options(convention="french")
    71         sage: T
    72           4  5
    73           1  2  3
    74 
    75     Changing notation for tableaux also changes the convention for partitions
    76     and vice versa::
    77 
    78         sage: P = Partition([3,3,1])
    79         sage: print P.ferrers_diagram()
    80         *
    81         ***
    82         ***
    83         sage: Partitions.options(notation="english")
    84         sage: print P.ferrers_diagram()
    85         ***
    86         ***
    87         *
    88         sage: T
    89           1  2  3
    90           4  5
    91         sage: Tableaux.options(display="list")
    92     """
    93     global tableau_options
    94     if kwargs == {}:
    95         return copy.copy(tableau_options)
    96 
    97     if "display" in kwargs:
    98         if kwargs["display"] not in ["list", "array"]:
    99             raise ValueError("invalid display option")
    100         tableau_options["display"] = kwargs["display"]
    101 
    102     if "latex" in kwargs:
    103         if kwargs["latex"] not in ["young_diagram", "list"]:
    104             raise ValueError("invalid latex option")
    105         tableau_options["latex"] = kwargs["latex"]
    106 
    107     if "notation" in kwargs:
    108         kwargs["convention"] = kwargs["notation"]
    109 
    110     if "convention" in kwargs:
    111         if kwargs["convention"] not in ["english", "french"]:
    112             raise ValueError("convention must be either 'english' or 'french'")
    113 
    114         from sage.combinat.partition_options import partition_options
    115         global partition_options
    116         partition_options["convention"] = kwargs["convention"]
    117         tableau_options["convention"] = kwargs["convention"]
  • sage/combinat/tableau_tuple.py

    diff --git a/sage/combinat/tableau_tuple.py b/sage/combinat/tableau_tuple.py
    a b from sage.rings.integer import Integer 
    230230from sage.structure.element import Element
    231231from sage.structure.parent import Parent
    232232from sage.structure.unique_representation import UniqueRepresentation
    233 from sage.combinat.tableau_options import TableauOptions, tableau_options
    234233
    235234import permutation
    236235
    class TableauTuple(CombinatorialObject,E 
    432431            sage: TableauTuple([[],[],[],[]])
    433432            ([], [], [], [])
    434433        """
    435         try:
    436             repr = getattr(self, '_repr_' + tableau_options["display"])
    437         except AttributeError:
    438             raise ValueError("Invalid display option")
    439 
    440         return repr()
     434        return self.parent().global_options.dispatch(self,'_repr_','display')
    441435
    442436    def _repr_list(self):
    443437        """
    class TableauTuple(CombinatorialObject,E 
    450444        """
    451445        return '('+', '.join('%s'%s for s in self)+')'
    452446
    453     def _repr_array(self):
     447    def _repr_compact(self):
     448        """
     449        Return a compact string representation of ``self``.
     450
     451        EXAMPLES::
     452
     453            sage: TableauTuple([[],[],[],[]])._repr_compact()
     454            '-|-|-|-'
     455            sage: TableauTuple([[[1,2,3],[4,5]],[],[[6]],[]])._repr_compact()
     456            '1,2,3/4,5|-|6|-'
     457        """
     458        return '|'.join('%s'%s._repr_compact() for s in self)
     459
     460    def _repr_diagram(self):
    454461        """
    455462        Return a string representation of ``self`` as an array.
    456463
    457464        EXAMPLES::
    458465
    459             sage: print TableauTuple([[[2,3]],[[1]],[[4],[5]],[]])._repr_array()
     466            sage: print TableauTuple([[[2,3]],[[1]],[[4],[5]],[]])._repr_diagram()
    460467                 2  3     1     4   -
    461468                                5
    462             sage: print TableauTuple([[[2,3]],[],[[4],[5]],[]])._repr_array()   
     469            sage: print TableauTuple([[[2,3]],[],[[4],[5]],[]])._repr_diagram()   
    463470                 2  3     -     4   -
    464471                                5
     472            sage: TableauTuples.global_options(convention='French')
     473            sage: print TableauTuple([[[2,3]],[[1]],[[4],[5]],[]])._repr_diagram()
     474                                5
     475                 2  3     1     4   -
     476            sage: print TableauTuple([[[2,3]],[],[[4],[5]],[]])._repr_diagram()   
     477                                5
     478                 2  3     -     4   -
     479            sage: TableauTuples.global_options.reset()
    465480        """
    466        
    467         global tableau_options
    468         convention = tableau_options["convention"]
    469         if convention not in ["english", "french"]:
    470             raise ValueError("convention must be either 'english' or 'french'")
    471 
    472481        col_len = [len(t)>0 and len(t[0]) or 1 for t in self]  # columns per component
    473482        row_max = max(len(t) for t in self)                    # maximum row length
    474483        # There should be a fancier list compression for this but I couldn't get
    475484        # one to work in the cases where a component was the empty partition
    476         diag = ''
    477         for row in range(row_max):
    478             if row > 0:
    479                 diag += '\n'
     485        diag = []
     486        for row in xrange(row_max):
     487            line=''
    480488            for c in range(len(self)):
    481489                if row == 0 and self[c] == []:
    482                     diag += '     -'
     490                    line += '     -'
    483491                elif row < len(self[c]):
    484                     if convention == "english":
    485                         diag += '   '+''.join(map(lambda x: "%3s"%str(x) , self[c][row]))+'   '*(col_len[c]-len(self[c][row]))
    486                     else: # convention == "french":
    487                         diag += '   '+''.join(map(lambda x: "%3s"%str(x) , self[c][len(self[c])-1-row]))+'   '*(col_len[c]-len(self[c][len(self[c])-1-row]))
     492                    line += '   '+''.join(map(lambda x: "%3s"%str(x) , self[c][row]))+'   '*(col_len[c]-len(self[c][row]))
    488493                else:
    489                     diag += '   '+'   '*col_len[c]
    490         return diag
     494                    line += '   '+'   '*col_len[c]
     495            diag.append(line)
     496        if TableauTuples.global_options('convention')=='english':
     497            return '\n'.join(map(str,diag))
     498        else:
     499            return '\n'.join(map(str,diag[::-1]))
     500
     501    def _latex_(self):
     502        r"""
     503        Returns a LaTeX version of ``self``.
     504
     505        EXAMPLES::
     506
     507            sage: t=TableauTuple([ [[1,2],[3]], [], [[4,5],[6,7]] ])
     508            sage: latex(t)    # indirect doctest
     509            \Bigg( {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     510            \raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     511            \lr{1}&\lr{2}\\\cline{1-2}
     512            \lr{3}\\\cline{1-1}
     513            \end{array}$},\emptyset,\raisebox{-.6ex}{$\begin{array}[b]{*{2}c}\cline{1-2}
     514            \lr{4}&\lr{5}\\\cline{1-2}
     515            \lr{6}&\lr{7}\\\cline{1-2}
     516            \end{array}$}
     517            } \Bigg)
     518            sage: TableauTuples.global_options(convention="french")
     519            sage: latex(t)    # indirect doctest
     520            \Bigg( {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}
     521            \raisebox{-.6ex}{$\begin{array}[t]{*{2}c}\cline{1-1}
     522            \lr{3}\\\cline{1-2}
     523            \lr{1}&\lr{2}\\\cline{1-2}
     524            \end{array}$},r\emptyset,\raisebox{-.6ex}{$\begin{array}[t]{*{2}c}\cline{1-2}
     525            \lr{6}&\lr{7}\\\cline{1-2}
     526            \lr{4}&\lr{5}\\\cline{1-2}
     527            \end{array}$}
     528            } \Bigg)
     529            sage: TableauTuples.global_options.reset()
     530        """
     531        return self.parent().global_options.dispatch(self,'_latex_','latex')
     532
     533    _latex_list=_repr_list
     534
     535    def _latex_diagram(self):
     536        from output import tex_from_array_tuple
     537        return r'\Bigg( %s \Bigg)' % tex_from_array_tuple(self)
     538
    491539
    492540    def components(self):
    493541        """
    class TableauTuple(CombinatorialObject,E 
    627675                3           10 11
    628676                4           12
    629677                            13
    630             sage: T = TableauTuple([ [[1,2,3],[4,5],[6],[9]], [[1,2,3],[4,5,8]], [[11,12,13],[14]] ])
    631             sage: T.pp()
     678            sage: t = TableauTuple([ [[1,2,3],[4,5],[6],[9]], [[1,2,3],[4,5,8]], [[11,12,13],[14]] ])
     679            sage: t.pp()
    632680                1  2  3     1  2  3    11 12 13
    633681                4  5        4  5  8    14
    634682                6
    635683                9
    636             sage: TableauTuples.options(convention="french")
    637             sage: T.pp()
    638                  9           4  5  8    14     
    639                  6           1  2  3    11 12 13
    640                  4  5                          
    641                  1  2  3          
    642             sage: TableauTuples.options(convention="english")
     684            sage: TableauTuples.global_options(convention="french")
     685            sage: t.pp()
     686                 9                             
     687                 6                              
     688                 4  5        4  5  8    14     
     689                 1  2  3     1  2  3    11 12 13
     690            sage: TableauTuples.global_options.reset()
    643691        """
    644         print self._repr_array()
     692        print self._repr_diagram()
    645693
    646694    def to_word_by_row(self):
    647695        """
    class TableauTuples(UniqueRepresentation 
    15611609        sage: TestSuite( TableauTuples(level=6, size=10) ).run()
    15621610    """
    15631611    Element = TableauTuple
     1612    global_options=Tableaux.global_options
    15641613
    15651614    @staticmethod
    15661615    def __classcall_private__(cls, level=None, size=None):
    class TableauTuples(UniqueRepresentation 
    17301779        else:
    17311780            raise NotImplementedError, 'this is an infinite set of tableaux'
    17321781
    1733     options = staticmethod(TableauOptions)
    17341782
    17351783class TableauTuples_all(TableauTuples):
    17361784    """
  • new file sage/structure/global_options.py

    diff --git a/sage/structure/global_options.py b/sage/structure/global_options.py
    new file mode 100644
    - +  
     1r"""
     2Global options
     3==============
     4
     5The :class:`GlobalOptions` class provides a generic mechanism for setting and
     6accessing global options for ``sage`` classes. This class is intended to be used
     7by developers either for organising the ``global options`` for a number of
     8related classes (parents) or for looking after the options of particular
     9instances of a class.
     10
     11Construction of options classes
     12-------------------------------
     13
     14The general setup for creating set of global options is:
     15
     16.. code-block:: python
     17
     18    MyOptions=GlobalOptions('option name', doc='Nice options',
     19        end_doc='end of options documentation',
     20        first_option=dict(default='default value',
     21                          description='Changes the functionality of _repr_',
     22                          values=dict(with_bells='causes _repr_ to print with bells',
     23                                      with_whistles='causes _repr_ to print with whistles',
     24                                      ...),
     25                          aliases=dict(bells='option1', whistles='option2', ...),
     26        second_option-dict(...),
     27        third_option=dict()
     28    )
     29
     30Each option is specified as a dictionary which describes the possible values for
     31the option. The possible entries in this dictionary are:
     32
     33- ``alias``:       allows several natural guesses for option values to do the
     34                   same thing.
     35
     36- ``checker``:     a function which returns ``True`` or ``False`` depending on
     37                   whether a user supplied value is valid or not.Useful when it
     38                   it not possible to list all possible legal values, such as NN.
     39
     40- ``default``:     gives the default value of the option
     41
     42- ``description``: a one line of the option for its doc-string
     43
     44- ``doc``:         the top half of the documentation which appears
     45                   before the automatically generated list of options and their
     46                   possible values.
     47
     48- ``end_doc``:     the second half of the documentation which appears after the
     49                   list of options and their values
     50
     51- ``link_to``:     links to an in another set of global options (for example
     52                   this is used to allow :class:`Partitions` and
     53                   :class:`Tableaux` to use the same ``convention`` option).
     54
     55- ``setter``:      a function (class method) which is called whenever this
     56                   option changes.
     57
     58- ``values``:      a dictionary of the possible values with the entries
     59                   specifying the possible values, as keys, together with a
     60                   half line description of this option does
     61
     62Either a complete list of values for each option must be supplied via ``values``
     63or a validation function ``checker`` must be suppled. The doc-string arguments
     64``doc`` and ``end_doc`` are optional but encouraged, but some documentation for
     65each option must be supplied using either ``description`` or ``values`` (or
     66both).
     67
     68The values to the options can be quite arbitrary and they include the
     69possibility of passing in (user-defined) functions which can be used to change
     70the default behaviour of the classes -- for example, changing the output of
     71``_repr_`` or :func:`latex`. See the ``dispatcher`` section below.
     72
     73The basic structure for defining a :class:`GlobalOption` is best illustrated by an example.::
     74
     75    sage: from sage.structure.global_options import GlobalOptions
     76    sage: menu=GlobalOptions('menu', doc='Fancy documentation\n'+'-'*19, end_doc='The END!',
     77    ...       entree=dict(default='soup',
     78    ...                   description='The first course of a meal',
     79    ...                   values=dict(soup='soup of the day', bread='oven baked'),
     80    ...                   alias=dict(rye='bread')),
     81    ...       main=dict(default='pizza', description='Main meal',
     82    ...                   values=dict(pizza='thick crust', pasta='penne arrabiata')),
     83    ...       dessert=dict(default='espresso', description='Dessert',
     84    ...                   values=dict(espresso='life begins again',
     85    ...                               cake='waist begins again',
     86    ...                               cream='fluffy, white stuff')),
     87    ...       tip=dict(default=10, description='Reward for good service',
     88    ...       checker=lambda tip: tip in range(0,20))
     89    ...   )
     90    sage: menu
     91    options for menu
     92
     93Accessing and setting option values
     94-----------------------------------
     95
     96All options and their values, when they are strings, are forced to be lower
     97case. The values of an options class can be set and accessed by calling the
     98class or or by treating them as an array. Non-ambiguous abbreviations are
     99allowed for both the options and their values.::
     100
     101    sage: menu()
     102    Current options for menu
     103      - dessert: espresso
     104      - entree:  soup
     105      - main:    pizza
     106      - tip:     10
     107    sage: menu('dessert')
     108    'espresso'
     109    sage: menu['dessert']
     110    'espresso'
     111    sage: menu['d']
     112    'espresso'
     113    sage: menu('m','t',des='esp', ent='sou')  # get and set several values at once
     114    ['pizza', 10]
     115    sage: menu(t=15); menu['tip']
     116    15
     117    sage: menu(e='s', m='pi'); menu()
     118    Current options for menu
     119      - dessert: espresso
     120      - entree:  soup
     121      - main:    pizza
     122      - tip:     15
     123    sage: menu(m='p')
     124    Traceback (most recent call last):
     125    ...
     126    ValueError: p is not a valid value for main in the options for menu
     127
     128
     129All options and, their values, can be abbreviated
     130providing that this is unambiguous.
     131
     132
     133Setter functions
     134----------------
     135
     136Each option to a class of :class:`GlobalOptions` can be equipped with a
     137setter function which is called whenever the option changes. This is not useful
     138to global options which control several parents, however, when used with
     139options of particular instances of classes this ca be used to trigger changes to
     140them based on changes to the options.
     141
     142EXAMPLES::
     143
     144    sage: from sage.structure.global_options import GlobalOptions
     145    sage: class A(SageObject):
     146    ...       def add(self, option, val): self.a+=int(val)
     147    ...       def __init__(self,a):
     148    ...           self.a=a
     149    ...           self.options=GlobalOptions('A',
     150    ...              add=dict(default=1, checker=lambda v: int(v)>0,
     151    ...                       description='A simple setter',
     152    ...                       setter=self.add) )
     153    sage: a=A(2); a.a
     154    3
     155    sage: a.options()
     156    Current options for A
     157    - add: 1
     158    sage: a.options(add=4)
     159    sage: a.a
     160    7
     161    sage: a.options()
     162    Current options for A
     163    - add: 4
     164
     165Documentation for options
     166-------------------------
     167
     168A doc-string for an options class is generated from the  Documentation for a
     169:class:`GlobablOption` is automatically generated from the supplied options::
     170For example, the generated documentation for the ``menu`` options is the
     171following::
     172
     173    Fancy documentation
     174    -------------------
     175
     176    OPTIONS:
     177
     178    - dessert:  (default: espresso)
     179      Dessert
     180        - cake     -- waist begins again
     181        - cream    -- fluffy, white stuff
     182        - espresso -- life begins again
     183
     184    - entree:  (default: soup)
     185      The first course of a meal
     186        - bread -- oven baked
     187        - rye   -- alias for bread
     188        - soup  -- soup of the day
     189
     190    - main:  (default: pizza)
     191      Main meal
     192        - pasta -- penne arrabiata
     193        - pizza -- thick crust
     194
     195    - tip:  (default: 10)
     196      Reward for good service
     197
     198    The END!
     199
     200    See :class:`GlobalOptions` for more features of these options.'''
     201
     202In addition, help on each option and its' list of possible values, can be
     203obtained by (trying to) set it equal to '?'::
     204
     205    sage: menu(des='?')
     206    - dessert:  (default: espresso)
     207      Dessert
     208        - cake     -- waist begins again
     209        - cream    -- fluffy, white stuff
     210        - espresso -- life begins again
     211      Current value: espresso
     212
     213Dispatchers
     214-----------
     215
     216The whole idea of a :class:`GlobalOption` class is that the options change the
     217default behaviour of associated classes. This can be done either by simply
     218checking what the current value of the relevant option is. Another possibility
     219is to use the options class as a dispatcher to the associated methods, each of
     220which are implemented as methods in the associated classes with their names all
     221having a common prefix combined with the values of the option.
     222
     223For example, the options  `MyOptions` can be used to dispatch the ``_repr_``
     224method of the associated class ``MyClass`` as follows:
     225
     226.. code-block:: python
     227
     228    class MyClass(...):
     229        global_options=MyOptions
     230        def _repr_(self):
     231            return self.global_options.dispatch(self,'_repr_','first_option')
     232        def _repr_with_bells(self):
     233            print 'Bell!'
     234        def _repr_with_whistles(self):
     235            print 'Whistles!'
     236
     237In this example, ``first_option`` is an option of ``MyOptions`` which takes
     238values ``bells``, ``whistles`` and so on. Note that it is necessary to make
     239``self``, which is an instance of ``MyClass``, an argument of the dispatcher
     240because :meth:`dispatch` is a method of :class:`GlobalOptions` and not a method
     241of ``MyClass``. Apart form ``MyOptions``, as it is a method of this class, the
     242arguments are the attached class (here ``MyClass``), e prefix of the method of
     243``MyClass`` being dispatched, the the option of ``MyOptions`` which controls he
     244dispatching. All other arguments are passed through to he corresponding methods
     245of ``MyClass``. In general, a dispatcher is invoked as::
     246
     247    self.options.dispatch(self, dispatch_to, option, *args, **kargs)
     248
     249Usually this will result in the method ``dispatch_to+'_'+MyOptions(options)``
     250of ``self`` being called with argumsnts ``*args`` and ``**kargs``. (If
     251``dispatch_to[-1]=='_'`` then the method  ``dispatch_to+MyOptions(options)``
     252is called.).
     253
     254If ``MyOptions(options)`` is itself a function then the dispatcher will call
     255this function instead. In this way, it is possible to allow the user to
     256customise the default behaviour of this method. See :meth:`dispatch` for an
     257example of how this can be one.
     258
     259The dispatching option allows options to be applied automatically and without
     260the need to parse the actions (the cost is that there must be a method for each
     261option). The dispatching capabilities  can also be used to make one option
     262control several methods:
     263
     264.. code-block:: python
     265
     266    def __le__(self, other):
     267        return self.options.dispatch(self, '_le_','cmp', other)
     268    def __ge__(self, other):
     269        return self.options.dispatch(self, '_ge_','cmp', other)
     270    def _le_option_a(self, other):
     271        return ...
     272    def _ge_option_a(self, other):
     273        return ...
     274    def _le_option_b(self, other):
     275        return ...
     276    def _ge_option_b(self, other):
     277        return ...
     278
     279Doc testing
     280-----------
     281
     282All of the options and their effects should be doc tested, however, in order not
     283to break other tests all options should be returned to their default state at
     284the end of each test. To make this easier, every :class:`GlobalOption` has a
     285:meth:`reset` method for doing exactly this.
     286
     287.. WARNING::
     288
     289    Default values for :class:`GlobalOptions` can be automatically overridden by
     290    calling the individual instances of the :class:`GlobalOptions` inside
     291    ``$HOME/.sage/init.sage``. However, this needs to be disabled by developers
     292    when they are writing or checking doc-tests.
     293
     294
     295.. SEEALSO:
     296
     297    For better examples of :class:`GlobalOptions` in action see
     298    :func:`~sage/combinat.partition.PartitionOptions` and
     299    :func:`~sage/combinat.tableau.TableauOptions`.
     300
     301
     302TESTS::
     303
     304As options classes to not know how they are created they cannot be
     305pickled.
     306
     307    sage: menu=GlobalOptions('menu', doc='Fancy documentation\n'+'-'*19, end_doc='The END!',
     308    ...       entree=dict(default='soup',
     309    ...                   description='The first course of a meal',
     310    ...                   values=dict(soup='soup of the day', bread='oven baked'),
     311    ...                   alias=dict(rye='bread')),
     312    ...       main=dict(default='pizza', description='Main meal',
     313    ...                   values=dict(pizza='thick crust', pasta='penne arrabiata')),
     314    ...       dessert=dict(default='espresso', description='Dessert',
     315    ...                   values=dict(espresso='life begins again',
     316    ...                               cake='waist begins again',
     317    ...                               cream='fluffy, white stuff')),
     318    ...       tip=dict(default=10, description='Reward for good service',
     319    ...       checker=lambda tip: tip in range(0,20))
     320    ...   )
     321    sage: TestSuite(menu).run(skip='_test_pickling')
     322
     323AUTHORS:
     324
     325- Andrew Mathas (2013): initial version
     326
     327
     328Methods for global options
     329--------------------------
     330"""
     331
     332#-------------------------------------------------------------------------------
     333#  Copyright (C) 2013 Andrew Mathas <andrew dot mathas at sydney dot edu dot au>
     334#
     335#  Distributed under the terms of the GNU General Public License (GPL)
     336#                  http://www.gnu.org/licenses/
     337#-------------------------------------------------------------------------------
     338
     339from __builtin__ import str
     340from sage.structure.sage_object import SageObject
     341
     342class GlobalOptions(SageObject):
     343    r"""
     344    The :class:`SageOptions` class is a generic class for setting and accessing
     345    global options for ``sage`` objects. It takes as inputs a ``name`` for the
     346    collection of options and a dictionary of dictionaries which specifies the
     347    individual options. The allowed/expected keys in the dictionary are the
     348    following:
     349
     350    INPUTS:
     351
     352    - name:    specifies a name for the options class (required)
     353    - doc:     initial documentation string
     354    - end_doc: final documentation string
     355    - <options>=dict(...)   dictionary specifying an option
     356
     357    The options specified by keyword arguments with their values being a
     358    dictionary which describes the option. The allowed/expected keys in the
     359    dictionary are:
     360
     361    - ``alias``        defines alias/synonym for option values
     362    - ``doc``          start ofthe doc string, before the list of optons
     363    - ``end_doc``      end of the doc string, after the list of optons
     364    - ``checker``      a function for checking whether a particular value for
     365                       the option is valid.
     366    - ``default``      the default value of the option
     367    - ``description``  documentation string
     368    - ``link_to``      links to an option for this set of options to an
     369                       option in another :class:`GlobalOptions`.
     370    - ``setter``:      a function (class method) which is called whenever this
     371                       option changes.
     372    - ``values``       a dictionary of the legal values for this option (this
     373                       automatically defines the corresponding ``checker``).
     374                       This dictionary gives the possible options, as keys,
     375                       together with a brief description of them.
     376
     377    The values of all options are forced to be in lower case. Options, and their
     378    values, can be abbreviated provided that this abbreviation is a prefix of a
     379    unique option.
     380
     381    Calling the options with no arguments results in the list of current options
     382    being printed.
     383
     384    EXAMPLES::
     385
     386        sage: from sage.structure.global_options import GlobalOptions
     387        sage: menu=GlobalOptions('menu', doc='Fancy documentation\n'+'-'*19, end_doc='End of Fancy documentation',
     388        ...       entree=dict(default='soup',
     389        ...                   description='The first course of a meal',
     390        ...                   values=dict(soup='soup of the day', bread='oven baked'),
     391        ...                   alias=dict(rye='bread')),
     392        ...       main=dict(default='pizza', description='Main meal',
     393        ...                 values=dict(pizza='thick crust', pasta='penne arrabiata')),
     394        ...       dessert=dict(default='espresso', description='Dessert',
     395        ...                    values=dict(espresso='life begins again',
     396        ...                                cake='waist begins again',
     397        ...                                cream='fluffy white stuff')),
     398        ...       tip=dict(default=10, description='Reward for good service',
     399        ...                checker=lambda tip: tip in range(0,20))
     400        ...   )
     401        sage: menu
     402        options for menu
     403        sage: menu(entree='s')         # unambiguous abbreviations are allowed
     404        sage: menu(t=15);
     405        sage: (menu['tip'], menu('t'))
     406        (15, 15)
     407        sage: menu()
     408        Current options for menu
     409          - dessert: espresso
     410          - entree:  soup
     411          - main:    pizza
     412          - tip:     15
     413        sage: menu.reset(); menu()
     414        Current options for menu
     415          - dessert: espresso
     416          - entree:  soup
     417          - main:    pizza
     418          - tip:     10
     419        sage: menu['tip']=40
     420        Traceback (most recent call last):
     421        ...
     422        ValueError: 40 is not a valid value for tip in the options for menu
     423        sage: menu(m='p')           # ambiguous abbreviations are not allowed
     424        Traceback (most recent call last):
     425        ...
     426        ValueError: p is not a valid value for main in the options for menu
     427
     428    The documentation for the options class is automatically generated from the
     429    information which specifies the options::
     430
     431        Fancy documentation
     432        -------------------
     433
     434        OPTIONS:
     435
     436        - dessert:  (default: espresso)
     437          Dessert
     438            - cake     -- waist begins again
     439            - cream    -- fluffy white stuff
     440            - espresso -- life begins again
     441
     442        - entree:  (default: soup)
     443          The first course of a meal
     444            - bread -- oven baked
     445            - rye   -- alias for bread
     446            - soup  -- soup of the day
     447
     448        - main:  (default: pizza)
     449          Main meal
     450            - pasta -- penne arrabiata
     451            - pizza -- thick crust
     452
     453        - tip:  (default: 10)
     454          Reward for good service
     455
     456        End of Fancy documentation
     457
     458        See :class:`GlobalOptions` for more features of these options.
     459
     460   The possible values for an individual option can be obtained by
     461   (trying to) set it equal to '?'::
     462
     463    sage: menu(des='?')
     464    - dessert:  (default: espresso)
     465      Dessert
     466        - cake     -- waist begins again
     467        - cream    -- fluffy white stuff
     468        - espresso -- life begins again
     469      Current value: espresso
     470    """
     471    def __init__(self, name, doc='', end_doc='',**options):
     472        self._name=name
     473        # initialise the various dictionaries used by GlobalOptions
     474        self._alias={}            # alias for the values of some options
     475        self._checker={}          # validity checkers for each option
     476        self._default_value={}    # the default options
     477        self._doc={}              # the linked options force us to keep a dictionary of doc strings
     478        self._linked_value={}     # linked to other global options as (link, linked_option)
     479        self._setter={}           # a dictionary of the list of setters
     480        self._value={}            # the current options
     481        self._values={}           # a dictionary of lists of the legal values for each option
     482        for option in options:
     483            self._add_option(option, options[option])
     484        # finally build the doc string
     485        self.__doc__='{start}\n\nOPTIONS:\n\n{options}\n\n{end_doc}\n\n{g_opts}'.format(
     486                       start=doc, end_doc=end_doc,
     487                       options='\n'.join(self._doc[opt] for opt in sorted(self._doc)),
     488                       g_opts='See :class:`GlobalOptions` for more features of these options.'
     489        )
     490
     491
     492    def _repr_(self):
     493        r"""
     494        Return a string representation of for this collection of options.
     495
     496        EXAMPLES::
     497
     498            sage: from sage.structure.global_options import GlobalOptions
     499            sage: FoodOptions=GlobalOptions('daily meal',
     500            ...          food=dict(default='apple', values=dict(apple='a nice fruit',pear='fruit')),
     501            ...          drink=dict(default='water', values=dict(water='wet',milk='white')))
     502            sage: FoodOptions
     503            options for daily meal
     504        """
     505        return 'options for %s'%self._name
     506
     507
     508    def __call__(self, *get_value, **set_value):
     509        r"""
     510        The ``__call__`` method of a :class:`GlobalOption` is used to print the
     511        current options as well as for setting these options.
     512
     513        EXAMPLES::
     514
     515            sage: from sage.structure.global_options import GlobalOptions
     516            sage: FoodOptions=GlobalOptions('daily meal',
     517            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     518            ...         drink=dict(default='water', values=dict(water='a drink',coffee='a lifestyle')))
     519            sage: FoodOptions()
     520            Current options for daily meal
     521              - drink: water
     522              - food:  apple
     523            sage: FoodOptions('food')
     524            'apple'
     525            sage: FoodOptions(food="pair"); FoodOptions()
     526            Current options for daily meal
     527              - drink: water
     528              - food:  pair
     529            sage: FoodOptions(food="apple", drink="coffee"); FoodOptions()
     530            Current options for daily meal
     531              - drink: coffee
     532              - food:  apple
     533        """
     534        if get_value==() and set_value=={}:
     535            print 'Current %s' % self
     536            options=self._value.keys()+self._linked_value.keys()
     537            options.sort()
     538            width=1+max(len(option) for option in options)
     539            print '\n'.join('  - {:{}} {}'.format(option+':',width,self[option])
     540                            for option in options)
     541
     542        # return these options
     543        if get_value!=():
     544            if len(get_value)==1:
     545                return self[get_value[0]]
     546            else:
     547                return [self[option] for option in get_value]
     548
     549        # set these options
     550        if set_value!=[]:
     551            for option in set_value:
     552                self[option]=set_value[option]
     553
     554
     555    def __getitem__(self, option):
     556        r"""
     557        We define ``__getitem__`` so that it can be used to return the current
     558        value of the option. This is not strictly necessary because this functionality
     559        is also provided by ``__call__``, however, we provide a second way of
     560        doing this because this syntax is likely to be expected and it is
     561        intuitive.
     562
     563        EXAMPLES::
     564
     565            sage: from sage.structure.global_options import GlobalOptions
     566            sage: FoodOptions=GlobalOptions('daily meal',
     567            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     568            ...         drink=dict(default='water', values=dict(water='a drink',coffee='a lifestyle')))
     569            sage: FoodOptions['drink']
     570            'water'
     571            sage: FoodOptions['d']
     572            'water'
     573            sage: FoodOptions('f')
     574            'apple'
     575        """
     576        option=self._match_option(option)
     577        if option in self._linked_value:
     578            link,linked_opt=self._linked_value[option]
     579            return link[linked_opt]
     580        elif option in self._value:
     581            return self._value[option]
     582
     583
     584    def __setitem__(self, option, value):
     585        r"""
     586        The ``__setitem__`` method is used to change the current values of the
     587        options. It also checkes that the supplied options are valid and changes
     588        any alias to its generic value.
     589
     590        EXAMPLES::
     591
     592            sage: from sage.structure.global_options import GlobalOptions
     593            sage: FoodOptions=GlobalOptions('daily meal',
     594            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     595            ...         drink=dict(default='water', values=dict(water='a drink',coffee='a lifestyle')))
     596            sage: FoodOptions['drink']='coffee'; FoodOptions()
     597            Current options for daily meal
     598              - drink: coffee
     599              - food:  apple
     600            sage: FoodOptions(drink='w'); FoodOptions()
     601            Current options for daily meal
     602              - drink: water
     603              - food:  apple
     604            sage: FoodOptions(drink='?')
     605            - drink:  (default: water)
     606            - coffee -- a lifestyle
     607            - water  -- a drink
     608            Current value: water
     609        """
     610        option=self._match_option(option)
     611        if not callable(value): value=self._match_value(option, value)
     612
     613        if value=='?':  # return help
     614            print '%s\nCurrent value: %s' % (self._doc[option], self._value[option])
     615            return      # we do not want to call the setter below
     616
     617        elif option in self._linked_value:
     618            link, linked_opt=self._linked_value[option]
     619            link[linked_opt]=value
     620
     621        else:
     622            self._value[option]=value
     623
     624        if option in self._setter:
     625            # if a setter function exists then call it with the associated
     626            # class, option and value
     627            self._setter[option](option, value)
     628
     629    def _add_option(self, option, specifications):
     630        r"""
     631        Each ``option`` in a :class:`GlobalOptions` is determined by a
     632        dictionary which can have the following keys::
     633        - ``alias``        defines alias/synonym for option values
     634        - ``checker``      a function for checking whether a particular value for
     635                           this option is valid.
     636        - ``default``      the default value of the option
     637        - ``doc``:         the top half of the documentation which appears
     638                           before the automatically generated list of options and their
     639                           possible values.
     640        - ``end_doc``:     the second half of the documentation which appears after the
     641                           list of options and their values
     642        - ``description``  documentation string
     643        - ``link_to``      links to an option for this set of options to an
     644                           option in another :class:`GlobalOptions`.
     645        - ``setter``:      a function (class method) which is called whenever this
     646                           option changes.
     647        - ``values``       a dictionary of the legal values for this option (this
     648                           automatically defines the corresponding ``checker``),
     649                           together with a doc string describing this option
     650        """
     651        doc={}  # will be used to build the doc string
     652        self._values[option]=[]
     653        for spec in sorted(specifications):   # NB: options processed alphabetically!
     654            if spec=='alias':
     655                self._alias[option]=specifications[spec]
     656                self._values[option]+=specifications[spec].keys()
     657                for opt in specifications[spec]:
     658                    doc[opt]='alias for %s' % specifications[spec][opt]
     659            elif spec=='checker':
     660                if not callable(specifications['checker']):
     661                    raise ValueError('the checker for %s must be callable'%option)
     662                self._checker[option]=specifications['checker']
     663            elif spec=='default':
     664                self._default_value[option]=specifications['default']
     665            elif spec=='link_to':
     666                if (isinstance(specifications[spec],tuple) and len(specifications[spec])==2
     667                        and isinstance(specifications[spec][0],GlobalOptions)
     668                        and specifications[spec][1] in specifications[spec][0]._value):
     669                    self._linked_value[option]=specifications['link_to']
     670                    link, linked_opt=specifications['link_to']  # for sanity
     671                    doc=link._doc[linked_opt]
     672                else:
     673                    raise ValueError('linked options must be specified as a tuple: (link,linked_option)')
     674            elif spec=='setter':
     675                if callable(specifications[spec]):
     676                    self._setter[option]=specifications[spec]
     677                else:
     678                    raise ValueError('the setter for %s must be a function' % option)
     679            elif spec=='values':
     680                for val in specifications[spec]:
     681                    doc[val]=specifications[spec][val]
     682                doc.update(specifications[spec])
     683                self._values[option]+=[val.lower() for val in specifications[spec].keys()]
     684            elif spec!='description':
     685                raise ValueError('Initialisation error in Global options for %s: %s not recognised!' % (self._name, spec))
     686
     687        # now build the doc string for this option
     688        if doc=={} and not 'description' in specifications:
     689            raise ValueError('no documentation specified for %s in the %s' % (option, self))
     690
     691        self._doc[option.lower()]=''   # a hack to put option in self._doc because __setitem_ calls _match_option
     692        if option in self._linked_value:
     693            self._doc[option]=doc
     694        else:
     695            width=max(len(v) for v in doc.keys()) if doc!={} else 0
     696            self._doc[option.lower()]='- {}:  (default: {})\n{}{}'.format(
     697                option, self.default_value(option),
     698                '  %s\n'%specifications['description'] if 'description' in specifications else '',
     699                '\n'.join('    - {:{}} -- {}'.format(val,width,doc[val]) for val in sorted(doc)))
     700
     701        # sanity check for non-linked options
     702        if not option in self._linked_value:
     703            if 'default' not in specifications:
     704                raise ValueError('a default value for %s must be given' % option)
     705
     706            if not (option in self._checker or option in self._values):
     707                raise ValueError('a value checker or a list of valid values for %s must be given' % option)
     708
     709            # finally, set, check and process the default value using  __setitem__
     710            self[option]=self._default_value[option]
     711            self._default_value[option]=self._value[option]  # in case the default is an alias
     712
     713
     714    def _match_option(self, option):
     715        r"""
     716        Check to see whether ``option`` is indeed an option for ``self``. If it
     717        is not an option then try and match it with a prefix to an option and
     718        this is this is not possible raise a ValueError.
     719
     720        EXAMPLES::
     721
     722            sage: from sage.structure.global_options import GlobalOptions
     723            sage: FoodOptions=GlobalOptions('daily meal',
     724            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     725            ...         drink=dict(default='water', values=dict(water='a drink',coffee='a lifestyle')))
     726            sage: FoodOptions('food')
     727            'apple'
     728            sage: FoodOptions('f')
     729            'apple'
     730        """
     731        # the keys of self._doc is a list of the options, both normal and linked
     732        option=option.lower()
     733        if option in self._doc: return option
     734
     735        # as it is not an option try and match it with a prefix to an option
     736        matches=[opt for opt in self._doc if opt.startswith(option)]
     737        if len(matches)>0 and all(m.startswith(matches[0]) for m in matches):
     738            return matches[0]
     739        elif len(matches)>1:
     740            raise ValueError('%s is an ambiguous option for %s'%(option, self._name))
     741
     742        # if we are still here this is not a good option!
     743        raise ValueError('%s is not an option for %s' % (option, self._name))
     744
     745
     746    def _match_value(self, option, value):
     747        r"""
     748        Check to see whether ``option`` is indeed an option for ``self``. If it
     749        is not an option then try and match it with a prefix to an option and
     750        this is this is not possible raise a ValueError.
     751
     752        EXAMPLES::
     753
     754            sage: from sage.structure.global_options import GlobalOptions
     755            sage: FoodOptions=GlobalOptions('daily meal',
     756            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     757            ...         drink=dict(default='water', values=dict(water='a drink',wine='a lifestyle')))
     758            sage: FoodOptions(f='a'); FoodOptions('f')
     759            'apple'
     760            sage: FoodOptions(d='wi'); FoodOptions('f')
     761            'apple'
     762            sage: FoodOptions(d='w')
     763            Traceback (most recent call last):
     764            ...
     765            ValueError: w is not a valid value for drink in the options for daily meal
     766        """
     767        if value=="?": return value   # help on this value
     768
     769        if option in self._linked_value:
     770            link, linked_opt=self._linked_value[option]
     771            return link._match_value(option,value)
     772
     773        # convert value to lower case if it is a string
     774        if isinstance(value, str): value=value.lower()
     775
     776        if option in self._values:
     777            if value in self._values[option]:
     778                if option in self._alias and value in self._alias[option]:
     779                    return self._alias[option][value]
     780                else: return value
     781
     782            # as it is not a value try and match it with a prefix of a value
     783            matches=[val for val in self._values[option] if val.startswith(value)]
     784            if len(matches)>0 and all(m.startswith(matches[0]) for m in matches):
     785                val=matches[0]
     786                if option in self._alias and val in self._alias[option]:
     787                    return self._alias[option][val]
     788                else: return val
     789
     790        if option in self._checker and self._checker[option](value):
     791            return value
     792
     793        # replace any value alias with its "real" value
     794        if option in self._alias and value in self._alias[option]:
     795            value=self._alias[option][value]
     796
     797        # if we are still here this is not a good value!
     798        raise ValueError('%s is not a valid value for %s in the %s'%(value, option, self))
     799
     800
     801    def default_value(self, option):
     802        r"""
     803        Returns the default value of the option.
     804
     805        EXAMPLES:
     806
     807            sage: from sage.structure.global_options import GlobalOptions
     808            sage: FoodOptions=GlobalOptions('daily meal',
     809            ...         food=dict(default='apple', values=dict(apple='a fruit',pair='of what?')),
     810            ...         drink=dict(default='water', values=dict(water='a drink',wine='a lifestyle')))
     811            sage: FoodOptions.default_value('food')
     812            'apple'
     813        """
     814        option=self._match_option(option)
     815        if option in self._default_value:
     816            return self._default_value[option]
     817        else:
     818            link, linked_opt=self._linked_value[option]
     819            return link._default_value(linked_opt)
     820
     821
     822    def dispatch(self, obj, dispatch_to, option, *args, **kargs):
     823        r"""
     824        The *dispatchable* options are options which dispatch related methods of
     825        the corresponding class - or user defined methods which are passed to
     826        :class:`GlobalOptions`. The format for specifying a dispatchable option
     827        is to include ``dispatch_to=<option name>`` in the specifications for the
     828        options and then to add the options to the (element) class. Each option
     829        is then assumed to be a method of the element class with a name of the
     830        form `` <option name>+'_'+<current vale for this option'.`` These
     831        options are called by the element class via::
     832
     833            return self.options.dispatch(self, dispatch_to, option, *args, **kargs)
     834
     835        Note that the argument ``self`` is necessary here because the dispatcher
     836        is a method of the options class and not of self. The value of the
     837        option can also be set to a user-defined function, with arguments
     838        ``self`` and ``option`` in which case the user's function is called
     839        instead.
     840
     841        Here is a contrived example.
     842
     843        EXAMPLES::
     844
     845            sage: from sage.structure.global_options import GlobalOptions
     846            sage: DelimitedListOptions=GlobalOptions('list delimiters',
     847            ...             delim=dict(default='b', values={'b':'brackets', 'p':'parentheses'}))
     848            sage: class DelimitedList(CombinatorialObject):
     849            ...      options=DelimitedListOptions
     850            ...      def _repr_b(self): return '[%s]' % ','.join('%s'%i for i in self._list)
     851            ...      def _repr_p(self): return '(%s)' % ','.join('%s'%i for i in self._list)
     852            ...      def _repr_(self): return self.options.dispatch(self, '_repr_','delim')
     853            sage: dlist=DelimitedList([1,2,3]); dlist
     854            [1,2,3]
     855            sage: dlist.options(delim='p'); dlist
     856            (1,2,3)
     857            sage: dlist.options(delim=lambda self: '<%s>' % ','.join('%s'%i for i in self._list)); dlist
     858            <1,2,3>
     859        """
     860        if callable(self._value[option]):
     861            try:
     862                return self._value[option](obj, *args, **kargs)
     863            except TypeError:
     864                raise ValueError('the user defined dispatcher function failed!')
     865        else:
     866            if dispatch_to[-1]=='_': dispatch_to=dispatch_to[:-1]
     867            dispatch=getattr(obj,dispatch_to+'_'+self._value[option])
     868            return dispatch(*args, **kargs)
     869
     870        raise ValueError('%s is not a dispatchable option!' % option)
     871
     872
     873    def reset(self, option=None):
     874        r"""
     875        Reset all options to their default value unless, optionally, ``option``
     876        is specified in which case only this option is reset to its' default.
     877
     878        EXAMPLES::
     879
     880            sage: from sage.structure.global_options import GlobalOptions
     881            sage: opts=GlobalOptions('daily meal',
     882            ...      food=dict(default='bread', values=dict(bread='rye bread', salmon='a fish')),
     883            ...      drink=dict(default='water',values=dict(water='essential for life',wine='essential')))
     884            sage: opts(food='salmon'); opts()
     885            Current options for daily meal
     886              - drink: water
     887              - food:  salmon
     888            sage: opts.reset('drink'); opts()
     889            Current options for daily meal
     890              - drink: water
     891              - food:  salmon
     892            sage: opts.reset(); opts()
     893            Current options for daily meal
     894              - drink: water
     895              - food:  bread
     896        """
     897        if option is None:
     898            for option in self._default_value:
     899                self._value[option]=self._default_value[option]
     900            for option in self._linked_value:
     901                link, linked_opt=self._linked_value[option]
     902                link.reset(linked_opt)
     903        else:
     904            option=self._match_option(option)
     905            if option in self._default_value:
     906                self._value[option]=self._default_value[option]
     907            elif option in self._linked_value:
     908                link, linked_opt=self._linked_value[option]
     909                link.reset(linked_opt)