Skip to content

Commit

Permalink
Trac #18024: Mutability of tableaux part II: replacing CombinatorialO…
Browse files Browse the repository at this point in the history
…bject by ClonableList

This branch refactors `Tableau` and `SkewTableau` to derive from
`ClonableList` instead of `CombinatorialObject`. While we do not
currently use the cloning context-manager provided by `ClonableList`,
this refactoring still has the advantage of moving to a more modern
paradigm and simplifying the changes in #18013. A number of cleanup and
optimization changes are also done here. (The methods deleted from
`ribbon_tableau.py` and `ribbon_shape_tableau.py` are slow
implementations of methods that are implemented in a better way on a
superclass in `skew_tableau`. No functionality is lost.)

The speed changes range from significant speedups to minor slowdowns,
the latter being mainly on methods (such as Tableau's `restrict`) which
ducktype the result as follows:
{{{
        # attempt to return a tableau of the same type
        try:
            return self.parent()( res )
        except Exception:
            try:
                return self.parent().Element( res )
            except Exception:
                return Tableau(res)
}}}

Two unpickling doctests are broken: one in ribbon_tableau.py, and one in
ribbon_shape_tableau.py. One of them makes no sense to me, but the other
might be worth salvaging.

URL: http://trac.sagemath.org/18024
Reported by: darij
Ticket author(s): Jan Keitel, Darij Grinberg
Reviewer(s): Josh Swanson, Travis Scrimshaw
  • Loading branch information
Release Manager authored and vbraun committed Apr 18, 2015
2 parents 018b506 + 8a21007 commit e092901
Show file tree
Hide file tree
Showing 8 changed files with 539 additions and 298 deletions.
2 changes: 1 addition & 1 deletion src/sage/combinat/all.py
Expand Up @@ -86,7 +86,7 @@
from tableau import Tableau, SemistandardTableau, StandardTableau, \
Tableaux, StandardTableaux, SemistandardTableaux
from skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux, SemistandardSkewTableaux
from ribbon_shaped_tableau import RibbonShapedTableau, StandardRibbonShapedTableaux
from ribbon_shaped_tableau import RibbonShapedTableau, RibbonShapedTableaux, StandardRibbonShapedTableaux
from ribbon_tableau import RibbonTableaux, RibbonTableau, MultiSkewTableaux, MultiSkewTableau, SemistandardMultiSkewTableaux
from composition_tableau import CompositionTableau, CompositionTableaux

Expand Down
5 changes: 5 additions & 0 deletions src/sage/combinat/combinat.py
Expand Up @@ -830,6 +830,11 @@ def __init__(self, l, copy=True):
list and the hash of its parent's class. Thus, each
CombinatorialObject should have a unique string representation.
.. WARNING::
This class is slowly being deprecated. Use
:class:`~sage.structure.list_clone.ClonableList` instead.
INPUT:
- ``l`` -- a list or any object that can be converted to a
Expand Down
10 changes: 4 additions & 6 deletions src/sage/combinat/k_tableau.py
Expand Up @@ -478,7 +478,7 @@ def chi(x):
return x
return "%s"%x
if self.parent()._representation in ['core', 'bounded']:
t = [[chi(x) for x in row] for row in self._list]
t = [[chi(x) for x in row] for row in self]
from output import tex_from_array
return tex_from_array(t)
else:
Expand Down Expand Up @@ -738,7 +738,6 @@ def __init__(self, parent, t):
sage: TestSuite(t).run()
"""
self.k = parent.k
self._list = [r for r in t]
ClonableList.__init__(self, parent, t)

def _repr_diagram(self):
Expand Down Expand Up @@ -821,7 +820,7 @@ def check(self):
...
ValueError: The tableau is not semistandard!
"""
if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self._list,self.k).weight():
if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self,self.k).weight():
raise ValueError("The weight of the parent does not agree with the weight of the tableau!")
t = SkewTableau(list(self))
if not t in SemistandardSkewTableaux():
Expand Down Expand Up @@ -1016,7 +1015,7 @@ def list_of_standard_cells(self):
raise ValueError("This method only works for straight tableaux!")
if self.weight() not in Partitions(sum(self.weight())):
raise ValueError("This method only works for weak tableaux with partition weight!")
if self._list == []:
if not self:
return []
mu = Partition(self.weight()).conjugate()
already_used = []
Expand Down Expand Up @@ -1448,10 +1447,9 @@ def __init__(self, parent, t):
"""
k = parent.k
self.k = k
self._list = [list(r) for r in t]
if parent._outer_shape.conjugate().length() > k:
raise ValueError("%s is not a %s-bounded tableau"%(t, k))
ClonableList.__init__(self, parent, self._list)
ClonableList.__init__(self, parent, [list(r) for r in t])

def _repr_diagram(self):
r"""
Expand Down
186 changes: 117 additions & 69 deletions src/sage/combinat/ribbon_shaped_tableau.py
Expand Up @@ -16,24 +16,29 @@
# http://www.gnu.org/licenses/
#*****************************************************************************

from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.combinat.skew_tableau import SkewTableau, StandardSkewTableaux
from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux
from sage.combinat.tableau import TableauOptions
from sage.combinat.permutation import Permutation, descents_composition_first, descents_composition_list, descents_composition_last
from sage.combinat.skew_partition import SkewPartition
from sage.rings.integer import Integer
from combinat import CombinatorialObject
from sage.combinat.words.words import Words
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
from sage.categories.sets_cat import Sets

class RibbonShapedTableau(SkewTableau):
r"""
A ribbon.
A ribbon shaped tableau.
A ribbon is a skew tableau that does not contain a `2 \times 2` box. A
ribbon is given by a list of the rows from top to bottom.
For the purposes of this class, a ribbon shaped tableau is a skew
tableau whose shape is a skew partition which:
- has at least one cell in row `1`;
- has at least one cell in column `1`;
- has exactly one cell in each of `q` consecutive diagonals, for
some nonnegative integer `q`.
A ribbon is given by a list of the rows from top to bottom.
EXAMPLES::
Expand All @@ -47,29 +52,40 @@ class RibbonShapedTableau(SkewTableau):
[5, 4, 2] / [3, 1]
The entries labeled by ``None`` correspond to the inner partition.
Using ``None`` is optional, the entries will be shifted accordingly. ::
Using ``None`` is optional; the entries will be shifted accordingly. ::
sage: x = RibbonShapedTableau([[2,3],[1,4,5],[3,2]]); x.pp()
. . . 2 3
. 1 4 5
3 2
TESTS::
sage: r = RibbonShapedTableau([[1], [2,3], [4, 5, 6]])
sage: r.to_permutation()
[4, 5, 6, 2, 3, 1]
sage: RibbonShapedTableau([[1,2],[3,4]]).evaluation()
[1, 1, 1, 1]
"""
@staticmethod
def __classcall_private__(cls, r):
r"""
Return a ribbon tableau object.
Return a ribbon shaped tableau object.
EXAMPLES::
sage: RibbonShapedTableau([[2,3],[1,4,5]])
[[None, None, 2, 3], [1, 4, 5]]
"""
if isinstance(r, list):
if len(r) == 0:
return StandardRibbonShapedTableaux()(r)
if all(isinstance(i, list) for i in r):
if all(all(j is None or (isinstance(j, (int, Integer)) and j>0) for j in i) for i in r):
return StandardRibbonShapedTableaux()(r)
try:
r = map(tuple, r)
except TypeError:
raise TypeError("r must be a list of positive integers")
if not r:
return StandardRibbonShapedTableaux()(r)
if all(all(j is None or (isinstance(j, (int, Integer)) and j>0) for j in i) for i in r):
return StandardRibbonShapedTableaux()(r)
raise TypeError("r must be a list of positive integers")

def __init__(self, parent, t):
Expand Down Expand Up @@ -97,26 +113,6 @@ def __init__(self, parent, t):

SkewTableau.__init__(self, parent, t)

def __setstate__(self, state):
r"""
In order to maintain backwards compatibility and be able to unpickle
a old pickle from ``Ribbon_class`` we have to override the
default ``__setstate__``.
EXAMPLES::
sage: loads( 'x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@<c \x8f\x07\xc40\x012xSSK\x93\xf4\x00l\x811\x17')
[[1, 2], [3, 4]]
sage: loads(dumps( RibbonShapedTableau([[3,2,1], [1,1]]) )) # indirect doctest
[[None, 3, 2, 1], [1, 1]]
"""
if isinstance(state, dict): # for old pickles from Ribbon_class
self._set_parent(StandardRibbonShapedTableaux())
self.__dict__ = state
else:
self._set_parent(state[0])
self.__dict__ = state[1]

def height(self):
"""
Return the height of ``self``.
Expand Down Expand Up @@ -157,48 +153,74 @@ def width(self):
#return 1+sum([len(r)-1 for r in self])
return len(self[0]) if len(self) > 0 else 0

def to_skew_tableau(self):

class RibbonShapedTableaux(SkewTableaux):
"""
The set of all ribbon shaped tableaux.
"""
@staticmethod
def __classcall_private__(cls, shape=None, **kwds):
"""
This is deprecated in :trac:`14101` since :class:`RibbonShapedTableau`
inherits from :class:`SkewTableau`.
Normalize input to ensure a unique representation and pick the correct
class based on input.
The ``shape`` parameter is currently ignored.
EXAMPLES::
sage: RibbonShapedTableau([[2,3],[1,4,5]]).to_skew_tableau()
doctest:...: DeprecationWarning: this method is deprecated since ribbon shaped tableaux are skew partitions
See http://trac.sagemath.org/14101 for details.
[[None, None, 2, 3], [1, 4, 5]]
sage: S1 = RibbonShapedTableaux([4, 2, 2, 1])
sage: S2 = RibbonShapedTableaux((4, 2, 2, 1))
sage: S1 is S2
True
"""
from sage.misc.superseded import deprecation
deprecation(14101,'this method is deprecated since ribbon shaped tableaux are skew partitions')
return self
#if shape is not None:
# from sage.combinat.partition import Partition
# return RibbonShapedTableaux_shape(Partition(shape))

# Otherwise arg0 takes the place of the category in pickling
return super(RibbonShapedTableaux, cls).__classcall__(cls, **kwds)

def to_permutation(self):
def __init__(self, category=None):
"""
Returns the permutation corresponding to the ribbon tableau.
Initialize ``self``.
EXAMPLES::
sage: r = RibbonShapedTableau([[1], [2,3], [4, 5, 6]])
sage: r.to_permutation()
[4, 5, 6, 2, 3, 1]
sage: S = RibbonShapedTableaux()
sage: TestSuite(S).run()
"""
return Permutation(self.to_word())
if category is None:
category = Sets()

def evaluation(self):
SkewTableaux.__init__(self, category=category)

def _repr_(self):
"""
Return the evaluation of the word from ribbon.
TESTS::
EXAMPLES::
sage: repr(RibbonShapedTableaux()) # indirect doctest
'Ribbon shaped tableaux'
"""
return "Ribbon shaped tableaux"

sage: RibbonShapedTableau([[1,2],[3,4]]).evaluation()
[1, 1, 1, 1]
Element = RibbonShapedTableau
global_options = TableauOptions

def from_shape_and_word(self, shape, word):
"""
ed = self.to_word().evaluation_dict()
entries = ed.keys()
m = max(entries) + 1 if entries else -1
return [ed.get(k,0) for k in range(1,m)]
Return the ribbon corresponding to the given ribbon shape and word.
EXAMPLES::
sage: RibbonShapedTableaux().from_shape_and_word([1,3],[1,3,3,7])
[[None, None, 1], [3, 3, 7]]
"""
pos = 0
r = []
for l in shape:
r.append(word[pos:pos+l])
pos += l
return self.element_class(self, r)

class StandardRibbonShapedTableaux(StandardSkewTableaux):
"""
Expand Down Expand Up @@ -242,6 +264,15 @@ def __init__(self, category=None):

StandardSkewTableaux.__init__(self, category=category)

def _repr_(self):
"""
TESTS::
sage: repr(StandardRibbonShapedTableaux()) # indirect doctest
'Standard ribbon shaped tableaux'
"""
return "Standard ribbon shaped tableaux"

def __iter__(self):
"""
Iterate through ``self``.
Expand All @@ -259,8 +290,7 @@ def __iter__(self):
[[None, 1], [2, 3]],
[[1], [2], [3]],
[[1, 2, 3, 4]],
[[None, None, 3],
[1, 2, 4]]]
[[None, None, 3], [1, 2, 4]]]
"""
from sage.combinat.partition import _Partitions
for p in _Partitions:
Expand Down Expand Up @@ -322,12 +352,12 @@ def from_permutation(self, p):

class StandardRibbonShapedTableaux_shape(StandardRibbonShapedTableaux):
"""
Class of standard ribbon tableaux of ribbon shape ``shape``.
Class of standard ribbon shaped tableaux of ribbon shape ``shape``.
EXAMPLES::
sage: StandardRibbonShapedTableaux([2,2])
Standard ribbon tableaux of shape [2, 2]
Standard ribbon shaped tableaux of shape [2, 2]
sage: StandardRibbonShapedTableaux([2,2]).first()
[[None, 2, 4], [1, 3]]
sage: StandardRibbonShapedTableaux([2,2]).last()
Expand Down Expand Up @@ -372,9 +402,9 @@ def _repr_(self):
TESTS::
sage: StandardRibbonShapedTableaux([2,2])
Standard ribbon tableaux of shape [2, 2]
Standard ribbon shaped tableaux of shape [2, 2]
"""
return "Standard ribbon tableaux of shape %s"%list(self.shape)
return "Standard ribbon shaped tableaux of shape %s"%list(self.shape)

def first(self):
"""
Expand Down Expand Up @@ -414,7 +444,25 @@ def __iter__(self):
for p in descents_composition_list(self.shape):
yield self.from_permutation(p)

class Ribbon_class(RibbonShapedTableau):
"""
This exists solely for unpickling ``Ribbon_class`` objects.
"""
def __setstate__(self, state):
r"""
Unpickle old ``Ribbon_class`` objects.
EXAMPLES::
sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@<c \x8f\x07\xc40\x012xSSK\x93\xf4\x00l\x811\x17')
[[None, 1, 2], [3, 4]]
sage: loads(dumps( RibbonShapedTableau([[3,2,1], [1,1]]) )) # indirect doctest
[[None, 3, 2, 1], [1, 1]]
"""
self.__class__ = RibbonShapedTableau
self.__init__(RibbonShapedTableaux(), state['_list'])

from sage.structure.sage_object import register_unpickle_override
register_unpickle_override('sage.combinat.ribbon', 'Ribbon_class', RibbonShapedTableau)
register_unpickle_override('sage.combinat.ribbon', 'Ribbon_class', Ribbon_class)
register_unpickle_override('sage.combinat.ribbon', 'StandardRibbons_shape', StandardRibbonShapedTableaux)

0 comments on commit e092901

Please sign in to comment.