Ticket #3661: trac_3661-2.patch

File trac_3661-2.patch, 12.1 KB (added by mhansen, 11 years ago)
  • sage/combinat/family.py

    # HG changeset patch
    # User Mike Hansen <mhansen@gmail.com>
    # Date 1216181237 18000
    # Node ID 770d745eca589b9bc5877206b9a4b2325a34ed41
    # Parent  b870354dc81bb12bca773c0cf302ba8a1678792b
    Added doctests and improved pickling functionality for families.
    
    diff -r b870354dc81b -r 770d745eca58 sage/combinat/family.py
    a b  
     1"""
     2Families
     3"""
     4#*****************************************************************************
     5#       Copyright (C) 2008 Nicolas Thiery <nthiery at users.sf.net>,
     6#                          Mike Hansen <mhansen@gmail.com>,
     7#
     8#  Distributed under the terms of the GNU General Public License (GPL)
     9#
     10#    This code is distributed in the hope that it will be useful,
     11#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13#    General Public License for more details.
     14#
     15#  The full text of the GPL is available at:
     16#
     17#                  http://www.gnu.org/licenses/
     18#*****************************************************************************
    119from sage.combinat.combinat import CombinatorialClass
    220from sage.combinat.finite_class import FiniteCombinatorialClass_l
    321
     
    4159            ['a', 'b', 'd']
    4260            sage: f.keys()
    4361            [3, 4, 7]
    44             sage: 'b' in f       # todo: not implemented
     62            sage: 'b' in f 
    4563            True
    46             sage: 'e' in f       # todo: not implemented
     64            sage: 'e' in f
    4765            False
    4866
    4967        A familly can also be constructed by its index set $I$ and a
     
    6987        list to be hashable. One can ask instead for the images $f(i)$
    7088        to be computed lazily, when needed:
    7189
    72             sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     90            sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
    7391            sage: f
    7492            Lazy family (f(i))_{i in [3, 4, 7]}
    7593            sage: f[7]
     
    82100            3
    83101
    84102        This allows in particular for modeling infinite families:
    85             sage: f = Family(ZZ, lambda i: 2*i)
     103            sage: f = Family(ZZ, lambda i: 2r*i)
    86104            sage: f
    87105            Lazy family (f(i))_{i in Integer Ring}
    88106            sage: f.keys()
     
    95113            sage: i.next(), i.next(), i.next(), i.next(), i.next()
    96114            (0, 2, -2, 4, -4)
    97115
    98         Caveat: families with lazy behavior cannot be pickled
    99 
     116        Caveat: Only certain families with lazy behavior can be pickled. In
     117        particular, only functions that work with Sage's pickle_function
     118        and unpickle_function (in sage.misc.fpickle) will correctly
     119        unpickle.
    100120
    101121        Finally, it can occasionally be useful to add some hidden
    102         elements in a familly, which are accessible as f[i], but
     122        elements in a family, which are accessible as f[i], but
    103123        do not appear in the keys or the container operations.
    104124
    105125            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     
    226246    raise NotImplementedError
    227247
    228248class AbstractFamily(CombinatorialClass):
    229 
    230249    def hidden_keys(self):
    231250        """
    232         Returns the hidden keys of the family, if any
     251        Returns the hidden keys of the family, if any.
     252
     253        EXAMPLES:
     254            sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
     255            sage: f.hidden_keys()
     256            []
    233257        """
    234258        return []
    235259
     
    293317        ['a', 'b', 'd']
    294318        sage: [ x for x in f ]
    295319        ['a', 'b', 'd']
    296         sage: f == loads(dumps(f))
    297         True
    298320    """
    299321
    300322    def __init__(self, dictionary, keys = None):
     323        """
     324        TESTS:
     325            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     326            sage: f == loads(dumps(f))
     327            True
     328        """
    301329        # TODO: use keys to specify the order of the elements
    302330        self.dictionary = dictionary
    303331        self.keys = dictionary.keys
    304         self.__iter__ = dictionary.itervalues
    305         self.list = dictionary.values # should not be required
    306332        self.values = dictionary.values
    307         self.__getitem__ = dictionary.__getitem__
    308333
    309334    def __repr__(self):
     335        """
     336        EXAMPLES:
     337            sage: FiniteFamily({3: 'a'})
     338            Finite family {3: 'a'}
     339        """
    310340        return "Finite family %s"%self.dictionary
    311341
     342    def __contains__(self, x):
     343        """
     344        EXAMPLES:
     345            sage: f = FiniteFamily({3: 'a'})
     346            sage: 'a' in f
     347            True
     348            sage: 'b' in f
     349            False
     350        """
     351        return x in self.values()
     352
    312353    def count(self):
     354        """
     355        Returns the number of elements in self.
     356
     357        EXAMPLES:
     358            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     359            sage: f.count()
     360            3       
     361        """
    313362        return len(self.dictionary)
    314363
    315     # Why isn't it sufficient to set self.__getitem__ as above?
     364    def iterator(self):
     365        """
     366        EXAMPLES:
     367            sage: f = FiniteFamily({3: 'a'})
     368            sage: i = iter(f)
     369            sage: i.next()
     370            'a'
     371
     372        """
     373        return iter(self.values())
     374
    316375    def __getitem__(self, i):
    317         return self.__getitem__(i)
     376        """
     377       
     378        Note that we can't just do self.__getitem__ = dictionary.__getitem__ in the
     379        __init__ method since Python queries the object's type/class
     380        for the special methods rather than querying the object itself.
     381
     382        EXAMPLES:
     383            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     384            sage: f[3]
     385            'a'
     386        """
     387        return self.dictionary.__getitem__(i)
    318388
    319389    # For the pickle and copy modules
    320390    def __getstate__(self):
     391        """
     392        TESTS:
     393            sage: f = FiniteFamily({3: 'a'})
     394            sage: f.__getstate__()
     395            {'dictionary': {3: 'a'}}
     396        """
    321397        return {'dictionary': self.dictionary}
    322398
    323399    def __setstate__(self, state):
     400        """
     401        EXAMPLES:
     402            sage: f = FiniteFamily({3: 'a'})
     403            sage: f.__setstate__({'dictionary': {4:'b'}})
     404            sage: f
     405            Finite family {4: 'b'}
     406
     407        """
    324408        self.__init__(state['dictionary'])
    325409
    326410class FiniteFamilyWithHiddenKeys(FiniteFamily):
     
    330414    remembered). Instances should be created via the Family factory,
    331415    which see for examples and tests.
    332416
    333     Caveat: instances of this class cannot be pickled, because the
    334     hidden_function itself cannot.
     417    Caveat: Only instances of this class whose functions are
     418    compatible with sage.misc.fpickle can be pickled.
    335419    """
    336420    def __init__(self, dictionary, hidden_keys, hidden_function):
     421        """
     422        EXAMPLES:
     423            sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
     424            sage: f == loads(dumps(f))
     425            True
     426        """
    337427        FiniteFamily.__init__(self, dictionary)
    338428        self._hidden_keys = hidden_keys
    339429        self.hidden_function = hidden_function
     
    344434        #self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i]
    345435
    346436    def __getitem__(self, i):
    347         if self.dictionary.has_key(i):
     437        """
     438        EXAMPLES:
     439            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     440            sage: f[3]
     441            6
     442            sage: f[2]
     443            4
     444            sage: f[5]
     445            Traceback (most recent call last):
     446            ...
     447            KeyError
     448           
     449        """
     450        if i in self.dictionary:
    348451            return self.dictionary[i]
    349         if not self.hidden_dictionary.has_key(i):
    350             if not i in self._hidden_keys:
     452
     453        if i not in self.hidden_dictionary:
     454            if i not in self._hidden_keys:
    351455                raise KeyError
    352456            self.hidden_dictionary[i] = self.hidden_function(i)
     457
    353458        return self.hidden_dictionary[i]
    354459
    355460    def hidden_keys(self):
     461        """
     462        Returns self's hidden keys.
     463
     464        EXAMPLES:
     465            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     466            sage: f.hidden_keys()
     467            [2]
     468        """
    356469        return self._hidden_keys
    357470
    358471    def __getstate__(self):
    359         raise NotImplementedError
     472        """
     473        EXAMPLES:
     474            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     475            sage: d = f.__getstate__()
     476            sage: d['hidden_keys']
     477            [2]
     478        """
     479        from sage.misc.fpickle import pickle_function
     480        f = pickle_function(self.hidden_function)
     481        return {'dictionary': self.dictionary,
     482                'hidden_keys': self._hidden_keys,
     483                'hidden_dictionary': self.hidden_dictionary,
     484                'hidden_function': f}
     485
     486    def __setstate__(self, d):
     487        """
     488        EXAMPLES:
     489            sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
     490            sage: d = f.__getstate__()
     491            sage: f = Family([4,5,6], lambda i: 2r*i, hidden_keys=[2])
     492            sage: f.__setstate__(d)
     493            sage: f.keys()
     494            [3, 4, 7]
     495            sage: f[3]
     496            6
     497        """
     498        from sage.misc.fpickle import unpickle_function
     499        hidden_function = unpickle_function(d['hidden_function'])
     500        self.__init__(d['dictionary'], d['hidden_keys'], hidden_function)
     501        self.hidden_dictionary = d['hidden_dictionary']
     502
    360503
    361504class LazyFamily(AbstractFamily):
    362505    r"""
     
    366509    Instances should be created via the Family factory, which see for
    367510    examples and tests.
    368511    """
    369 
    370512    def __init__(self, set, function, name = "f"):
     513        """
     514        EXAMPLES:
     515            sage: f = LazyFamily([3,4,7], lambda i: 2r*i); f
     516            Lazy family (f(i))_{i in [3, 4, 7]}
     517            sage: f == loads(dumps(f))
     518            True
     519        """
    371520        self.set = set
    372521        self.name = name
    373         self.__getitem__ = function
     522        self.function = function
    374523
    375524    def __repr__(self):
     525        """
     526        EXAMPLES:
     527            sage: f = LazyFamily([3,4,7], lambda i: 2*i); f
     528            Lazy family (f(i))_{i in [3, 4, 7]}
     529        """
    376530        return "Lazy family (%s(i))_{i in %s}"%(self.name,self.set)
    377531
    378532    def keys(self):
     533        """
     534        Returns self's keys.
     535
     536        EXAMPLES:
     537            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     538            sage: f.keys()
     539            [3, 4, 7]
     540        """
    379541        return self.set
    380542
    381     def __iter__(self):
    382         for i in self.set.__iter__():
     543    def iterator(self):
     544        """
     545        EXAMPLES:
     546            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     547            sage: [i for i in f]
     548            [6, 8, 14]
     549        """
     550        for i in self.set:
    383551            yield self[i]
    384552
    385     # Should disappear
    386     iterator = __iter__
     553    def __getitem__(self, i):
     554        """       
     555        EXAMPLES:
     556            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     557            sage: f[3]
     558            6
     559           
     560        TESTS:
     561            sage: f[5]
     562            10
     563        """
     564        return self.function(i)
    387565
    388     # Why isn't it sufficient to set self.__getitem__ as above?
    389     def __getitem__(self, i):
    390         return self.__getitem__(i)
     566    def __getstate__(self):
     567        """       
     568        EXAMPLES:
     569            sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     570            sage: d = f.__getstate__()
     571            sage: d['set']
     572            [3, 4, 7]
     573       
     574        """
     575        from sage.misc.fpickle import pickle_function
     576        f = pickle_function(self.function)
     577        return {'set': self.set,
     578                'name': self.name,
     579                'function': f}
     580
     581    def __setstate__(self, d):
     582        """
     583        EXAMPLES:
     584            sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     585            sage: d = f.__getstate__()
     586            sage: f = LazyFamily([4,5,6], lambda i: 2r*i)
     587            sage: f.__setstate__(d)
     588            sage: f.keys()
     589            [3, 4, 7]
     590            sage: f[3]
     591            6
     592        """
     593        from sage.misc.fpickle import unpickle_function
     594        function = unpickle_function(d['function'])
     595        self.__init__(d['set'], function, d['name'])